mirror of https://github.com/AMT-Cheif/drift.git
Don't write variables in `CREATE VIEW`
This commit is contained in:
parent
3c50437821
commit
4ddbed5cca
|
@ -3,6 +3,7 @@
|
|||
- Add `DataClassName.extending` to control the superclass of generated row
|
||||
classes.
|
||||
- Add `setup` parameter to the constructors of `WebDatabase` too.
|
||||
- Don't write variables for expressions in `CREATE VIEW` statements.
|
||||
|
||||
## 1.4.0
|
||||
|
||||
|
|
|
@ -60,6 +60,12 @@ class Variable<T> extends Expression<T> {
|
|||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
if (!context.supportsVariables) {
|
||||
// Write as constant instead.
|
||||
Constant<T>(value).writeInto(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var explicitStart = context.explicitVariableIndex;
|
||||
|
||||
var mark = '?';
|
||||
|
|
|
@ -30,6 +30,12 @@ class GenerationContext {
|
|||
/// query.
|
||||
final DatabaseConnectionUser? executor;
|
||||
|
||||
/// Whether variables are supported and can be written as `?` to be bound
|
||||
/// later.
|
||||
///
|
||||
/// This is almost always the case, but not in a `CREATE VIEW` statement.
|
||||
final bool supportsVariables;
|
||||
|
||||
final List<dynamic> _boundVariables = [];
|
||||
|
||||
/// The values of [introducedVariables] that will be sent to the underlying
|
||||
|
@ -51,7 +57,7 @@ class GenerationContext {
|
|||
|
||||
/// Constructs a [GenerationContext] by copying the relevant fields from the
|
||||
/// database.
|
||||
GenerationContext.fromDb(this.executor)
|
||||
GenerationContext.fromDb(this.executor, {this.supportsVariables = true})
|
||||
: typeSystem = executor?.typeSystem ?? SqlTypeSystem.defaultInstance,
|
||||
// ignore: invalid_null_aware_operator, (doesn't seem to actually work)
|
||||
dialect = executor?.executor?.dialect ?? SqlDialect.sqlite;
|
||||
|
@ -59,7 +65,7 @@ class GenerationContext {
|
|||
/// Constructs a custom [GenerationContext] by setting the fields manually.
|
||||
/// See [GenerationContext.fromDb] for a more convenient factory.
|
||||
GenerationContext(this.typeSystem, this.executor,
|
||||
{this.dialect = SqlDialect.sqlite});
|
||||
{this.dialect = SqlDialect.sqlite, this.supportsVariables = true});
|
||||
|
||||
/// Introduces a variable that will be sent to the database engine. Whenever
|
||||
/// this method is called, a question mark should be added to the [buffer] so
|
||||
|
|
|
@ -324,7 +324,7 @@ class Migrator {
|
|||
if (stmt != null) {
|
||||
await _issueCustomQuery(stmt, const []);
|
||||
} else if (view.query != null) {
|
||||
final context = GenerationContext.fromDb(_db);
|
||||
final context = GenerationContext.fromDb(_db, supportsVariables: false);
|
||||
context.generatingForView = view.entityName;
|
||||
context.buffer.write('CREATE VIEW IF NOT EXISTS ${view.entityName} AS ');
|
||||
view.query!.writeInto(context);
|
||||
|
|
|
@ -121,10 +121,12 @@ abstract class CategoryTodoCountView extends View {
|
|||
TodosTable get todos;
|
||||
Categories get categories;
|
||||
|
||||
Expression<String> get description =>
|
||||
categories.description + const Variable('!');
|
||||
Expression<int> get itemCount => todos.id.count();
|
||||
|
||||
@override
|
||||
Query as() => select([categories.description, itemCount])
|
||||
Query as() => select([description, itemCount])
|
||||
.from(categories)
|
||||
.join([innerJoin(todos, todos.category.equalsExp(categories.id))]);
|
||||
}
|
||||
|
|
|
@ -1362,7 +1362,7 @@ class CategoryTodoCountViewData extends DataClass {
|
|||
final effectivePrefix = prefix ?? '';
|
||||
return CategoryTodoCountViewData(
|
||||
description: const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}categories.desc'])!,
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}description'])!,
|
||||
itemCount: const IntType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}item_count'])!,
|
||||
);
|
||||
|
@ -1423,7 +1423,7 @@ class $CategoryTodoCountViewView
|
|||
$TodosTableTable get todos => attachedDatabase.todosTable;
|
||||
$CategoriesTable get categories => attachedDatabase.categories;
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [categories.description, itemCount];
|
||||
List<GeneratedColumn> get $columns => [description, itemCount];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@override
|
||||
|
@ -1440,8 +1440,10 @@ class $CategoryTodoCountViewView
|
|||
}
|
||||
|
||||
late final GeneratedColumn<String?> description = GeneratedColumn<String?>(
|
||||
'desc', aliasedName, false,
|
||||
type: const StringType(), $customConstraints: 'NOT NULL UNIQUE');
|
||||
'description', aliasedName, false,
|
||||
type: const StringType(),
|
||||
generatedAs:
|
||||
GeneratedAs(categories.description + const Variable('!'), false));
|
||||
late final GeneratedColumn<int?> itemCount = GeneratedColumn<int?>(
|
||||
'item_count', aliasedName, false,
|
||||
type: const IntType(), generatedAs: GeneratedAs(todos.id.count(), false));
|
||||
|
|
|
@ -54,7 +54,15 @@ void main() {
|
|||
|
||||
variable.writeInto(ctx);
|
||||
|
||||
expect('NULL', ctx.sql);
|
||||
expect(ctx.sql, 'NULL');
|
||||
expect(ctx.boundVariables, isEmpty);
|
||||
});
|
||||
|
||||
test('writes constants when variables are not supported', () {
|
||||
const variable = Variable<String?>("hello world'");
|
||||
final ctx = GenerationContext.fromDb(TodoDb(), supportsVariables: false);
|
||||
variable.writeInto(ctx);
|
||||
|
||||
expect(ctx.sql, "'hello world'''");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ void main() {
|
|||
|
||||
verify(mockExecutor.runCustom(
|
||||
'CREATE VIEW IF NOT EXISTS category_todo_count_view AS SELECT '
|
||||
'categories."desc" AS "categories.desc", '
|
||||
'categories."desc" || \'!\' AS "description", '
|
||||
'COUNT(todos.id) AS "item_count" '
|
||||
'FROM categories '
|
||||
'INNER JOIN todos '
|
||||
|
|
Loading…
Reference in New Issue