mirror of https://github.com/AMT-Cheif/drift.git
Migrate some trigger code to refactorings on develop
This commit is contained in:
parent
ba603f22cc
commit
04f75d11d3
|
@ -31,6 +31,12 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
|
||||||
/// A list of tables specified in this database.
|
/// A list of tables specified in this database.
|
||||||
List<TableInfo> get allTables;
|
List<TableInfo> get allTables;
|
||||||
|
|
||||||
|
/// A list of all [DatabaseSchemaEntity] that are specified in this database.
|
||||||
|
///
|
||||||
|
/// This contains [allTables], but also advanced entities like triggers.
|
||||||
|
// return allTables for backwards compatibility
|
||||||
|
List<DatabaseSchemaEntity> get allSchemaEntities => allTables;
|
||||||
|
|
||||||
/// A [Type] can't be sent across isolates. Instances of this class shouldn't
|
/// A [Type] can't be sent across isolates. Instances of this class shouldn't
|
||||||
/// be sent over isolates either, so let's keep a reference to a [Type] that
|
/// be sent over isolates either, so let's keep a reference to a [Type] that
|
||||||
/// definitely prohibits this.
|
/// definitely prohibits this.
|
||||||
|
|
|
@ -69,7 +69,7 @@ class Migrator {
|
||||||
/// Creates all tables, triggers, views, indexes and everything else defined
|
/// Creates all tables, triggers, views, indexes and everything else defined
|
||||||
/// in the database, if they don't exist.
|
/// in the database, if they don't exist.
|
||||||
Future<void> createAll() async {
|
Future<void> createAll() async {
|
||||||
for (var entity in _db.allEntities) {
|
for (final entity in _db.allSchemaEntities) {
|
||||||
if (entity is TableInfo) {
|
if (entity is TableInfo) {
|
||||||
await createTable(entity);
|
await createTable(entity);
|
||||||
} else if (entity is Trigger) {
|
} else if (entity is Trigger) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ part 'expressions/text.dart';
|
||||||
part 'expressions/variables.dart';
|
part 'expressions/variables.dart';
|
||||||
|
|
||||||
part 'schema/columns.dart';
|
part 'schema/columns.dart';
|
||||||
|
part 'schema/entities.dart';
|
||||||
part 'schema/table_info.dart';
|
part 'schema/table_info.dart';
|
||||||
|
|
||||||
part 'statements/select/custom_select.dart';
|
part 'statements/select/custom_select.dart';
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
part of '../query_builder.dart';
|
||||||
|
|
||||||
/// Some abstract schema entity that can be stored in a database. This includes
|
/// Some abstract schema entity that can be stored in a database. This includes
|
||||||
/// tables, triggers, views, indexes, etc.
|
/// tables, triggers, views, indexes, etc.
|
||||||
abstract class DatabaseSchemaEntity {
|
abstract class DatabaseSchemaEntity {
|
||||||
|
@ -10,10 +12,11 @@ abstract class DatabaseSchemaEntity {
|
||||||
/// In moor, triggers can only be declared in `.moor` files.
|
/// In moor, triggers can only be declared in `.moor` files.
|
||||||
///
|
///
|
||||||
/// For more information on triggers, see the [CREATE TRIGGER][sqlite-docs]
|
/// For more information on triggers, see the [CREATE TRIGGER][sqlite-docs]
|
||||||
/// documentation from sqlite, or the [entry on sqlitetutorial.net][sql-tutorial].
|
/// documentation from sqlite, or the [entry on sqlitetutorial.net][sql-tut].
|
||||||
///
|
///
|
||||||
/// [sqlite-docs]: (https://sqlite.org/lang_createtrigger.html)
|
///
|
||||||
/// [sql-tutorial]: (https://www.sqlitetutorial.net/sqlite-trigger/)
|
/// [sqlite-docs]: https://sqlite.org/lang_createtrigger.html
|
||||||
|
/// [sql-tut]: https://www.sqlitetutorial.net/sqlite-trigger/
|
||||||
class Trigger extends DatabaseSchemaEntity {
|
class Trigger extends DatabaseSchemaEntity {
|
||||||
/// The `CREATE TRIGGER` sql statement that can be used to create this
|
/// The `CREATE TRIGGER` sql statement that can be used to create this
|
||||||
/// trigger.
|
/// trigger.
|
||||||
|
|
|
@ -35,7 +35,7 @@ void main() {
|
||||||
final mockExecutor = MockExecutor();
|
final mockExecutor = MockExecutor();
|
||||||
final mockQueryExecutor = MockQueryExecutor();
|
final mockQueryExecutor = MockQueryExecutor();
|
||||||
final db = CustomTablesDb(mockExecutor);
|
final db = CustomTablesDb(mockExecutor);
|
||||||
await Migrator(db, mockQueryExecutor).createAllTables();
|
await Migrator(db, mockQueryExecutor).createAll();
|
||||||
|
|
||||||
verify(mockQueryExecutor.call(_createNoIds, []));
|
verify(mockQueryExecutor.call(_createNoIds, []));
|
||||||
verify(mockQueryExecutor.call(_createWithDefaults, []));
|
verify(mockQueryExecutor.call(_createWithDefaults, []));
|
||||||
|
|
|
@ -65,7 +65,7 @@ class Database extends _$Database {
|
||||||
MigrationStrategy get migration {
|
MigrationStrategy get migration {
|
||||||
return MigrationStrategy(
|
return MigrationStrategy(
|
||||||
onCreate: (Migrator m) {
|
onCreate: (Migrator m) {
|
||||||
return m.createAllTables();
|
return m.createAll();
|
||||||
},
|
},
|
||||||
onUpgrade: (Migrator m, int from, int to) async {
|
onUpgrade: (Migrator m, int from, int to) async {
|
||||||
if (from == 1) {
|
if (from == 1) {
|
||||||
|
|
|
@ -7,12 +7,12 @@ import 'package:sqlparser/sqlparser.dart';
|
||||||
/// Handles `REFERENCES` clauses in tables by resolving their columns and
|
/// Handles `REFERENCES` clauses in tables by resolving their columns and
|
||||||
/// reporting errors if they don't exist. Further, sets the
|
/// reporting errors if they don't exist. Further, sets the
|
||||||
/// [MoorTable.references] field for tables declared in moor.
|
/// [MoorTable.references] field for tables declared in moor.
|
||||||
class TableHandler {
|
class EntityHandler {
|
||||||
final AnalyzeMoorStep step;
|
final AnalyzeMoorStep step;
|
||||||
final ParsedMoorFile file;
|
final ParsedMoorFile file;
|
||||||
final List<MoorTable> availableTables;
|
final List<MoorTable> availableTables;
|
||||||
|
|
||||||
TableHandler(this.step, this.file, this.availableTables);
|
EntityHandler(this.step, this.file, this.availableTables);
|
||||||
|
|
||||||
void handle() {
|
void handle() {
|
||||||
for (final table in file.declaredTables) {
|
for (final table in file.declaredTables) {
|
||||||
|
@ -25,7 +25,7 @@ class TableHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReferenceResolvingVisitor extends RecursiveVisitor<void, void> {
|
class _ReferenceResolvingVisitor extends RecursiveVisitor<void, void> {
|
||||||
final TableHandler handler;
|
final EntityHandler handler;
|
||||||
|
|
||||||
_ReferenceResolvingVisitor(this.handler);
|
_ReferenceResolvingVisitor(this.handler);
|
||||||
|
|
|
@ -6,9 +6,11 @@ import 'package:moor_generator/src/model/sql_query.dart';
|
||||||
import 'package:sqlparser/sqlparser.dart';
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
|
|
||||||
abstract class FileResult {
|
abstract class FileResult {
|
||||||
final List<MoorTable> declaredTables;
|
final List<MoorSchemaEntity> declaredEntities;
|
||||||
|
|
||||||
FileResult(this.declaredTables);
|
Iterable<MoorTable> get declaredTables => declaredEntities.whereType();
|
||||||
|
|
||||||
|
FileResult(this.declaredEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParsedDartFile extends FileResult {
|
class ParsedDartFile extends FileResult {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:moor/moor.dart';
|
||||||
import 'package:moor_generator/moor_generator.dart';
|
import 'package:moor_generator/moor_generator.dart';
|
||||||
import 'package:moor_generator/src/analyzer/dart/parser.dart';
|
import 'package:moor_generator/src/analyzer/dart/parser.dart';
|
||||||
import 'package:moor_generator/src/analyzer/errors.dart';
|
import 'package:moor_generator/src/analyzer/errors.dart';
|
||||||
import 'package:moor_generator/src/analyzer/moor/table_handler.dart';
|
import 'package:moor_generator/src/analyzer/moor/entity_handler.dart';
|
||||||
import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
|
import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
|
||||||
import 'package:moor_generator/src/analyzer/runner/results.dart';
|
import 'package:moor_generator/src/analyzer/runner/results.dart';
|
||||||
import 'package:moor_generator/src/analyzer/moor/inline_dart_resolver.dart';
|
import 'package:moor_generator/src/analyzer/moor/inline_dart_resolver.dart';
|
||||||
|
@ -14,7 +14,8 @@ import 'package:moor_generator/src/analyzer/sql_queries/sql_parser.dart';
|
||||||
import 'package:moor_generator/src/analyzer/sql_queries/type_mapping.dart';
|
import 'package:moor_generator/src/analyzer/sql_queries/type_mapping.dart';
|
||||||
import 'package:moor_generator/src/analyzer/runner/task.dart';
|
import 'package:moor_generator/src/analyzer/runner/task.dart';
|
||||||
import 'package:moor_generator/src/model/sql_query.dart';
|
import 'package:moor_generator/src/model/sql_query.dart';
|
||||||
import 'package:moor_generator/src/utils/table_reference_sorter.dart';
|
import 'package:moor_generator/src/utils/entity_reference_sorter.dart';
|
||||||
|
|
||||||
import 'package:source_gen/source_gen.dart';
|
import 'package:source_gen/source_gen.dart';
|
||||||
|
|
||||||
part 'steps/analyze_dart.dart';
|
part 'steps/analyze_dart.dart';
|
||||||
|
@ -53,8 +54,12 @@ abstract class AnalyzingStep extends Step {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Iterable<MoorSchemaEntity> _availableEntities(List<FoundFile> imports) {
|
||||||
|
return imports.expand<MoorSchemaEntity>((file) =>
|
||||||
|
file.currentResult?.declaredEntities ?? const Iterable.empty());
|
||||||
|
}
|
||||||
|
|
||||||
Iterable<MoorTable> _availableTables(List<FoundFile> imports) {
|
Iterable<MoorTable> _availableTables(List<FoundFile> imports) {
|
||||||
return imports.expand<MoorTable>(
|
return _availableEntities(imports).whereType();
|
||||||
(file) => file.currentResult?.declaredTables ?? const Iterable.empty());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,12 @@ class AnalyzeDartStep extends AnalyzingStep {
|
||||||
for (final accessor in parseResult.dbAccessors) {
|
for (final accessor in parseResult.dbAccessors) {
|
||||||
final transitiveImports = _transitiveImports(accessor.imports);
|
final transitiveImports = _transitiveImports(accessor.imports);
|
||||||
|
|
||||||
var availableTables = _availableTables(transitiveImports)
|
var availableEntities = _availableEntities(transitiveImports)
|
||||||
.followedBy(accessor.declaredTables)
|
.followedBy(accessor.declaredTables)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
availableTables = sortTablesTopologically(availableTables);
|
availableEntities = sortEntitiesTopologically(availableEntities);
|
||||||
} on CircularReferenceException catch (e) {
|
} on CircularReferenceException catch (e) {
|
||||||
final msg = StringBuffer(
|
final msg = StringBuffer(
|
||||||
'Found a circular reference in your database. This can cause '
|
'Found a circular reference in your database. This can cause '
|
||||||
|
@ -39,6 +39,7 @@ class AnalyzeDartStep extends AnalyzingStep {
|
||||||
.whereType<ParsedMoorFile>()
|
.whereType<ParsedMoorFile>()
|
||||||
.expand((f) => f.resolvedQueries);
|
.expand((f) => f.resolvedQueries);
|
||||||
|
|
||||||
|
final availableTables = availableEntities.whereType<MoorTable>().toList();
|
||||||
final parser = SqlParser(this, availableTables, accessor.declaredQueries);
|
final parser = SqlParser(this, availableTables, accessor.declaredQueries);
|
||||||
parser.parse();
|
parser.parse();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ class AnalyzeMoorStep extends AnalyzingStep {
|
||||||
final parser = SqlParser(this, availableTables, parseResult.queries)
|
final parser = SqlParser(this, availableTables, parseResult.queries)
|
||||||
..parse();
|
..parse();
|
||||||
|
|
||||||
TableHandler(this, parseResult, availableTables).handle();
|
EntityHandler(this, parseResult, availableTables).handle();
|
||||||
|
|
||||||
parseResult.resolvedQueries = parser.foundQueries;
|
parseResult.resolvedQueries = parser.foundQueries;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/// Some schema entity found.
|
||||||
|
///
|
||||||
|
/// Most commonly a table, but it can also be a trigger.
|
||||||
|
abstract class MoorSchemaEntity {
|
||||||
|
/// All entities that have to be created before this entity can be created.
|
||||||
|
///
|
||||||
|
/// For tables, this can be contents of a `REFERENCES` clause. For triggers,
|
||||||
|
/// it would be the tables watched.
|
||||||
|
///
|
||||||
|
/// The generator will verify that the graph of entities and [references]
|
||||||
|
/// is acyclic and sort them topologically.
|
||||||
|
Iterable<MoorSchemaEntity> get references;
|
||||||
|
|
||||||
|
/// A human readable name of this entity, like the table name.
|
||||||
|
String get displayName;
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
export 'base_entity.dart';
|
||||||
export 'column.dart';
|
export 'column.dart';
|
||||||
export 'database.dart';
|
export 'database.dart';
|
||||||
export 'declarations/declaration.dart';
|
export 'declarations/declaration.dart';
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import 'package:moor_generator/src/analyzer/sql_queries/meta/declarations.dart';
|
|
||||||
import 'package:recase/recase.dart';
|
|
||||||
|
|
||||||
/// An abstract schema entity that isn't a table.
|
|
||||||
///
|
|
||||||
/// This includes triggers or indexes.
|
|
||||||
abstract class SpecifiedEntity {
|
|
||||||
final String name;
|
|
||||||
|
|
||||||
String get dartFieldName => ReCase(name).camelCase;
|
|
||||||
|
|
||||||
SpecifiedEntity(this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about a trigger defined in a `.moor` file.
|
|
||||||
class SpecifiedTrigger extends SpecifiedEntity {
|
|
||||||
/// Information on where this trigger was created.
|
|
||||||
final BaseDeclaration declaration;
|
|
||||||
|
|
||||||
/// The `CREATE TRIGGER` sql statement that creates this trigger.
|
|
||||||
final String sql;
|
|
||||||
|
|
||||||
SpecifiedTrigger(String name, this.sql, this.declaration) : super(name);
|
|
||||||
}
|
|
|
@ -4,12 +4,13 @@ import 'package:moor_generator/src/model/used_type_converter.dart';
|
||||||
import 'package:recase/recase.dart';
|
import 'package:recase/recase.dart';
|
||||||
import 'package:sqlparser/sqlparser.dart';
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
|
|
||||||
|
import 'base_entity.dart';
|
||||||
import 'column.dart';
|
import 'column.dart';
|
||||||
import 'declarations/declaration.dart';
|
import 'declarations/declaration.dart';
|
||||||
|
|
||||||
/// A parsed table, declared in code by extending `Table` and referencing that
|
/// A parsed table, declared in code by extending `Table` and referencing that
|
||||||
/// table in `@UseMoor` or `@UseDao`.
|
/// table in `@UseMoor` or `@UseDao`.
|
||||||
class MoorTable implements HasDeclaration {
|
class MoorTable implements HasDeclaration, MoorSchemaEntity {
|
||||||
/// The [ClassElement] for the class that declares this table or null if
|
/// The [ClassElement] for the class that declares this table or null if
|
||||||
/// the table was inferred from a `CREATE TABLE` statement.
|
/// the table was inferred from a `CREATE TABLE` statement.
|
||||||
final ClassElement fromClass;
|
final ClassElement fromClass;
|
||||||
|
@ -80,8 +81,7 @@ class MoorTable implements HasDeclaration {
|
||||||
/// `customConstraints` getter in the table class with this value.
|
/// `customConstraints` getter in the table class with this value.
|
||||||
final List<String> overrideTableConstraints;
|
final List<String> overrideTableConstraints;
|
||||||
|
|
||||||
/// The set of tables referenced somewhere in the declaration of this table,
|
@override
|
||||||
/// for instance by using a `REFERENCES` column constraint.
|
|
||||||
final Set<MoorTable> references = {};
|
final Set<MoorTable> references = {};
|
||||||
|
|
||||||
/// Returns whether this table was created from a `CREATE VIRTUAL TABLE`
|
/// Returns whether this table was created from a `CREATE VIRTUAL TABLE`
|
||||||
|
@ -116,6 +116,7 @@ class MoorTable implements HasDeclaration {
|
||||||
Iterable<UsedTypeConverter> get converters =>
|
Iterable<UsedTypeConverter> get converters =>
|
||||||
columns.map((c) => c.typeConverter).where((t) => t != null);
|
columns.map((c) => c.typeConverter).where((t) => t != null);
|
||||||
|
|
||||||
|
@override
|
||||||
String get displayName {
|
String get displayName {
|
||||||
if (isFromSql) {
|
if (isFromSql) {
|
||||||
return sqlName;
|
return sqlName;
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
import 'package:moor_generator/moor_generator.dart';
|
import 'package:moor_generator/moor_generator.dart';
|
||||||
|
|
||||||
/// Topologically sorts a list of [MoorTable]s by their
|
/// Topologically sorts a list of [MoorSchemaEntity]s by their
|
||||||
/// [MoorTable.references] relationship: Tables appearing first in the
|
/// [MoorSchemaEntity.references] relationship: Tables appearing first in the
|
||||||
/// output have to be created first so the table creation script doesn't crash
|
/// output have to be created first so the table creation script doesn't crash
|
||||||
/// because of tables not existing.
|
/// because of tables not existing.
|
||||||
///
|
///
|
||||||
/// If there is a circular reference between [MoorTable]s, an error will
|
/// If there is a circular reference between [MoorTable]s, an error will
|
||||||
/// be added that contains the name of the tables in question.
|
/// be added that contains the name of the tables in question.
|
||||||
List<MoorTable> sortTablesTopologically(Iterable<MoorTable> tables) {
|
List<MoorSchemaEntity> sortEntitiesTopologically(
|
||||||
|
Iterable<MoorSchemaEntity> tables) {
|
||||||
final run = _SortRun();
|
final run = _SortRun();
|
||||||
|
|
||||||
for (final table in tables) {
|
for (final entity in tables) {
|
||||||
if (!run.didVisitAlready(table)) {
|
if (!run.didVisitAlready(entity)) {
|
||||||
run.previous[table] = null;
|
run.previous[entity] = null;
|
||||||
_visit(table, run);
|
_visit(entity, run);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return run.result;
|
return run.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _visit(MoorTable table, _SortRun run) {
|
void _visit(MoorSchemaEntity table, _SortRun run) {
|
||||||
for (final reference in table.references) {
|
for (final reference in table.references) {
|
||||||
if (run.result.contains(reference)) {
|
if (run.result.contains(reference)) {
|
||||||
// already handled, nothing to do
|
// already handled, nothing to do
|
||||||
|
@ -38,34 +39,34 @@ void _visit(MoorTable table, _SortRun run) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SortRun {
|
class _SortRun {
|
||||||
final Map<MoorTable, MoorTable> previous = {};
|
final Map<MoorSchemaEntity, MoorSchemaEntity> previous = {};
|
||||||
final List<MoorTable> result = [];
|
final List<MoorSchemaEntity> result = [];
|
||||||
|
|
||||||
/// Throws a [CircularReferenceException] because the [last] table depends on
|
/// Throws a [CircularReferenceException] because the [last] table depends on
|
||||||
/// [first], which (transitively) depends on [last] as well. The path in the
|
/// [first], which (transitively) depends on [last] as well. The path in the
|
||||||
/// thrown exception will go from [first] to [last].
|
/// thrown exception will go from [first] to [last].
|
||||||
void throwCircularException(MoorTable last, MoorTable first) {
|
void throwCircularException(MoorSchemaEntity last, MoorSchemaEntity first) {
|
||||||
final constructedPath = <MoorTable>[];
|
final constructedPath = <MoorSchemaEntity>[];
|
||||||
for (var current = last; current != first; current = previous[current]) {
|
for (var current = last; current != first; current = previous[current]) {
|
||||||
constructedPath.insert(0, current);
|
constructedPath.insert(0, current);
|
||||||
}
|
}
|
||||||
constructedPath.insert(0, first);
|
constructedPath.insert(0, first);
|
||||||
|
|
||||||
throw CircularReferenceException(constructedPath);
|
throw CircularReferenceException._(constructedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool didVisitAlready(MoorTable table) {
|
bool didVisitAlready(MoorSchemaEntity table) {
|
||||||
return previous[table] != null || result.contains(table);
|
return previous[table] != null || result.contains(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Thrown by [sortTablesTopologically] when the graph formed by
|
/// Thrown by [sortEntitiesTopologically] when the graph formed by
|
||||||
/// [MoorTable]s and their [MoorTable.references] is not acyclic.
|
/// [MoorSchemaEntity.references] is not acyclic.
|
||||||
class CircularReferenceException implements Exception {
|
class CircularReferenceException implements Exception {
|
||||||
/// The list of tables forming a circular reference, so that the first table
|
/// The list of entities forming a circular reference, so that the first
|
||||||
/// in this list references the second one and so on. The last table in this
|
/// entity in this list references the second one and so on. The last entity
|
||||||
/// list references the first one.
|
/// in this list references the first one, thus forming a cycle.
|
||||||
final List<MoorTable> affected;
|
final List<MoorSchemaEntity> affected;
|
||||||
|
|
||||||
CircularReferenceException(this.affected);
|
CircularReferenceException._(this.affected);
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:moor_generator/moor_generator.dart';
|
import 'package:moor_generator/moor_generator.dart';
|
||||||
import 'package:moor_generator/src/utils/table_reference_sorter.dart';
|
import 'package:moor_generator/src/utils/entity_reference_sorter.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -39,14 +39,14 @@ void main() {
|
||||||
a.references.add(b);
|
a.references.add(b);
|
||||||
b.references.add(c);
|
b.references.add(c);
|
||||||
|
|
||||||
final sorted = sortTablesTopologically([a, b, c, d]);
|
final sorted = sortEntitiesTopologically([a, b, c, d]);
|
||||||
expect(sorted, [c, b, a, d]);
|
expect(sorted, [c, b, a, d]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
CircularReferenceException _expectFails(Iterable<MoorTable> table) {
|
CircularReferenceException _expectFails(Iterable<MoorTable> table) {
|
||||||
try {
|
try {
|
||||||
sortTablesTopologically(table);
|
sortEntitiesTopologically(table);
|
||||||
fail('Expected sortTablesTopologically to throw here');
|
fail('Expected sortTablesTopologically to throw here');
|
||||||
} on CircularReferenceException catch (e) {
|
} on CircularReferenceException catch (e) {
|
||||||
return e;
|
return e;
|
|
@ -9,7 +9,9 @@ class Block extends AstNode {
|
||||||
Block(this.statements);
|
Block(this.statements);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T accept<T>(AstVisitor<T> visitor) => visitor.visitBlock(this);
|
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||||
|
return visitor.visitBlock(this, arg);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Iterable<AstNode> get childNodes => statements;
|
Iterable<AstNode> get childNodes => statements;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
part of '../ast.dart';
|
part of '../ast.dart';
|
||||||
|
|
||||||
abstract class TableInducingStatement extends Statement
|
abstract class TableInducingStatement extends Statement
|
||||||
implements PartOfMoorFile, SchemaStatement {
|
implements SchemaStatement {
|
||||||
final bool ifNotExists;
|
final bool ifNotExists;
|
||||||
final String tableName;
|
final String tableName;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
part of '../ast.dart';
|
part of '../ast.dart';
|
||||||
|
|
||||||
/// A "CREATE TRIGGER" statement, see https://sqlite.org/lang_createtrigger.html
|
/// A "CREATE TRIGGER" statement, see https://sqlite.org/lang_createtrigger.html
|
||||||
class CreateTriggerStatement extends Statement with SchemaStatement {
|
class CreateTriggerStatement extends Statement implements SchemaStatement {
|
||||||
final bool ifNotExists;
|
final bool ifNotExists;
|
||||||
final String triggerName;
|
final String triggerName;
|
||||||
IdentifierToken triggerNameToken;
|
IdentifierToken triggerNameToken;
|
||||||
|
@ -24,8 +24,8 @@ class CreateTriggerStatement extends Statement with SchemaStatement {
|
||||||
@required this.action});
|
@required this.action});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T accept<T>(AstVisitor<T> visitor) {
|
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||||
return visitor.visitCreateTriggerStatement(this);
|
return visitor.visitCreateTriggerStatement(this, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -53,7 +53,7 @@ abstract class TriggerTarget {
|
||||||
int get hashCode => runtimeType.hashCode;
|
int get hashCode => runtimeType.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(other) => other.runtimeType == runtimeType;
|
bool operator ==(dynamic other) => other.runtimeType == runtimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteTarget extends TriggerTarget {
|
class DeleteTarget extends TriggerTarget {
|
||||||
|
|
|
@ -10,6 +10,7 @@ abstract class AstVisitor<A, R> {
|
||||||
R visitUpdateStatement(UpdateStatement e, A arg);
|
R visitUpdateStatement(UpdateStatement e, A arg);
|
||||||
R visitCreateTableStatement(CreateTableStatement e, A arg);
|
R visitCreateTableStatement(CreateTableStatement e, A arg);
|
||||||
R visitCreateVirtualTableStatement(CreateVirtualTableStatement e, A arg);
|
R visitCreateVirtualTableStatement(CreateVirtualTableStatement e, A arg);
|
||||||
|
R visitCreateTriggerStatement(CreateTriggerStatement e, A arg);
|
||||||
|
|
||||||
R visitWithClause(WithClause e, A arg);
|
R visitWithClause(WithClause e, A arg);
|
||||||
R visitCommonTableExpression(CommonTableExpression e, A arg);
|
R visitCommonTableExpression(CommonTableExpression e, A arg);
|
||||||
|
@ -50,6 +51,8 @@ abstract class AstVisitor<A, R> {
|
||||||
R visitNumberedVariable(NumberedVariable e, A arg);
|
R visitNumberedVariable(NumberedVariable e, A arg);
|
||||||
R visitNamedVariable(ColonNamedVariable e, A arg);
|
R visitNamedVariable(ColonNamedVariable e, A arg);
|
||||||
|
|
||||||
|
R visitBlock(Block block, A arg);
|
||||||
|
|
||||||
R visitMoorFile(MoorFile e, A arg);
|
R visitMoorFile(MoorFile e, A arg);
|
||||||
R visitMoorImportStatement(ImportStatement e, A arg);
|
R visitMoorImportStatement(ImportStatement e, A arg);
|
||||||
R visitMoorDeclaredStatement(DeclaredStatement e, A arg);
|
R visitMoorDeclaredStatement(DeclaredStatement e, A arg);
|
||||||
|
@ -91,12 +94,16 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
|
||||||
return visitTableInducingStatement(e, arg);
|
return visitTableInducingStatement(e, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
@override
|
@override
|
||||||
R visitCreateVirtualTableStatement(CreateVirtualTableStatement e, A arg) {
|
R visitCreateVirtualTableStatement(CreateVirtualTableStatement e, A arg) {
|
||||||
return visitTableInducingStatement(e, arg);
|
return visitTableInducingStatement(e, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
R visitCreateTriggerStatement(CreateTriggerStatement e, A arg) {
|
||||||
|
return visitCreateTriggerStatement(e, arg);
|
||||||
|
}
|
||||||
|
|
||||||
R visitBaseSelectStatement(BaseSelectStatement stmt, A arg) {
|
R visitBaseSelectStatement(BaseSelectStatement stmt, A arg) {
|
||||||
return visitCrudStatement(stmt, arg);
|
return visitCrudStatement(stmt, arg);
|
||||||
}
|
}
|
||||||
|
@ -204,6 +211,11 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
|
||||||
return visitChildren(e, arg);
|
return visitChildren(e, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
R visitBlock(Block e, A arg) {
|
||||||
|
return visitChildren(e, arg);
|
||||||
|
}
|
||||||
|
|
||||||
// Moor-specific additions
|
// Moor-specific additions
|
||||||
@override
|
@override
|
||||||
R visitMoorFile(MoorFile e, A arg) {
|
R visitMoorFile(MoorFile e, A arg) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:test/test.dart';
|
||||||
|
|
||||||
import 'utils.dart';
|
import 'utils.dart';
|
||||||
|
|
||||||
final block = Block([
|
final _block = Block([
|
||||||
UpdateStatement(table: TableReference('tbl'), set: [
|
UpdateStatement(table: TableReference('tbl'), set: [
|
||||||
SetComponent(
|
SetComponent(
|
||||||
column: Reference(columnName: 'foo'),
|
column: Reference(columnName: 'foo'),
|
||||||
|
@ -36,7 +36,7 @@ void main() {
|
||||||
mode: TriggerMode.after,
|
mode: TriggerMode.after,
|
||||||
target: const DeleteTarget(),
|
target: const DeleteTarget(),
|
||||||
onTable: TableReference('tbl'),
|
onTable: TableReference('tbl'),
|
||||||
action: block,
|
action: _block,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -61,7 +61,7 @@ void main() {
|
||||||
Reference(columnName: 'bar'),
|
Reference(columnName: 'bar'),
|
||||||
]),
|
]),
|
||||||
onTable: TableReference('tbl'),
|
onTable: TableReference('tbl'),
|
||||||
action: block,
|
action: _block,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -89,7 +89,7 @@ void main() {
|
||||||
Reference(tableName: 'new', columnName: 'foo'),
|
Reference(tableName: 'new', columnName: 'foo'),
|
||||||
NullLiteral(token(TokenType.$null)),
|
NullLiteral(token(TokenType.$null)),
|
||||||
),
|
),
|
||||||
action: block,
|
action: _block,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue