Merge remote-tracking branch 'simolus3/develop' into views

This commit is contained in:
westito 2021-12-02 09:20:02 +01:00
commit d22bbcbadf
5 changed files with 58 additions and 12 deletions

View File

@ -16,15 +16,21 @@ class VerifierImplementation implements SchemaVerifier {
@override @override
Future<void> migrateAndValidate(GeneratedDatabase db, int expectedVersion, Future<void> migrateAndValidate(GeneratedDatabase db, int expectedVersion,
{bool validateDropped = false}) async { {bool validateDropped = false}) async {
final virtualTables = <String>[
for (final table in db.allTables)
if (table is VirtualTableInfo) table.entityName,
];
// Open the database to collect its schema. Put a delegate in between // Open the database to collect its schema. Put a delegate in between
// claiming that the actual version is what we expect. // claiming that the actual version is what we expect.
await db.executor.ensureOpen(_DelegatingUser(expectedVersion, db)); await db.executor.ensureOpen(_DelegatingUser(expectedVersion, db));
final actualSchema = await db.executor.collectSchemaInput(); final actualSchema = await db.executor.collectSchemaInput(virtualTables);
// Open another connection to instantiate and extract the reference schema. // Open another connection to instantiate and extract the reference schema.
final otherConnection = await startAt(expectedVersion); final otherConnection = await startAt(expectedVersion);
await otherConnection.executor.ensureOpen(_DelegatingUser(expectedVersion)); await otherConnection.executor.ensureOpen(_DelegatingUser(expectedVersion));
final referenceSchema = await otherConnection.executor.collectSchemaInput(); final referenceSchema =
await otherConnection.executor.collectSchemaInput(virtualTables);
await otherConnection.executor.close(); await otherConnection.executor.close();
final result = final result =
@ -80,13 +86,16 @@ class VerifierImplementation implements SchemaVerifier {
} }
extension on QueryExecutor { extension on QueryExecutor {
Future<List<Input>> collectSchemaInput() async { Future<List<Input>> collectSchemaInput(List<String> virtualTables) async {
final result = await runSelect('SELECT * FROM sqlite_master;', const []); final result = await runSelect('SELECT * FROM sqlite_master;', const []);
final inputs = <Input>[]; final inputs = <Input>[];
for (final row in result) { for (final row in result) {
final name = row['name'] as String; final name = row['name'] as String;
// Skip sqlite-internal tables
if (name.startsWith('sqlite_autoindex')) continue; if (name.startsWith('sqlite_autoindex')) continue;
if (virtualTables.any((v) => name.startsWith('${v}_'))) continue;
inputs.add(Input(name, row['sql'] as String)); inputs.add(Input(name, row['sql'] as String));
} }

View File

@ -19,5 +19,5 @@ Replace `_v2` with the current `schemaVersion`.
Run Run
``` ```
dart run drift_dev schema generate moor_migrations/ test/generated/ --data-classes --companions dart run drift_dev schema generate drift_migrations/ test/generated/ --data-classes --companions
``` ```

View File

@ -716,9 +716,8 @@ class Parser {
final token = _peek; final token = _peek;
Literal? _parseInner() { Literal? _parseInner() {
if (_matchOne(TokenType.numberLiteral)) { if (_check(TokenType.numberLiteral)) {
final number = token as NumericToken; return _numericLiteral();
return NumericLiteral(number.parsedNumber, token);
} }
if (_matchOne(TokenType.stringLiteral)) { if (_matchOne(TokenType.stringLiteral)) {
return StringLiteral(token as StringLiteralToken); return StringLiteral(token as StringLiteralToken);
@ -752,6 +751,12 @@ class Parser {
return literal; return literal;
} }
NumericLiteral _numericLiteral() {
final number = _consume(TokenType.numberLiteral, 'Expected a number here')
as NumericToken;
return NumericLiteral(number.parsedNumber, number)..setSpan(number, number);
}
Expression _primary() { Expression _primary() {
final literal = _literalOrNull(); final literal = _literalOrNull();
if (literal != null) return literal; if (literal != null) return literal;
@ -2442,10 +2447,17 @@ class Parser {
return CheckColumn(resolvedName, expr)..setSpan(first, _previous); return CheckColumn(resolvedName, expr)..setSpan(first, _previous);
} }
if (_matchOne(TokenType.$default)) { if (_matchOne(TokenType.$default)) {
Expression? expr = _literalOrNull(); Expression expr;
// when not a literal, expect an expression in parentheses if (_match(const [TokenType.plus, TokenType.minus])) {
expr ??= _expressionInParentheses(); // Signed number
final operator = _previous;
expr = UnaryExpression(operator, _numericLiteral())
..setSpan(operator, _previous);
} else {
// Literal or an expression in parentheses
expr = _literalOrNull() ?? _expressionInParentheses();
}
return Default(resolvedName, expr)..setSpan(first, _previous); return Default(resolvedName, expr)..setSpan(first, _previous);
} }

View File

@ -300,4 +300,26 @@ void main() {
), ),
); );
}); });
test('parses DEFAULT with a negative literal', () {
// regression test for https://github.com/simolus3/moor/discussions/1550
testStatement(
'CREATE TABLE a (b INTEGER NOT NULL DEFAULT -1);',
CreateTableStatement(
tableName: 'a',
columns: [
ColumnDefinition(columnName: 'b', typeName: 'INTEGER', constraints: [
NotNull(null),
Default(
null,
UnaryExpression(
Token(TokenType.minus, fakeSpan('-')),
NumericLiteral(1, NumericToken(fakeSpan('1'))),
),
)
])
],
),
);
});
} }

View File

@ -38,8 +38,11 @@ void testMoorFile(String moorFile, MoorFile expected) {
} }
void testStatement(String sql, AstNode expected, {bool moorMode = false}) { void testStatement(String sql, AstNode expected, {bool moorMode = false}) {
final parsed = final result =
SqlEngine(EngineOptions(useMoorExtensions: moorMode)).parse(sql).rootNode; SqlEngine(EngineOptions(useMoorExtensions: moorMode)).parse(sql);
expect(result.errors, isEmpty);
final parsed = result.rootNode;
enforceHasSpan(parsed); enforceHasSpan(parsed);
enforceEqual(parsed, expected); enforceEqual(parsed, expected);
} }