diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index d8b2a197..917509bb 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -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 diff --git a/drift/lib/src/runtime/query_builder/expressions/variables.dart b/drift/lib/src/runtime/query_builder/expressions/variables.dart index a5134e56..3e8c7430 100644 --- a/drift/lib/src/runtime/query_builder/expressions/variables.dart +++ b/drift/lib/src/runtime/query_builder/expressions/variables.dart @@ -60,6 +60,12 @@ class Variable extends Expression { @override void writeInto(GenerationContext context) { + if (!context.supportsVariables) { + // Write as constant instead. + Constant(value).writeInto(context); + return; + } + var explicitStart = context.explicitVariableIndex; var mark = '?'; diff --git a/drift/lib/src/runtime/query_builder/generation_context.dart b/drift/lib/src/runtime/query_builder/generation_context.dart index 8a7c90ac..dcfca8ef 100644 --- a/drift/lib/src/runtime/query_builder/generation_context.dart +++ b/drift/lib/src/runtime/query_builder/generation_context.dart @@ -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 _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 diff --git a/drift/lib/src/runtime/query_builder/migration.dart b/drift/lib/src/runtime/query_builder/migration.dart index ef5b6940..91540605 100644 --- a/drift/lib/src/runtime/query_builder/migration.dart +++ b/drift/lib/src/runtime/query_builder/migration.dart @@ -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); diff --git a/drift/test/data/tables/todos.dart b/drift/test/data/tables/todos.dart index cb2a0783..0459cf96 100644 --- a/drift/test/data/tables/todos.dart +++ b/drift/test/data/tables/todos.dart @@ -121,10 +121,12 @@ abstract class CategoryTodoCountView extends View { TodosTable get todos; Categories get categories; + Expression get description => + categories.description + const Variable('!'); Expression 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))]); } diff --git a/drift/test/data/tables/todos.g.dart b/drift/test/data/tables/todos.g.dart index c17b4df9..e19fceed 100644 --- a/drift/test/data/tables/todos.g.dart +++ b/drift/test/data/tables/todos.g.dart @@ -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 get $columns => [categories.description, itemCount]; + List get $columns => [description, itemCount]; @override String get aliasedName => _alias ?? entityName; @override @@ -1440,8 +1440,10 @@ class $CategoryTodoCountViewView } late final GeneratedColumn description = GeneratedColumn( - '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 itemCount = GeneratedColumn( 'item_count', aliasedName, false, type: const IntType(), generatedAs: GeneratedAs(todos.id.count(), false)); diff --git a/drift/test/expressions/variable_test.dart b/drift/test/expressions/variable_test.dart index bb14c962..a5bfb3d3 100644 --- a/drift/test/expressions/variable_test.dart +++ b/drift/test/expressions/variable_test.dart @@ -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("hello world'"); + final ctx = GenerationContext.fromDb(TodoDb(), supportsVariables: false); + variable.writeInto(ctx); + + expect(ctx.sql, "'hello world'''"); + }); } diff --git a/drift/test/schema_test.dart b/drift/test/schema_test.dart index 19aa6b46..e49fc88c 100644 --- a/drift/test/schema_test.dart +++ b/drift/test/schema_test.dart @@ -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 '