From 5df5e3cacc4a26b5a05923d574426e9ec7672aff Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 30 Jul 2019 09:35:19 +0200 Subject: [PATCH 1/4] Fix typename parsing, set span on default constraint --- sqlparser/lib/src/reader/parser/schema.dart | 45 +++-- sqlparser/test/parser/create_table_test.dart | 199 ++++++++++--------- 2 files changed, 136 insertions(+), 108 deletions(-) diff --git a/sqlparser/lib/src/reader/parser/schema.dart b/sqlparser/lib/src/reader/parser/schema.dart index 78ac76e7..7b429ff0 100644 --- a/sqlparser/lib/src/reader/parser/schema.dart +++ b/sqlparser/lib/src/reader/parser/schema.dart @@ -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 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'); diff --git a/sqlparser/test/parser/create_table_test.dart b/sqlparser/test/parser/create_table_test.dart index 57cf5295..c80fbad2 100644 --- a/sqlparser/test/parser/create_table_test.dart +++ b/sqlparser/test/parser/create_table_test.dart @@ -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, + ), + ) + ], + ), + ); + }); } From aa3706ae9d832b848e8da6c0d8ef02bb1a4855b7 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 30 Jul 2019 10:13:47 +0200 Subject: [PATCH 2/4] Support table constraints in CREATE TABLE --- moor/lib/src/dsl/table.dart | 4 + moor/lib/src/runtime/expressions/custom.dart | 2 - moor/lib/src/runtime/migration.dart | 12 +- moor/test/data/tables/custom_tables.dart | 11 + moor/test/data/tables/custom_tables.g.dart | 450 ++++++++++++++++++ moor/test/data/tables/tables.moor | 16 + moor/test/data/tables/test.moor | 10 - moor/test/data/tables/todos.dart | 1 - moor/test/data/tables/todos.g.dart | 327 +------------ .../lib/src/model/specified_table.dart | 12 +- .../lib/src/parser/moor/parsed_moor_file.dart | 5 +- .../lib/src/parser/use_dao_parser.dart | 3 +- .../lib/src/parser/use_moor_parser.dart | 3 +- .../lib/src/writer/table_writer.dart | 17 + 14 files changed, 528 insertions(+), 345 deletions(-) create mode 100644 moor/test/data/tables/custom_tables.dart create mode 100644 moor/test/data/tables/custom_tables.g.dart create mode 100644 moor/test/data/tables/tables.moor delete mode 100644 moor/test/data/tables/test.moor diff --git a/moor/lib/src/dsl/table.dart b/moor/lib/src/dsl/table.dart index 1f9a85ab..c405cf43 100644 --- a/moor/lib/src/dsl/table.dart +++ b/moor/lib/src/dsl/table.dart @@ -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 { diff --git a/moor/lib/src/runtime/expressions/custom.dart b/moor/lib/src/runtime/expressions/custom.dart index 36abefbe..f25d00e1 100644 --- a/moor/lib/src/runtime/expressions/custom.dart +++ b/moor/lib/src/runtime/expressions/custom.dart @@ -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. diff --git a/moor/lib/src/runtime/migration.dart b/moor/lib/src/runtime/migration.dart index 17f4c82b..6c676e62 100644 --- a/moor/lib/src/runtime/migration.dart +++ b/moor/lib/src/runtime/migration.dart @@ -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); } diff --git a/moor/test/data/tables/custom_tables.dart b/moor/test/data/tables/custom_tables.dart new file mode 100644 index 00000000..027b1735 --- /dev/null +++ b/moor/test/data/tables/custom_tables.dart @@ -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; +} diff --git a/moor/test/data/tables/custom_tables.g.dart b/moor/test/data/tables/custom_tables.g.dart new file mode 100644 index 00000000..2e56353c --- /dev/null +++ b/moor/test/data/tables/custom_tables.g.dart @@ -0,0 +1,450 @@ +// 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 { + final Uint8List payload; + NoId({@required this.payload}); + factory NoId.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final uint8ListType = db.typeSystem.forDartType(); + return NoId( + payload: uint8ListType + .mapFromDatabaseResponse(data['${effectivePrefix}payload']), + ); + } + factory NoId.fromJson(Map json, + {ValueSerializer serializer = const ValueSerializer.defaults()}) { + return NoId( + payload: serializer.fromJson(json['payload']), + ); + } + @override + Map toJson( + {ValueSerializer serializer = const ValueSerializer.defaults()}) { + return { + 'payload': serializer.toJson(payload), + }; + } + + @override + T createCompanion>(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 { + final Value payload; + const NoIdsCompanion({ + this.payload = const Value.absent(), + }); +} + +class NoIds extends Table with TableInfo { + 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 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 get $primaryKey => {}; + @override + NoId map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return NoId.fromData(data, _db, prefix: effectivePrefix); + } + + @override + Map entityToSql(NoIdsCompanion d) { + final map = {}; + if (d.payload.present) { + map['payload'] = Variable(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 { + final String a; + final int b; + WithDefault({this.a, this.b}); + factory WithDefault.fromData(Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + return WithDefault( + a: stringType.mapFromDatabaseResponse(data['${effectivePrefix}a']), + b: intType.mapFromDatabaseResponse(data['${effectivePrefix}b']), + ); + } + factory WithDefault.fromJson(Map json, + {ValueSerializer serializer = const ValueSerializer.defaults()}) { + return WithDefault( + a: serializer.fromJson(json['a']), + b: serializer.fromJson(json['b']), + ); + } + @override + Map toJson( + {ValueSerializer serializer = const ValueSerializer.defaults()}) { + return { + 'a': serializer.toJson(a), + 'b': serializer.toJson(b), + }; + } + + @override + T createCompanion>(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 { + final Value a; + final Value b; + const WithDefaultsCompanion({ + this.a = const Value.absent(), + this.b = const Value.absent(), + }); +} + +class WithDefaults extends Table with TableInfo { + 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\''); + } + + final VerificationMeta _bMeta = const VerificationMeta('b'); + GeneratedIntColumn _b; + GeneratedIntColumn get b => _b ??= _constructB(); + GeneratedIntColumn _constructB() { + return GeneratedIntColumn('b', $tableName, true, + $customConstraints: 'UNIQUE'); + } + + @override + List 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 get $primaryKey => {}; + @override + WithDefault map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return WithDefault.fromData(data, _db, prefix: effectivePrefix); + } + + @override + Map entityToSql(WithDefaultsCompanion d) { + final map = {}; + if (d.a.present) { + map['a'] = Variable(d.a.value); + } + if (d.b.present) { + map['b'] = Variable(d.b.value); + } + return map; + } + + @override + WithDefaults createAlias(String alias) { + return WithDefaults(_db, alias); + } +} + +class WithConstraint extends DataClass implements Insertable { + final String a; + final int b; + final double c; + WithConstraint({@required this.a, @required this.b, this.c}); + factory WithConstraint.fromData( + Map data, GeneratedDatabase db, + {String prefix}) { + final effectivePrefix = prefix ?? ''; + final stringType = db.typeSystem.forDartType(); + final intType = db.typeSystem.forDartType(); + final doubleType = db.typeSystem.forDartType(); + return WithConstraint( + a: stringType.mapFromDatabaseResponse(data['${effectivePrefix}a']), + b: intType.mapFromDatabaseResponse(data['${effectivePrefix}b']), + c: doubleType.mapFromDatabaseResponse(data['${effectivePrefix}c']), + ); + } + factory WithConstraint.fromJson(Map json, + {ValueSerializer serializer = const ValueSerializer.defaults()}) { + return WithConstraint( + a: serializer.fromJson(json['a']), + b: serializer.fromJson(json['b']), + c: serializer.fromJson(json['c']), + ); + } + @override + Map toJson( + {ValueSerializer serializer = const ValueSerializer.defaults()}) { + return { + 'a': serializer.toJson(a), + 'b': serializer.toJson(b), + 'c': serializer.toJson(c), + }; + } + + @override + T createCompanion>( + 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 { + final Value a; + final Value b; + final Value c; + const WithConstraintsCompanion({ + this.a = const Value.absent(), + this.b = const Value.absent(), + this.c = const Value.absent(), + }); +} + +class WithConstraints extends Table + with TableInfo { + 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, false, + $customConstraints: 'NOT NULL'); + } + + 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 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 get $primaryKey => {}; + @override + WithConstraint map(Map data, {String tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; + return WithConstraint.fromData(data, _db, prefix: effectivePrefix); + } + + @override + Map entityToSql(WithConstraintsCompanion d) { + final map = {}; + if (d.a.present) { + map['a'] = Variable(d.a.value); + } + if (d.b.present) { + map['b'] = Variable(d.b.value); + } + if (d.c.present) { + map['c'] = Variable(d.c.value); + } + return map; + } + + @override + WithConstraints createAlias(String alias) { + return WithConstraints(_db, alias); + } + + @override + final List 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 get allTables => [noIds, withDefaults, withConstraints]; +} diff --git a/moor/test/data/tables/tables.moor b/moor/test/data/tables/tables.moor new file mode 100644 index 00000000..c9921c8a --- /dev/null +++ b/moor/test/data/tables/tables.moor @@ -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 NOT NULL, + b INT NOT NULL, + c FLOAT(10, 2), + + FOREIGN KEY (a, b) REFERENCES with_defaults (a, b) +) \ No newline at end of file diff --git a/moor/test/data/tables/test.moor b/moor/test/data/tables/test.moor deleted file mode 100644 index 4c3f2368..00000000 --- a/moor/test/data/tables/test.moor +++ /dev/null @@ -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 -) \ No newline at end of file diff --git a/moor/test/data/tables/todos.dart b/moor/test/data/tables/todos.dart index 1fcca815..9a6d1543 100644 --- a/moor/test/data/tables/todos.dart +++ b/moor/test/data/tables/todos.dart @@ -88,7 +88,6 @@ class CustomConverter extends TypeConverter { 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', diff --git a/moor/test/data/tables/todos.g.dart b/moor/test/data/tables/todos.g.dart index fe7dad43..3982fe20 100644 --- a/moor/test/data/tables/todos.g.dart +++ b/moor/test/data/tables/todos.g.dart @@ -1187,325 +1187,6 @@ class $PureDefaultsTable extends PureDefaults } } -class State extends DataClass implements Insertable { - final int id; - final String name; - State({@required this.id, @required this.name}); - factory State.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final intType = db.typeSystem.forDartType(); - final stringType = db.typeSystem.forDartType(); - return State( - id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - name: stringType.mapFromDatabaseResponse(data['${effectivePrefix}name']), - ); - } - factory State.fromJson(Map json, - {ValueSerializer serializer = const ValueSerializer.defaults()}) { - return State( - id: serializer.fromJson(json['id']), - name: serializer.fromJson(json['name']), - ); - } - @override - Map toJson( - {ValueSerializer serializer = const ValueSerializer.defaults()}) { - return { - 'id': serializer.toJson(id), - 'name': serializer.toJson(name), - }; - } - - @override - T createCompanion>(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 { - final Value id; - final Value name; - const StatesCompanion({ - this.id = const Value.absent(), - this.name = const Value.absent(), - }); -} - -class States extends Table with TableInfo { - 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 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 get $primaryKey => {id}; - @override - State map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return State.fromData(data, _db, prefix: effectivePrefix); - } - - @override - Map entityToSql(StatesCompanion d) { - final map = {}; - if (d.id.present) { - map['id'] = Variable(d.id.value); - } - if (d.name.present) { - map['name'] = Variable(d.name.value); - } - return map; - } - - @override - States createAlias(String alias) { - return States(_db, alias); - } -} - -class Experiment extends DataClass implements Insertable { - final int id; - final String description; - final int state; - Experiment({@required this.id, @required this.description, this.state}); - factory Experiment.fromData(Map data, GeneratedDatabase db, - {String prefix}) { - final effectivePrefix = prefix ?? ''; - final intType = db.typeSystem.forDartType(); - final stringType = db.typeSystem.forDartType(); - return Experiment( - id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']), - description: stringType - .mapFromDatabaseResponse(data['${effectivePrefix}description']), - state: intType.mapFromDatabaseResponse(data['${effectivePrefix}state']), - ); - } - factory Experiment.fromJson(Map json, - {ValueSerializer serializer = const ValueSerializer.defaults()}) { - return Experiment( - id: serializer.fromJson(json['id']), - description: serializer.fromJson(json['description']), - state: serializer.fromJson(json['state']), - ); - } - @override - Map toJson( - {ValueSerializer serializer = const ValueSerializer.defaults()}) { - return { - 'id': serializer.toJson(id), - 'description': serializer.toJson(description), - 'state': serializer.toJson(state), - }; - } - - @override - T createCompanion>(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 { - final Value id; - final Value description; - final Value state; - const ExperimentsCompanion({ - this.id = const Value.absent(), - this.description = const Value.absent(), - this.state = const Value.absent(), - }); -} - -class Experiments extends Table with TableInfo { - 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 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 get $primaryKey => {id}; - @override - Experiment map(Map data, {String tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null; - return Experiment.fromData(data, _db, prefix: effectivePrefix); - } - - @override - Map entityToSql(ExperimentsCompanion d) { - final map = {}; - if (d.id.present) { - map['id'] = Variable(d.id.value); - } - if (d.description.present) { - map['description'] = Variable(d.description.value); - } - if (d.state.present) { - map['state'] = Variable(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 ]; } diff --git a/moor_generator/lib/src/model/specified_table.dart b/moor_generator/lib/src/model/specified_table.dart index 3cc34f8d..298fb8d2 100644 --- a/moor_generator/lib/src/model/specified_table.dart +++ b/moor_generator/lib/src/model/specified_table.dart @@ -48,13 +48,23 @@ class SpecifiedTable { /// not been defined that way. final Set 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 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. diff --git a/moor_generator/lib/src/parser/moor/parsed_moor_file.dart b/moor_generator/lib/src/parser/moor/parsed_moor_file.dart index ad5075f0..ba29c7af 100644 --- a/moor_generator/lib/src/parser/moor/parsed_moor_file.dart +++ b/moor_generator/lib/src/parser/moor/parsed_moor_file.dart @@ -79,7 +79,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 +88,8 @@ class CreateTable { dartTypeName: dataClassNameForClassName(dartTableName), overriddenName: ReCase(tableName).pascalCase, primaryKey: primaryKey, + overrideWithoutRowId: table.withoutRowId ? true : null, + overrideTableConstraints: constraints.isNotEmpty ? constraints : null, ); } diff --git a/moor_generator/lib/src/parser/use_dao_parser.dart b/moor_generator/lib/src/parser/use_dao_parser.dart index 025f6c10..603d5366 100644 --- a/moor_generator/lib/src/parser/use_dao_parser.dart +++ b/moor_generator/lib/src/parser/use_dao_parser.dart @@ -13,7 +13,8 @@ class UseDaoParser { Future 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 diff --git a/moor_generator/lib/src/parser/use_moor_parser.dart b/moor_generator/lib/src/parser/use_moor_parser.dart index 999c1f2e..e15bde2f 100644 --- a/moor_generator/lib/src/parser/use_moor_parser.dart +++ b/moor_generator/lib/src/parser/use_moor_parser.dart @@ -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') diff --git a/moor_generator/lib/src/writer/table_writer.dart b/moor_generator/lib/src/writer/table_writer.dart index 88bdf42c..ad1caf20 100644 --- a/moor_generator/lib/src/writer/table_writer.dart +++ b/moor_generator/lib/src/writer/table_writer.dart @@ -63,6 +63,7 @@ class TableWriter { _writeAliasGenerator(buffer); _writeConvertersAsStaticFields(buffer); + _overrideFieldsIfNeeded(buffer); // close class buffer.write('}'); @@ -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 customConstraints = const [$value];'); + } + } } From b1820ef5aa704c5f15312b39375c3e53af185c48 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 30 Jul 2019 10:30:06 +0200 Subject: [PATCH 3/4] Generate code to match default values for CREATE TABLE --- .../lib/src/runtime/expressions/user_api.dart | 1 + moor/test/data/tables/custom_tables.g.dart | 4 ++- .../lib/src/model/specified_column.dart | 26 +++++++++---------- .../lib/src/parser/column_parser.dart | 2 +- .../lib/src/parser/moor/parsed_moor_file.dart | 13 +++++++++- .../lib/src/writer/table_writer.dart | 2 +- 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/moor/lib/src/runtime/expressions/user_api.dart b/moor/lib/src/runtime/expressions/user_api.dart index 633843f2..ea0a6b93 100644 --- a/moor/lib/src/runtime/expressions/user_api.dart +++ b/moor/lib/src/runtime/expressions/user_api.dart @@ -1,4 +1,5 @@ export 'bools.dart' show and, or, not; +export 'custom.dart'; export 'datetimes.dart'; export 'in.dart'; export 'null_check.dart'; diff --git a/moor/test/data/tables/custom_tables.g.dart b/moor/test/data/tables/custom_tables.g.dart index 2e56353c..4e13a709 100644 --- a/moor/test/data/tables/custom_tables.g.dart +++ b/moor/test/data/tables/custom_tables.g.dart @@ -201,7 +201,9 @@ class WithDefaults extends Table with TableInfo { GeneratedTextColumn get a => _a ??= _constructA(); GeneratedTextColumn _constructA() { return GeneratedTextColumn('a', $tableName, true, - $customConstraints: 'DEFAULT \'something\''); + $customConstraints: 'DEFAULT \'something\'', + defaultValue: + const CustomExpression('\'something\'')); } final VerificationMeta _bMeta = const VerificationMeta('b'); diff --git a/moor_generator/lib/src/model/specified_column.dart b/moor_generator/lib/src/model/specified_column.dart index 98fdba99..d95325ef 100644 --- a/moor_generator/lib/src/model/specified_column.dart +++ b/moor_generator/lib/src/model/specified_column.dart @@ -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 createVariable = { ColumnType.real: 'Variable.withReal', }; +const Map 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, diff --git a/moor_generator/lib/src/parser/column_parser.dart b/moor_generator/lib/src/parser/column_parser.dart index 8e66278a..3848cbdf 100644 --- a/moor_generator/lib/src/parser/column_parser.dart +++ b/moor_generator/lib/src/parser/column_parser.dart @@ -199,7 +199,7 @@ class ColumnParser extends ParserBase { customConstraints: foundCustomConstraint, nullable: nullable, features: foundFeatures, - defaultArgument: foundDefaultExpression, + defaultArgument: foundDefaultExpression?.toSource(), typeConverter: converter); } diff --git a/moor_generator/lib/src/parser/moor/parsed_moor_file.dart b/moor_generator/lib/src/parser/moor/parsed_moor_file.dart index ba29c7af..0fecc384 100644 --- a/moor_generator/lib/src/parser/moor/parsed_moor_file.dart +++ b/moor_generator/lib/src/parser/moor/parsed_moor_file.dart @@ -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; diff --git a/moor_generator/lib/src/writer/table_writer.dart b/moor_generator/lib/src/writer/table_writer.dart index ad1caf20..6927f7cb 100644 --- a/moor_generator/lib/src/writer/table_writer.dart +++ b/moor_generator/lib/src/writer/table_writer.dart @@ -149,7 +149,7 @@ class TableWriter { } if (column.defaultArgument != null) { - additionalParams['defaultValue'] = column.defaultArgument.toSource(); + additionalParams['defaultValue'] = column.defaultArgument; } expressionBuffer From 635b9023523ae786db6a6433ab234d201bfbf3eb Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 30 Jul 2019 10:33:32 +0200 Subject: [PATCH 4/4] Add test case without any additional constraints --- moor/test/data/tables/custom_tables.g.dart | 5 ++--- moor/test/data/tables/tables.moor | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/moor/test/data/tables/custom_tables.g.dart b/moor/test/data/tables/custom_tables.g.dart index 4e13a709..3e7463bb 100644 --- a/moor/test/data/tables/custom_tables.g.dart +++ b/moor/test/data/tables/custom_tables.g.dart @@ -269,7 +269,7 @@ class WithConstraint extends DataClass implements Insertable { final String a; final int b; final double c; - WithConstraint({@required this.a, @required this.b, this.c}); + WithConstraint({this.a, @required this.b, this.c}); factory WithConstraint.fromData( Map data, GeneratedDatabase db, {String prefix}) { @@ -354,8 +354,7 @@ class WithConstraints extends Table GeneratedTextColumn _a; GeneratedTextColumn get a => _a ??= _constructA(); GeneratedTextColumn _constructA() { - return GeneratedTextColumn('a', $tableName, false, - $customConstraints: 'NOT NULL'); + return GeneratedTextColumn('a', $tableName, true, $customConstraints: ''); } final VerificationMeta _bMeta = const VerificationMeta('b'); diff --git a/moor/test/data/tables/tables.moor b/moor/test/data/tables/tables.moor index c9921c8a..59ee6c39 100644 --- a/moor/test/data/tables/tables.moor +++ b/moor/test/data/tables/tables.moor @@ -8,7 +8,7 @@ CREATE TABLE with_defaults ( ) CREATE TABLE with_constraints ( - a TEXT NOT NULL, + a TEXT, b INT NOT NULL, c FLOAT(10, 2),