Merge branch 'develop' into analyzer-plugin

This commit is contained in:
Simon Binder 2019-07-30 14:17:37 +02:00
commit 4e75cee785
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
19 changed files with 693 additions and 469 deletions

View File

@ -19,6 +19,10 @@ abstract class Table {
@visibleForOverriding
String get tableName => null;
/// Whether to append a `WITHOUT ROWID` clause in the `CREATE TABLE`
/// statement.
bool get withoutRowId => false;
/// Override this to specify custom primary keys:
/// ```dart
/// class IngredientInRecipes extends Table {

View File

@ -6,8 +6,6 @@ import 'package:moor/src/runtime/expressions/expression.dart';
/// The [CustomExpression.content] will be written into the query without any
/// modification.
///
/// When this statement appears in a query
///
/// See also:
/// - [currentDate] and [currentDateAndTime], which use a [CustomExpression]
/// internally.

View File

@ -1,4 +1,5 @@
export 'bools.dart' show and, or, not;
export 'custom.dart';
export 'datetimes.dart';
export 'in.dart';
export 'null_check.dart';

View File

@ -109,13 +109,21 @@ class Migrator {
context.buffer.write(')');
}
final constraints = table.asDslTable.customConstraints ?? [];
final dslTable = table.asDslTable;
final constraints = dslTable.customConstraints ?? [];
for (var i = 0; i < constraints.length; i++) {
context.buffer..write(', ')..write(constraints[i]);
}
context.buffer.write(');');
context.buffer.write(')');
// == true because of nullability
if (dslTable.withoutRowId == true) {
context.buffer.write(' WITHOUT ROWID');
}
context.buffer.write(';');
return issueCustomQuery(context.sql, context.boundVariables);
}

View File

@ -0,0 +1,11 @@
import 'package:moor/moor.dart';
part 'custom_tables.g.dart';
@UseMoor(include: {'tables.moor'})
class CustomTablesDb extends _$CustomTablesDb {
CustomTablesDb(QueryExecutor e) : super(e);
@override
int get schemaVersion => 1;
}

View File

@ -0,0 +1,451 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'custom_tables.dart';
// **************************************************************************
// MoorGenerator
// **************************************************************************
// ignore_for_file: unnecessary_brace_in_string_interps
class NoId extends DataClass implements Insertable<NoId> {
final Uint8List payload;
NoId({@required this.payload});
factory NoId.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final uint8ListType = db.typeSystem.forDartType<Uint8List>();
return NoId(
payload: uint8ListType
.mapFromDatabaseResponse(data['${effectivePrefix}payload']),
);
}
factory NoId.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return NoId(
payload: serializer.fromJson<Uint8List>(json['payload']),
);
}
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'payload': serializer.toJson<Uint8List>(payload),
};
}
@override
T createCompanion<T extends UpdateCompanion<NoId>>(bool nullToAbsent) {
return NoIdsCompanion(
payload: payload == null && nullToAbsent
? const Value.absent()
: Value(payload),
) as T;
}
NoId copyWith({Uint8List payload}) => NoId(
payload: payload ?? this.payload,
);
@override
String toString() {
return (StringBuffer('NoId(')..write('payload: $payload')..write(')'))
.toString();
}
@override
int get hashCode => $mrjf(payload.hashCode);
@override
bool operator ==(other) =>
identical(this, other) || (other is NoId && other.payload == payload);
}
class NoIdsCompanion extends UpdateCompanion<NoId> {
final Value<Uint8List> payload;
const NoIdsCompanion({
this.payload = const Value.absent(),
});
}
class NoIds extends Table with TableInfo<NoIds, NoId> {
final GeneratedDatabase _db;
final String _alias;
NoIds(this._db, [this._alias]);
final VerificationMeta _payloadMeta = const VerificationMeta('payload');
GeneratedBlobColumn _payload;
GeneratedBlobColumn get payload => _payload ??= _constructPayload();
GeneratedBlobColumn _constructPayload() {
return GeneratedBlobColumn('payload', $tableName, false,
$customConstraints: 'NOT NULL');
}
@override
List<GeneratedColumn> get $columns => [payload];
@override
NoIds get asDslTable => this;
@override
String get $tableName => _alias ?? 'no_ids';
@override
final String actualTableName = 'no_ids';
@override
VerificationContext validateIntegrity(NoIdsCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.payload.present) {
context.handle(_payloadMeta,
payload.isAcceptableValue(d.payload.value, _payloadMeta));
} else if (payload.isRequired && isInserting) {
context.missing(_payloadMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
@override
NoId map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return NoId.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(NoIdsCompanion d) {
final map = <String, Variable>{};
if (d.payload.present) {
map['payload'] = Variable<Uint8List, BlobType>(d.payload.value);
}
return map;
}
@override
NoIds createAlias(String alias) {
return NoIds(_db, alias);
}
@override
final bool withoutRowId = true;
}
class WithDefault extends DataClass implements Insertable<WithDefault> {
final String a;
final int b;
WithDefault({this.a, this.b});
factory WithDefault.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final stringType = db.typeSystem.forDartType<String>();
final intType = db.typeSystem.forDartType<int>();
return WithDefault(
a: stringType.mapFromDatabaseResponse(data['${effectivePrefix}a']),
b: intType.mapFromDatabaseResponse(data['${effectivePrefix}b']),
);
}
factory WithDefault.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return WithDefault(
a: serializer.fromJson<String>(json['a']),
b: serializer.fromJson<int>(json['b']),
);
}
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'a': serializer.toJson<String>(a),
'b': serializer.toJson<int>(b),
};
}
@override
T createCompanion<T extends UpdateCompanion<WithDefault>>(bool nullToAbsent) {
return WithDefaultsCompanion(
a: a == null && nullToAbsent ? const Value.absent() : Value(a),
b: b == null && nullToAbsent ? const Value.absent() : Value(b),
) as T;
}
WithDefault copyWith({String a, int b}) => WithDefault(
a: a ?? this.a,
b: b ?? this.b,
);
@override
String toString() {
return (StringBuffer('WithDefault(')
..write('a: $a, ')
..write('b: $b')
..write(')'))
.toString();
}
@override
int get hashCode => $mrjf($mrjc(a.hashCode, b.hashCode));
@override
bool operator ==(other) =>
identical(this, other) ||
(other is WithDefault && other.a == a && other.b == b);
}
class WithDefaultsCompanion extends UpdateCompanion<WithDefault> {
final Value<String> a;
final Value<int> b;
const WithDefaultsCompanion({
this.a = const Value.absent(),
this.b = const Value.absent(),
});
}
class WithDefaults extends Table with TableInfo<WithDefaults, WithDefault> {
final GeneratedDatabase _db;
final String _alias;
WithDefaults(this._db, [this._alias]);
final VerificationMeta _aMeta = const VerificationMeta('a');
GeneratedTextColumn _a;
GeneratedTextColumn get a => _a ??= _constructA();
GeneratedTextColumn _constructA() {
return GeneratedTextColumn('a', $tableName, true,
$customConstraints: 'DEFAULT \'something\'',
defaultValue:
const CustomExpression<String, StringType>('\'something\''));
}
final VerificationMeta _bMeta = const VerificationMeta('b');
GeneratedIntColumn _b;
GeneratedIntColumn get b => _b ??= _constructB();
GeneratedIntColumn _constructB() {
return GeneratedIntColumn('b', $tableName, true,
$customConstraints: 'UNIQUE');
}
@override
List<GeneratedColumn> get $columns => [a, b];
@override
WithDefaults get asDslTable => this;
@override
String get $tableName => _alias ?? 'with_defaults';
@override
final String actualTableName = 'with_defaults';
@override
VerificationContext validateIntegrity(WithDefaultsCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.a.present) {
context.handle(_aMeta, a.isAcceptableValue(d.a.value, _aMeta));
} else if (a.isRequired && isInserting) {
context.missing(_aMeta);
}
if (d.b.present) {
context.handle(_bMeta, b.isAcceptableValue(d.b.value, _bMeta));
} else if (b.isRequired && isInserting) {
context.missing(_bMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
@override
WithDefault map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return WithDefault.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(WithDefaultsCompanion d) {
final map = <String, Variable>{};
if (d.a.present) {
map['a'] = Variable<String, StringType>(d.a.value);
}
if (d.b.present) {
map['b'] = Variable<int, IntType>(d.b.value);
}
return map;
}
@override
WithDefaults createAlias(String alias) {
return WithDefaults(_db, alias);
}
}
class WithConstraint extends DataClass implements Insertable<WithConstraint> {
final String a;
final int b;
final double c;
WithConstraint({this.a, @required this.b, this.c});
factory WithConstraint.fromData(
Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final stringType = db.typeSystem.forDartType<String>();
final intType = db.typeSystem.forDartType<int>();
final doubleType = db.typeSystem.forDartType<double>();
return WithConstraint(
a: stringType.mapFromDatabaseResponse(data['${effectivePrefix}a']),
b: intType.mapFromDatabaseResponse(data['${effectivePrefix}b']),
c: doubleType.mapFromDatabaseResponse(data['${effectivePrefix}c']),
);
}
factory WithConstraint.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return WithConstraint(
a: serializer.fromJson<String>(json['a']),
b: serializer.fromJson<int>(json['b']),
c: serializer.fromJson<double>(json['c']),
);
}
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'a': serializer.toJson<String>(a),
'b': serializer.toJson<int>(b),
'c': serializer.toJson<double>(c),
};
}
@override
T createCompanion<T extends UpdateCompanion<WithConstraint>>(
bool nullToAbsent) {
return WithConstraintsCompanion(
a: a == null && nullToAbsent ? const Value.absent() : Value(a),
b: b == null && nullToAbsent ? const Value.absent() : Value(b),
c: c == null && nullToAbsent ? const Value.absent() : Value(c),
) as T;
}
WithConstraint copyWith({String a, int b, double c}) => WithConstraint(
a: a ?? this.a,
b: b ?? this.b,
c: c ?? this.c,
);
@override
String toString() {
return (StringBuffer('WithConstraint(')
..write('a: $a, ')
..write('b: $b, ')
..write('c: $c')
..write(')'))
.toString();
}
@override
int get hashCode => $mrjf($mrjc(a.hashCode, $mrjc(b.hashCode, c.hashCode)));
@override
bool operator ==(other) =>
identical(this, other) ||
(other is WithConstraint && other.a == a && other.b == b && other.c == c);
}
class WithConstraintsCompanion extends UpdateCompanion<WithConstraint> {
final Value<String> a;
final Value<int> b;
final Value<double> c;
const WithConstraintsCompanion({
this.a = const Value.absent(),
this.b = const Value.absent(),
this.c = const Value.absent(),
});
}
class WithConstraints extends Table
with TableInfo<WithConstraints, WithConstraint> {
final GeneratedDatabase _db;
final String _alias;
WithConstraints(this._db, [this._alias]);
final VerificationMeta _aMeta = const VerificationMeta('a');
GeneratedTextColumn _a;
GeneratedTextColumn get a => _a ??= _constructA();
GeneratedTextColumn _constructA() {
return GeneratedTextColumn('a', $tableName, true, $customConstraints: '');
}
final VerificationMeta _bMeta = const VerificationMeta('b');
GeneratedIntColumn _b;
GeneratedIntColumn get b => _b ??= _constructB();
GeneratedIntColumn _constructB() {
return GeneratedIntColumn('b', $tableName, false,
$customConstraints: 'NOT NULL');
}
final VerificationMeta _cMeta = const VerificationMeta('c');
GeneratedRealColumn _c;
GeneratedRealColumn get c => _c ??= _constructC();
GeneratedRealColumn _constructC() {
return GeneratedRealColumn('c', $tableName, true, $customConstraints: '');
}
@override
List<GeneratedColumn> get $columns => [a, b, c];
@override
WithConstraints get asDslTable => this;
@override
String get $tableName => _alias ?? 'with_constraints';
@override
final String actualTableName = 'with_constraints';
@override
VerificationContext validateIntegrity(WithConstraintsCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.a.present) {
context.handle(_aMeta, a.isAcceptableValue(d.a.value, _aMeta));
} else if (a.isRequired && isInserting) {
context.missing(_aMeta);
}
if (d.b.present) {
context.handle(_bMeta, b.isAcceptableValue(d.b.value, _bMeta));
} else if (b.isRequired && isInserting) {
context.missing(_bMeta);
}
if (d.c.present) {
context.handle(_cMeta, c.isAcceptableValue(d.c.value, _cMeta));
} else if (c.isRequired && isInserting) {
context.missing(_cMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
@override
WithConstraint map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return WithConstraint.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(WithConstraintsCompanion d) {
final map = <String, Variable>{};
if (d.a.present) {
map['a'] = Variable<String, StringType>(d.a.value);
}
if (d.b.present) {
map['b'] = Variable<int, IntType>(d.b.value);
}
if (d.c.present) {
map['c'] = Variable<double, RealType>(d.c.value);
}
return map;
}
@override
WithConstraints createAlias(String alias) {
return WithConstraints(_db, alias);
}
@override
final List<String> customConstraints = const [
'FOREIGN KEY (a, b) REFERENCES with_defaults (a, b)'
];
}
abstract class _$CustomTablesDb extends GeneratedDatabase {
_$CustomTablesDb(QueryExecutor e)
: super(const SqlTypeSystem.withDefaults(), e);
NoIds _noIds;
NoIds get noIds => _noIds ??= NoIds(this);
WithDefaults _withDefaults;
WithDefaults get withDefaults => _withDefaults ??= WithDefaults(this);
WithConstraints _withConstraints;
WithConstraints get withConstraints =>
_withConstraints ??= WithConstraints(this);
@override
List<TableInfo> get allTables => [noIds, withDefaults, withConstraints];
}

View File

@ -0,0 +1,16 @@
CREATE TABLE no_ids (
payload BLOB NOT NULL
) WITHOUT ROWID;
CREATE TABLE with_defaults (
a TEXT DEFAULT 'something',
b INT UNIQUE
)
CREATE TABLE with_constraints (
a TEXT,
b INT NOT NULL,
c FLOAT(10, 2),
FOREIGN KEY (a, b) REFERENCES with_defaults (a, b)
)

View File

@ -1,10 +0,0 @@
CREATE TABLE states (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
);
CREATE TABLE experiments (
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
description TEXT NOT NULL,
state INT REFERENCES states(id) ON UPDATE CASCADE ON DELETE SET NULL
)

View File

@ -88,7 +88,6 @@ class CustomConverter extends TypeConverter<MyCustomObject, String> {
PureDefaults,
],
daos: [SomeDao],
include: {'test.moor'},
queries: {
'allTodosWithCategory': 'SELECT t.*, c.id as catId, c."desc" as catDesc '
'FROM todos t INNER JOIN categories c ON c.id = t.category',

View File

@ -1187,325 +1187,6 @@ class $PureDefaultsTable extends PureDefaults
}
}
class State extends DataClass implements Insertable<State> {
final int id;
final String name;
State({@required this.id, @required this.name});
factory State.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>();
final stringType = db.typeSystem.forDartType<String>();
return State(
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
name: stringType.mapFromDatabaseResponse(data['${effectivePrefix}name']),
);
}
factory State.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return State(
id: serializer.fromJson<int>(json['id']),
name: serializer.fromJson<String>(json['name']),
);
}
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': serializer.toJson<int>(id),
'name': serializer.toJson<String>(name),
};
}
@override
T createCompanion<T extends UpdateCompanion<State>>(bool nullToAbsent) {
return StatesCompanion(
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
name: name == null && nullToAbsent ? const Value.absent() : Value(name),
) as T;
}
State copyWith({int id, String name}) => State(
id: id ?? this.id,
name: name ?? this.name,
);
@override
String toString() {
return (StringBuffer('State(')
..write('id: $id, ')
..write('name: $name')
..write(')'))
.toString();
}
@override
int get hashCode => $mrjf($mrjc(id.hashCode, name.hashCode));
@override
bool operator ==(other) =>
identical(this, other) ||
(other is State && other.id == id && other.name == name);
}
class StatesCompanion extends UpdateCompanion<State> {
final Value<int> id;
final Value<String> name;
const StatesCompanion({
this.id = const Value.absent(),
this.name = const Value.absent(),
});
}
class States extends Table with TableInfo<States, State> {
final GeneratedDatabase _db;
final String _alias;
States(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id;
GeneratedIntColumn get id => _id ??= _constructId();
GeneratedIntColumn _constructId() {
return GeneratedIntColumn('id', $tableName, false,
hasAutoIncrement: true,
$customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT');
}
final VerificationMeta _nameMeta = const VerificationMeta('name');
GeneratedTextColumn _name;
GeneratedTextColumn get name => _name ??= _constructName();
GeneratedTextColumn _constructName() {
return GeneratedTextColumn('name', $tableName, false,
$customConstraints: 'NOT NULL');
}
@override
List<GeneratedColumn> get $columns => [id, name];
@override
States get asDslTable => this;
@override
String get $tableName => _alias ?? 'states';
@override
final String actualTableName = 'states';
@override
VerificationContext validateIntegrity(StatesCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.id.present) {
context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta));
} else if (id.isRequired && isInserting) {
context.missing(_idMeta);
}
if (d.name.present) {
context.handle(
_nameMeta, name.isAcceptableValue(d.name.value, _nameMeta));
} else if (name.isRequired && isInserting) {
context.missing(_nameMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
State map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return State.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(StatesCompanion d) {
final map = <String, Variable>{};
if (d.id.present) {
map['id'] = Variable<int, IntType>(d.id.value);
}
if (d.name.present) {
map['name'] = Variable<String, StringType>(d.name.value);
}
return map;
}
@override
States createAlias(String alias) {
return States(_db, alias);
}
}
class Experiment extends DataClass implements Insertable<Experiment> {
final int id;
final String description;
final int state;
Experiment({@required this.id, @required this.description, this.state});
factory Experiment.fromData(Map<String, dynamic> data, GeneratedDatabase db,
{String prefix}) {
final effectivePrefix = prefix ?? '';
final intType = db.typeSystem.forDartType<int>();
final stringType = db.typeSystem.forDartType<String>();
return Experiment(
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
description: stringType
.mapFromDatabaseResponse(data['${effectivePrefix}description']),
state: intType.mapFromDatabaseResponse(data['${effectivePrefix}state']),
);
}
factory Experiment.fromJson(Map<String, dynamic> json,
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return Experiment(
id: serializer.fromJson<int>(json['id']),
description: serializer.fromJson<String>(json['description']),
state: serializer.fromJson<int>(json['state']),
);
}
@override
Map<String, dynamic> toJson(
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
return {
'id': serializer.toJson<int>(id),
'description': serializer.toJson<String>(description),
'state': serializer.toJson<int>(state),
};
}
@override
T createCompanion<T extends UpdateCompanion<Experiment>>(bool nullToAbsent) {
return ExperimentsCompanion(
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
description: description == null && nullToAbsent
? const Value.absent()
: Value(description),
state:
state == null && nullToAbsent ? const Value.absent() : Value(state),
) as T;
}
Experiment copyWith({int id, String description, int state}) => Experiment(
id: id ?? this.id,
description: description ?? this.description,
state: state ?? this.state,
);
@override
String toString() {
return (StringBuffer('Experiment(')
..write('id: $id, ')
..write('description: $description, ')
..write('state: $state')
..write(')'))
.toString();
}
@override
int get hashCode =>
$mrjf($mrjc(id.hashCode, $mrjc(description.hashCode, state.hashCode)));
@override
bool operator ==(other) =>
identical(this, other) ||
(other is Experiment &&
other.id == id &&
other.description == description &&
other.state == state);
}
class ExperimentsCompanion extends UpdateCompanion<Experiment> {
final Value<int> id;
final Value<String> description;
final Value<int> state;
const ExperimentsCompanion({
this.id = const Value.absent(),
this.description = const Value.absent(),
this.state = const Value.absent(),
});
}
class Experiments extends Table with TableInfo<Experiments, Experiment> {
final GeneratedDatabase _db;
final String _alias;
Experiments(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id;
GeneratedIntColumn get id => _id ??= _constructId();
GeneratedIntColumn _constructId() {
return GeneratedIntColumn('id', $tableName, false,
hasAutoIncrement: true,
$customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT');
}
final VerificationMeta _descriptionMeta =
const VerificationMeta('description');
GeneratedTextColumn _description;
GeneratedTextColumn get description =>
_description ??= _constructDescription();
GeneratedTextColumn _constructDescription() {
return GeneratedTextColumn('description', $tableName, false,
$customConstraints: 'NOT NULL');
}
final VerificationMeta _stateMeta = const VerificationMeta('state');
GeneratedIntColumn _state;
GeneratedIntColumn get state => _state ??= _constructState();
GeneratedIntColumn _constructState() {
return GeneratedIntColumn('state', $tableName, true,
$customConstraints:
'REFERENCES states(id) ON UPDATE CASCADE ON DELETE SET NULL');
}
@override
List<GeneratedColumn> get $columns => [id, description, state];
@override
Experiments get asDslTable => this;
@override
String get $tableName => _alias ?? 'experiments';
@override
final String actualTableName = 'experiments';
@override
VerificationContext validateIntegrity(ExperimentsCompanion d,
{bool isInserting = false}) {
final context = VerificationContext();
if (d.id.present) {
context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta));
} else if (id.isRequired && isInserting) {
context.missing(_idMeta);
}
if (d.description.present) {
context.handle(_descriptionMeta,
description.isAcceptableValue(d.description.value, _descriptionMeta));
} else if (description.isRequired && isInserting) {
context.missing(_descriptionMeta);
}
if (d.state.present) {
context.handle(
_stateMeta, state.isAcceptableValue(d.state.value, _stateMeta));
} else if (state.isRequired && isInserting) {
context.missing(_stateMeta);
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
Experiment map(Map<String, dynamic> data, {String tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
return Experiment.fromData(data, _db, prefix: effectivePrefix);
}
@override
Map<String, Variable> entityToSql(ExperimentsCompanion d) {
final map = <String, Variable>{};
if (d.id.present) {
map['id'] = Variable<int, IntType>(d.id.value);
}
if (d.description.present) {
map['description'] = Variable<String, StringType>(d.description.value);
}
if (d.state.present) {
map['state'] = Variable<int, IntType>(d.state.value);
}
return map;
}
@override
Experiments createAlias(String alias) {
return Experiments(_db, alias);
}
}
class AllTodosWithCategoryResult {
final int id;
final String title;
@ -1548,10 +1229,6 @@ abstract class _$TodoDb extends GeneratedDatabase {
$PureDefaultsTable _pureDefaults;
$PureDefaultsTable get pureDefaults =>
_pureDefaults ??= $PureDefaultsTable(this);
States _states;
States get states => _states ??= States(this);
Experiments _experiments;
Experiments get experiments => _experiments ??= Experiments(this);
SomeDao _someDao;
SomeDao get someDao => _someDao ??= SomeDao(this as TodoDb);
AllTodosWithCategoryResult _rowToAllTodosWithCategoryResult(QueryRow row) {
@ -1690,9 +1367,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
users,
sharedTodos,
tableWithoutPK,
pureDefaults,
states,
experiments
pureDefaults
];
}

View File

@ -1,4 +1,3 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:built_value/built_value.dart';
import 'package:moor_generator/src/model/used_type_converter.dart';
@ -61,6 +60,15 @@ const Map<ColumnType, String> createVariable = {
ColumnType.real: 'Variable.withReal',
};
const Map<ColumnType, String> sqlTypes = {
ColumnType.boolean: 'BoolType',
ColumnType.text: 'StringType',
ColumnType.integer: 'IntType',
ColumnType.datetime: 'DateTimeType',
ColumnType.blob: 'BlobType',
ColumnType.real: 'RealType',
};
/// A column, as specified by a getter in a table.
class SpecifiedColumn {
/// The getter name of this column in the table class. It will also be used
@ -95,10 +103,9 @@ class SpecifiedColumn {
/// default ones.
final String customConstraints;
/// If a default expression has been provided as the argument of
/// ColumnBuilder.withDefault, contains the Dart code that references that
/// expression.
final Expression defaultArgument;
/// Dart code that generates the default expression for this column, or null
/// if there is no default expression.
final String defaultArgument;
/// The [UsedTypeConverter], if one has been set on this column.
final UsedTypeConverter typeConverter;
@ -142,14 +149,7 @@ class SpecifiedColumn {
/// The class inside the moor library that represents the same sql type as
/// this column.
String get sqlTypeName => const {
ColumnType.boolean: 'BoolType',
ColumnType.text: 'StringType',
ColumnType.integer: 'IntType',
ColumnType.datetime: 'DateTimeType',
ColumnType.blob: 'BlobType',
ColumnType.real: 'RealType',
}[type];
String get sqlTypeName => sqlTypes[type];
const SpecifiedColumn({
this.type,

View File

@ -48,13 +48,23 @@ class SpecifiedTable {
/// not been defined that way.
final Set<SpecifiedColumn> primaryKey;
/// When non-null, the generated table class will override the `withoutRowId`
/// getter on the table class with this value.
final bool overrideWithoutRowId;
/// When non-null, the generated table class will override the
/// `customConstraints` getter in the table class with this value.
final List<String> overrideTableConstraints;
const SpecifiedTable(
{this.fromClass,
this.columns,
this.sqlName,
this.dartTypeName,
this.primaryKey,
String overriddenName})
String overriddenName,
this.overrideWithoutRowId,
this.overrideTableConstraints})
: _overriddenName = overriddenName;
/// Finds all type converters used in this tables.

View File

@ -199,7 +199,7 @@ class ColumnParser extends ParserBase {
customConstraints: foundCustomConstraint,
nullable: nullable,
features: foundFeatures,
defaultArgument: foundDefaultExpression,
defaultArgument: foundDefaultExpression?.toSource(),
typeConverter: converter);
}

View File

@ -2,6 +2,7 @@ import 'package:moor_generator/src/model/specified_column.dart';
import 'package:moor_generator/src/model/specified_table.dart';
import 'package:moor_generator/src/parser/sql/type_mapping.dart';
import 'package:moor_generator/src/utils/names.dart';
import 'package:moor_generator/src/utils/string_escaper.dart';
import 'package:recase/recase.dart';
import 'package:sqlparser/sqlparser.dart';
@ -45,6 +46,8 @@ class CreateTable {
final sqlName = column.name;
final dartName = ReCase(sqlName).camelCase;
final constraintWriter = StringBuffer();
final moorType = mapper.resolvedToMoor(column.type);
String defaultValue;
for (var constraint in column.constraints) {
if (constraint is PrimaryKeyColumn) {
@ -53,6 +56,13 @@ class CreateTable {
features.add(AutoIncrement());
}
}
if (constraint is Default) {
final dartType = dartTypeNames[moorType];
final sqlType = sqlTypes[moorType];
final expressionName = 'const CustomExpression<$dartType, $sqlType>';
final sqlDefault = constraint.expression.span.text;
defaultValue = '$expressionName(${asDartLiteral(sqlDefault)})';
}
if (constraintWriter.isNotEmpty) {
constraintWriter.write(' ');
@ -61,13 +71,14 @@ class CreateTable {
}
final parsed = SpecifiedColumn(
type: mapper.resolvedToMoor(column.type),
type: moorType,
nullable: column.type.nullable,
dartGetterName: dartName,
name: ColumnName.implicitly(sqlName),
declaredAsPrimaryKey: isPrimaryKey,
features: features,
customConstraints: constraintWriter.toString(),
defaultArgument: defaultValue,
);
foundColumns[column.name] = parsed;
@ -79,7 +90,8 @@ class CreateTable {
final tableName = table.name;
final dartTableName = ReCase(tableName).pascalCase;
// todo include WITHOUT ROWID clause and table constraints
final constraints = table.tableConstraints.map((c) => c.span.text).toList();
return SpecifiedTable(
fromClass: null,
columns: foundColumns.values.toList(),
@ -87,6 +99,8 @@ class CreateTable {
dartTypeName: dataClassNameForClassName(dartTableName),
overriddenName: ReCase(tableName).pascalCase,
primaryKey: primaryKey,
overrideWithoutRowId: table.withoutRowId ? true : null,
overrideTableConstraints: constraints.isNotEmpty ? constraints : null,
);
}

View File

@ -13,7 +13,8 @@ class UseDaoParser {
Future<SpecifiedDao> parseDao(
ClassElement element, ConstantReader annotation) async {
final tableTypes =
annotation.peek('tables').listValue.map((obj) => obj.toTypeValue());
annotation.peek('tables')?.listValue?.map((obj) => obj.toTypeValue()) ??
[];
final queryStrings = annotation.peek('queries')?.mapValue ?? {};
final includes = annotation

View File

@ -15,7 +15,8 @@ class UseMoorParser {
ClassElement element, ConstantReader annotation) async {
// the types declared in UseMoor.tables
final tableTypes =
annotation.peek('tables').listValue.map((obj) => obj.toTypeValue());
annotation.peek('tables')?.listValue?.map((obj) => obj.toTypeValue()) ??
[];
final queryStrings = annotation.peek('queries')?.mapValue ?? {};
final includes = annotation
.read('include')

View File

@ -63,6 +63,7 @@ class TableWriter {
_writeAliasGenerator(buffer);
_writeConvertersAsStaticFields(buffer);
_overrideFieldsIfNeeded(buffer);
// close class
buffer.write('}');
@ -148,7 +149,7 @@ class TableWriter {
}
if (column.defaultArgument != null) {
additionalParams['defaultValue'] = column.defaultArgument.toSource();
additionalParams['defaultValue'] = column.defaultArgument;
}
expressionBuffer
@ -259,4 +260,20 @@ class TableWriter {
..write('return $typeName(_db, alias);')
..write('}');
}
void _overrideFieldsIfNeeded(StringBuffer buffer) {
if (table.overrideWithoutRowId != null) {
final value = table.overrideWithoutRowId ? 'true' : 'false';
buffer..write('@override\n')..write('final bool withoutRowId = $value;');
}
if (table.overrideTableConstraints != null) {
final value =
table.overrideTableConstraints.map(asDartLiteral).join(', ');
buffer
..write('@override\n')
..write('final List<String> customConstraints = const [$value];');
}
}
}

View File

@ -1,12 +1,5 @@
part of 'parser.dart';
const _tokensInTypename = [
TokenType.identifier,
TokenType.leftParen,
TokenType.rightParen,
TokenType.numberLiteral,
];
mixin SchemaParser on ParserBase {
CreateTableStatement _createTable() {
if (!_matchOne(TokenType.create)) return null;
@ -70,14 +63,7 @@ mixin SchemaParser on ParserBase {
final name = _consume(TokenType.identifier, 'Expected a column name')
as IdentifierToken;
final typeNameBuilder = StringBuffer();
while (_match(_tokensInTypename)) {
typeNameBuilder.write(_previous.lexeme);
}
final typeName =
typeNameBuilder.isEmpty ? null : typeNameBuilder.toString();
final typeName = _typeName();
final constraints = <ColumnConstraint>[];
ColumnConstraint constraint;
while ((constraint = _columnConstraint(orNull: true)) != null) {
@ -91,6 +77,33 @@ mixin SchemaParser on ParserBase {
)..setSpan(name, _previous);
}
String _typeName() {
// sqlite doesn't really define what a type name is and has very loose rules
// at turning them into a type affinity. We support this pattern:
// typename = identifier [ "(" { identifier | comma | number_literal } ")" ]
if (!_matchOne(TokenType.identifier)) return null;
final typeNameBuilder = StringBuffer(_previous.lexeme);
if (_matchOne(TokenType.leftParen)) {
typeNameBuilder.write('(');
const inBrackets = [
TokenType.identifier,
TokenType.comma,
TokenType.numberLiteral
];
while (_match(inBrackets)) {
typeNameBuilder..write(' ')..write(_previous.lexeme);
}
_consume(TokenType.rightParen,
'Expected closing paranthesis to finish type name');
}
return typeNameBuilder.toString();
}
ColumnConstraint _columnConstraint({bool orNull = false}) {
final first = _peek;
@ -127,7 +140,7 @@ mixin SchemaParser on ParserBase {
// when not a literal, expect an expression in parentheses
expr ??= _expressionInParentheses();
return Default(resolvedName, expr);
return Default(resolvedName, expr)..setSpan(first, _previous);
}
if (_matchOne(TokenType.collate)) {
final collation = _consumeIdentifier('Expected the collation name');

View File

@ -1,103 +1,118 @@
import 'package:sqlparser/sqlparser.dart';
import 'package:sqlparser/src/ast/ast.dart';
import 'package:test_core/test_core.dart';
import '../common_data.dart';
import 'utils.dart';
void main() {
testStatement(
createTableStmt,
CreateTableStatement(
tableName: 'users',
ifNotExists: true,
withoutRowId: false,
columns: [
ColumnDefinition(
columnName: 'id',
typeName: 'INT',
constraints: [
NotNull(null),
PrimaryKeyColumn(
null,
autoIncrement: true,
onConflict: ConflictClause.rollback,
mode: OrderingMode.descending,
),
],
),
ColumnDefinition(
columnName: 'email',
typeName: 'VARCHAR',
constraints: [
NotNull(null),
UniqueColumn(null, ConflictClause.abort),
],
),
ColumnDefinition(
columnName: 'score',
typeName: 'INT',
constraints: [
NotNull('score set'),
Default(null, NumericLiteral(420, token(TokenType.numberLiteral))),
CheckColumn(
null,
BinaryExpression(
Reference(columnName: 'score'),
token(TokenType.more),
NumericLiteral(
0,
token(TokenType.numberLiteral),
test('parsers simple create table statements', () {
testStatement(
'CREATE TABLE my_tbl (a INT, b TEXT)',
CreateTableStatement(tableName: 'my_tbl', columns: [
ColumnDefinition(columnName: 'a', typeName: 'INT'),
ColumnDefinition(columnName: 'b', typeName: 'TEXT'),
]),
);
});
test('parses complex CREATE TABLE statements', () {
testStatement(
createTableStmt,
CreateTableStatement(
tableName: 'users',
ifNotExists: true,
withoutRowId: false,
columns: [
ColumnDefinition(
columnName: 'id',
typeName: 'INT',
constraints: [
NotNull(null),
PrimaryKeyColumn(
null,
autoIncrement: true,
onConflict: ConflictClause.rollback,
mode: OrderingMode.descending,
),
],
),
ColumnDefinition(
columnName: 'email',
typeName: 'VARCHAR',
constraints: [
NotNull(null),
UniqueColumn(null, ConflictClause.abort),
],
),
ColumnDefinition(
columnName: 'score',
typeName: 'INT',
constraints: [
NotNull('score set'),
Default(
null, NumericLiteral(420, token(TokenType.numberLiteral))),
CheckColumn(
null,
BinaryExpression(
Reference(columnName: 'score'),
token(TokenType.more),
NumericLiteral(
0,
token(TokenType.numberLiteral),
),
),
),
),
],
),
ColumnDefinition(
columnName: 'display_name',
typeName: 'VARCHAR',
constraints: [
CollateConstraint(
null,
'BINARY',
),
ForeignKeyColumnConstraint(
null,
ForeignKeyClause(
foreignTable: TableReference('some', null),
columnNames: [Reference(columnName: 'thing')],
onUpdate: ReferenceAction.cascade,
onDelete: ReferenceAction.setNull,
),
),
],
)
],
tableConstraints: [
KeyClause(
null,
isPrimaryKey: false,
indexedColumns: [
Reference(columnName: 'score'),
Reference(columnName: 'display_name'),
],
onConflict: ConflictClause.abort,
),
ForeignKeyTableConstraint(
null,
columns: [
Reference(columnName: 'id'),
Reference(columnName: 'email'),
],
clause: ForeignKeyClause(
foreignTable: TableReference('another', null),
columnNames: [
Reference(columnName: 'a'),
Reference(columnName: 'b'),
],
onDelete: ReferenceAction.noAction,
onUpdate: ReferenceAction.restrict,
),
)
],
),
);
ColumnDefinition(
columnName: 'display_name',
typeName: 'VARCHAR',
constraints: [
CollateConstraint(
null,
'BINARY',
),
ForeignKeyColumnConstraint(
null,
ForeignKeyClause(
foreignTable: TableReference('some', null),
columnNames: [Reference(columnName: 'thing')],
onUpdate: ReferenceAction.cascade,
onDelete: ReferenceAction.setNull,
),
),
],
)
],
tableConstraints: [
KeyClause(
null,
isPrimaryKey: false,
indexedColumns: [
Reference(columnName: 'score'),
Reference(columnName: 'display_name'),
],
onConflict: ConflictClause.abort,
),
ForeignKeyTableConstraint(
null,
columns: [
Reference(columnName: 'id'),
Reference(columnName: 'email'),
],
clause: ForeignKeyClause(
foreignTable: TableReference('another', null),
columnNames: [
Reference(columnName: 'a'),
Reference(columnName: 'b'),
],
onDelete: ReferenceAction.noAction,
onUpdate: ReferenceAction.restrict,
),
)
],
),
);
});
}