Alias Dart view columns and tables

This commit is contained in:
Simon Binder 2022-05-17 21:47:10 +02:00
parent befe3f33ef
commit 4d3d794f15
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
9 changed files with 65 additions and 44 deletions

View File

@ -27,6 +27,7 @@ abstract class TodoCategoryItemCount extends View {
TodoCategories get todoCategories;
Expression<int> get itemCount => todoItems.id.count();
//
@override
Query as() => select([

View File

@ -538,8 +538,9 @@ class $TodoCategoryItemCountView
@override
final _$Database attachedDatabase;
$TodoCategoryItemCountView(this.attachedDatabase, [this._alias]);
$TodoItemsTable get todoItems => attachedDatabase.todoItems;
$TodoCategoriesTable get todoCategories => attachedDatabase.todoCategories;
$TodoItemsTable get todoItems => attachedDatabase.todoItems.createAlias('t0');
$TodoCategoriesTable get todoCategories =>
attachedDatabase.todoCategories.createAlias('t1');
@override
List<GeneratedColumn> get $columns => [todoCategories.name, itemCount];
@override
@ -647,8 +648,9 @@ class $TodoItemWithCategoryNameViewView extends ViewInfo<
@override
final _$Database attachedDatabase;
$TodoItemWithCategoryNameViewView(this.attachedDatabase, [this._alias]);
$TodoItemsTable get todoItems => attachedDatabase.todoItems;
$TodoCategoriesTable get todoCategories => attachedDatabase.todoCategories;
$TodoItemsTable get todoItems => attachedDatabase.todoItems.createAlias('t0');
$TodoCategoriesTable get todoCategories =>
attachedDatabase.todoCategories.createAlias('t1');
@override
List<GeneratedColumn> get $columns => [todoItems.id, title];
@override

View File

@ -350,8 +350,11 @@ class Migrator {
await _issueCustomQuery(stmt, const []);
} else if (view.query != null) {
final context = GenerationContext.fromDb(_db, supportsVariables: false);
final columnNames = view.$columns.map((e) => e.escapedName).join(', ');
context.generatingForView = view.entityName;
context.buffer.write('CREATE VIEW IF NOT EXISTS ${view.entityName} AS ');
context.buffer.write(
'CREATE VIEW IF NOT EXISTS ${view.entityName} ($columnNames) AS ');
view.query!.writeInto(context);
await _issueCustomQuery(context.sql, const []);
}

View File

@ -70,22 +70,24 @@ void main() {
[]));
verify(mockExecutor.runCustom(
'CREATE VIEW IF NOT EXISTS category_todo_count_view AS SELECT '
'categories."desc" || \'!\' AS "description", '
'COUNT(todos.id) AS "item_count" '
'FROM categories '
'INNER JOIN todos '
'ON todos.category = categories.id '
'GROUP BY categories.id',
'CREATE VIEW IF NOT EXISTS category_todo_count_view '
'(description, item_count) AS SELECT '
't1."desc" || \'!\' AS "description", '
'COUNT(t0.id) AS "item_count" '
'FROM categories t1 '
'INNER JOIN todos t0 '
'ON t0.category = t1.id '
'GROUP BY t1.id',
[]));
verify(mockExecutor.runCustom(
'CREATE VIEW IF NOT EXISTS todo_with_category_view AS SELECT '
'todos.title AS "todos.title", '
'categories."desc" AS "categories.desc" '
'FROM todos '
'INNER JOIN categories '
'ON categories.id = todos.category',
'CREATE VIEW IF NOT EXISTS todo_with_category_view '
'(title, "desc") AS SELECT '
't0.title AS "t0.title", '
't1."desc" AS "t1.desc" '
'FROM todos t0 '
'INNER JOIN categories t1 '
'ON t1.id = t0.category',
[]));
});
@ -105,17 +107,18 @@ void main() {
[]));
});
test('creates views through `create()`', () async {
test('creates views through create()', () async {
await db.createMigrator().create(db.categoryTodoCountView);
verify(mockExecutor.runCustom(
'CREATE VIEW IF NOT EXISTS category_todo_count_view AS SELECT '
'categories."desc" || \'!\' AS "description", '
'COUNT(todos.id) AS "item_count" '
'FROM categories '
'INNER JOIN todos '
'ON todos.category = categories.id '
'GROUP BY categories.id',
'CREATE VIEW IF NOT EXISTS category_todo_count_view '
'(description, item_count) AS SELECT '
't1."desc" || \'!\' AS "description", '
'COUNT(t0.id) AS "item_count" '
'FROM categories t1 '
'INNER JOIN todos t0 '
'ON t0.category = t1.id '
'GROUP BY t1.id',
[]));
});

View File

@ -1460,8 +1460,9 @@ class $CategoryTodoCountViewView
@override
final _$TodoDb attachedDatabase;
$CategoryTodoCountViewView(this.attachedDatabase, [this._alias]);
$TodosTableTable get todos => attachedDatabase.todosTable;
$CategoriesTable get categories => attachedDatabase.categories;
$TodosTableTable get todos => attachedDatabase.todosTable.createAlias('t0');
$CategoriesTable get categories =>
attachedDatabase.categories.createAlias('t1');
@override
List<GeneratedColumn> get $columns => [description, itemCount];
@override
@ -1570,8 +1571,9 @@ class $TodoWithCategoryViewView
@override
final _$TodoDb attachedDatabase;
$TodoWithCategoryViewView(this.attachedDatabase, [this._alias]);
$TodosTableTable get todos => attachedDatabase.todosTable;
$CategoriesTable get categories => attachedDatabase.categories;
$TodosTableTable get todos => attachedDatabase.todosTable.createAlias('t0');
$CategoriesTable get categories =>
attachedDatabase.categories.createAlias('t1');
@override
List<GeneratedColumn> get $columns => [todos.title, categories.description];
@override

View File

@ -155,11 +155,12 @@ class ViewParser {
final expression = (node.body as ExpressionFunctionBody).expression;
return MoorColumn(
type: sqlType,
dartGetterName: field.name,
name: ColumnName.implicitly(ReCase(field.name).snakeCase),
nullable: dartType.nullabilitySuffix == NullabilitySuffix.question,
generatedAs: ColumnGeneratedAs(expression.toString(), false));
type: sqlType,
dartGetterName: field.name,
name: ColumnName.implicitly(ReCase(field.name).snakeCase),
nullable: dartType.nullabilitySuffix == NullabilitySuffix.question,
generatedAs: ColumnGeneratedAs(expression.toString(), false),
);
}).toList());
return results.whereType();
@ -275,8 +276,7 @@ class ViewParser {
final column =
columns.firstWhere((col) => col.dartGetterName == parts[0]);
return MapEntry('${column.dartGetterName}', column);
});
final columnMap = Map.fromEntries(columnList);
}).toList();
target = target.parent as MethodInvocation;
if (target.methodName.toString() != 'from') {
@ -291,7 +291,7 @@ class ViewParser {
final query =
body.expression.toString().substring(target.toString().length);
return ViewQueryInformation(columnMap, from, query);
return ViewQueryInformation(columnList, from, query);
} catch (e) {
print(e);
throw analysisError(

View File

@ -101,7 +101,9 @@ class MoorView extends MoorEntityWithResultSet {
}
class ViewQueryInformation {
final Map<String, MoorColumn> columns;
/// All columns from this Dart-defined view, in the order in which they were
/// added to the `query` getter.
final List<MapEntry<String, MoorColumn>> columns;
final String from;
final String query;

View File

@ -38,7 +38,7 @@ class DataClassWriter {
// write view columns
final view = table;
if (view is MoorView && view.viewQuery != null) {
columns.addAll(view.viewQuery!.columns.values);
columns.addAll(view.viewQuery!.columns.map((e) => e.value));
} else {
columns.addAll(table.columns);
}

View File

@ -49,9 +49,16 @@ class ViewWriter extends TableOrViewWriter {
final declaration = view.declaration;
if (declaration is DartViewDeclaration) {
// A view may read from the same table more than once, so we implicitly
// introduce aliases for tables.
var tableCounter = 0;
for (final ref in declaration.staticReferences) {
final declaration = '${ref.table.entityInfoName} get ${ref.name} => '
'attachedDatabase.${ref.table.dbGetterName};';
final table = ref.table;
final alias = asDartLiteral('t${tableCounter++}');
final declaration = '${table.entityInfoName} get ${ref.name} => '
'attachedDatabase.${table.dbGetterName}.createAlias($alias);';
buffer.writeln(declaration);
}
}
@ -59,7 +66,7 @@ class ViewWriter extends TableOrViewWriter {
if (view.viewQuery == null) {
writeGetColumnsOverride();
} else {
final columns = view.viewQuery!.columns.keys.join(', ');
final columns = view.viewQuery!.columns.map((e) => e.key).join(', ');
buffer.write('@override\nList<GeneratedColumn> get \$columns => '
'[$columns];\n');
}
@ -80,7 +87,8 @@ class ViewWriter extends TableOrViewWriter {
writeAsDslTable();
writeMappingMethod(scope);
for (final column in view.viewQuery?.columns.values ?? view.columns) {
final columns = view.viewQuery?.columns.map((e) => e.value) ?? view.columns;
for (final column in columns) {
writeColumnGetter(column, scope.generationOptions, false);
}