Refactor generator: Extract common operations

This commit is contained in:
Simon Binder 2019-06-29 15:23:14 +02:00
parent 33682a0ad1
commit 53d57d6a96
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
9 changed files with 87 additions and 89 deletions

View File

@ -54,18 +54,13 @@ class TableWithoutPK extends Table {
@UseMoor(
tables: [TodosTable, Categories, Users, SharedTodos, TableWithoutPK],
daos: [SomeDao],
queries: [
Sql(
'allTodosWithCategory',
'SELECT t.*, c.id as catId, c."desc" as catDesc '
'FROM todos t INNER JOIN categories c ON c.id = t.category',
),
Sql(
'todosForUser',
'SELECT t.* FROM todos t '
'INNER JOIN shared_todos st ON st.todo = t.id '
'INNER JOIN users u ON u.id = st.user '
'WHERE u.id = :user'),
],
)
class TodoDb extends _$TodoDb {
@ -77,3 +72,18 @@ class TodoDb extends _$TodoDb {
@override
int get schemaVersion => 1;
}
@UseDao(
tables: [Users, SharedTodos, TodosTable],
queries: [
Sql(
'todosForUser',
'SELECT t.* FROM todos t '
'INNER JOIN shared_todos st ON st.todo = t.id '
'INNER JOIN users u ON u.id = st.user '
'WHERE u.id = :user'),
],
)
class SomeDao extends DatabaseAccessor<TodoDb> with _$SomeDaoMixin {
SomeDao(TodoDb db) : super(db);
}

View File

@ -1024,21 +1024,6 @@ class AllTodosWithCategoryResult {
});
}
class TodosForUserResult {
final int id;
final String title;
final String content;
final DateTime targetDate;
final int category;
TodosForUserResult({
this.id,
this.title,
this.content,
this.targetDate,
this.category,
});
}
abstract class _$TodoDb extends GeneratedDatabase {
_$TodoDb(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e);
$TodosTableTable _todosTable;
@ -1052,6 +1037,8 @@ abstract class _$TodoDb extends GeneratedDatabase {
$TableWithoutPKTable _tableWithoutPK;
$TableWithoutPKTable get tableWithoutPK =>
_tableWithoutPK ??= $TableWithoutPKTable(this);
SomeDao _someDao;
SomeDao get someDao => _someDao ??= SomeDao(this as TodoDb);
AllTodosWithCategoryResult _rowToAllTodosWithCategoryResult(QueryRow row) {
return AllTodosWithCategoryResult(
id: row.readInt('id'),
@ -1081,38 +1068,17 @@ abstract class _$TodoDb extends GeneratedDatabase {
}).map((rows) => rows.map(_rowToAllTodosWithCategoryResult).toList());
}
TodosForUserResult _rowToTodosForUserResult(QueryRow row) {
return TodosForUserResult(
id: row.readInt('id'),
title: row.readString('title'),
content: row.readString('content'),
targetDate: row.readDateTime('target_date'),
category: row.readInt('category'),
);
}
Future<List<TodosForUserResult>> todosForUser(int user) {
return customSelect(
'SELECT t.* FROM todos t INNER JOIN shared_todos st ON st.todo = t.id INNER JOIN users u ON u.id = st.user WHERE u.id = :user',
variables: [
Variable.withInt(user),
]).then((rows) => rows.map(_rowToTodosForUserResult).toList());
}
Stream<List<TodosForUserResult>> watchTodosForUser(int user) {
return customSelectStream(
'SELECT t.* FROM todos t INNER JOIN shared_todos st ON st.todo = t.id INNER JOIN users u ON u.id = st.user WHERE u.id = :user',
variables: [
Variable.withInt(user),
],
readsFrom: {
users,
todosTable,
sharedTodos
}).map((rows) => rows.map(_rowToTodosForUserResult).toList());
}
@override
List<TableInfo> get allTables =>
[todosTable, categories, users, sharedTodos, tableWithoutPK];
}
// **************************************************************************
// DaoGenerator
// **************************************************************************
mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
$UsersTable get users => db.users;
$SharedTodosTable get sharedTodos => db.sharedTodos;
$TodosTableTable get todosTable => db.todosTable;
}

View File

@ -1,6 +1,7 @@
import 'package:build/build.dart';
import 'package:moor_generator/src/dao_generator.dart';
import 'package:moor_generator/src/options.dart';
import 'package:moor_generator/src/shared_state.dart';
import 'package:source_gen/source_gen.dart';
import 'package:moor_generator/src/moor_generator.dart';
@ -8,7 +9,7 @@ Builder moorBuilder(BuilderOptions options) {
final writeFromString =
options.config['write_from_json_string_constructor'] as bool ?? false;
final parsedOptions = MoorOptions(writeFromString);
final state = SharedState(parsedOptions);
return SharedPartBuilder(
[MoorGenerator(parsedOptions), DaoGenerator()], 'moor');
return SharedPartBuilder([MoorGenerator(state), DaoGenerator()], 'moor');
}

View File

@ -1,4 +1,3 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:moor/moor.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/results.dart'; // ignore: implementation_imports
@ -10,6 +9,7 @@ import 'package:moor_generator/src/model/specified_table.dart';
import 'package:moor_generator/src/options.dart';
import 'package:moor_generator/src/parser/column_parser.dart';
import 'package:moor_generator/src/parser/table_parser.dart';
import 'package:moor_generator/src/shared_state.dart';
import 'package:moor_generator/src/writer/database_writer.dart';
import 'package:source_gen/source_gen.dart';
@ -17,18 +17,10 @@ import 'model/sql_query.dart';
import 'parser/sql/sql_parser.dart';
class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
//final Map<String, ParsedLibraryResult> _astForLibs = {};
final ErrorStore errors = ErrorStore();
final MoorOptions options;
final SharedState state;
MoorOptions get options => state.options;
TableParser tableParser;
ColumnParser columnParser;
final tableTypeChecker = const TypeChecker.fromRuntime(Table);
final Map<DartType, SpecifiedTable> _foundTables = {};
MoorGenerator(this.options);
MoorGenerator(this.state);
ElementDeclarationResult loadElementDeclaration(Element element) {
/*final result = _astForLibs.putIfAbsent(element.library.name, () {
@ -52,29 +44,30 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
.toList();
final queries = annotation.peek('queries')?.listValue ?? [];
tableParser ??= TableParser(this);
columnParser ??= ColumnParser(this);
state.tableParser ??= TableParser(this);
state.columnParser ??= ColumnParser(this);
final tablesForThisDb = <SpecifiedTable>[];
var resolvedQueries = <SqlQuery>[];
for (var table in tableTypes) {
if (!tableTypeChecker.isAssignableFrom(table.element)) {
errors.add(MoorError(
if (!state.tableTypeChecker.isAssignableFrom(table.element)) {
state.errors.add(MoorError(
critical: true,
message: 'The type $table is not a moor table',
affectedElement: element));
} else {
final specifiedTable = tableParser.parse(table.element as ClassElement);
_foundTables[table] = specifiedTable;
final specifiedTable =
state.tableParser.parse(table.element as ClassElement);
state.foundTables[table] = specifiedTable;
tablesForThisDb.add(specifiedTable);
}
}
if (errors.errors.isNotEmpty) {
if (state.errors.errors.isNotEmpty) {
print('Warning: There were some errors while running moor_generator:');
for (var error in errors.errors) {
for (var error in state.errors.errors) {
print(error.message);
if (error.affectedElement != null) {
@ -82,17 +75,17 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
print('${span.start.toolString}\n${span.highlight()}');
}
}
errors.errors.clear();
state.errors.errors.clear();
}
if (queries.isNotEmpty) {
final parser = SqlParser(options, tablesForThisDb, queries)..parse();
errors.errors.addAll(parser.errors);
state.errors.errors.addAll(parser.errors);
resolvedQueries = parser.foundQueries;
}
if (_foundTables.isEmpty) return '';
if (tablesForThisDb.isEmpty) return '';
final specifiedDb = SpecifiedDatabase(
element as ClassElement, tablesForThisDb, daoTypes, resolvedQueries);

View File

@ -52,7 +52,7 @@ class ColumnParser extends ParserBase {
final expr = returnExpressionOfMethod(getter);
if (!(expr is FunctionExpressionInvocation)) {
generator.errors.add(MoorError(
generator.state.errors.add(MoorError(
affectedElement: getter.declaredElement,
message: _errorMessage,
critical: true,
@ -84,7 +84,7 @@ class ColumnParser extends ParserBase {
switch (methodName) {
case _methodNamed:
if (foundExplicitName != null) {
generator.errors.add(
generator.state.errors.add(
MoorError(
critical: false,
affectedElement: getter.declaredElement,
@ -97,7 +97,7 @@ class ColumnParser extends ParserBase {
foundExplicitName =
readStringLiteral(remainingExpr.argumentList.arguments.first, () {
generator.errors.add(
generator.state.errors.add(
MoorError(
critical: false,
affectedElement: getter.declaredElement,
@ -133,7 +133,7 @@ class ColumnParser extends ParserBase {
case _methodCustomConstraint:
foundCustomConstraint =
readStringLiteral(remainingExpr.argumentList.arguments.first, () {
generator.errors.add(
generator.state.errors.add(
MoorError(
critical: false,
affectedElement: getter.declaredElement,

View File

@ -18,7 +18,7 @@ class ParserBase {
final body = method.body;
if (!(body is ExpressionFunctionBody)) {
generator.errors.add(MoorError(
generator.state.errors.add(MoorError(
affectedElement: method.declaredElement,
critical: true,
message:

View File

@ -58,7 +58,7 @@ class TableParser extends ParserBase {
tableNameDeclaration.node as MethodDeclaration);
final tableName = readStringLiteral(returnExpr, () {
generator.errors.add(MoorError(
generator.state.errors.add(MoorError(
critical: true,
message:
'This getter must return a string literal, and do nothing more',
@ -79,7 +79,7 @@ class TableParser extends ParserBase {
as MethodDeclaration;
final body = ast.body;
if (body is! ExpressionFunctionBody) {
generator.errors.add(MoorError(
generator.state.errors.add(MoorError(
affectedElement: primaryKeyGetter,
message: 'This must return a set literal using the => syntax!'));
return null;
@ -103,7 +103,7 @@ class TableParser extends ParserBase {
}
}
} else {
generator.errors.add(MoorError(
generator.state.errors.add(MoorError(
affectedElement: primaryKeyGetter,
message: 'This must return a set literal!'));
}
@ -118,7 +118,7 @@ class TableParser extends ParserBase {
final node = generator.loadElementDeclaration(field.getter).node
as MethodDeclaration;
return generator.columnParser.parse(node, field.getter);
return generator.state.columnParser.parse(node, field.getter);
}).toList();
}
}

View File

@ -0,0 +1,25 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:moor/moor.dart' show Table;
import 'package:moor_generator/src/parser/column_parser.dart';
import 'package:moor_generator/src/parser/table_parser.dart';
import 'package:source_gen/source_gen.dart';
import 'errors.dart';
import 'model/specified_table.dart';
import 'options.dart';
/// Information that is needed for both the regular generator and the dao
/// generator. Kept in sync so it only needs to be evaluated once.
class SharedState {
final ErrorStore errors = ErrorStore();
final MoorOptions options;
TableParser tableParser;
ColumnParser columnParser;
final tableTypeChecker = const TypeChecker.fromRuntime(Table);
final Map<DartType, SpecifiedTable> foundTables = {};
SharedState(this.options);
}

View File

@ -4,12 +4,14 @@ import 'package:moor_generator/src/options.dart';
import 'package:moor_generator/src/parser/column_parser.dart';
import 'package:moor_generator/src/parser/table_parser.dart';
import 'package:moor_generator/src/moor_generator.dart';
import 'package:moor_generator/src/shared_state.dart';
import 'package:test_api/test_api.dart';
import 'package:build_test/build_test.dart';
void main() async {
LibraryElement testLib;
MoorGenerator generator;
SharedState state;
setUpAll(() async {
testLib = await resolveSource(r'''
@ -51,8 +53,9 @@ void main() async {
});
setUp(() {
generator = MoorGenerator(const MoorOptions.defaults());
generator
state = SharedState(const MoorOptions.defaults());
generator = MoorGenerator(state);
state
..columnParser = ColumnParser(generator)
..tableParser = TableParser(generator);
});
@ -74,7 +77,7 @@ void main() async {
test('should not parse for complex methods', () async {
TableParser(generator).parse(testLib.getType('WrongName'));
expect(generator.errors.errors, isNotEmpty);
expect(state.errors.errors, isNotEmpty);
});
});