Generate code for CREATE TRIGGER statements

This commit is contained in:
Simon Binder 2019-10-21 18:13:28 +02:00
parent e553d37de6
commit 8a54fd4729
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
13 changed files with 115 additions and 8 deletions

View File

@ -866,6 +866,9 @@ abstract class _$Database extends GeneratedDatabase {
@override
List<TableInfo> get allTables =>
[categories, recipes, ingredients, ingredientInRecipes];
@override
List<DatabaseSchemaEntity> get allEntities =>
[categories, recipes, ingredients, ingredientInRecipes];
}
class TotalWeightResult {

View File

@ -369,6 +369,7 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
MigrationStrategy get _resolvedMigration => _cachedMigration ??= migration;
/// A list of tables specified in this database.
// todo: Replace all usages with allEntities.whereType()
List<TableInfo> get allTables;
/// All entities (tables, views, triggers, indexes) that are declared in this

View File

@ -888,6 +888,10 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
ConfigTable get config => _config ??= ConfigTable(this);
Mytable _mytable;
Mytable get mytable => _mytable ??= Mytable(this);
Trigger _myTrigger;
Trigger get myTrigger => _myTrigger ??= Trigger(
'CREATE TRIGGER my_trigger AFTER INSERT ON config BEGIN\n INSERT INTO with_defaults VALUES (new.config_key, LENGTH(new.config_value));\nEND;',
'my_trigger');
Config _rowToConfig(QueryRow row) {
return Config(
configKey: row.readString('config_key'),
@ -953,6 +957,9 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
@override
List<TableInfo> get allTables =>
[noIds, withDefaults, withConstraints, config, mytable];
@override
List<DatabaseSchemaEntity> get allEntities =>
[noIds, withDefaults, withConstraints, config, mytable, myTrigger];
}
class ReadRowIdResult {

View File

@ -27,6 +27,10 @@ CREATE TABLE mytable (
somedate DATETIME
);
CREATE TRIGGER my_trigger AFTER INSERT ON config BEGIN
INSERT INTO with_defaults VALUES (new.config_key, LENGTH(new.config_value));
END;
readConfig: SELECT * FROM config WHERE config_key = ?;
readMultiple: SELECT * FROM config WHERE config_key IN ? ORDER BY $clause;
readDynamic: SELECT * FROM config WHERE $predicate;

View File

@ -1417,6 +1417,15 @@ abstract class _$TodoDb extends GeneratedDatabase {
tableWithoutPK,
pureDefaults
];
@override
List<DatabaseSchemaEntity> get allEntities => [
todosTable,
categories,
users,
sharedTodos,
tableWithoutPK,
pureDefaults
];
}
class AllTodosWithCategoryResult {

View File

@ -19,6 +19,7 @@ class MoorParser {
final createdReaders = <CreateTableReader>[];
final queryDeclarations = <DeclaredMoorQuery>[];
final importStatements = <ImportStatement>[];
final otherComponents = <PartOfMoorFile>[];
for (var parsedStmt in parsedFile.statements) {
if (parsedStmt is ImportStatement) {
@ -29,6 +30,8 @@ class MoorParser {
createdReaders.add(CreateTableReader(parsedStmt, step));
} else if (parsedStmt is DeclaredStatement) {
queryDeclarations.add(DeclaredMoorQuery.fromStatement(parsedStmt));
} else if (parsedStmt is CreateTriggerStatement) {
otherComponents.add(parsedStmt);
}
}
@ -54,6 +57,7 @@ class MoorParser {
queries: queryDeclarations,
imports: importStatements,
tableDeclarations: tableDeclarations,
otherComponents: otherComponents,
);
for (var decl in queryDeclarations) {
decl.file = analyzedFile;

View File

@ -36,6 +36,10 @@ class ParsedMoorFile extends FileResult {
final List<ImportStatement> imports;
final List<DeclaredQuery> queries;
/// Schema component that are neither tables nor queries. This can include
/// triggers or indexes.
final List<PartOfMoorFile> otherComponents;
List<SqlQuery> resolvedQueries;
Map<CreateTableStatement, SpecifiedTable> tableDeclarations;
Map<ImportStatement, FoundFile> resolvedImports;
@ -44,6 +48,7 @@ class ParsedMoorFile extends FileResult {
{List<SpecifiedTable> declaredTables = const [],
this.queries = const [],
this.imports = const [],
this.otherComponents = const [],
this.tableDeclarations = const {}})
: super(declaredTables);
}

View File

@ -1,7 +1,7 @@
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:moor/moor.dart';
import 'package:moor/moor.dart' show Table, UseMoor, UseDao;
import 'package:moor_generator/src/analyzer/dart/parser.dart';
import 'package:moor_generator/src/analyzer/errors.dart';
import 'package:moor_generator/src/analyzer/moor/table_handler.dart';
@ -9,14 +9,17 @@ 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/moor/inline_dart_resolver.dart';
import 'package:moor_generator/src/analyzer/moor/parser.dart';
import 'package:moor_generator/src/analyzer/sql_queries/meta/declarations.dart';
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/runner/task.dart';
import 'package:moor_generator/src/model/specified_db_classes.dart';
import 'package:moor_generator/src/model/specified_entities.dart';
import 'package:moor_generator/src/model/specified_table.dart';
import 'package:moor_generator/src/model/sql_query.dart';
import 'package:moor_generator/src/utils/table_reference_sorter.dart';
import 'package:source_gen/source_gen.dart';
import 'package:sqlparser/sqlparser.dart' hide Table;
part 'steps/analyze_dart.dart';
part 'steps/analyze_moor.dart';

View File

@ -34,10 +34,12 @@ class AnalyzeDartStep extends AnalyzingStep {
));
}
final availableQueries = transitiveImports
final transitiveMoorFiles = transitiveImports
.map((f) => f.currentResult)
.whereType<ParsedMoorFile>()
.expand((f) => f.resolvedQueries);
.whereType<ParsedMoorFile>();
final availableQueries =
transitiveMoorFiles.expand((f) => f.resolvedQueries);
final parser = SqlParser(this, availableTables, accessor.queries);
parser.parse();
@ -46,6 +48,21 @@ class AnalyzeDartStep extends AnalyzingStep {
accessor.resolvedQueries =
availableQueries.followedBy(parser.foundQueries).toList();
if (accessor is SpecifiedDatabase) {
accessor.otherEntities = transitiveMoorFiles.expand((file) {
return file.otherComponents.map((component) {
final declaration = BaseDeclaration(null, null, component);
if (component is CreateTriggerStatement) {
return SpecifiedTrigger(
component.triggerName, component.span.text, declaration);
}
throw AssertionError('Unexpected component: $component');
});
}).toList();
}
}
}
}

View File

@ -1,6 +1,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
import 'package:moor_generator/src/model/specified_entities.dart';
import 'package:moor_generator/src/model/specified_table.dart';
import 'package:moor_generator/src/model/sql_query.dart';
@ -41,7 +42,15 @@ class SpecifiedDao extends SpecifiedDbAccessor {
class SpecifiedDatabase extends SpecifiedDbAccessor {
final List<DartType> daos;
SpecifiedDatabase(ClassElement fromClass, List<SpecifiedTable> tables,
this.daos, List<String> includes, List<DeclaredQuery> queries)
: super(fromClass, tables, includes, queries);
/// Other entities (such as triggers or components) that are available to this
/// database.
List<SpecifiedEntity> otherEntities;
SpecifiedDatabase(
ClassElement fromClass,
List<SpecifiedTable> tables,
this.daos,
List<String> includes,
List<DeclaredQuery> queries,
) : super(fromClass, tables, includes, queries);
}

View File

@ -0,0 +1,24 @@
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);
}

View File

@ -1,4 +1,6 @@
import 'package:moor_generator/src/model/specified_db_classes.dart';
import 'package:moor_generator/src/model/specified_entities.dart';
import 'package:moor_generator/src/utils/string_escaper.dart';
import 'package:moor_generator/src/writer/queries/query_writer.dart';
import 'package:moor_generator/src/writer/tables/table_writer.dart';
import 'package:moor_generator/src/writer/utils/memoized_getter.dart';
@ -26,6 +28,7 @@ class DatabaseWriter {
'$className(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); \n');
final tableGetters = <String>[];
final entityGetters = <String>[];
for (var table in db.allTables) {
tableGetters.add(table.tableFieldName);
@ -38,6 +41,21 @@ class DatabaseWriter {
code: '$tableClassName(this)',
);
}
entityGetters.addAll(tableGetters);
for (var otherEntity in db.otherEntities) {
entityGetters.add(otherEntity.dartFieldName);
if (otherEntity is SpecifiedTrigger) {
writeMemoizedGetter(
buffer: dbScope.leaf(),
getterName: otherEntity.dartFieldName,
returnType: 'Trigger',
code: 'Trigger(${asDartLiteral(otherEntity.sql)}, '
'${asDartLiteral(otherEntity.name)})',
);
}
}
// Write fields to access an dao. We use a lazy getter for that.
for (var dao in db.daos) {
@ -63,6 +81,9 @@ class DatabaseWriter {
dbScope.leaf()
..write('@override\nList<TableInfo> get allTables => [')
..write(tableGetters.join(','))
..write('];\n')
..write('@override\nList<DatabaseSchemaEntity> get allEntities => [')
..write(entityGetters.join(','))
..write('];\n}');
}
}

View File

@ -332,7 +332,7 @@ class Parser extends ParserBase
for (var stmt = _parseAsStatement(_crud);
stmt != null || _lastStmtHadParsingError;
stmt = _parseAsStatement(_crud)) {
stmts.add(stmt);
if (stmt != null) stmts.add(stmt);
}
final end = _consume(TokenType.end, 'Expected END');