Migrator support for indexes, tests

This commit is contained in:
Simon Binder 2020-01-03 20:08:10 +01:00
parent 5b04a08786
commit 00c1d2a2e7
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
6 changed files with 59 additions and 14 deletions

View File

@ -74,6 +74,8 @@ class Migrator {
await createTable(entity); await createTable(entity);
} else if (entity is Trigger) { } else if (entity is Trigger) {
await createTrigger(entity); await createTrigger(entity);
} else if (entity is Index) {
await createIndex(entity);
} else { } else {
throw AssertionError('Unknown entity: $entity'); throw AssertionError('Unknown entity: $entity');
} }
@ -167,6 +169,11 @@ class Migrator {
return issueCustomQuery(trigger.createTriggerStmt, const []); return issueCustomQuery(trigger.createTriggerStmt, const []);
} }
/// Executes a `CREATE INDEX` statement to create the [index].
Future<void> createIndex(Index index) {
return issueCustomQuery(index.createIndexStmt, const []);
}
/// Deletes the table with the given name. Note that this function does not /// Deletes the table with the given name. Note that this function does not
/// escape the [name] parameter. /// escape the [name] parameter.
Future<void> deleteTable(String name) async { Future<void> deleteTable(String name) async {

View File

@ -1089,6 +1089,9 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
_$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c); _$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c);
ConfigTable _config; ConfigTable _config;
ConfigTable get config => _config ??= ConfigTable(this); ConfigTable get config => _config ??= ConfigTable(this);
Index _valueIdx;
Index get valueIdx => _valueIdx ??= Index('value_idx',
'CREATE INDEX IF NOT EXISTS value_idx ON config (config_value);');
WithDefaults _withDefaults; WithDefaults _withDefaults;
WithDefaults get withDefaults => _withDefaults ??= WithDefaults(this); WithDefaults get withDefaults => _withDefaults ??= WithDefaults(this);
Trigger _myTrigger; Trigger _myTrigger;
@ -1216,8 +1219,16 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
@override @override
Iterable<TableInfo> get allTables => allSchemaEntities.whereType<TableInfo>(); Iterable<TableInfo> get allTables => allSchemaEntities.whereType<TableInfo>();
@override @override
List<DatabaseSchemaEntity> get allSchemaEntities => List<DatabaseSchemaEntity> get allSchemaEntities => [
[config, withDefaults, myTrigger, noIds, withConstraints, mytable, email]; config,
valueIdx,
withDefaults,
myTrigger,
noIds,
withConstraints,
mytable,
email
];
} }
class MultipleResult { class MultipleResult {

View File

@ -20,6 +20,8 @@ create table config (
config_value TEXT config_value TEXT
) AS "Config"; ) AS "Config";
CREATE INDEX IF NOT EXISTS value_idx ON config (config_value);
CREATE TABLE mytable ( CREATE TABLE mytable (
someid INTEGER NOT NULL PRIMARY KEY, someid INTEGER NOT NULL PRIMARY KEY,
sometext TEXT, sometext TEXT,

View File

@ -26,17 +26,20 @@ const _createMyTable = 'CREATE TABLE IF NOT EXISTS mytable ('
'somebool INTEGER, ' 'somebool INTEGER, '
'somedate INTEGER);'; 'somedate INTEGER);';
const _createEmail = 'CREATE VIRTUAL TABLE IF NOT EXISTS email USING '
'fts5(sender, title, body);';
const _createMyTrigger = const _createMyTrigger =
'''CREATE TRIGGER my_trigger AFTER INSERT ON config BEGIN '''CREATE TRIGGER my_trigger AFTER INSERT ON config BEGIN
INSERT INTO with_defaults VALUES (new.config_key, LENGTH(new.config_value)); INSERT INTO with_defaults VALUES (new.config_key, LENGTH(new.config_value));
END;'''; END;''';
const _createEmail = 'CREATE VIRTUAL TABLE IF NOT EXISTS email USING ' const _createValueIndex =
'fts5(sender, title, body);'; 'CREATE INDEX IF NOT EXISTS value_idx ON config (config_value);';
void main() { void main() {
// see ../data/tables/tables.moor // see ../data/tables/tables.moor
test('creates tables as specified in .moor files', () async { test('creates everything as specified in .moor files', () async {
final mockExecutor = MockExecutor(); final mockExecutor = MockExecutor();
final mockQueryExecutor = MockQueryExecutor(); final mockQueryExecutor = MockQueryExecutor();
final db = CustomTablesDb(mockExecutor); final db = CustomTablesDb(mockExecutor);
@ -48,14 +51,8 @@ void main() {
verify(mockQueryExecutor.call(_createConfig, [])); verify(mockQueryExecutor.call(_createConfig, []));
verify(mockQueryExecutor.call(_createMyTable, [])); verify(mockQueryExecutor.call(_createMyTable, []));
verify(mockQueryExecutor.call(_createEmail, [])); verify(mockQueryExecutor.call(_createEmail, []));
});
test('creates triggers specified in .moor files', () async {
final mockQueryExecutor = MockQueryExecutor();
final db = CustomTablesDb(MockExecutor());
await Migrator(db, mockQueryExecutor).createAll();
verify(mockQueryExecutor.call(_createMyTrigger, [])); verify(mockQueryExecutor.call(_createMyTrigger, []));
verify(mockQueryExecutor.call(_createValueIndex, []));
}); });
test('can create trigger manually', () async { test('can create trigger manually', () async {
@ -66,6 +63,14 @@ void main() {
verify(mockQueryExecutor.call(_createMyTrigger, [])); verify(mockQueryExecutor.call(_createMyTrigger, []));
}); });
test('can create index manually', () async {
final mockQueryExecutor = MockQueryExecutor();
final db = CustomTablesDb(MockExecutor());
await Migrator(db, mockQueryExecutor).createIndex(db.valueIdx);
verify(mockQueryExecutor.call(_createValueIndex, []));
});
test('infers primary keys correctly', () async { test('infers primary keys correctly', () async {
final db = CustomTablesDb(null); final db = CustomTablesDb(null);

View File

@ -37,7 +37,7 @@ class EntityHandler extends BaseAnalyzer {
entity.bodyReferences.clear(); entity.bodyReferences.clear();
final node = final node =
_handleMoorDeclaration(entity, _tables) as CreateTriggerStatement; _handleMoorDeclaration(entity, _triggers) as CreateTriggerStatement;
// triggers can have complex statements, so run the linter on them // triggers can have complex statements, so run the linter on them
final context = engine.analyzeNode(node, file.parseResult.sql); final context = engine.analyzeNode(node, file.parseResult.sql);
@ -55,7 +55,7 @@ class EntityHandler extends BaseAnalyzer {
} else if (entity is MoorIndex) { } else if (entity is MoorIndex) {
entity.table = null; entity.table = null;
_handleMoorDeclaration<MoorTableDeclaration>(entity, _indexes); _handleMoorDeclaration<MoorIndexDeclaration>(entity, _indexes);
} }
} }
} }

View File

@ -78,6 +78,26 @@ END;
}, },
); );
}); });
test('in an index', () async {
final state = TestState.withContent(const {
'foo|lib/a.moor': '''
import 'b.moor';
CREATE INDEX idx ON users (name);
''',
...definitions,
});
final file = await state.analyze('package:foo/a.moor');
expect(file.errors.errors, isEmpty);
final trigger = file.currentResult.declaredEntities.single as MoorIndex;
expect(trigger.references, {
const TypeMatcher<MoorTable>()
.having((table) => table.displayName, 'displayName', 'users'),
});
});
}); });
group('issues error when referencing an unknown table', () { group('issues error when referencing an unknown table', () {