mirror of
https://github.com/immich-app/drift.git
synced 2026-09-30 13:22:57 +08:00
Support ordering mode for Dart indexes
https://github.com/simolus3/drift/discussions/3676
This commit is contained in:
@@ -312,6 +312,10 @@ users table contains a lot of rows:
|
||||
|
||||
{{ load_snippet('index','lib/snippets/dart_api/tables.dart.excerpt.json') }}
|
||||
|
||||
To specify the ordering mode for a column, you can use an `IndexedColumn` instance:
|
||||
|
||||
{{ load_snippet('index_ordering','lib/snippets/dart_api/tables.dart.excerpt.json') }}
|
||||
|
||||
#### SQL-based index
|
||||
|
||||
If you need more options in your index, for instance to define partial indexes,
|
||||
|
||||
@@ -203,6 +203,17 @@ class Users extends Table {
|
||||
}
|
||||
// #enddocregion index
|
||||
|
||||
// #docregion index_ordering
|
||||
@TableIndex(
|
||||
name: 'log_entries_at',
|
||||
columns: {IndexedColumn(#loggedAt, orderBy: OrderingMode.desc)},
|
||||
)
|
||||
class LogEntries extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
DateTimeColumn get loggedAt => dateTime()();
|
||||
}
|
||||
// #enddocregion index_ordering
|
||||
|
||||
// #docregion indexsql
|
||||
@TableIndex.sql('''
|
||||
CREATE INDEX pending_orders ON orders (creation_time)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.29.0-dev
|
||||
|
||||
- Allow specifying ordering for columns in `@TableIndex` annotation.
|
||||
|
||||
## 2.28.2
|
||||
|
||||
- Legacy wasm database: Fix cast issue when compiling with `dart2wasm`.
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ targets:
|
||||
named_parameters: true
|
||||
fatal_warnings: true
|
||||
sql:
|
||||
dialect: sqlite
|
||||
dialects: [sqlite, postgres]
|
||||
options:
|
||||
version: "3.37"
|
||||
modules:
|
||||
|
||||
@@ -699,8 +699,10 @@ abstract class _$Database extends GeneratedDatabase {
|
||||
$TodoCategoryItemCountView(this);
|
||||
late final $TodoItemWithCategoryNameViewView customViewName =
|
||||
$TodoItemWithCategoryNameViewView(this);
|
||||
late final Index itemTitle =
|
||||
Index('item_title', 'CREATE INDEX item_title ON todo_items (title)');
|
||||
late final Index itemTitle = Index.byDialect('item_title', {
|
||||
SqlDialect.sqlite: 'CREATE INDEX item_title ON todo_items (title)',
|
||||
SqlDialect.postgres: 'CREATE INDEX item_title ON todo_items (title)',
|
||||
});
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
|
||||
@@ -289,11 +289,16 @@ final class TableIndex {
|
||||
|
||||
/// The columns of the table that should be part of the index.
|
||||
///
|
||||
/// This can either be a [Symbol] for the default options or an
|
||||
/// [IndexedColumn] instance.
|
||||
///
|
||||
/// Columns are referenced with a [Symbol] of their getter name used in the
|
||||
/// column definition. For instance, a table declaring a column as
|
||||
/// `IntColumn get nextUpdateSnapshot => ...()` could reference this column
|
||||
/// using `#nextUpdateSnapshot`.
|
||||
final Set<Symbol> columns;
|
||||
///
|
||||
/// To further control options of the index, use an [IndexedColumn] instance.
|
||||
final Set<Object /*IndexedColumn | Symbol*/ > columns;
|
||||
|
||||
/// As an alternative to [name], [unique] and [columns], a `CREATE INDEX` SQL
|
||||
/// statement defining the index.
|
||||
@@ -324,6 +329,24 @@ final class TableIndex {
|
||||
columns = const {};
|
||||
}
|
||||
|
||||
/// A column that can appear in a [TableIndex].
|
||||
final class IndexedColumn {
|
||||
/// The columns of the table that should be part of the index.
|
||||
///
|
||||
/// Columns are referenced with a [Symbol] of their getter name used in the
|
||||
/// column definition. For instance, a table declaring a column as
|
||||
/// `IntColumn get nextUpdateSnapshot => ...()` could reference this column
|
||||
/// using `#nextUpdateSnapshot`.
|
||||
final Symbol columnName;
|
||||
|
||||
/// The [OrderingMode] to use for the index, controlling the order of values
|
||||
/// in the b-tree.
|
||||
final OrderingMode? orderBy;
|
||||
|
||||
/// Creates an indexed column from a [Symbol] and index options.
|
||||
const IndexedColumn(this.columnName, {required this.orderBy});
|
||||
}
|
||||
|
||||
/// A class to be used as an annotation on [Table] classes to customize the
|
||||
/// name for the data class that will be generated for the table class. The data
|
||||
/// class is a dart object that will be used to represent a row in the table.
|
||||
|
||||
@@ -34,7 +34,7 @@ extension WriteDefinition on GenerationContext {
|
||||
String pickForDialect(Map<SqlDialect, String> sql) {
|
||||
assert(
|
||||
sql.containsKey(dialect),
|
||||
'Tried running SQL optimized for the following dialects: ${sql.keys.join}. '
|
||||
'Tried running SQL optimized for the following dialects: ${sql.keys.join(', ')}. '
|
||||
'However, the database is running $dialect. Has that dialect been added '
|
||||
'to the `dialects` drift builder option?',
|
||||
);
|
||||
|
||||
@@ -92,6 +92,11 @@ void main() {
|
||||
'INNER JOIN "categories" "t1" '
|
||||
'ON "t1"."id" = "t0"."category"',
|
||||
[]));
|
||||
|
||||
verify(mockExecutor.runCustom(
|
||||
'CREATE INDEX categories_desc ON categories ("desc" DESC, priority)',
|
||||
[],
|
||||
));
|
||||
});
|
||||
|
||||
test('creates individual tables', () async {
|
||||
|
||||
@@ -218,7 +218,13 @@ abstract class _$_GeopolyTestDatabase extends GeneratedDatabase {
|
||||
late final GeopolyTest geopolyTest = GeopolyTest(this);
|
||||
Selectable<double?> area(int var1) {
|
||||
return customSelect(
|
||||
'SELECT geopoly_area(_shape) AS _c0 FROM geopoly_test WHERE "rowid" = ?1',
|
||||
switch (executor.dialect) {
|
||||
SqlDialect.sqlite =>
|
||||
'SELECT geopoly_area(_shape) AS _c0 FROM geopoly_test WHERE "rowid" = ?1',
|
||||
SqlDialect.postgres ||
|
||||
_ =>
|
||||
'SELECT geopoly_area(_shape) AS _c0 FROM geopoly_test WHERE "rowid" = \$1',
|
||||
},
|
||||
variables: [
|
||||
Variable<int>(var1)
|
||||
],
|
||||
|
||||
@@ -57,6 +57,13 @@ class Users extends Table with AutoIncrement {
|
||||
}
|
||||
|
||||
@DataClassName('Category')
|
||||
@TableIndex(
|
||||
name: 'categories_desc',
|
||||
columns: {
|
||||
IndexedColumn(#description, orderBy: OrderingMode.desc),
|
||||
#priority,
|
||||
},
|
||||
)
|
||||
class Categories extends Table with AutoIncrement {
|
||||
late final description =
|
||||
text().named('desc').customConstraint('NOT NULL UNIQUE')();
|
||||
|
||||
@@ -659,13 +659,15 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
|
||||
static const VerificationMeta _isAwesomeMeta =
|
||||
const VerificationMeta('isAwesome');
|
||||
@override
|
||||
late final GeneratedColumn<bool> isAwesome = GeneratedColumn<bool>(
|
||||
'is_awesome', aliasedName, false,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('CHECK ("is_awesome" IN (0, 1))'),
|
||||
defaultValue: const Constant(true));
|
||||
late final GeneratedColumn<bool> isAwesome =
|
||||
GeneratedColumn<bool>('is_awesome', aliasedName, false,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: GeneratedColumn.constraintsDependsOnDialect({
|
||||
SqlDialect.sqlite: 'CHECK ("is_awesome" IN (0, 1))',
|
||||
SqlDialect.postgres: '',
|
||||
}),
|
||||
defaultValue: const Constant(true));
|
||||
static const VerificationMeta _profilePictureMeta =
|
||||
const VerificationMeta('profilePicture');
|
||||
@override
|
||||
@@ -1687,12 +1689,14 @@ class $TableWithEveryColumnTypeTable extends TableWithEveryColumnType
|
||||
.withConverter<RowId>($TableWithEveryColumnTypeTable.$converterid);
|
||||
static const VerificationMeta _aBoolMeta = const VerificationMeta('aBool');
|
||||
@override
|
||||
late final GeneratedColumn<bool> aBool = GeneratedColumn<bool>(
|
||||
'a_bool', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('CHECK ("a_bool" IN (0, 1))'));
|
||||
late final GeneratedColumn<bool> aBool =
|
||||
GeneratedColumn<bool>('a_bool', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: GeneratedColumn.constraintsDependsOnDialect({
|
||||
SqlDialect.sqlite: 'CHECK ("a_bool" IN (0, 1))',
|
||||
SqlDialect.postgres: '',
|
||||
}));
|
||||
static const VerificationMeta _aDateTimeMeta =
|
||||
const VerificationMeta('aDateTime');
|
||||
@override
|
||||
@@ -3327,6 +3331,12 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
||||
$CategoryTodoCountViewView(this);
|
||||
late final $TodoWithCategoryViewView todoWithCategoryView =
|
||||
$TodoWithCategoryViewView(this);
|
||||
late final Index categoriesDesc = Index.byDialect('categories_desc', {
|
||||
SqlDialect.sqlite:
|
||||
'CREATE INDEX categories_desc ON categories ("desc" DESC, priority)',
|
||||
SqlDialect.postgres:
|
||||
'CREATE INDEX categories_desc ON categories ("desc" DESC, priority)',
|
||||
});
|
||||
late final SomeDao someDao = SomeDao(this as TodoDb);
|
||||
Selectable<AllTodosWithCategoryResult> allTodosWithCategory() {
|
||||
return customSelect(
|
||||
@@ -3354,7 +3364,10 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
||||
|
||||
Future<int> deleteTodoById(RowId var1) {
|
||||
return customUpdate(
|
||||
'DELETE FROM todos WHERE id = ?1',
|
||||
switch (executor.dialect) {
|
||||
SqlDialect.sqlite => 'DELETE FROM todos WHERE id = ?1',
|
||||
SqlDialect.postgres || _ => 'DELETE FROM todos WHERE id = \$1',
|
||||
},
|
||||
variables: [Variable<int>($TodosTableTable.$converterid.toSql(var1))],
|
||||
updates: {todosTable},
|
||||
updateKind: UpdateKind.delete,
|
||||
@@ -3366,7 +3379,13 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
||||
final expandedvar3 = $expandVar($arrayStartIndex, var3.length);
|
||||
$arrayStartIndex += var3.length;
|
||||
return customSelect(
|
||||
'SELECT * FROM todos WHERE title = ?2 OR id IN ($expandedvar3) OR title = ?1',
|
||||
switch (executor.dialect) {
|
||||
SqlDialect.sqlite =>
|
||||
'SELECT * FROM todos WHERE title = ?2 OR id IN ($expandedvar3) OR title = ?1',
|
||||
SqlDialect.postgres ||
|
||||
_ =>
|
||||
'SELECT * FROM todos WHERE title = \$2 OR id IN ($expandedvar3) OR title = \$1',
|
||||
},
|
||||
variables: [
|
||||
Variable<String>(var1),
|
||||
Variable<String>(var2),
|
||||
@@ -3380,7 +3399,13 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
||||
|
||||
Selectable<TodoEntry> search({required RowId id}) {
|
||||
return customSelect(
|
||||
'SELECT * FROM todos WHERE CASE WHEN -1 = ?1 THEN 1 ELSE id = ?1 END',
|
||||
switch (executor.dialect) {
|
||||
SqlDialect.sqlite =>
|
||||
'SELECT * FROM todos WHERE CASE WHEN -1 = ?1 THEN 1 ELSE id = ?1 END',
|
||||
SqlDialect.postgres ||
|
||||
_ =>
|
||||
'SELECT * FROM todos WHERE CASE WHEN -1 = \$1 THEN 1 ELSE id = \$1 END',
|
||||
},
|
||||
variables: [
|
||||
Variable<int>($TodosTableTable.$converterid.toSql(id))
|
||||
],
|
||||
@@ -3417,7 +3442,8 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
||||
store,
|
||||
listing,
|
||||
categoryTodoCountView,
|
||||
todoWithCategoryView
|
||||
todoWithCategoryView,
|
||||
categoriesDesc
|
||||
];
|
||||
}
|
||||
|
||||
@@ -5977,7 +6003,13 @@ mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
|
||||
attachedDatabase.todoWithCategoryView;
|
||||
Selectable<TodoEntry> todosForUser({required RowId user}) {
|
||||
return customSelect(
|
||||
'SELECT t.* FROM todos AS t INNER JOIN shared_todos AS st ON st.todo = t.id INNER JOIN users AS u ON u.id = st.user WHERE u.id = ?1',
|
||||
switch (executor.dialect) {
|
||||
SqlDialect.sqlite =>
|
||||
'SELECT t.* FROM todos AS t INNER JOIN shared_todos AS st ON st.todo = t.id INNER JOIN users AS u ON u.id = st.user WHERE u.id = ?1',
|
||||
SqlDialect.postgres ||
|
||||
_ =>
|
||||
'SELECT t.* FROM todos AS t INNER JOIN shared_todos AS st ON st.todo = t.id INNER JOIN users AS u ON u.id = st."user" WHERE u.id = \$1',
|
||||
},
|
||||
variables: [
|
||||
Variable<int>($UsersTable.$converterid.toSql(user))
|
||||
],
|
||||
|
||||
@@ -210,8 +210,8 @@ class _Fake$TodoWithCategoryViewView_16 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeSomeDao_17 extends _i1.SmartFake implements _i3.SomeDao {
|
||||
_FakeSomeDao_17(
|
||||
class _FakeIndex_17 extends _i1.SmartFake implements _i2.Index {
|
||||
_FakeIndex_17(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -220,9 +220,19 @@ class _FakeSomeDao_17 extends _i1.SmartFake implements _i3.SomeDao {
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeGeneratedDatabase_18 extends _i1.SmartFake
|
||||
class _FakeSomeDao_18 extends _i1.SmartFake implements _i3.SomeDao {
|
||||
_FakeSomeDao_18(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
parent,
|
||||
parentInvocation,
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeGeneratedDatabase_19 extends _i1.SmartFake
|
||||
implements _i2.GeneratedDatabase {
|
||||
_FakeGeneratedDatabase_18(
|
||||
_FakeGeneratedDatabase_19(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -231,9 +241,9 @@ class _FakeGeneratedDatabase_18 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeStreamQueryUpdateRules_19 extends _i1.SmartFake
|
||||
class _FakeStreamQueryUpdateRules_20 extends _i1.SmartFake
|
||||
implements _i2.StreamQueryUpdateRules {
|
||||
_FakeStreamQueryUpdateRules_19(
|
||||
_FakeStreamQueryUpdateRules_20(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -242,9 +252,9 @@ class _FakeStreamQueryUpdateRules_19 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeDatabaseConnection_20 extends _i1.SmartFake
|
||||
class _FakeDatabaseConnection_21 extends _i1.SmartFake
|
||||
implements _i2.DatabaseConnection {
|
||||
_FakeDatabaseConnection_20(
|
||||
_FakeDatabaseConnection_21(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -253,8 +263,8 @@ class _FakeDatabaseConnection_20 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeQueryExecutor_21 extends _i1.SmartFake implements _i2.QueryExecutor {
|
||||
_FakeQueryExecutor_21(
|
||||
class _FakeQueryExecutor_22 extends _i1.SmartFake implements _i2.QueryExecutor {
|
||||
_FakeQueryExecutor_22(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -263,9 +273,9 @@ class _FakeQueryExecutor_21 extends _i1.SmartFake implements _i2.QueryExecutor {
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeStreamQueryStore_22 extends _i1.SmartFake
|
||||
class _FakeStreamQueryStore_23 extends _i1.SmartFake
|
||||
implements _i4.StreamQueryStore {
|
||||
_FakeStreamQueryStore_22(
|
||||
_FakeStreamQueryStore_23(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -274,9 +284,9 @@ class _FakeStreamQueryStore_22 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeDatabaseConnectionUser_23 extends _i1.SmartFake
|
||||
class _FakeDatabaseConnectionUser_24 extends _i1.SmartFake
|
||||
implements _i2.DatabaseConnectionUser {
|
||||
_FakeDatabaseConnectionUser_23(
|
||||
_FakeDatabaseConnectionUser_24(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -285,8 +295,8 @@ class _FakeDatabaseConnectionUser_23 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeSelectable_24<T> extends _i1.SmartFake implements _i2.Selectable<T> {
|
||||
_FakeSelectable_24(
|
||||
class _FakeSelectable_25<T> extends _i1.SmartFake implements _i2.Selectable<T> {
|
||||
_FakeSelectable_25(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -295,8 +305,8 @@ class _FakeSelectable_24<T> extends _i1.SmartFake implements _i2.Selectable<T> {
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeMigrator_25 extends _i1.SmartFake implements _i2.Migrator {
|
||||
_FakeMigrator_25(
|
||||
class _FakeMigrator_26 extends _i1.SmartFake implements _i2.Migrator {
|
||||
_FakeMigrator_26(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -305,8 +315,8 @@ class _FakeMigrator_25 extends _i1.SmartFake implements _i2.Migrator {
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeFuture_26<T1> extends _i1.SmartFake implements _i5.Future<T1> {
|
||||
_FakeFuture_26(
|
||||
class _FakeFuture_27<T1> extends _i1.SmartFake implements _i5.Future<T1> {
|
||||
_FakeFuture_27(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -315,9 +325,9 @@ class _FakeFuture_26<T1> extends _i1.SmartFake implements _i5.Future<T1> {
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeInsertStatement_27<T1 extends _i2.Table, D1> extends _i1.SmartFake
|
||||
class _FakeInsertStatement_28<T1 extends _i2.Table, D1> extends _i1.SmartFake
|
||||
implements _i2.InsertStatement<T1, D1> {
|
||||
_FakeInsertStatement_27(
|
||||
_FakeInsertStatement_28(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -326,9 +336,9 @@ class _FakeInsertStatement_27<T1 extends _i2.Table, D1> extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeUpdateStatement_28<T extends _i2.Table, D> extends _i1.SmartFake
|
||||
class _FakeUpdateStatement_29<T extends _i2.Table, D> extends _i1.SmartFake
|
||||
implements _i2.UpdateStatement<T, D> {
|
||||
_FakeUpdateStatement_28(
|
||||
_FakeUpdateStatement_29(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -337,9 +347,9 @@ class _FakeUpdateStatement_28<T extends _i2.Table, D> extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeSimpleSelectStatement_29<T1 extends _i2.HasResultSet, D>
|
||||
class _FakeSimpleSelectStatement_30<T1 extends _i2.HasResultSet, D>
|
||||
extends _i1.SmartFake implements _i2.SimpleSelectStatement<T1, D> {
|
||||
_FakeSimpleSelectStatement_29(
|
||||
_FakeSimpleSelectStatement_30(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -348,9 +358,9 @@ class _FakeSimpleSelectStatement_29<T1 extends _i2.HasResultSet, D>
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeJoinedSelectStatement_30<FirstT extends _i2.HasResultSet, FirstD>
|
||||
class _FakeJoinedSelectStatement_31<FirstT extends _i2.HasResultSet, FirstD>
|
||||
extends _i1.SmartFake implements _i2.JoinedSelectStatement<FirstT, FirstD> {
|
||||
_FakeJoinedSelectStatement_30(
|
||||
_FakeJoinedSelectStatement_31(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -359,9 +369,9 @@ class _FakeJoinedSelectStatement_30<FirstT extends _i2.HasResultSet, FirstD>
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeBaseSelectStatement_31<Row> extends _i1.SmartFake
|
||||
class _FakeBaseSelectStatement_32<Row> extends _i1.SmartFake
|
||||
implements _i2.BaseSelectStatement<Row> {
|
||||
_FakeBaseSelectStatement_31(
|
||||
_FakeBaseSelectStatement_32(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -370,9 +380,9 @@ class _FakeBaseSelectStatement_31<Row> extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeDeleteStatement_32<T1 extends _i2.Table, D1> extends _i1.SmartFake
|
||||
class _FakeDeleteStatement_33<T1 extends _i2.Table, D1> extends _i1.SmartFake
|
||||
implements _i2.DeleteStatement<T1, D1> {
|
||||
_FakeDeleteStatement_32(
|
||||
_FakeDeleteStatement_33(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -381,9 +391,9 @@ class _FakeDeleteStatement_32<T1 extends _i2.Table, D1> extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeGenerationContext_33 extends _i1.SmartFake
|
||||
class _FakeGenerationContext_34 extends _i1.SmartFake
|
||||
implements _i2.GenerationContext {
|
||||
_FakeGenerationContext_33(
|
||||
_FakeGenerationContext_34(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@@ -653,14 +663,27 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
) as _i3.$TodoWithCategoryViewView);
|
||||
|
||||
@override
|
||||
_i2.Index get categoriesDesc => (super.noSuchMethod(
|
||||
Invocation.getter(#categoriesDesc),
|
||||
returnValue: _FakeIndex_17(
|
||||
this,
|
||||
Invocation.getter(#categoriesDesc),
|
||||
),
|
||||
returnValueForMissingStub: _FakeIndex_17(
|
||||
this,
|
||||
Invocation.getter(#categoriesDesc),
|
||||
),
|
||||
) as _i2.Index);
|
||||
|
||||
@override
|
||||
_i3.SomeDao get someDao => (super.noSuchMethod(
|
||||
Invocation.getter(#someDao),
|
||||
returnValue: _FakeSomeDao_17(
|
||||
returnValue: _FakeSomeDao_18(
|
||||
this,
|
||||
Invocation.getter(#someDao),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSomeDao_17(
|
||||
returnValueForMissingStub: _FakeSomeDao_18(
|
||||
this,
|
||||
Invocation.getter(#someDao),
|
||||
),
|
||||
@@ -684,11 +707,11 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
@override
|
||||
_i2.GeneratedDatabase get attachedDatabase => (super.noSuchMethod(
|
||||
Invocation.getter(#attachedDatabase),
|
||||
returnValue: _FakeGeneratedDatabase_18(
|
||||
returnValue: _FakeGeneratedDatabase_19(
|
||||
this,
|
||||
Invocation.getter(#attachedDatabase),
|
||||
),
|
||||
returnValueForMissingStub: _FakeGeneratedDatabase_18(
|
||||
returnValueForMissingStub: _FakeGeneratedDatabase_19(
|
||||
this,
|
||||
Invocation.getter(#attachedDatabase),
|
||||
),
|
||||
@@ -697,11 +720,11 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
@override
|
||||
_i2.StreamQueryUpdateRules get streamUpdateRules => (super.noSuchMethod(
|
||||
Invocation.getter(#streamUpdateRules),
|
||||
returnValue: _FakeStreamQueryUpdateRules_19(
|
||||
returnValue: _FakeStreamQueryUpdateRules_20(
|
||||
this,
|
||||
Invocation.getter(#streamUpdateRules),
|
||||
),
|
||||
returnValueForMissingStub: _FakeStreamQueryUpdateRules_19(
|
||||
returnValueForMissingStub: _FakeStreamQueryUpdateRules_20(
|
||||
this,
|
||||
Invocation.getter(#streamUpdateRules),
|
||||
),
|
||||
@@ -710,11 +733,11 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
@override
|
||||
_i2.DatabaseConnection get connection => (super.noSuchMethod(
|
||||
Invocation.getter(#connection),
|
||||
returnValue: _FakeDatabaseConnection_20(
|
||||
returnValue: _FakeDatabaseConnection_21(
|
||||
this,
|
||||
Invocation.getter(#connection),
|
||||
),
|
||||
returnValueForMissingStub: _FakeDatabaseConnection_20(
|
||||
returnValueForMissingStub: _FakeDatabaseConnection_21(
|
||||
this,
|
||||
Invocation.getter(#connection),
|
||||
),
|
||||
@@ -736,11 +759,11 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
@override
|
||||
_i2.QueryExecutor get executor => (super.noSuchMethod(
|
||||
Invocation.getter(#executor),
|
||||
returnValue: _FakeQueryExecutor_21(
|
||||
returnValue: _FakeQueryExecutor_22(
|
||||
this,
|
||||
Invocation.getter(#executor),
|
||||
),
|
||||
returnValueForMissingStub: _FakeQueryExecutor_21(
|
||||
returnValueForMissingStub: _FakeQueryExecutor_22(
|
||||
this,
|
||||
Invocation.getter(#executor),
|
||||
),
|
||||
@@ -749,11 +772,11 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
@override
|
||||
_i4.StreamQueryStore get streamQueries => (super.noSuchMethod(
|
||||
Invocation.getter(#streamQueries),
|
||||
returnValue: _FakeStreamQueryStore_22(
|
||||
returnValue: _FakeStreamQueryStore_23(
|
||||
this,
|
||||
Invocation.getter(#streamQueries),
|
||||
),
|
||||
returnValueForMissingStub: _FakeStreamQueryStore_22(
|
||||
returnValueForMissingStub: _FakeStreamQueryStore_23(
|
||||
this,
|
||||
Invocation.getter(#streamQueries),
|
||||
),
|
||||
@@ -762,11 +785,11 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
@override
|
||||
_i2.DatabaseConnectionUser get resolvedEngine => (super.noSuchMethod(
|
||||
Invocation.getter(#resolvedEngine),
|
||||
returnValue: _FakeDatabaseConnectionUser_23(
|
||||
returnValue: _FakeDatabaseConnectionUser_24(
|
||||
this,
|
||||
Invocation.getter(#resolvedEngine),
|
||||
),
|
||||
returnValueForMissingStub: _FakeDatabaseConnectionUser_23(
|
||||
returnValueForMissingStub: _FakeDatabaseConnectionUser_24(
|
||||
this,
|
||||
Invocation.getter(#resolvedEngine),
|
||||
),
|
||||
@@ -779,7 +802,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#allTodosWithCategory,
|
||||
[],
|
||||
),
|
||||
returnValue: _FakeSelectable_24<_i3.AllTodosWithCategoryResult>(
|
||||
returnValue: _FakeSelectable_25<_i3.AllTodosWithCategoryResult>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#allTodosWithCategory,
|
||||
@@ -787,7 +810,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub:
|
||||
_FakeSelectable_24<_i3.AllTodosWithCategoryResult>(
|
||||
_FakeSelectable_25<_i3.AllTodosWithCategoryResult>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#allTodosWithCategory,
|
||||
@@ -821,7 +844,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
var3,
|
||||
],
|
||||
),
|
||||
returnValue: _FakeSelectable_24<_i3.TodoEntry>(
|
||||
returnValue: _FakeSelectable_25<_i3.TodoEntry>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#withIn,
|
||||
@@ -832,7 +855,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSelectable_24<_i3.TodoEntry>(
|
||||
returnValueForMissingStub: _FakeSelectable_25<_i3.TodoEntry>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#withIn,
|
||||
@@ -853,7 +876,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
[],
|
||||
{#id: id},
|
||||
),
|
||||
returnValue: _FakeSelectable_24<_i3.TodoEntry>(
|
||||
returnValue: _FakeSelectable_25<_i3.TodoEntry>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#search,
|
||||
@@ -861,7 +884,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
{#id: id},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSelectable_24<_i3.TodoEntry>(
|
||||
returnValueForMissingStub: _FakeSelectable_25<_i3.TodoEntry>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#search,
|
||||
@@ -877,14 +900,14 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#findCustom,
|
||||
[],
|
||||
),
|
||||
returnValue: _FakeSelectable_24<_i3.MyCustomObject>(
|
||||
returnValue: _FakeSelectable_25<_i3.MyCustomObject>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#findCustom,
|
||||
[],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSelectable_24<_i3.MyCustomObject>(
|
||||
returnValueForMissingStub: _FakeSelectable_25<_i3.MyCustomObject>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#findCustom,
|
||||
@@ -899,14 +922,14 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#createMigrator,
|
||||
[],
|
||||
),
|
||||
returnValue: _FakeMigrator_25(
|
||||
returnValue: _FakeMigrator_26(
|
||||
this,
|
||||
Invocation.method(
|
||||
#createMigrator,
|
||||
[],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeMigrator_25(
|
||||
returnValueForMissingStub: _FakeMigrator_26(
|
||||
this,
|
||||
Invocation.method(
|
||||
#createMigrator,
|
||||
@@ -1038,7 +1061,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#doWhenOpened,
|
||||
@@ -1055,7 +1078,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#doWhenOpened,
|
||||
@@ -1072,14 +1095,14 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#into,
|
||||
[table],
|
||||
),
|
||||
returnValue: _FakeInsertStatement_27<T, D>(
|
||||
returnValue: _FakeInsertStatement_28<T, D>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#into,
|
||||
[table],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeInsertStatement_27<T, D>(
|
||||
returnValueForMissingStub: _FakeInsertStatement_28<T, D>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#into,
|
||||
@@ -1096,14 +1119,14 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#update,
|
||||
[table],
|
||||
),
|
||||
returnValue: _FakeUpdateStatement_28<Tbl, R>(
|
||||
returnValue: _FakeUpdateStatement_29<Tbl, R>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#update,
|
||||
[table],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeUpdateStatement_28<Tbl, R>(
|
||||
returnValueForMissingStub: _FakeUpdateStatement_29<Tbl, R>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#update,
|
||||
@@ -1123,7 +1146,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
[table],
|
||||
{#distinct: distinct},
|
||||
),
|
||||
returnValue: _FakeSimpleSelectStatement_29<T, R>(
|
||||
returnValue: _FakeSimpleSelectStatement_30<T, R>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#select,
|
||||
@@ -1131,7 +1154,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
{#distinct: distinct},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSimpleSelectStatement_29<T, R>(
|
||||
returnValueForMissingStub: _FakeSimpleSelectStatement_30<T, R>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#select,
|
||||
@@ -1152,7 +1175,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
[table],
|
||||
{#distinct: distinct},
|
||||
),
|
||||
returnValue: _FakeJoinedSelectStatement_30<T, R>(
|
||||
returnValue: _FakeJoinedSelectStatement_31<T, R>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#selectOnly,
|
||||
@@ -1160,7 +1183,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
{#distinct: distinct},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeJoinedSelectStatement_30<T, R>(
|
||||
returnValueForMissingStub: _FakeJoinedSelectStatement_31<T, R>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#selectOnly,
|
||||
@@ -1178,14 +1201,14 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#selectExpressions,
|
||||
[columns],
|
||||
),
|
||||
returnValue: _FakeBaseSelectStatement_31<_i2.TypedResult>(
|
||||
returnValue: _FakeBaseSelectStatement_32<_i2.TypedResult>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#selectExpressions,
|
||||
[columns],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeBaseSelectStatement_31<_i2.TypedResult>(
|
||||
returnValueForMissingStub: _FakeBaseSelectStatement_32<_i2.TypedResult>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#selectExpressions,
|
||||
@@ -1202,14 +1225,14 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#delete,
|
||||
[table],
|
||||
),
|
||||
returnValue: _FakeDeleteStatement_32<T, D>(
|
||||
returnValue: _FakeDeleteStatement_33<T, D>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#delete,
|
||||
[table],
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeDeleteStatement_32<T, D>(
|
||||
returnValueForMissingStub: _FakeDeleteStatement_33<T, D>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#delete,
|
||||
@@ -1295,7 +1318,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#readsFrom: readsFrom,
|
||||
},
|
||||
),
|
||||
returnValue: _FakeSelectable_24<_i2.QueryRow>(
|
||||
returnValue: _FakeSelectable_25<_i2.QueryRow>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#customSelect,
|
||||
@@ -1306,7 +1329,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSelectable_24<_i2.QueryRow>(
|
||||
returnValueForMissingStub: _FakeSelectable_25<_i2.QueryRow>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#customSelect,
|
||||
@@ -1334,7 +1357,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#readsFrom: readsFrom,
|
||||
},
|
||||
),
|
||||
returnValue: _FakeSelectable_24<_i2.QueryRow>(
|
||||
returnValue: _FakeSelectable_25<_i2.QueryRow>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#customSelectQuery,
|
||||
@@ -1345,7 +1368,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeSelectable_24<_i2.QueryRow>(
|
||||
returnValueForMissingStub: _FakeSelectable_25<_i2.QueryRow>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#customSelectQuery,
|
||||
@@ -1397,7 +1420,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#transaction,
|
||||
@@ -1416,7 +1439,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#transaction,
|
||||
@@ -1443,7 +1466,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#exclusively,
|
||||
@@ -1460,7 +1483,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#exclusively,
|
||||
@@ -1502,7 +1525,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#runWithInterceptor,
|
||||
@@ -1521,7 +1544,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
),
|
||||
(T v) => _i5.Future<T>.value(v),
|
||||
) ??
|
||||
_FakeFuture_26<T>(
|
||||
_FakeFuture_27<T>(
|
||||
this,
|
||||
Invocation.method(
|
||||
#runWithInterceptor,
|
||||
@@ -1546,7 +1569,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
#startIndex: startIndex,
|
||||
},
|
||||
),
|
||||
returnValue: _FakeGenerationContext_33(
|
||||
returnValue: _FakeGenerationContext_34(
|
||||
this,
|
||||
Invocation.method(
|
||||
#$write,
|
||||
@@ -1557,7 +1580,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeGenerationContext_33(
|
||||
returnValueForMissingStub: _FakeGenerationContext_34(
|
||||
this,
|
||||
Invocation.method(
|
||||
#$write,
|
||||
@@ -1585,7 +1608,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
],
|
||||
{#startIndex: startIndex},
|
||||
),
|
||||
returnValue: _FakeGenerationContext_33(
|
||||
returnValue: _FakeGenerationContext_34(
|
||||
this,
|
||||
Invocation.method(
|
||||
#$writeInsertable,
|
||||
@@ -1596,7 +1619,7 @@ class MockTodoDb extends _i1.Mock implements _i3.TodoDb {
|
||||
{#startIndex: startIndex},
|
||||
),
|
||||
),
|
||||
returnValueForMissingStub: _FakeGenerationContext_33(
|
||||
returnValueForMissingStub: _FakeGenerationContext_34(
|
||||
this,
|
||||
Invocation.method(
|
||||
#$writeInsertable,
|
||||
|
||||
@@ -30,16 +30,39 @@ class DartIndexResolver extends LocalElementResolver<DiscoveredDartIndex> {
|
||||
|
||||
final unique = computed?.getField('unique')?.toBoolValue() ?? false;
|
||||
|
||||
final columns = <DriftColumn>[];
|
||||
final columns = <DriftIndexedColumn>[];
|
||||
|
||||
final referencedColumns = computed?.getField('columns')?.toSetValue();
|
||||
for (final column in referencedColumns ?? const <DartObject>{}) {
|
||||
final columnName = column.toSymbolValue();
|
||||
// Column can either be a Symbol or an IndexedColumn instance.
|
||||
String? columnName;
|
||||
OrderingMode? orderBy;
|
||||
if (column.toSymbolValue() case final symbol?) {
|
||||
columnName = symbol;
|
||||
} else {
|
||||
columnName = column.getField('columnName')?.toSymbolValue();
|
||||
if (column.getField('orderBy')?.getField('_name')?.toStringValue()
|
||||
case final orderByName?) {
|
||||
orderBy = switch (orderByName) {
|
||||
'asc' => OrderingMode.ascending,
|
||||
'desc' => OrderingMode.descending,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (columnName == null) {
|
||||
reportError(DriftAnalysisError.forDartElement(
|
||||
discovered.dartElement,
|
||||
'Unknown entry in columns array, should be a symbols or an IndexedColumn instance.',
|
||||
));
|
||||
}
|
||||
|
||||
final tableColumn =
|
||||
table?.columns.firstWhereOrNull((c) => c.nameInDart == columnName);
|
||||
|
||||
if (tableColumn != null) {
|
||||
columns.add(tableColumn);
|
||||
columns.add(DriftIndexedColumn(column: tableColumn, orderBy: orderBy));
|
||||
} else {
|
||||
reportError(DriftAnalysisError.forDartElement(
|
||||
discovered.dartElement,
|
||||
|
||||
@@ -17,7 +17,7 @@ class DriftIndex extends DriftSchemaElement {
|
||||
/// This list is empty for indices created in SQL because it can't represent
|
||||
/// all expressions being indexed. It is useful for Dart-defined indices to
|
||||
/// implement [createStatementForDartDefinition].
|
||||
List<DriftColumn> indexedColumns;
|
||||
List<DriftIndexedColumn> indexedColumns;
|
||||
|
||||
/// Whethet the index has been declared to be unique.
|
||||
final bool unique;
|
||||
@@ -69,10 +69,20 @@ class DriftIndex extends DriftSchemaElement {
|
||||
unique: unique,
|
||||
columns: [
|
||||
for (final column in indexedColumns)
|
||||
IndexedColumn(Reference(columnName: column.nameInSql))
|
||||
IndexedColumn(
|
||||
Reference(columnName: column.column.nameInSql),
|
||||
column.orderBy,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DriftIndexDefintion {}
|
||||
final class DriftIndexedColumn {
|
||||
final DriftColumn column;
|
||||
final OrderingMode? orderBy;
|
||||
|
||||
DriftIndexedColumn({required this.column, required this.orderBy});
|
||||
}
|
||||
|
||||
sealed class DriftIndexDefinition {}
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:analyzer/dart/element/element2.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:drift/drift.dart' show DriftSqlType, UpdateKind;
|
||||
import 'package:sqlparser/sqlparser.dart' show ReferenceAction;
|
||||
import 'package:sqlparser/sqlparser.dart' show OrderingMode, ReferenceAction;
|
||||
|
||||
import 'driver/driver.dart';
|
||||
import 'driver/state.dart';
|
||||
@@ -75,7 +75,11 @@ class ElementSerializer {
|
||||
'type': 'index',
|
||||
'sql': element.createStmt,
|
||||
'columns': [
|
||||
for (final column in element.indexedColumns) column.nameInSql,
|
||||
for (final column in element.indexedColumns)
|
||||
{
|
||||
'column': column.column.nameInSql,
|
||||
'order_by': column.orderBy?.name,
|
||||
},
|
||||
],
|
||||
'unique': element.unique,
|
||||
};
|
||||
@@ -594,8 +598,16 @@ class ElementDeserializer {
|
||||
table: onTable,
|
||||
createStmt: json['sql'] as String?,
|
||||
indexedColumns: [
|
||||
for (final entry in json['columns'] as List)
|
||||
onTable!.columnBySqlName[entry as String]!,
|
||||
for (final entry
|
||||
in (json['columns'] as List).cast<Map<String, Object?>>())
|
||||
DriftIndexedColumn(
|
||||
column: onTable!.columnBySqlName[entry['column'] as String]!,
|
||||
orderBy: switch (entry['order_by']) {
|
||||
null => null,
|
||||
final orderBy =>
|
||||
OrderingMode.values.byName(orderBy as String),
|
||||
},
|
||||
),
|
||||
],
|
||||
unique: json['unique'] as bool,
|
||||
);
|
||||
|
||||
@@ -162,7 +162,11 @@ class SchemaWriter {
|
||||
'sql': entity.createStmt,
|
||||
'unique': entity.unique,
|
||||
'columns': [
|
||||
for (final column in entity.indexedColumns) column.nameInSql,
|
||||
for (final column in entity.indexedColumns)
|
||||
{
|
||||
'column': column.column.nameInSql,
|
||||
'order_by': column.orderBy?.name,
|
||||
},
|
||||
],
|
||||
};
|
||||
} else if (entity is DriftView) {
|
||||
@@ -446,13 +450,33 @@ class SchemaReader {
|
||||
final sql = content['sql'] as String?;
|
||||
|
||||
if (_version.supportsDartIndex) {
|
||||
DriftIndexedColumn readColumn(Object serialized) {
|
||||
if (serialized case final String name) {
|
||||
// Older versions used to write index columns by name.
|
||||
return DriftIndexedColumn(
|
||||
column: on.columnBySqlName[name]!,
|
||||
orderBy: null,
|
||||
);
|
||||
} else {
|
||||
// Newer schemas encode {name, order_by}.
|
||||
serialized as Map<String, Object?>;
|
||||
return DriftIndexedColumn(
|
||||
column: on.columnBySqlName[serialized['column'] as String]!,
|
||||
orderBy: switch (serialized['order_by']) {
|
||||
null => null,
|
||||
final ordering => OrderingMode.values.byName(ordering as String),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final index = DriftIndex(
|
||||
_id(name),
|
||||
_declaration,
|
||||
table: on,
|
||||
indexedColumns: [
|
||||
for (final col in content['columns'] as List)
|
||||
on.columnBySqlName[col]!,
|
||||
readColumn(col as Object),
|
||||
],
|
||||
unique: content['unique'] as bool,
|
||||
createStmt: sql,
|
||||
@@ -478,7 +502,11 @@ class SchemaReader {
|
||||
unique: stmt.unique,
|
||||
indexedColumns: [
|
||||
for (final column in stmt.columns)
|
||||
on.columnBySqlName[(column.expression as Reference).columnName]!,
|
||||
DriftIndexedColumn(
|
||||
column: on.columnBySqlName[
|
||||
(column.expression as Reference).columnName]!,
|
||||
orderBy: column.ordering,
|
||||
)
|
||||
],
|
||||
)..parsedStatement = stmt;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:build_test/build_test.dart';
|
||||
import 'package:drift_dev/src/analysis/results/results.dart';
|
||||
import 'package:sqlparser/sqlparser.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../../../utils.dart';
|
||||
@@ -32,13 +33,13 @@ class MyTable extends Table {
|
||||
|
||||
expect(indexA.table, table);
|
||||
expect(indexA.unique, false);
|
||||
expect(indexA.indexedColumns, [table.columnBySqlName['a']]);
|
||||
expect(indexA.indexedColumns, [indexedColumn('a')]);
|
||||
|
||||
expect(indexBC.table, table);
|
||||
expect(indexBC.unique, true);
|
||||
expect(indexBC.indexedColumns, [
|
||||
table.columnBySqlName['b'],
|
||||
table.columnBySqlName['c'],
|
||||
indexedColumn('b'),
|
||||
indexedColumn('c'),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -61,6 +62,28 @@ class MyTable extends Table {
|
||||
]);
|
||||
});
|
||||
|
||||
test('reads ordering mode', () async {
|
||||
final backend = await TestBackend.inTest({
|
||||
'a|lib/a.dart': '''
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
@TableIndex(columns: {IndexedColumn(#a, orderBy: OrderingMode.desc)}, name: 'tbl_a')
|
||||
class MyTable extends Table {
|
||||
IntColumn get a => integer()();
|
||||
TextColumn get b => text()();
|
||||
TextColumn get c => text()();
|
||||
}
|
||||
''',
|
||||
});
|
||||
|
||||
final file = await backend.analyze('package:a/a.dart');
|
||||
backend.expectNoErrors();
|
||||
|
||||
final indexA = file.analysis[file.id('tbl_a')]!.result as DriftIndex;
|
||||
expect(indexA.indexedColumns,
|
||||
[indexedColumn('a', ordering: OrderingMode.descending)]);
|
||||
});
|
||||
|
||||
group('SQL', () {
|
||||
test('can create index', () async {
|
||||
final results = await emulateDriftBuild(
|
||||
@@ -124,3 +147,10 @@ class MyTable extends Table {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
TypeMatcher<DriftIndexedColumn> indexedColumn(String name,
|
||||
{OrderingMode? ordering}) {
|
||||
return isA<DriftIndexedColumn>()
|
||||
.having((e) => e.column.nameInSql, 'nameInSql', name)
|
||||
.having((e) => e.orderBy, 'orderBy', ordering);
|
||||
}
|
||||
|
||||
@@ -222,6 +222,70 @@ class Database {}
|
||||
expect(generated, isNot(contains('GeneratedAs')));
|
||||
});
|
||||
|
||||
test('can export Dart-defined index', () async {
|
||||
final backend = await TestBackend.inTest({
|
||||
'a|lib/main.dart': '''
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
@TableIndex(name: 'tbl_name', columns: {IndexedColumn(#name, orderBy: OrderingMode.desc)})
|
||||
class MyTable extends Table {
|
||||
IntColumn get id => integer()();
|
||||
TextColumn get name => text()();
|
||||
}
|
||||
|
||||
@DriftDatabase(tables: [MyTable])
|
||||
class Database {}
|
||||
''',
|
||||
});
|
||||
|
||||
final file = await backend.analyze('package:a/main.dart');
|
||||
backend.expectNoErrors();
|
||||
|
||||
final db = file.fileAnalysis!.resolvedDatabases.values.single;
|
||||
|
||||
final schemaJson =
|
||||
await SchemaWriter(db.availableElements).createSchemaJson();
|
||||
final serializedIndex = (schemaJson['entities'] as List)[1];
|
||||
|
||||
expect(serializedIndex['data'], {
|
||||
'on': 0,
|
||||
'name': 'tbl_name',
|
||||
'sql': null,
|
||||
'unique': false,
|
||||
'columns': [
|
||||
{'column': 'name', 'order_by': 'descending'}
|
||||
]
|
||||
});
|
||||
|
||||
final newFormat = schemaJson;
|
||||
// Older versions of drift_dev used to only include the column name in the
|
||||
// schema and did not support specifying an ordering mode.
|
||||
final oldFormat = json.decode(json.encode(newFormat));
|
||||
oldFormat['entities'][1]['data']['columns'] = ['name'];
|
||||
|
||||
for (final format in [oldFormat, newFormat]) {
|
||||
final reader = SchemaReader.readJson(format as Map<String, Object?>);
|
||||
final fakeBuildConfig = runInBuildConfigZone(() {
|
||||
return BuildConfig(buildTargets: {});
|
||||
}, 'drift_dev', []);
|
||||
final generated = await GenerateUtils.generateSchemaCode(
|
||||
DriftDevCli()
|
||||
..project = DriftProject(fakeBuildConfig, Directory(sandbox)),
|
||||
1,
|
||||
ExportedSchema(reader.entities.toList(), {}),
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
if (format == newFormat) {
|
||||
expect(generated,
|
||||
contains('CREATE INDEX tbl_name ON my_table (name DESC)'));
|
||||
} else {
|
||||
expect(generated, contains('CREATE INDEX tbl_name ON my_table (name)'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
group('generates correct datetime mode', () {
|
||||
Future<void> runTest(bool storeAsText, String expectedDefault) async {
|
||||
final options =
|
||||
|
||||
Reference in New Issue
Block a user