diff --git a/docs/pages/docs/Advanced Features/isolates.md b/docs/pages/docs/Advanced Features/isolates.md index 2c56245f..684939f6 100644 --- a/docs/pages/docs/Advanced Features/isolates.md +++ b/docs/pages/docs/Advanced Features/isolates.md @@ -43,8 +43,11 @@ import 'package:moor/isolate.dart'; // This needs to be a top-level method because it's run on a background isolate DatabaseConnection _backgroundConnection() { - // construct the database. You can also wrap the VmDatabase in a "LazyDatabase" if you need to run - // work before the database opens. + // Construct the database to use. This example uses a non-persistent in-memory database each + // time. You can use your existing VmDatabase with a file as well, or a `LazyDatabase` if you + // need to construct it asynchronously. + // When using a Flutter plugin like `path_provider` to determine the path, also see the + // "Initialization on the main thread" section below! final database = VmDatabase.memory(); return DatabaseConnection.fromExecutor(database); } diff --git a/moor_generator/lib/src/analyzer/sql_queries/explicit_alias_transformer.dart b/moor_generator/lib/src/analyzer/sql_queries/explicit_alias_transformer.dart index 3b8888ed..4846ff3d 100644 --- a/moor_generator/lib/src/analyzer/sql_queries/explicit_alias_transformer.dart +++ b/moor_generator/lib/src/analyzer/sql_queries/explicit_alias_transformer.dart @@ -1,14 +1,24 @@ import 'package:sqlparser/sqlparser.dart'; +/// A transformer adding explicit aliases to columns in a projection. +/// +/// In sqlite3, the result name of columns without an alias is undefined. While +/// the names of direct column references (`SELECT foo FROM bar`) is unlikely +/// to change, we shouldn't assume that for more complex columns (`SELECT +/// MAX(id) * 14 FROM bar`). This transformer adds an alias to such columns +/// which avoids undefined behavior that might be different across sqlite3 +/// versions. class ExplicitAliasTransformer extends Transformer { int _aliasCounter = 0; final Map _renamed = {}; + /// Rewrites an SQL [node] to use explicit aliases for columns. AstNode rewrite(AstNode node) { node = transform(node, true)!; return _PatchReferences(this).transform(node, null)!; } + /// Obtain the new name for a [column] after an alias has been added. String? newNameFor(Column column) { while (column is CompoundSelectColumn) { // In compound select statement, the first column determines the overall @@ -55,6 +65,14 @@ class ExplicitAliasTransformer extends Transformer { return super.visitExpressionResultColumn(e, arg); } } + + @override + AstNode? visitSubQuery(SubQuery e, bool arg) { + // Subquery expressions only have a single column, so the inner column + // doesn't matter. For instance, `SELECT (SELECT 1) AS foo` has no undefined + // behavior, even though the inner `1` has no alias. + return e..transformChildren(this, false); + } } class _PatchReferences extends Transformer { diff --git a/moor_generator/test/analyzer/sql_queries/explicit_alias_transformer_test.dart b/moor_generator/test/analyzer/sql_queries/explicit_alias_transformer_test.dart index 5c3e6336..15d08575 100644 --- a/moor_generator/test/analyzer/sql_queries/explicit_alias_transformer_test.dart +++ b/moor_generator/test/analyzer/sql_queries/explicit_alias_transformer_test.dart @@ -30,6 +30,10 @@ void main() { 'SELECT _c0 FROM (SELECT 1 + 2 AS _c0)'); }); + test('does not rewrite subquery expressions', () { + _test('SELECT (SELECT 1)', 'SELECT (SELECT 1) AS _c0'); + }); + test('rewrites compound select statements', () { _test("SELECT 1 + 2, 'foo' UNION ALL SELECT 3+ 4, 'bar'", "SELECT 1 + 2 AS _c0, 'foo' AS _c1 UNION ALL SELECT 3 + 4, 'bar'");