mirror of https://github.com/AMT-Cheif/drift.git
Merge branch 'develop' into geopoly
This commit is contained in:
commit
b94516acc7
|
@ -0,0 +1,270 @@
|
|||
import 'package:drift/drift.dart';
|
||||
|
||||
part 'manager.g.dart';
|
||||
|
||||
class TodoItems extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get title => text().withLength(min: 6, max: 32)();
|
||||
TextColumn get content => text().named('body')();
|
||||
IntColumn get category =>
|
||||
integer().nullable().references(TodoCategory, #id)();
|
||||
DateTimeColumn get createdAt => dateTime().nullable()();
|
||||
}
|
||||
|
||||
class TodoCategory extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get description => text()();
|
||||
}
|
||||
|
||||
// #docregion user_group_tables
|
||||
|
||||
class Users extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text()();
|
||||
}
|
||||
|
||||
class Groups extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text()();
|
||||
@ReferenceName("administeredGroups")
|
||||
IntColumn get admin => integer().nullable().references(Users, #id)();
|
||||
@ReferenceName("ownedGroups")
|
||||
IntColumn get owner => integer().references(Users, #id)();
|
||||
}
|
||||
|
||||
// #enddocregion user_group_tables
|
||||
|
||||
@DriftDatabase(tables: [TodoItems, TodoCategory, Groups, Users])
|
||||
class AppDatabase extends _$AppDatabase {
|
||||
AppDatabase(super.e);
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
||||
|
||||
extension ManagerExamples on AppDatabase {
|
||||
// #docregion manager_create
|
||||
Future<void> createTodoItem() async {
|
||||
// Create a new item
|
||||
await managers.todoItems
|
||||
.create((o) => o(title: 'Title', content: 'Content'));
|
||||
|
||||
// We can also use `mode` and `onConflict` parameters, just
|
||||
// like in the `[InsertStatement.insert]` method on the table
|
||||
await managers.todoItems.create(
|
||||
(o) => o(title: 'Title', content: 'New Content'),
|
||||
mode: InsertMode.replace);
|
||||
|
||||
// We can also create multiple items at once
|
||||
await managers.todoItems.bulkCreate(
|
||||
(o) => [
|
||||
o(title: 'Title 1', content: 'Content 1'),
|
||||
o(title: 'Title 2', content: 'Content 2'),
|
||||
],
|
||||
);
|
||||
}
|
||||
// #enddocregion manager_create
|
||||
|
||||
// #docregion manager_update
|
||||
Future<void> updateTodoItems() async {
|
||||
// Update all items
|
||||
await managers.todoItems.update((o) => o(content: Value('New Content')));
|
||||
|
||||
// Update multiple items
|
||||
await managers.todoItems
|
||||
.filter((f) => f.id.isIn([1, 2, 3]))
|
||||
.update((o) => o(content: Value('New Content')));
|
||||
}
|
||||
// #enddocregion manager_update
|
||||
|
||||
// #docregion manager_replace
|
||||
Future<void> replaceTodoItems() async {
|
||||
// Replace a single item
|
||||
var obj = await managers.todoItems.filter((o) => o.id(1)).getSingle();
|
||||
obj = obj.copyWith(content: 'New Content');
|
||||
await managers.todoItems.replace(obj);
|
||||
|
||||
// Replace multiple items
|
||||
var objs =
|
||||
await managers.todoItems.filter((o) => o.id.isIn([1, 2, 3])).get();
|
||||
objs = objs.map((o) => o.copyWith(content: 'New Content')).toList();
|
||||
await managers.todoItems.bulkReplace(objs);
|
||||
}
|
||||
// #enddocregion manager_replace
|
||||
|
||||
// #docregion manager_delete
|
||||
Future<void> deleteTodoItems() async {
|
||||
// Delete all items
|
||||
await managers.todoItems.delete();
|
||||
|
||||
// Delete a single item
|
||||
await managers.todoItems.filter((f) => f.id(5)).delete();
|
||||
}
|
||||
// #enddocregion manager_delete
|
||||
|
||||
// #docregion manager_select
|
||||
Future<void> selectTodoItems() async {
|
||||
// Get all items
|
||||
managers.todoItems.get();
|
||||
|
||||
// A stream of all the todo items, updated in real-time
|
||||
managers.todoItems.watch();
|
||||
|
||||
// To get a single item, apply a filter and call `getSingle`
|
||||
await managers.todoItems.filter((f) => f.id(1)).getSingle();
|
||||
}
|
||||
// #enddocregion manager_select
|
||||
|
||||
// #docregion manager_filter
|
||||
Future<void> filterTodoItems() async {
|
||||
// All items with a title of "Title"
|
||||
managers.todoItems.filter((f) => f.title("Title"));
|
||||
|
||||
// All items with a title of "Title" and content of "Content"
|
||||
managers.todoItems.filter((f) => f.title("Title") & f.content("Content"));
|
||||
|
||||
// All items with a title of "Title" or content that is not null
|
||||
managers.todoItems.filter((f) => f.title("Title") | f.content.not.isNull());
|
||||
}
|
||||
// #enddocregion manager_filter
|
||||
|
||||
// #docregion manager_type_specific_filter
|
||||
Future filterWithType() async {
|
||||
// Filter all items created since 7 days ago
|
||||
managers.todoItems.filter(
|
||||
(f) => f.createdAt.isAfter(DateTime.now().subtract(Duration(days: 7))));
|
||||
|
||||
// Filter all items with a title that starts with "Title"
|
||||
managers.todoItems.filter((f) => f.title.startsWith('Title'));
|
||||
}
|
||||
// #enddocregion manager_type_specific_filter
|
||||
|
||||
// #docregion manager_ordering
|
||||
Future orderWithType() async {
|
||||
// Order all items by their creation date in ascending order
|
||||
managers.todoItems.orderBy((o) => o.createdAt.asc());
|
||||
|
||||
// Order all items by their title in ascending order and then by their content in ascending order
|
||||
managers.todoItems.orderBy((o) => o.title.asc() & o.content.asc());
|
||||
}
|
||||
// #enddocregion manager_ordering
|
||||
|
||||
// #docregion manager_count
|
||||
Future count() async {
|
||||
// Count all items
|
||||
await managers.todoItems.count();
|
||||
|
||||
// Count all items with a title of "Title"
|
||||
await managers.todoItems.filter((f) => f.title("Title")).count();
|
||||
}
|
||||
// #enddocregion manager_count
|
||||
|
||||
// #docregion manager_exists
|
||||
Future exists() async {
|
||||
// Check if any items exist
|
||||
await managers.todoItems.exists();
|
||||
|
||||
// Check if any items with a title of "Title" exist
|
||||
await managers.todoItems.filter((f) => f.title("Title")).exists();
|
||||
}
|
||||
// #enddocregion manager_exists
|
||||
|
||||
// #docregion manager_filter_forward_references
|
||||
Future relationalFilter() async {
|
||||
// Get all items with a category description of "School"
|
||||
managers.todoItems
|
||||
.filter((f) => f.category((f) => f.description("School")));
|
||||
|
||||
// These can be combined with other filters
|
||||
// For example, get all items with a title of "Title" or a category description of "School"
|
||||
await managers.todoItems
|
||||
.filter(
|
||||
(f) => f.title("Title") | f.category((f) => f.description("School")),
|
||||
)
|
||||
.exists();
|
||||
}
|
||||
// #enddocregion manager_filter_forward_references
|
||||
|
||||
// #docregion manager_filter_back_references
|
||||
Future reverseRelationalFilter() async {
|
||||
// Get the category that has a todo item with an id of 1
|
||||
managers.todoCategory.filter((f) => f.todoItemsRefs((f) => f.id(1)));
|
||||
|
||||
// These can be combined with other filters
|
||||
// For example, get all categories with a description of "School" or a todo item with an id of 1
|
||||
managers.todoCategory.filter(
|
||||
(f) => f.description("School") | f.todoItemsRefs((f) => f.id(1)),
|
||||
);
|
||||
}
|
||||
// #enddocregion manager_filter_back_references
|
||||
|
||||
// #docregion manager_filter_custom_back_references
|
||||
Future reverseNamedRelationalFilter() async {
|
||||
// Get all users who are administrators of a group with a name containing "Business"
|
||||
// or who own a group with an id of 1, 2, 4, or 5
|
||||
managers.users.filter(
|
||||
(f) =>
|
||||
f.administeredGroups((f) => f.name.contains("Business")) |
|
||||
f.ownedGroups((f) => f.id.isIn([1, 2, 4, 5])),
|
||||
);
|
||||
}
|
||||
// #enddocregion manager_filter_custom_back_references
|
||||
}
|
||||
|
||||
// #docregion manager_filter_extensions
|
||||
// Extend drifts built-in filters by combining the existing filters to create a new one
|
||||
// or by creating a new filter from scratch
|
||||
extension After2000Filter on ColumnFilters<DateTime> {
|
||||
// Create a new filter by combining existing filters
|
||||
ComposableFilter after2000orBefore1900() =>
|
||||
isAfter(DateTime(2000)) | isBefore(DateTime(1900));
|
||||
|
||||
// Create a new filter from scratch using the `column` property
|
||||
ComposableFilter filterOnUnixEpoch(int value) =>
|
||||
ComposableFilter(column.unixepoch.equals(value), inverted: inverted);
|
||||
}
|
||||
|
||||
Future filterWithExtension(AppDatabase db) async {
|
||||
// Use the custom filters on any column that is of type DateTime
|
||||
db.managers.todoItems.filter((f) => f.createdAt.after2000orBefore1900());
|
||||
|
||||
// Use the custom filter on the `unixepoch` column
|
||||
db.managers.todoItems.filter((f) => f.createdAt.filterOnUnixEpoch(0));
|
||||
}
|
||||
// #enddocregion manager_filter_extensions
|
||||
|
||||
// #docregion manager_ordering_extensions
|
||||
// Extend drifts built-in orderings by create a new ordering from scratch
|
||||
extension After2000Ordering on ColumnOrderings<DateTime> {
|
||||
ComposableOrdering byUnixEpoch() => ColumnOrderings(column.unixepoch).asc();
|
||||
}
|
||||
|
||||
Future orderingWithExtension(AppDatabase db) async {
|
||||
// Use the custom orderings on any column that is of type DateTime
|
||||
db.managers.todoItems.orderBy((f) => f.createdAt.byUnixEpoch());
|
||||
}
|
||||
// #enddocregion manager_ordering_extensions
|
||||
|
||||
// #docregion manager_custom_filter
|
||||
// Extend the generated table filter composer to add a custom filter
|
||||
extension NoContentOrBefore2000FilterX on $$TodoItemsTableFilterComposer {
|
||||
ComposableFilter noContentOrBefore2000() =>
|
||||
(content.isNull() | createdAt.isBefore(DateTime(2000)));
|
||||
}
|
||||
|
||||
Future customFilter(AppDatabase db) async {
|
||||
// Use the custom filter on the `TodoItems` table
|
||||
db.managers.todoItems.filter((f) => f.noContentOrBefore2000());
|
||||
}
|
||||
// #enddocregion manager_custom_filter
|
||||
|
||||
// #docregion manager_custom_ordering
|
||||
// Extend the generated table filter composer to add a custom filter
|
||||
extension ContentThenCreationDataX on $$TodoItemsTableOrderingComposer {
|
||||
ComposableOrdering contentThenCreatedAt() => content.asc() & createdAt.asc();
|
||||
}
|
||||
|
||||
Future customOrdering(AppDatabase db) async {
|
||||
// Use the custom ordering on the `TodoItems` table
|
||||
db.managers.todoItems.orderBy((f) => f.contentThenCreatedAt());
|
||||
}
|
||||
// #enddocregion manager_custom_ordering
|
|
@ -1,9 +1,11 @@
|
|||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:drift_docs/snippets/_shared/todo_tables.drift.dart' as i1;
|
||||
import 'package:drift/internal/modular.dart' as i2;
|
||||
|
||||
abstract class $MyDatabase extends i0.GeneratedDatabase {
|
||||
$MyDatabase(i0.QueryExecutor e) : super(e);
|
||||
$MyDatabaseManager get managers => $MyDatabaseManager(this);
|
||||
late final i1.$CategoriesTable categories = i1.$CategoriesTable(this);
|
||||
late final i1.$TodoItemsTable todoItems = i1.$TodoItemsTable(this);
|
||||
i0.Selectable<CategoriesWithCountResult> categoriesWithCount() {
|
||||
|
@ -28,6 +30,227 @@ abstract class $MyDatabase extends i0.GeneratedDatabase {
|
|||
[categories, todoItems];
|
||||
}
|
||||
|
||||
class $$CategoriesTableFilterComposer
|
||||
extends i0.FilterComposer<i0.GeneratedDatabase, i1.$CategoriesTable> {
|
||||
$$CategoriesTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get id => i0.ColumnFilters($table.id);
|
||||
i0.ColumnFilters<String> get name => i0.ColumnFilters($table.name);
|
||||
i0.ComposableFilter todoItemsRefs(
|
||||
i0.ComposableFilter Function($$TodoItemsTableFilterComposer f) f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i2.ReadDatabaseContainer($db)
|
||||
.resultSet<i1.$TodoItemsTable>('todo_items'),
|
||||
getCurrentColumn: (f) => f.id,
|
||||
getReferencedColumn: (f) => f.category,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$TodoItemsTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
}
|
||||
|
||||
class $$CategoriesTableOrderingComposer
|
||||
extends i0.OrderingComposer<i0.GeneratedDatabase, i1.$CategoriesTable> {
|
||||
$$CategoriesTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get id => i0.ColumnOrderings($table.id);
|
||||
i0.ColumnOrderings<String> get name => i0.ColumnOrderings($table.name);
|
||||
}
|
||||
|
||||
class $$CategoriesTableProcessedTableManager extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$CategoriesTable,
|
||||
i1.Category,
|
||||
$$CategoriesTableFilterComposer,
|
||||
$$CategoriesTableOrderingComposer,
|
||||
$$CategoriesTableProcessedTableManager,
|
||||
$$CategoriesTableInsertCompanionBuilder,
|
||||
$$CategoriesTableUpdateCompanionBuilder> {
|
||||
const $$CategoriesTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$CategoriesTableInsertCompanionBuilder = i1.CategoriesCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
required String name,
|
||||
});
|
||||
typedef $$CategoriesTableUpdateCompanionBuilder = i1.CategoriesCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
i0.Value<String> name,
|
||||
});
|
||||
|
||||
class $$CategoriesTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$CategoriesTable,
|
||||
i1.Category,
|
||||
$$CategoriesTableFilterComposer,
|
||||
$$CategoriesTableOrderingComposer,
|
||||
$$CategoriesTableProcessedTableManager,
|
||||
$$CategoriesTableInsertCompanionBuilder,
|
||||
$$CategoriesTableUpdateCompanionBuilder> {
|
||||
$$CategoriesTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$CategoriesTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$CategoriesTableFilterComposer(db, table),
|
||||
orderingComposer: $$CategoriesTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$CategoriesTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
i0.Value<String> name = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.CategoriesCompanion(
|
||||
id: id,
|
||||
name: name,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
required String name,
|
||||
}) =>
|
||||
i1.CategoriesCompanion.insert(
|
||||
id: id,
|
||||
name: name,
|
||||
)));
|
||||
}
|
||||
|
||||
class $$TodoItemsTableFilterComposer
|
||||
extends i0.FilterComposer<i0.GeneratedDatabase, i1.$TodoItemsTable> {
|
||||
$$TodoItemsTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get id => i0.ColumnFilters($table.id);
|
||||
i0.ColumnFilters<String> get title => i0.ColumnFilters($table.title);
|
||||
i0.ColumnFilters<String> get content => i0.ColumnFilters($table.content);
|
||||
i0.ColumnFilters<int> get categoryId => i0.ColumnFilters($table.category);
|
||||
i0.ComposableFilter category(
|
||||
i0.ComposableFilter Function($$CategoriesTableFilterComposer f) f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i2.ReadDatabaseContainer($db)
|
||||
.resultSet<i1.$CategoriesTable>('categories'),
|
||||
getCurrentColumn: (f) => f.category,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$CategoriesTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
|
||||
i0.ColumnFilters<DateTime> get dueDate => i0.ColumnFilters($table.dueDate);
|
||||
}
|
||||
|
||||
class $$TodoItemsTableOrderingComposer
|
||||
extends i0.OrderingComposer<i0.GeneratedDatabase, i1.$TodoItemsTable> {
|
||||
$$TodoItemsTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get id => i0.ColumnOrderings($table.id);
|
||||
i0.ColumnOrderings<String> get title => i0.ColumnOrderings($table.title);
|
||||
i0.ColumnOrderings<String> get content => i0.ColumnOrderings($table.content);
|
||||
i0.ColumnOrderings<int> get categoryId => i0.ColumnOrderings($table.category);
|
||||
i0.ComposableOrdering category(
|
||||
i0.ComposableOrdering Function($$CategoriesTableOrderingComposer o) o) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i2.ReadDatabaseContainer($db)
|
||||
.resultSet<i1.$CategoriesTable>('categories'),
|
||||
getCurrentColumn: (f) => f.category,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$CategoriesTableOrderingComposer(db, table),
|
||||
builder: o);
|
||||
}
|
||||
|
||||
i0.ColumnOrderings<DateTime> get dueDate =>
|
||||
i0.ColumnOrderings($table.dueDate);
|
||||
}
|
||||
|
||||
class $$TodoItemsTableProcessedTableManager extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$TodoItemsTable,
|
||||
i1.TodoItem,
|
||||
$$TodoItemsTableFilterComposer,
|
||||
$$TodoItemsTableOrderingComposer,
|
||||
$$TodoItemsTableProcessedTableManager,
|
||||
$$TodoItemsTableInsertCompanionBuilder,
|
||||
$$TodoItemsTableUpdateCompanionBuilder> {
|
||||
const $$TodoItemsTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$TodoItemsTableInsertCompanionBuilder = i1.TodoItemsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
required String title,
|
||||
required String content,
|
||||
i0.Value<int?> category,
|
||||
i0.Value<DateTime?> dueDate,
|
||||
});
|
||||
typedef $$TodoItemsTableUpdateCompanionBuilder = i1.TodoItemsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
i0.Value<String> title,
|
||||
i0.Value<String> content,
|
||||
i0.Value<int?> category,
|
||||
i0.Value<DateTime?> dueDate,
|
||||
});
|
||||
|
||||
class $$TodoItemsTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$TodoItemsTable,
|
||||
i1.TodoItem,
|
||||
$$TodoItemsTableFilterComposer,
|
||||
$$TodoItemsTableOrderingComposer,
|
||||
$$TodoItemsTableProcessedTableManager,
|
||||
$$TodoItemsTableInsertCompanionBuilder,
|
||||
$$TodoItemsTableUpdateCompanionBuilder> {
|
||||
$$TodoItemsTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$TodoItemsTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$TodoItemsTableFilterComposer(db, table),
|
||||
orderingComposer: $$TodoItemsTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$TodoItemsTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
i0.Value<String> title = const i0.Value.absent(),
|
||||
i0.Value<String> content = const i0.Value.absent(),
|
||||
i0.Value<int?> category = const i0.Value.absent(),
|
||||
i0.Value<DateTime?> dueDate = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.TodoItemsCompanion(
|
||||
id: id,
|
||||
title: title,
|
||||
content: content,
|
||||
category: category,
|
||||
dueDate: dueDate,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
required String title,
|
||||
required String content,
|
||||
i0.Value<int?> category = const i0.Value.absent(),
|
||||
i0.Value<DateTime?> dueDate = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.TodoItemsCompanion.insert(
|
||||
id: id,
|
||||
title: title,
|
||||
content: content,
|
||||
category: category,
|
||||
dueDate: dueDate,
|
||||
)));
|
||||
}
|
||||
|
||||
class $MyDatabaseManager {
|
||||
final $MyDatabase _db;
|
||||
$MyDatabaseManager(this._db);
|
||||
$$CategoriesTableTableManager get categories =>
|
||||
$$CategoriesTableTableManager(_db, _db.categories);
|
||||
$$TodoItemsTableTableManager get todoItems =>
|
||||
$$TodoItemsTableTableManager(_db, _db.todoItems);
|
||||
}
|
||||
|
||||
class CategoriesWithCountResult {
|
||||
final int id;
|
||||
final String name;
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:drift_docs/snippets/modular/many_to_many/json.dart' as i3;
|
|||
|
||||
abstract class $JsonBasedDatabase extends i0.GeneratedDatabase {
|
||||
$JsonBasedDatabase(i0.QueryExecutor e) : super(e);
|
||||
$JsonBasedDatabaseManager get managers => $JsonBasedDatabaseManager(this);
|
||||
late final i1.$BuyableItemsTable buyableItems = i1.$BuyableItemsTable(this);
|
||||
late final i2.$ShoppingCartsTable shoppingCarts =
|
||||
i2.$ShoppingCartsTable(this);
|
||||
|
@ -18,6 +19,177 @@ abstract class $JsonBasedDatabase extends i0.GeneratedDatabase {
|
|||
[buyableItems, shoppingCarts];
|
||||
}
|
||||
|
||||
class $$BuyableItemsTableFilterComposer
|
||||
extends i0.FilterComposer<i0.GeneratedDatabase, i1.$BuyableItemsTable> {
|
||||
$$BuyableItemsTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get id => i0.ColumnFilters($table.id);
|
||||
i0.ColumnFilters<String> get description =>
|
||||
i0.ColumnFilters($table.description);
|
||||
i0.ColumnFilters<int> get price => i0.ColumnFilters($table.price);
|
||||
}
|
||||
|
||||
class $$BuyableItemsTableOrderingComposer
|
||||
extends i0.OrderingComposer<i0.GeneratedDatabase, i1.$BuyableItemsTable> {
|
||||
$$BuyableItemsTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get id => i0.ColumnOrderings($table.id);
|
||||
i0.ColumnOrderings<String> get description =>
|
||||
i0.ColumnOrderings($table.description);
|
||||
i0.ColumnOrderings<int> get price => i0.ColumnOrderings($table.price);
|
||||
}
|
||||
|
||||
class $$BuyableItemsTableProcessedTableManager extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$BuyableItemsTable,
|
||||
i1.BuyableItem,
|
||||
$$BuyableItemsTableFilterComposer,
|
||||
$$BuyableItemsTableOrderingComposer,
|
||||
$$BuyableItemsTableProcessedTableManager,
|
||||
$$BuyableItemsTableInsertCompanionBuilder,
|
||||
$$BuyableItemsTableUpdateCompanionBuilder> {
|
||||
const $$BuyableItemsTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$BuyableItemsTableInsertCompanionBuilder = i1.BuyableItemsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
required String description,
|
||||
required int price,
|
||||
});
|
||||
typedef $$BuyableItemsTableUpdateCompanionBuilder = i1.BuyableItemsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
i0.Value<String> description,
|
||||
i0.Value<int> price,
|
||||
});
|
||||
|
||||
class $$BuyableItemsTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$BuyableItemsTable,
|
||||
i1.BuyableItem,
|
||||
$$BuyableItemsTableFilterComposer,
|
||||
$$BuyableItemsTableOrderingComposer,
|
||||
$$BuyableItemsTableProcessedTableManager,
|
||||
$$BuyableItemsTableInsertCompanionBuilder,
|
||||
$$BuyableItemsTableUpdateCompanionBuilder> {
|
||||
$$BuyableItemsTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$BuyableItemsTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$BuyableItemsTableFilterComposer(db, table),
|
||||
orderingComposer: $$BuyableItemsTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$BuyableItemsTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
i0.Value<String> description = const i0.Value.absent(),
|
||||
i0.Value<int> price = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.BuyableItemsCompanion(
|
||||
id: id,
|
||||
description: description,
|
||||
price: price,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
required String description,
|
||||
required int price,
|
||||
}) =>
|
||||
i1.BuyableItemsCompanion.insert(
|
||||
id: id,
|
||||
description: description,
|
||||
price: price,
|
||||
)));
|
||||
}
|
||||
|
||||
class $$ShoppingCartsTableFilterComposer
|
||||
extends i0.FilterComposer<i0.GeneratedDatabase, i2.$ShoppingCartsTable> {
|
||||
$$ShoppingCartsTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get id => i0.ColumnFilters($table.id);
|
||||
i0.ColumnFilters<String> get entriesValue => i0.ColumnFilters($table.entries);
|
||||
i0.ColumnWithTypeConverterFilters<
|
||||
i3.ShoppingCartEntries,
|
||||
i3.ShoppingCartEntries,
|
||||
String> get entries => i0.ColumnWithTypeConverterFilters($table.entries);
|
||||
}
|
||||
|
||||
class $$ShoppingCartsTableOrderingComposer
|
||||
extends i0.OrderingComposer<i0.GeneratedDatabase, i2.$ShoppingCartsTable> {
|
||||
$$ShoppingCartsTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get id => i0.ColumnOrderings($table.id);
|
||||
i0.ColumnOrderings<String> get entries => i0.ColumnOrderings($table.entries);
|
||||
}
|
||||
|
||||
class $$ShoppingCartsTableProcessedTableManager
|
||||
extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i2.$ShoppingCartsTable,
|
||||
i2.ShoppingCart,
|
||||
$$ShoppingCartsTableFilterComposer,
|
||||
$$ShoppingCartsTableOrderingComposer,
|
||||
$$ShoppingCartsTableProcessedTableManager,
|
||||
$$ShoppingCartsTableInsertCompanionBuilder,
|
||||
$$ShoppingCartsTableUpdateCompanionBuilder> {
|
||||
const $$ShoppingCartsTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$ShoppingCartsTableInsertCompanionBuilder = i2.ShoppingCartsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
required i3.ShoppingCartEntries entries,
|
||||
});
|
||||
typedef $$ShoppingCartsTableUpdateCompanionBuilder = i2.ShoppingCartsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
i0.Value<i3.ShoppingCartEntries> entries,
|
||||
});
|
||||
|
||||
class $$ShoppingCartsTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i2.$ShoppingCartsTable,
|
||||
i2.ShoppingCart,
|
||||
$$ShoppingCartsTableFilterComposer,
|
||||
$$ShoppingCartsTableOrderingComposer,
|
||||
$$ShoppingCartsTableProcessedTableManager,
|
||||
$$ShoppingCartsTableInsertCompanionBuilder,
|
||||
$$ShoppingCartsTableUpdateCompanionBuilder> {
|
||||
$$ShoppingCartsTableTableManager(
|
||||
i0.GeneratedDatabase db, i2.$ShoppingCartsTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$ShoppingCartsTableFilterComposer(db, table),
|
||||
orderingComposer: $$ShoppingCartsTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$ShoppingCartsTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
i0.Value<i3.ShoppingCartEntries> entries =
|
||||
const i0.Value.absent(),
|
||||
}) =>
|
||||
i2.ShoppingCartsCompanion(
|
||||
id: id,
|
||||
entries: entries,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
required i3.ShoppingCartEntries entries,
|
||||
}) =>
|
||||
i2.ShoppingCartsCompanion.insert(
|
||||
id: id,
|
||||
entries: entries,
|
||||
)));
|
||||
}
|
||||
|
||||
class $JsonBasedDatabaseManager {
|
||||
final $JsonBasedDatabase _db;
|
||||
$JsonBasedDatabaseManager(this._db);
|
||||
$$BuyableItemsTableTableManager get buyableItems =>
|
||||
$$BuyableItemsTableTableManager(_db, _db.buyableItems);
|
||||
$$ShoppingCartsTableTableManager get shoppingCarts =>
|
||||
$$ShoppingCartsTableTableManager(_db, _db.shoppingCarts);
|
||||
}
|
||||
|
||||
class $ShoppingCartsTable extends i3.ShoppingCarts
|
||||
with i0.TableInfo<$ShoppingCartsTable, i2.ShoppingCart> {
|
||||
@override
|
||||
|
|
|
@ -4,10 +4,12 @@ import 'package:drift_docs/snippets/modular/many_to_many/shared.drift.dart'
|
|||
as i1;
|
||||
import 'package:drift_docs/snippets/modular/many_to_many/relational.drift.dart'
|
||||
as i2;
|
||||
import 'package:drift_docs/snippets/modular/many_to_many/relational.dart' as i3;
|
||||
import 'package:drift/internal/modular.dart' as i3;
|
||||
import 'package:drift_docs/snippets/modular/many_to_many/relational.dart' as i4;
|
||||
|
||||
abstract class $RelationalDatabase extends i0.GeneratedDatabase {
|
||||
$RelationalDatabase(i0.QueryExecutor e) : super(e);
|
||||
$RelationalDatabaseManager get managers => $RelationalDatabaseManager(this);
|
||||
late final i1.$BuyableItemsTable buyableItems = i1.$BuyableItemsTable(this);
|
||||
late final i2.$ShoppingCartsTable shoppingCarts =
|
||||
i2.$ShoppingCartsTable(this);
|
||||
|
@ -21,7 +23,334 @@ abstract class $RelationalDatabase extends i0.GeneratedDatabase {
|
|||
[buyableItems, shoppingCarts, shoppingCartEntries];
|
||||
}
|
||||
|
||||
class $ShoppingCartsTable extends i3.ShoppingCarts
|
||||
class $$BuyableItemsTableFilterComposer
|
||||
extends i0.FilterComposer<i0.GeneratedDatabase, i1.$BuyableItemsTable> {
|
||||
$$BuyableItemsTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get id => i0.ColumnFilters($table.id);
|
||||
i0.ColumnFilters<String> get description =>
|
||||
i0.ColumnFilters($table.description);
|
||||
i0.ColumnFilters<int> get price => i0.ColumnFilters($table.price);
|
||||
i0.ComposableFilter shoppingCartEntriesRefs(
|
||||
i0.ComposableFilter Function($$ShoppingCartEntriesTableFilterComposer f)
|
||||
f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i3.ReadDatabaseContainer($db)
|
||||
.resultSet<i2.$ShoppingCartEntriesTable>('shopping_cart_entries'),
|
||||
getCurrentColumn: (f) => f.id,
|
||||
getReferencedColumn: (f) => f.item,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$ShoppingCartEntriesTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
}
|
||||
|
||||
class $$BuyableItemsTableOrderingComposer
|
||||
extends i0.OrderingComposer<i0.GeneratedDatabase, i1.$BuyableItemsTable> {
|
||||
$$BuyableItemsTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get id => i0.ColumnOrderings($table.id);
|
||||
i0.ColumnOrderings<String> get description =>
|
||||
i0.ColumnOrderings($table.description);
|
||||
i0.ColumnOrderings<int> get price => i0.ColumnOrderings($table.price);
|
||||
}
|
||||
|
||||
class $$BuyableItemsTableProcessedTableManager extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$BuyableItemsTable,
|
||||
i1.BuyableItem,
|
||||
$$BuyableItemsTableFilterComposer,
|
||||
$$BuyableItemsTableOrderingComposer,
|
||||
$$BuyableItemsTableProcessedTableManager,
|
||||
$$BuyableItemsTableInsertCompanionBuilder,
|
||||
$$BuyableItemsTableUpdateCompanionBuilder> {
|
||||
const $$BuyableItemsTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$BuyableItemsTableInsertCompanionBuilder = i1.BuyableItemsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
required String description,
|
||||
required int price,
|
||||
});
|
||||
typedef $$BuyableItemsTableUpdateCompanionBuilder = i1.BuyableItemsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
i0.Value<String> description,
|
||||
i0.Value<int> price,
|
||||
});
|
||||
|
||||
class $$BuyableItemsTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i1.$BuyableItemsTable,
|
||||
i1.BuyableItem,
|
||||
$$BuyableItemsTableFilterComposer,
|
||||
$$BuyableItemsTableOrderingComposer,
|
||||
$$BuyableItemsTableProcessedTableManager,
|
||||
$$BuyableItemsTableInsertCompanionBuilder,
|
||||
$$BuyableItemsTableUpdateCompanionBuilder> {
|
||||
$$BuyableItemsTableTableManager(
|
||||
i0.GeneratedDatabase db, i1.$BuyableItemsTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$BuyableItemsTableFilterComposer(db, table),
|
||||
orderingComposer: $$BuyableItemsTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$BuyableItemsTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
i0.Value<String> description = const i0.Value.absent(),
|
||||
i0.Value<int> price = const i0.Value.absent(),
|
||||
}) =>
|
||||
i1.BuyableItemsCompanion(
|
||||
id: id,
|
||||
description: description,
|
||||
price: price,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
required String description,
|
||||
required int price,
|
||||
}) =>
|
||||
i1.BuyableItemsCompanion.insert(
|
||||
id: id,
|
||||
description: description,
|
||||
price: price,
|
||||
)));
|
||||
}
|
||||
|
||||
class $$ShoppingCartsTableFilterComposer
|
||||
extends i0.FilterComposer<i0.GeneratedDatabase, i2.$ShoppingCartsTable> {
|
||||
$$ShoppingCartsTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get id => i0.ColumnFilters($table.id);
|
||||
i0.ComposableFilter shoppingCartEntriesRefs(
|
||||
i0.ComposableFilter Function($$ShoppingCartEntriesTableFilterComposer f)
|
||||
f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i3.ReadDatabaseContainer($db)
|
||||
.resultSet<i2.$ShoppingCartEntriesTable>('shopping_cart_entries'),
|
||||
getCurrentColumn: (f) => f.id,
|
||||
getReferencedColumn: (f) => f.shoppingCart,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$ShoppingCartEntriesTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
}
|
||||
|
||||
class $$ShoppingCartsTableOrderingComposer
|
||||
extends i0.OrderingComposer<i0.GeneratedDatabase, i2.$ShoppingCartsTable> {
|
||||
$$ShoppingCartsTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get id => i0.ColumnOrderings($table.id);
|
||||
}
|
||||
|
||||
class $$ShoppingCartsTableProcessedTableManager
|
||||
extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i2.$ShoppingCartsTable,
|
||||
i2.ShoppingCart,
|
||||
$$ShoppingCartsTableFilterComposer,
|
||||
$$ShoppingCartsTableOrderingComposer,
|
||||
$$ShoppingCartsTableProcessedTableManager,
|
||||
$$ShoppingCartsTableInsertCompanionBuilder,
|
||||
$$ShoppingCartsTableUpdateCompanionBuilder> {
|
||||
const $$ShoppingCartsTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$ShoppingCartsTableInsertCompanionBuilder = i2.ShoppingCartsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
});
|
||||
typedef $$ShoppingCartsTableUpdateCompanionBuilder = i2.ShoppingCartsCompanion
|
||||
Function({
|
||||
i0.Value<int> id,
|
||||
});
|
||||
|
||||
class $$ShoppingCartsTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i2.$ShoppingCartsTable,
|
||||
i2.ShoppingCart,
|
||||
$$ShoppingCartsTableFilterComposer,
|
||||
$$ShoppingCartsTableOrderingComposer,
|
||||
$$ShoppingCartsTableProcessedTableManager,
|
||||
$$ShoppingCartsTableInsertCompanionBuilder,
|
||||
$$ShoppingCartsTableUpdateCompanionBuilder> {
|
||||
$$ShoppingCartsTableTableManager(
|
||||
i0.GeneratedDatabase db, i2.$ShoppingCartsTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$ShoppingCartsTableFilterComposer(db, table),
|
||||
orderingComposer: $$ShoppingCartsTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$ShoppingCartsTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
}) =>
|
||||
i2.ShoppingCartsCompanion(
|
||||
id: id,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
i0.Value<int> id = const i0.Value.absent(),
|
||||
}) =>
|
||||
i2.ShoppingCartsCompanion.insert(
|
||||
id: id,
|
||||
)));
|
||||
}
|
||||
|
||||
class $$ShoppingCartEntriesTableFilterComposer extends i0
|
||||
.FilterComposer<i0.GeneratedDatabase, i2.$ShoppingCartEntriesTable> {
|
||||
$$ShoppingCartEntriesTableFilterComposer(super.db, super.table);
|
||||
i0.ColumnFilters<int> get shoppingCartId =>
|
||||
i0.ColumnFilters($table.shoppingCart);
|
||||
i0.ComposableFilter shoppingCart(
|
||||
i0.ComposableFilter Function($$ShoppingCartsTableFilterComposer f) f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i3.ReadDatabaseContainer($db)
|
||||
.resultSet<i2.$ShoppingCartsTable>('shopping_carts'),
|
||||
getCurrentColumn: (f) => f.shoppingCart,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$ShoppingCartsTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
|
||||
i0.ColumnFilters<int> get itemId => i0.ColumnFilters($table.item);
|
||||
i0.ComposableFilter item(
|
||||
i0.ComposableFilter Function($$BuyableItemsTableFilterComposer f) f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i3.ReadDatabaseContainer($db)
|
||||
.resultSet<i1.$BuyableItemsTable>('buyable_items'),
|
||||
getCurrentColumn: (f) => f.item,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$BuyableItemsTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
}
|
||||
|
||||
class $$ShoppingCartEntriesTableOrderingComposer extends i0
|
||||
.OrderingComposer<i0.GeneratedDatabase, i2.$ShoppingCartEntriesTable> {
|
||||
$$ShoppingCartEntriesTableOrderingComposer(super.db, super.table);
|
||||
i0.ColumnOrderings<int> get shoppingCartId =>
|
||||
i0.ColumnOrderings($table.shoppingCart);
|
||||
i0.ComposableOrdering shoppingCart(
|
||||
i0.ComposableOrdering Function($$ShoppingCartsTableOrderingComposer o)
|
||||
o) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i3.ReadDatabaseContainer($db)
|
||||
.resultSet<i2.$ShoppingCartsTable>('shopping_carts'),
|
||||
getCurrentColumn: (f) => f.shoppingCart,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$ShoppingCartsTableOrderingComposer(db, table),
|
||||
builder: o);
|
||||
}
|
||||
|
||||
i0.ColumnOrderings<int> get itemId => i0.ColumnOrderings($table.item);
|
||||
i0.ComposableOrdering item(
|
||||
i0.ComposableOrdering Function($$BuyableItemsTableOrderingComposer o) o) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: i3.ReadDatabaseContainer($db)
|
||||
.resultSet<i1.$BuyableItemsTable>('buyable_items'),
|
||||
getCurrentColumn: (f) => f.item,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$BuyableItemsTableOrderingComposer(db, table),
|
||||
builder: o);
|
||||
}
|
||||
}
|
||||
|
||||
class $$ShoppingCartEntriesTableProcessedTableManager
|
||||
extends i0.ProcessedTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i2.$ShoppingCartEntriesTable,
|
||||
i2.ShoppingCartEntry,
|
||||
$$ShoppingCartEntriesTableFilterComposer,
|
||||
$$ShoppingCartEntriesTableOrderingComposer,
|
||||
$$ShoppingCartEntriesTableProcessedTableManager,
|
||||
$$ShoppingCartEntriesTableInsertCompanionBuilder,
|
||||
$$ShoppingCartEntriesTableUpdateCompanionBuilder> {
|
||||
const $$ShoppingCartEntriesTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$ShoppingCartEntriesTableInsertCompanionBuilder
|
||||
= i2.ShoppingCartEntriesCompanion Function({
|
||||
required int shoppingCart,
|
||||
required int item,
|
||||
i0.Value<int> rowid,
|
||||
});
|
||||
typedef $$ShoppingCartEntriesTableUpdateCompanionBuilder
|
||||
= i2.ShoppingCartEntriesCompanion Function({
|
||||
i0.Value<int> shoppingCart,
|
||||
i0.Value<int> item,
|
||||
i0.Value<int> rowid,
|
||||
});
|
||||
|
||||
class $$ShoppingCartEntriesTableTableManager extends i0.RootTableManager<
|
||||
i0.GeneratedDatabase,
|
||||
i2.$ShoppingCartEntriesTable,
|
||||
i2.ShoppingCartEntry,
|
||||
$$ShoppingCartEntriesTableFilterComposer,
|
||||
$$ShoppingCartEntriesTableOrderingComposer,
|
||||
$$ShoppingCartEntriesTableProcessedTableManager,
|
||||
$$ShoppingCartEntriesTableInsertCompanionBuilder,
|
||||
$$ShoppingCartEntriesTableUpdateCompanionBuilder> {
|
||||
$$ShoppingCartEntriesTableTableManager(
|
||||
i0.GeneratedDatabase db, i2.$ShoppingCartEntriesTable table)
|
||||
: super(i0.TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer:
|
||||
$$ShoppingCartEntriesTableFilterComposer(db, table),
|
||||
orderingComposer:
|
||||
$$ShoppingCartEntriesTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$ShoppingCartEntriesTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
i0.Value<int> shoppingCart = const i0.Value.absent(),
|
||||
i0.Value<int> item = const i0.Value.absent(),
|
||||
i0.Value<int> rowid = const i0.Value.absent(),
|
||||
}) =>
|
||||
i2.ShoppingCartEntriesCompanion(
|
||||
shoppingCart: shoppingCart,
|
||||
item: item,
|
||||
rowid: rowid,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
required int shoppingCart,
|
||||
required int item,
|
||||
i0.Value<int> rowid = const i0.Value.absent(),
|
||||
}) =>
|
||||
i2.ShoppingCartEntriesCompanion.insert(
|
||||
shoppingCart: shoppingCart,
|
||||
item: item,
|
||||
rowid: rowid,
|
||||
)));
|
||||
}
|
||||
|
||||
class $RelationalDatabaseManager {
|
||||
final $RelationalDatabase _db;
|
||||
$RelationalDatabaseManager(this._db);
|
||||
$$BuyableItemsTableTableManager get buyableItems =>
|
||||
$$BuyableItemsTableTableManager(_db, _db.buyableItems);
|
||||
$$ShoppingCartsTableTableManager get shoppingCarts =>
|
||||
$$ShoppingCartsTableTableManager(_db, _db.shoppingCarts);
|
||||
$$ShoppingCartEntriesTableTableManager get shoppingCartEntries =>
|
||||
$$ShoppingCartEntriesTableTableManager(_db, _db.shoppingCartEntries);
|
||||
}
|
||||
|
||||
class $ShoppingCartsTable extends i4.ShoppingCarts
|
||||
with i0.TableInfo<$ShoppingCartsTable, i2.ShoppingCart> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
|
@ -163,7 +492,7 @@ class ShoppingCartsCompanion extends i0.UpdateCompanion<i2.ShoppingCart> {
|
|||
}
|
||||
}
|
||||
|
||||
class $ShoppingCartEntriesTable extends i3.ShoppingCartEntries
|
||||
class $ShoppingCartEntriesTable extends i4.ShoppingCartEntries
|
||||
with i0.TableInfo<$ShoppingCartEntriesTable, i2.ShoppingCartEntry> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
|
|
|
@ -22,11 +22,19 @@ class TodoItems extends Table {
|
|||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get title => text().withLength(min: 6, max: 32)();
|
||||
TextColumn get content => text().named('body')();
|
||||
IntColumn get category => integer().nullable()();
|
||||
IntColumn get category =>
|
||||
integer().nullable().references(TodoCategory, #id)();
|
||||
DateTimeColumn get createdAt => dateTime().nullable()();
|
||||
}
|
||||
|
||||
class TodoCategory extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get description => text()();
|
||||
}
|
||||
|
||||
// #enddocregion table
|
||||
|
||||
@DriftDatabase(tables: [TodoItems])
|
||||
@DriftDatabase(tables: [TodoItems, TodoCategory])
|
||||
class AppDatabase extends _$AppDatabase {
|
||||
// #enddocregion before_generation
|
||||
// #enddocregion after_generation
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
---
|
||||
data:
|
||||
title: Manager
|
||||
description: Use easier bindings for common queries.
|
||||
weight: 1
|
||||
|
||||
template: layouts/docs/single
|
||||
path: /docs/getting-started/manager/
|
||||
---
|
||||
|
||||
{% assign snippets = 'package:drift_docs/snippets/dart_api/manager.dart.excerpt.json' | readString | json_decode %}
|
||||
|
||||
With generated code, drift allows writing SQL queries in type-safe Dart.
|
||||
While this is provides lots of flexibility, it requires familiarity with SQL.
|
||||
As a simpler alternative, drift 2.17 introduced a new set of APIs designed to
|
||||
make common queries much easier to write.
|
||||
|
||||
The examples on this page use the database from the [setup]({{ '../setup.md' | pageUrl }})
|
||||
instructions.
|
||||
|
||||
When manager generation is enabled (default), drift will generate a manager for each table in the database.
|
||||
A collection of these managers are accessed by a getter `managers` on the database class.
|
||||
Each table will have a manager generated for it unless it uses a custom row class.
|
||||
|
||||
## Select
|
||||
|
||||
The manager simplifies the process of retrieving rows from a table. Use it to read rows from the table or watch
|
||||
for changes.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_select' %}
|
||||
|
||||
The manager provides a really easy to use API for selecting rows from a table. These can be combined with `|` and `&` and parenthesis to construct more complex queries. Use `.not` to negate a condition.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_filter' %}
|
||||
|
||||
Every column has filters for equality, inequality and nullability.
|
||||
Type specific filters for `int`, `double`, `Int64`, `DateTime` and `String` are included out of the box.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_type_specific_filter' %}
|
||||
|
||||
|
||||
### Filtering across tables
|
||||
You can filter across references to other tables by using the generated reference filters. You can nest these as deep as you'd like and the manager will take care of adding the aliased joins behind the scenes.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_filter_forward_references' %}
|
||||
|
||||
You can also filter across back references. This is useful when you have a one-to-many relationship and want to filter the parent table based on the child table.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_filter_back_references' %}
|
||||
|
||||
The code generator will name this filterset using the name of the table that is being referenced. In the above example, the filterset is named `todoItemsRefs`, because the `TodoItems` table is being referenced.
|
||||
However, you can also specify a custom name for the filterset using the `@ReferenceName(...)` annotation on the foreign key. This may be necessary if you have multiple references to the same table, take the following example:
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'user_group_tables' %}
|
||||
|
||||
We can now use them in a query like this:
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_filter_custom_back_references' %}
|
||||
|
||||
In this example, had we not specified a custom name for the reference, the code generator would have named both filtersets `userRefs` for both references to the `User` table. This would have caused a conflict. By specifying a custom name, we can avoid this issue.
|
||||
|
||||
|
||||
### Ordering
|
||||
|
||||
You can also order the results of a query using the `orderBy` method. The syntax is similar to the `filter` method.
|
||||
Use the `&` to combine multiple orderings. Orderings are applied in the order they are added.
|
||||
You can also use ordering across multiple tables just like with filters.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_ordering' %}
|
||||
|
||||
|
||||
### Count and exists
|
||||
The manager makes it easy to check if a row exists or to count the number of rows that match a certain condition.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_count' %}
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_exists' %}
|
||||
|
||||
|
||||
## Updates
|
||||
We can use the manager to update rows in bulk or individual rows that meet a certain condition.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_update' %}
|
||||
|
||||
We can also replace an entire row with a new one. Or even replace multiple rows at once.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_replace' %}
|
||||
|
||||
## Creating rows
|
||||
The manager includes a method for quickly inserting rows into a table.
|
||||
We can insert a single row or multiple rows at once.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_create' %}
|
||||
|
||||
|
||||
## Deleting rows
|
||||
We may also delete rows from a table using the manager.
|
||||
Any rows that meet the specified condition will be deleted.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_delete' %}
|
||||
|
||||
## Extensions
|
||||
The manager provides a set of filters and orderings out of the box for common types, however you can
|
||||
extend them to add new filters and orderings.
|
||||
|
||||
#### Custom Column Filters
|
||||
If you want to add new filters for individual columns types, you can extend the `ColumnFilter<T>` class.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_filter_extensions' %}
|
||||
|
||||
#### Custom Table Filters
|
||||
You can also create custom filters that operate on multiple columns by extending generated filtersets.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_custom_filter' %}
|
||||
|
||||
#### Custom Column Orderings
|
||||
You can create new ordering methods for individual columns types by extending the `ColumnOrdering<T>` class.
|
||||
Use the `ComposableOrdering` class to create complex orderings.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_ordering_extensions' %}
|
||||
|
||||
#### Custom Table Filters
|
||||
You can also create custom filters that operate on multiple columns by extending generated filtersets.
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'manager_custom_filter' %}
|
|
@ -6,7 +6,7 @@ data:
|
|||
template: layouts/docs/list
|
||||
path: docs/advanced-features/builder_options/
|
||||
aliases:
|
||||
- "options/"
|
||||
- "options/"
|
||||
---
|
||||
|
||||
The `drift_dev` package supports a range of options that control how code
|
||||
|
@ -19,6 +19,7 @@ advice on which options to use.
|
|||
|
||||
To use the options, create a `build.yaml` file in the root of your project (e.g. next
|
||||
to your `pubspec.yaml`):
|
||||
|
||||
```yaml
|
||||
# build.yaml. This file is quite powerful, see https://pub.dev/packages/build_config
|
||||
|
||||
|
@ -34,59 +35,60 @@ targets:
|
|||
|
||||
At the moment, drift supports these options:
|
||||
|
||||
* `write_from_json_string_constructor`: boolean. Adds a `.fromJsonString` factory
|
||||
constructor to generated data classes. By default, we only write a `.fromJson`
|
||||
constructor that takes a `Map<String, dynamic>`.
|
||||
* `override_hash_and_equals_in_result_sets`: boolean. When drift generates another class
|
||||
to hold the result of generated select queries, this flag controls whether drift should
|
||||
override `operator ==` and `hashCode` in those classes. In recent versions, it will also
|
||||
override `toString` if this option is enabled.
|
||||
* `skip_verification_code`: Generated tables contain a significant chunk of code to verify integrity
|
||||
- `write_from_json_string_constructor`: boolean. Adds a `.fromJsonString` factory
|
||||
constructor to generated data classes. By default, we only write a `.fromJson`
|
||||
constructor that takes a `Map<String, dynamic>`.
|
||||
- `override_hash_and_equals_in_result_sets`: boolean. When drift generates another class
|
||||
to hold the result of generated select queries, this flag controls whether drift should
|
||||
override `operator ==` and `hashCode` in those classes. In recent versions, it will also
|
||||
override `toString` if this option is enabled.
|
||||
- `skip_verification_code`: Generated tables contain a significant chunk of code to verify integrity
|
||||
of inserted data and report detailed errors when the integrity is violated. If you're only using
|
||||
inserts with SQL, or don't need this functionality, enabling this flag can help to reduce the amount
|
||||
generated code.
|
||||
* `use_data_class_name_for_companions`: By default, the name for [companion classes]({{ "../Dart API/writes.md#updates-and-deletes" | pageUrl }})
|
||||
- `use_data_class_name_for_companions`: By default, the name for [companion classes]({{ "../Dart API/writes.md#updates-and-deletes" | pageUrl }})
|
||||
is based on the table name (e.g. a `@DataClassName('Users') class UsersTable extends Table` would generate
|
||||
a `UsersTableCompanion`). With this option, the name is based on the data class (so `UsersCompanion` in
|
||||
this case).
|
||||
* `use_column_name_as_json_key_when_defined_in_moor_file` (defaults to `true`): When serializing columns declared inside a
|
||||
- `use_column_name_as_json_key_when_defined_in_moor_file` (defaults to `true`): When serializing columns declared inside a
|
||||
`.drift` file from and to json, use their sql name instead of the generated Dart getter name
|
||||
(so a column named `user_name` would also use `user_name` as a json key instead of `userName`).
|
||||
You can always override the json key by using a `JSON KEY` column constraint
|
||||
(e.g. `user_name VARCHAR NOT NULL JSON KEY userName`).
|
||||
* `use_sql_column_name_as_json_key` (defaults to false): Uses the column name in SQL as the JSON key for serialization,
|
||||
- `use_sql_column_name_as_json_key` (defaults to false): Uses the column name in SQL as the JSON key for serialization,
|
||||
regardless of whether the table was defined in a drift file or not.
|
||||
* `generate_connect_constructor` (deprecated): Generates a named `connect()` constructor on database classes
|
||||
- `generate_connect_constructor` (deprecated): Generates a named `connect()` constructor on database classes
|
||||
that takes a `DatabaseConnection` instead of a `QueryExecutor`.
|
||||
This option was deprecated in drift 2.5 because `DatabaseConnection` now implements `QueryExecutor`.
|
||||
* `data_class_to_companions` (defaults to `true`): Controls whether drift will write the `toCompanion` method in generated
|
||||
data classes.
|
||||
* `mutable_classes` (defaults to `false`): The fields generated in generated data, companion and result set classes are final
|
||||
- `data_class_to_companions` (defaults to `true`): Controls whether drift will write the `toCompanion` method in generated
|
||||
data classes.
|
||||
- `mutable_classes` (defaults to `false`): The fields generated in generated data, companion and result set classes are final
|
||||
by default. You can make them mutable by setting `mutable_classes: true`.
|
||||
* `raw_result_set_data`: The generator will expose the underlying `QueryRow` for generated result set classes
|
||||
* `apply_converters_on_variables` (defaults to `true`): Applies type converters to variables in compiled statements.
|
||||
* `generate_values_in_copy_with` (defaults to `true`): Generates a `Value<T?>` instead of `T?` for nullable columns in `copyWith`. This allows to set
|
||||
- `raw_result_set_data`: The generator will expose the underlying `QueryRow` for generated result set classes
|
||||
- `apply_converters_on_variables` (defaults to `true`): Applies type converters to variables in compiled statements.
|
||||
- `generate_values_in_copy_with` (defaults to `true`): Generates a `Value<T?>` instead of `T?` for nullable columns in `copyWith`. This allows to set
|
||||
columns back to null (by using `Value(null)`). Passing `null` was ignored before, making it impossible to set columns
|
||||
to `null`.
|
||||
* `named_parameters`: Generates named parameters for named variables in SQL queries.
|
||||
* `named_parameters_always_required`: All named parameters (generated if `named_parameters` option is `true`) will be required in Dart.
|
||||
* `scoped_dart_components` (defaults to `true`): Generates a function parameter for [Dart placeholders]({{ '../SQL API/drift_files.md#dart-components-in-sql' | pageUrl }}) in SQL.
|
||||
- `named_parameters`: Generates named parameters for named variables in SQL queries.
|
||||
- `named_parameters_always_required`: All named parameters (generated if `named_parameters` option is `true`) will be required in Dart.
|
||||
- `scoped_dart_components` (defaults to `true`): Generates a function parameter for [Dart placeholders]({{ '../SQL API/drift_files.md#dart-components-in-sql' | pageUrl }}) in SQL.
|
||||
The function has a parameter for each table that is available in the query, making it easier to get aliases right when using
|
||||
Dart placeholders.
|
||||
* `store_date_time_values_as_text`: Whether date-time columns should be stored as ISO 8601 string instead of a unix timestamp.
|
||||
- `store_date_time_values_as_text`: Whether date-time columns should be stored as ISO 8601 string instead of a unix timestamp.
|
||||
For more information on these modes, see [datetime options]({{ '../Dart API/tables.md#datetime-options' | pageUrl }}).
|
||||
* `case_from_dart_to_sql` (defaults to `snake_case`): Controls how the table and column names are re-cased from the Dart identifiers.
|
||||
The possible values are `preserve`, `camelCase`, `CONSTANT_CASE`, `snake_case`, `PascalCase`, `lowercase` and `UPPERCASE` (default: `snake_case`).
|
||||
* `write_to_columns_mixins`: Whether the `toColumns` method should be written as a mixin instead of being added directly to the data class.
|
||||
This is useful when using [existing row classes]({{ '../custom_row_classes.md' | pageUrl }}), as the mixin is generated for those as well.
|
||||
* `has_separate_analyzer`: This option is only relevant when using the `drift_dev:not_shared` builder, which needs to use a less efficient
|
||||
- `case_from_dart_to_sql` (defaults to `snake_case`): Controls how the table and column names are re-cased from the Dart identifiers.
|
||||
The possible values are `preserve`, `camelCase`, `CONSTANT_CASE`, `snake_case`, `PascalCase`, `lowercase` and `UPPERCASE` (default: `snake_case`).
|
||||
- `write_to_columns_mixins`: Whether the `toColumns` method should be written as a mixin instead of being added directly to the data class.
|
||||
This is useful when using [existing row classes]({{ '../custom_row_classes.md' | pageUrl }}), as the mixin is generated for those as well.
|
||||
- `has_separate_analyzer`: This option is only relevant when using the `drift_dev:not_shared` builder, which needs to use a less efficient
|
||||
analysis implementation than the other builders by default. After also applying `drift_dev:analyzer` to the same build target, this option
|
||||
can be enabled to speed up builds. This option has no effect with the default or the modular builder.
|
||||
* `fatal_warnings`: When enabled (defaults to `false`), warnings found by `drift_dev` in the build process (like syntax errors in SQL queries or
|
||||
- `fatal_warnings`: When enabled (defaults to `false`), warnings found by `drift_dev` in the build process (like syntax errors in SQL queries or
|
||||
unresolved references in your Dart tables) will cause the build to fail.
|
||||
* `preamble`: This option is useful when using drift [as a standalone part builder](#using-drift-classes-in-other-builders) or when running a
|
||||
- `preamble`: This option is useful when using drift [as a standalone part builder](#using-drift-classes-in-other-builders) or when running a
|
||||
[modular build](#modular-code-generation). In these setups, the `preamble` option defined by the [source_gen package](https://pub.dev/packages/source_gen#preamble)
|
||||
would have no effect, which is why it has been added as an option for the drift builders.
|
||||
- `generate_manager`: When enabled (defaults to `true`), managers will be generated for each table in the database. These managers help perform simple actions without boilerplate.
|
||||
|
||||
## Assumed SQL environment
|
||||
|
||||
|
@ -151,7 +153,7 @@ targets:
|
|||
|
||||
### Available extensions
|
||||
|
||||
__Note__: This enables extensions in the analyzer for custom queries only. For instance, when the `json1` extension is
|
||||
**Note**: This enables extensions in the analyzer for custom queries only. For instance, when the `json1` extension is
|
||||
enabled, the [`json`](https://www.sqlite.org/json1.html) functions can be used in drift files. This doesn't necessarily
|
||||
mean that those functions are supported at runtime! Both extensions are available on iOS 11 or later. On Android, they're
|
||||
only available when using a `NativeDatabase`.
|
||||
|
@ -176,7 +178,7 @@ We currently support the following extensions:
|
|||
- [json1](https://www.sqlite.org/json1.html): Support static analysis for `json_` functions in moor files
|
||||
- [fts5](https://www.sqlite.org/fts5.html): Support `CREATE VIRTUAL TABLE` statements for `fts5` tables and the `MATCH` operator.
|
||||
Functions like `highlight` or `bm25` are available as well.
|
||||
- `rtree`: Static analysis support for the [R*Tree](https://www.sqlite.org/rtree.html) extension.
|
||||
- `rtree`: Static analysis support for the [R\*Tree](https://www.sqlite.org/rtree.html) extension.
|
||||
Enabling this option is safe when using a `NativeDatabase` with `sqlite3_flutter_libs`,
|
||||
which compiles sqlite3 with the R*Tree extension enabled.
|
||||
- [geopoly](https://www.sqlite.org/geopoly.html), a generalization of the R*Tree module supporting more complex
|
||||
|
|
|
@ -685,6 +685,7 @@ class $TodoItemWithCategoryNameViewView extends ViewInfo<
|
|||
|
||||
abstract class _$Database extends GeneratedDatabase {
|
||||
_$Database(QueryExecutor e) : super(e);
|
||||
_$DatabaseManager get managers => _$DatabaseManager(this);
|
||||
late final $TodoCategoriesTable todoCategories = $TodoCategoriesTable(this);
|
||||
late final $TodoItemsTable todoItems = $TodoItemsTable(this);
|
||||
late final $TodoCategoryItemCountView todoCategoryItemCount =
|
||||
|
@ -705,3 +706,212 @@ abstract class _$Database extends GeneratedDatabase {
|
|||
itemTitle
|
||||
];
|
||||
}
|
||||
|
||||
class $$TodoCategoriesTableFilterComposer
|
||||
extends FilterComposer<_$Database, $TodoCategoriesTable> {
|
||||
$$TodoCategoriesTableFilterComposer(super.db, super.table);
|
||||
ColumnFilters<int> get id => ColumnFilters($table.id);
|
||||
ColumnFilters<String> get name => ColumnFilters($table.name);
|
||||
ComposableFilter todoItemsRefs(
|
||||
ComposableFilter Function($$TodoItemsTableFilterComposer f) f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: $db.todoItems,
|
||||
getCurrentColumn: (f) => f.id,
|
||||
getReferencedColumn: (f) => f.categoryId,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$TodoItemsTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
}
|
||||
|
||||
class $$TodoCategoriesTableOrderingComposer
|
||||
extends OrderingComposer<_$Database, $TodoCategoriesTable> {
|
||||
$$TodoCategoriesTableOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<int> get id => ColumnOrderings($table.id);
|
||||
ColumnOrderings<String> get name => ColumnOrderings($table.name);
|
||||
}
|
||||
|
||||
class $$TodoCategoriesTableProcessedTableManager extends ProcessedTableManager<
|
||||
_$Database,
|
||||
$TodoCategoriesTable,
|
||||
TodoCategory,
|
||||
$$TodoCategoriesTableFilterComposer,
|
||||
$$TodoCategoriesTableOrderingComposer,
|
||||
$$TodoCategoriesTableProcessedTableManager,
|
||||
$$TodoCategoriesTableInsertCompanionBuilder,
|
||||
$$TodoCategoriesTableUpdateCompanionBuilder> {
|
||||
const $$TodoCategoriesTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$TodoCategoriesTableInsertCompanionBuilder = TodoCategoriesCompanion
|
||||
Function({
|
||||
Value<int> id,
|
||||
required String name,
|
||||
});
|
||||
typedef $$TodoCategoriesTableUpdateCompanionBuilder = TodoCategoriesCompanion
|
||||
Function({
|
||||
Value<int> id,
|
||||
Value<String> name,
|
||||
});
|
||||
|
||||
class $$TodoCategoriesTableTableManager extends RootTableManager<
|
||||
_$Database,
|
||||
$TodoCategoriesTable,
|
||||
TodoCategory,
|
||||
$$TodoCategoriesTableFilterComposer,
|
||||
$$TodoCategoriesTableOrderingComposer,
|
||||
$$TodoCategoriesTableProcessedTableManager,
|
||||
$$TodoCategoriesTableInsertCompanionBuilder,
|
||||
$$TodoCategoriesTableUpdateCompanionBuilder> {
|
||||
$$TodoCategoriesTableTableManager(_$Database db, $TodoCategoriesTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$TodoCategoriesTableFilterComposer(db, table),
|
||||
orderingComposer: $$TodoCategoriesTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$TodoCategoriesTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<int> id = const Value.absent(),
|
||||
Value<String> name = const Value.absent(),
|
||||
}) =>
|
||||
TodoCategoriesCompanion(
|
||||
id: id,
|
||||
name: name,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
Value<int> id = const Value.absent(),
|
||||
required String name,
|
||||
}) =>
|
||||
TodoCategoriesCompanion.insert(
|
||||
id: id,
|
||||
name: name,
|
||||
)));
|
||||
}
|
||||
|
||||
class $$TodoItemsTableFilterComposer
|
||||
extends FilterComposer<_$Database, $TodoItemsTable> {
|
||||
$$TodoItemsTableFilterComposer(super.db, super.table);
|
||||
ColumnFilters<int> get id => ColumnFilters($table.id);
|
||||
ColumnFilters<String> get title => ColumnFilters($table.title);
|
||||
ColumnFilters<String> get content => ColumnFilters($table.content);
|
||||
ColumnFilters<int> get categoryIdId => ColumnFilters($table.categoryId);
|
||||
ComposableFilter categoryId(
|
||||
ComposableFilter Function($$TodoCategoriesTableFilterComposer f) f) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: $db.todoCategories,
|
||||
getCurrentColumn: (f) => f.categoryId,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$TodoCategoriesTableFilterComposer(db, table),
|
||||
builder: f);
|
||||
}
|
||||
|
||||
ColumnFilters<String> get generatedText =>
|
||||
ColumnFilters($table.generatedText);
|
||||
}
|
||||
|
||||
class $$TodoItemsTableOrderingComposer
|
||||
extends OrderingComposer<_$Database, $TodoItemsTable> {
|
||||
$$TodoItemsTableOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<int> get id => ColumnOrderings($table.id);
|
||||
ColumnOrderings<String> get title => ColumnOrderings($table.title);
|
||||
ColumnOrderings<String> get content => ColumnOrderings($table.content);
|
||||
ColumnOrderings<int> get categoryIdId => ColumnOrderings($table.categoryId);
|
||||
ComposableOrdering categoryId(
|
||||
ComposableOrdering Function($$TodoCategoriesTableOrderingComposer o) o) {
|
||||
return $composeWithJoins(
|
||||
$db: $db,
|
||||
$table: $table,
|
||||
referencedTable: $db.todoCategories,
|
||||
getCurrentColumn: (f) => f.categoryId,
|
||||
getReferencedColumn: (f) => f.id,
|
||||
getReferencedComposer: (db, table) =>
|
||||
$$TodoCategoriesTableOrderingComposer(db, table),
|
||||
builder: o);
|
||||
}
|
||||
|
||||
ColumnOrderings<String> get generatedText =>
|
||||
ColumnOrderings($table.generatedText);
|
||||
}
|
||||
|
||||
class $$TodoItemsTableProcessedTableManager extends ProcessedTableManager<
|
||||
_$Database,
|
||||
$TodoItemsTable,
|
||||
TodoItem,
|
||||
$$TodoItemsTableFilterComposer,
|
||||
$$TodoItemsTableOrderingComposer,
|
||||
$$TodoItemsTableProcessedTableManager,
|
||||
$$TodoItemsTableInsertCompanionBuilder,
|
||||
$$TodoItemsTableUpdateCompanionBuilder> {
|
||||
const $$TodoItemsTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$TodoItemsTableInsertCompanionBuilder = TodoItemsCompanion Function({
|
||||
Value<int> id,
|
||||
required String title,
|
||||
Value<String?> content,
|
||||
required int categoryId,
|
||||
});
|
||||
typedef $$TodoItemsTableUpdateCompanionBuilder = TodoItemsCompanion Function({
|
||||
Value<int> id,
|
||||
Value<String> title,
|
||||
Value<String?> content,
|
||||
Value<int> categoryId,
|
||||
});
|
||||
|
||||
class $$TodoItemsTableTableManager extends RootTableManager<
|
||||
_$Database,
|
||||
$TodoItemsTable,
|
||||
TodoItem,
|
||||
$$TodoItemsTableFilterComposer,
|
||||
$$TodoItemsTableOrderingComposer,
|
||||
$$TodoItemsTableProcessedTableManager,
|
||||
$$TodoItemsTableInsertCompanionBuilder,
|
||||
$$TodoItemsTableUpdateCompanionBuilder> {
|
||||
$$TodoItemsTableTableManager(_$Database db, $TodoItemsTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$TodoItemsTableFilterComposer(db, table),
|
||||
orderingComposer: $$TodoItemsTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$TodoItemsTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<int> id = const Value.absent(),
|
||||
Value<String> title = const Value.absent(),
|
||||
Value<String?> content = const Value.absent(),
|
||||
Value<int> categoryId = const Value.absent(),
|
||||
}) =>
|
||||
TodoItemsCompanion(
|
||||
id: id,
|
||||
title: title,
|
||||
content: content,
|
||||
categoryId: categoryId,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
Value<int> id = const Value.absent(),
|
||||
required String title,
|
||||
Value<String?> content = const Value.absent(),
|
||||
required int categoryId,
|
||||
}) =>
|
||||
TodoItemsCompanion.insert(
|
||||
id: id,
|
||||
title: title,
|
||||
content: content,
|
||||
categoryId: categoryId,
|
||||
)));
|
||||
}
|
||||
|
||||
class _$DatabaseManager {
|
||||
final _$Database _db;
|
||||
_$DatabaseManager(this._db);
|
||||
$$TodoCategoriesTableTableManager get todoCategories =>
|
||||
$$TodoCategoriesTableTableManager(_db, _db.todoCategories);
|
||||
$$TodoItemsTableTableManager get todoItems =>
|
||||
$$TodoItemsTableTableManager(_db, _db.todoItems);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ export 'src/runtime/query_builder/query_builder.dart'
|
|||
hide CaseWhenExpressionWithBase, BaseCaseWhenExpression;
|
||||
export 'src/runtime/types/converters.dart';
|
||||
export 'src/runtime/types/mapping.dart' hide BaseSqlType, UserDefinedSqlType;
|
||||
export 'src/runtime/manager/manager.dart'
|
||||
hide JoinBuilder, HasJoinBuilders, Composer, BaseTableManager;
|
||||
export 'src/utils/lazy_database.dart';
|
||||
|
||||
/// A [ListEquality] instance used by generated drift code for the `==` and
|
||||
|
|
|
@ -409,3 +409,34 @@ class JsonKey {
|
|||
/// generated json. See the documentation for [JsonKey] for details.
|
||||
const JsonKey(this.key);
|
||||
}
|
||||
|
||||
/// Annotation to use on reference columns inside of a [Table] to define the name
|
||||
/// that the manager will use when refering to this relation in the reverse.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// class TodoEntries extends Table {
|
||||
/// IntColumn get id => integer().autoIncrement()();
|
||||
/// TextColumn get body => text()();
|
||||
/// @ReferenceName("categories")
|
||||
/// IntColumn get category => integer().nullable().references(Categories, #id)();
|
||||
/// }
|
||||
/// class Categories extends Table {
|
||||
/// IntColumn get id => integer().autoIncrement()();
|
||||
/// }
|
||||
/// /// The manager will now use the name `categories`
|
||||
/// categories.filter((f) => f.categories((f) => f.body("Todo")))
|
||||
///
|
||||
/// ```
|
||||
/// When these aren't specified, the manager will use the referenced tables name followed by `Refs`.
|
||||
/// If a reference name clashes with other fields on the table, the generator will show a warning,
|
||||
/// and filters and orderings wont be generated
|
||||
class ReferenceName {
|
||||
/// The name that this reference will use when generating filters and ordering in the reverse direction
|
||||
/// for [ReferenceName] for details.
|
||||
final String name;
|
||||
|
||||
/// Annotation to use on reference columns inside of a [Table] to define the name
|
||||
/// of the filters and orderings for the reverse relation.
|
||||
const ReferenceName(this.name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
part of 'manager.dart';
|
||||
|
||||
/// Base class for all composers
|
||||
///
|
||||
/// Any class that can be composed using the `&` or `|` operator is called a composable.
|
||||
/// [ComposableFilter] and [ComposableOrdering] are examples of composable classes.
|
||||
///
|
||||
/// The [Composer] class is a top level manager for this operation.
|
||||
/// ```dart
|
||||
/// filter((f) => f.id.equals(1) & f.name.equals('Bob'));
|
||||
/// ```
|
||||
/// `f` in this example is a [Composer] object, and `f.id.equals(1)` returns a [ComposableFilter] object.
|
||||
///
|
||||
/// The [Composer] class is responsible for creating joins between tables, and passing them down to the composable classes.
|
||||
@internal
|
||||
sealed class Composer<DB extends GeneratedDatabase, CT extends Table> {
|
||||
/// The database that the query will be executed on
|
||||
final DB $db;
|
||||
|
||||
/// The table that the query will be executed on
|
||||
final CT $table;
|
||||
|
||||
Composer(this.$db, this.$table);
|
||||
|
||||
/// Utility for creating a composer which contains the joins needed to
|
||||
/// execute a query on a table that is referenced by a foreign key.
|
||||
B $composeWithJoins<RT extends Table, QC extends Composer<DB, RT>,
|
||||
B extends HasJoinBuilders>({
|
||||
required DB $db,
|
||||
required CT $table,
|
||||
required GeneratedColumn Function(CT) getCurrentColumn,
|
||||
required RT referencedTable,
|
||||
required GeneratedColumn Function(RT) getReferencedColumn,
|
||||
required B Function(QC) builder,
|
||||
required QC Function(DB db, RT table) getReferencedComposer,
|
||||
}) {
|
||||
// The name of the alias will be created using the following logic:
|
||||
// "currentTableName__currentColumnName__referencedColumnName__referencedTableName"
|
||||
// This is to ensure that the alias is unique
|
||||
final currentColumn = getCurrentColumn($table);
|
||||
final tempReferencedColumn = getReferencedColumn(referencedTable);
|
||||
final aliasName =
|
||||
'${currentColumn.tableName}__${currentColumn.name}__${tempReferencedColumn.tableName}__${tempReferencedColumn.name}';
|
||||
final aliasedReferencedTable =
|
||||
$db.alias(referencedTable as TableInfo, aliasName);
|
||||
final aliasedReferencedColumn =
|
||||
getReferencedColumn(aliasedReferencedTable as RT);
|
||||
|
||||
// Create a join builder for the referenced table
|
||||
final joinBuilder = JoinBuilder(
|
||||
currentTable: $table,
|
||||
currentColumn: currentColumn,
|
||||
referencedTable: aliasedReferencedTable,
|
||||
referencedColumn: aliasedReferencedColumn,
|
||||
);
|
||||
|
||||
// Get the query composer for the referenced table, passing in the aliased
|
||||
// table and all the join builders
|
||||
final referencedComposer =
|
||||
getReferencedComposer($db, aliasedReferencedTable);
|
||||
|
||||
// Run the user provided builder with the referencedQueryComposer
|
||||
// This may return a filter or ordering, but we only enforce that it's
|
||||
// a HasJoinBuilders
|
||||
final result = builder(referencedComposer);
|
||||
result.addJoinBuilders({joinBuilder});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
part of 'manager.dart';
|
||||
|
||||
/// Defines a class which is used to wrap a column to only expose filter functions
|
||||
class ColumnFilters<T extends Object> {
|
||||
/// This class is a wrapper on top of the generated column class
|
||||
///
|
||||
/// It's used to expose filter functions for a column type
|
||||
///
|
||||
/// Use an extention to add more filters to any column type
|
||||
///
|
||||
/// ```dart
|
||||
/// extension on ColumnFilters<DateTime>{
|
||||
/// ComposableFilter after2000() => isAfter(DateTime(2000));
|
||||
///}
|
||||
/// ```
|
||||
const ColumnFilters(this.column, [this.inverted = false]);
|
||||
|
||||
/// Column that this [ColumnFilters] wraps
|
||||
final Expression<T> column;
|
||||
|
||||
/// If true, all filters will be inverted
|
||||
final bool inverted;
|
||||
|
||||
/// Returns a copy of these column filters where all the filters are inverted
|
||||
/// ```dart
|
||||
/// myColumn.not.equals(5); // All columns that aren't null and have a value that is not equal to 5
|
||||
/// ```
|
||||
/// Keep in mind that while using inverted filters, null is never returned.
|
||||
///
|
||||
/// If you would like to include them, use the [isNull] filter as well
|
||||
/// ```dart
|
||||
/// myColumn.not.equals(5) | myColumn.isNull(); // All columns that are null OR have a value that is not equal to 5 will be returned
|
||||
/// ```
|
||||
ColumnFilters<T> get not => ColumnFilters(column, !inverted);
|
||||
|
||||
/// Create a filter that checks if the column equals a value.
|
||||
ComposableFilter equals(T value) =>
|
||||
ComposableFilter(column.equals(value), inverted: inverted);
|
||||
|
||||
/// Create a filter that checks if the column is null.
|
||||
ComposableFilter isNull() =>
|
||||
ComposableFilter(column.isNull(), inverted: inverted);
|
||||
|
||||
/// Create a filter that checks if the column is in a list of values.
|
||||
ComposableFilter isIn(Iterable<T> values) =>
|
||||
ComposableFilter(column.isIn(values), inverted: inverted);
|
||||
|
||||
/// Shortcut for [equals]
|
||||
ComposableFilter call(T value) => equals(value);
|
||||
}
|
||||
|
||||
enum _StringFilterTypes { contains, startsWith, endsWith }
|
||||
|
||||
/// Built in filters for int/double columns
|
||||
extension StringFilters<T extends String> on ColumnFilters<String> {
|
||||
/// This function helps handle case insensitivity in like expressions
|
||||
/// This helps handle all the possible scenarios:
|
||||
/// 1. If a user hasn't set the database to be case sensitive in like expressions
|
||||
/// Then we are ok with having the query be performed on upper case values
|
||||
/// 2. If a user has set the database to be case sensitive in like expressions
|
||||
/// We still can perform a case insensitive search by default. We have all filters
|
||||
/// use `{bool caseInsensitive = true}` which will perform a case insensitive search
|
||||
/// 3. If a user has set the database to be case sensitive in like expressions and wan't
|
||||
/// to perform a case sensitive search, they can pass `caseInsensitive = false` manually
|
||||
///
|
||||
/// We are using the default of {bool caseInsensitive = true}, so that users who haven't set
|
||||
/// the database to be case sensitive wont be confues why their like expressions are case insensitive
|
||||
Expression<bool> _buildExpression(
|
||||
_StringFilterTypes type, String value, bool caseInsensitive) {
|
||||
final Expression<String> column;
|
||||
if (caseInsensitive) {
|
||||
value = value.toUpperCase();
|
||||
column = this.column.upper();
|
||||
} else {
|
||||
column = this.column;
|
||||
}
|
||||
switch (type) {
|
||||
case _StringFilterTypes.contains:
|
||||
return column.like('%$value%');
|
||||
case _StringFilterTypes.startsWith:
|
||||
return column.like('$value%');
|
||||
case _StringFilterTypes.endsWith:
|
||||
return column.like('%$value');
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a filter to check if the this text column contains a substring
|
||||
///
|
||||
/// Setting [caseInsensitive] to false will have no effect unless the database in configured to use
|
||||
/// case sensitive like expressions.
|
||||
///
|
||||
/// See https://www.sqlitetutorial.net/sqlite-like/ for more information on how
|
||||
/// to the like expression works.
|
||||
ComposableFilter contains(T value, {bool caseInsensitive = true}) {
|
||||
return ComposableFilter(
|
||||
_buildExpression(_StringFilterTypes.contains, value, caseInsensitive),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// Create a filter to check if the this text column starts with a substring
|
||||
///
|
||||
/// Setting [caseInsensitive] to false will have no effect unless the database in configured to use
|
||||
/// case sensitive like expressions.
|
||||
///
|
||||
/// See https://www.sqlitetutorial.net/sqlite-like/ for more information on how
|
||||
/// to the like expression works.
|
||||
ComposableFilter startsWith(T value, {bool caseInsensitive = true}) {
|
||||
return ComposableFilter(
|
||||
_buildExpression(_StringFilterTypes.startsWith, value, caseInsensitive),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// Create a filter to check if the this text column ends with a substring
|
||||
///
|
||||
/// Setting [caseInsensitive] to false will have no effect unless the database in configured to use
|
||||
/// case sensitive like expressions.
|
||||
///
|
||||
/// See https://www.sqlitetutorial.net/sqlite-like/ for more information on how
|
||||
/// to the like expression works.
|
||||
ComposableFilter endsWith(T value, {bool caseInsensitive = true}) {
|
||||
return ComposableFilter(
|
||||
_buildExpression(_StringFilterTypes.endsWith, value, caseInsensitive),
|
||||
inverted: inverted);
|
||||
}
|
||||
}
|
||||
|
||||
/// Built in filters for bool columns
|
||||
extension BoolFilters on ColumnFilters<bool> {
|
||||
/// Create a filter to check if the column is bigger than a value
|
||||
ComposableFilter isTrue() =>
|
||||
ComposableFilter(column.equals(true), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is small than a value
|
||||
ComposableFilter isFalse() =>
|
||||
ComposableFilter(column.equals(false), inverted: inverted);
|
||||
}
|
||||
|
||||
/// Built in filters for int/double columns
|
||||
extension NumFilters<T extends num> on ColumnFilters<T> {
|
||||
/// Create a filter to check if the column is bigger than a value
|
||||
ComposableFilter isBiggerThan(T value) =>
|
||||
ComposableFilter(column.isBiggerThanValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is small than a value
|
||||
ComposableFilter isSmallerThan(T value) =>
|
||||
ComposableFilter(column.isSmallerThanValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is bigger or equal to a value
|
||||
ComposableFilter isBiggerOrEqualTo(T value) =>
|
||||
ComposableFilter(column.isBiggerOrEqualValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is small or equal to a value
|
||||
ComposableFilter isSmallerOrEqualTo(T value) =>
|
||||
ComposableFilter(column.isSmallerOrEqualValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is between two values
|
||||
/// This is done inclusively, so the column can be equal to the lower or higher value
|
||||
/// E.G isBetween(1, 3) will return true for 1, 2, and 3
|
||||
ComposableFilter isBetween(T lower, T higher) =>
|
||||
ComposableFilter(column.isBetweenValues(lower, higher),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// Built in filters for BigInt columns
|
||||
extension BigIntFilters<T extends BigInt> on ColumnFilters<T> {
|
||||
/// Create a filter to check if the column is bigger than a value
|
||||
ComposableFilter isBiggerThan(T value) =>
|
||||
ComposableFilter(column.isBiggerThanValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is small than a value
|
||||
ComposableFilter isSmallerThan(T value) =>
|
||||
ComposableFilter(column.isSmallerThanValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is bigger or equal to a value
|
||||
ComposableFilter isBiggerOrEqualTo(T value) =>
|
||||
ComposableFilter(column.isBiggerOrEqualValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is small or equal to a value
|
||||
ComposableFilter isSmallerOrEqualTo(T value) =>
|
||||
ComposableFilter(column.isSmallerOrEqualValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is between two values
|
||||
/// This is done inclusively, so the column can be equal to the lower or higher value
|
||||
/// E.G isBetween(1, 3) will return true for 1, 2, and 3
|
||||
ComposableFilter isBetween(T lower, T higher) =>
|
||||
ComposableFilter(column.isBetweenValues(lower, higher),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// Built in filters for DateTime columns
|
||||
extension DateFilters<T extends DateTime> on ColumnFilters<T> {
|
||||
/// Create a filter to check if the column is after a [DateTime]
|
||||
ComposableFilter isAfter(T value) =>
|
||||
ComposableFilter(column.isBiggerThanValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is before a [DateTime]
|
||||
ComposableFilter isBefore(T value) =>
|
||||
ComposableFilter(column.isSmallerThanValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is on or after a [DateTime]
|
||||
ComposableFilter isAfterOrOn(T value) =>
|
||||
ComposableFilter(column.isBiggerOrEqualValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is before or on a [DateTime]
|
||||
ComposableFilter isBeforeOrOn(T value) =>
|
||||
ComposableFilter(column.isSmallerOrEqualValue(value), inverted: inverted);
|
||||
|
||||
/// Create a filter to check if the column is between 2 [DateTime]s
|
||||
/// This is done inclusively, so the column can be equal to the lower or higher value
|
||||
/// E.G isBetween(1, 3) will return true for 1, 2, and 3
|
||||
ComposableFilter isBetween(T lower, T higher) =>
|
||||
ComposableFilter(column.isBetweenValues(lower, higher),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// Defines a class which is used to wrap a column with a type converter to only expose filter functions
|
||||
// [CustomType] is the type that the user has defined in their type converter
|
||||
// [CustomTypeNonNullable] is the type that the user has defined in their type converter, but is non-nullable
|
||||
class ColumnWithTypeConverterFilters<CustomType, CustomTypeNonNullable,
|
||||
T extends Object> {
|
||||
/// Similar to [ColumnFilters] but for columns with type converters\
|
||||
const ColumnWithTypeConverterFilters(this.column, [this.inverted = false]);
|
||||
|
||||
/// If true, all filters will be inverted
|
||||
final bool inverted;
|
||||
|
||||
/// Column that this [ColumnWithTypeConverterFilters] wraps
|
||||
final GeneratedColumnWithTypeConverter<CustomType, T> column;
|
||||
|
||||
/// Returns a copy of these column filters where all the filters are inverted
|
||||
/// ```dart
|
||||
/// myColumn.not.equals(5); // All columns that aren't null and have a value that is not equal to 5
|
||||
/// ```
|
||||
/// Keep in mind that while using inverted filters, null is never returned.
|
||||
///
|
||||
/// If you would like to include them, use the [isNull] filter as well
|
||||
/// ```dart
|
||||
/// myColumn.not.equals(5) | myColumn.isNull(); // All columns that are null OR have a value that is not equal to 5
|
||||
/// ```
|
||||
ColumnWithTypeConverterFilters<CustomType, CustomTypeNonNullable, T>
|
||||
get not => ColumnWithTypeConverterFilters(column, !inverted);
|
||||
|
||||
/// Create a filter that checks if the column is null.
|
||||
ComposableFilter isNull() =>
|
||||
ComposableFilter(column.isNull(), inverted: inverted);
|
||||
|
||||
/// Get the actual value from the custom type
|
||||
T _customTypeToSql(CustomTypeNonNullable value) {
|
||||
assert(value != null,
|
||||
'The filter value cannot be null. This is likely a bug in the generated code. Please report this issue.');
|
||||
final mappedValue = column.converter.toSql(value as CustomType);
|
||||
|
||||
if (mappedValue == null) {
|
||||
throw ArgumentError(
|
||||
'The TypeConverter for this column returned null when converting the type to sql. Ensure that your TypeConverter never returns null when provided a non-null value.');
|
||||
}
|
||||
return mappedValue;
|
||||
}
|
||||
|
||||
/// Create a filter that checks if the column equals a value.
|
||||
ComposableFilter equals(CustomTypeNonNullable value) {
|
||||
return ComposableFilter(column.equals(_customTypeToSql(value)),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// Shortcut for [equals]
|
||||
ComposableFilter call(CustomTypeNonNullable value) => equals(value);
|
||||
|
||||
/// Create a filter that checks if the column is in a list of values.
|
||||
ComposableFilter isIn(Iterable<CustomTypeNonNullable> values) =>
|
||||
ComposableFilter(column.isIn(values.map(_customTypeToSql).toList()),
|
||||
inverted: inverted);
|
||||
}
|
||||
|
||||
/// This class is wrapper on the expression class
|
||||
///
|
||||
/// It contains the expression, along with any joins that are required
|
||||
/// to execute the expression. See [HasJoinBuilders] for more information
|
||||
/// on how joins are stored
|
||||
class ComposableFilter extends HasJoinBuilders {
|
||||
@override
|
||||
final Set<JoinBuilder> joinBuilders;
|
||||
|
||||
/// The expression that will be applied to the query
|
||||
late final Expression<bool> expression;
|
||||
|
||||
/// Create a new [ComposableFilter] for a column without any joins
|
||||
ComposableFilter(Expression<bool> expression, {required bool inverted})
|
||||
: joinBuilders = {} {
|
||||
this.expression = inverted ? expression.not() : expression;
|
||||
}
|
||||
|
||||
/// Create a new [ComposableFilter] for a column with joins
|
||||
ComposableFilter._(this.expression, this.joinBuilders);
|
||||
|
||||
/// Combine two filters with an AND
|
||||
ComposableFilter operator &(ComposableFilter other) {
|
||||
return ComposableFilter._(
|
||||
expression & other.expression,
|
||||
joinBuilders.union(other.joinBuilders),
|
||||
);
|
||||
}
|
||||
|
||||
/// Combine two filters with an OR
|
||||
ComposableFilter operator |(ComposableFilter other) {
|
||||
return ComposableFilter._(
|
||||
expression | other.expression,
|
||||
joinBuilders.union(other.joinBuilders),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The class that orchestrates the composition of filtering
|
||||
class FilterComposer<DB extends GeneratedDatabase, T extends Table>
|
||||
extends Composer<DB, T> {
|
||||
/// Create a filter composer with an empty state
|
||||
FilterComposer(super.$db, super.$table);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
part of 'manager.dart';
|
||||
|
||||
/// A class that contains the information needed to create a join
|
||||
@internal
|
||||
class JoinBuilder {
|
||||
/// The table that the join is being applied to
|
||||
final Table currentTable;
|
||||
|
||||
/// The referenced table that will be joined
|
||||
final Table referencedTable;
|
||||
|
||||
/// The column of the [currentTable] which will be use to create the join
|
||||
final GeneratedColumn currentColumn;
|
||||
|
||||
/// The column of the [referencedTable] which will be use to create the join
|
||||
final GeneratedColumn referencedColumn;
|
||||
|
||||
/// Class that describes how a ordering that is being
|
||||
/// applied to a referenced table
|
||||
/// should be joined to the current table
|
||||
JoinBuilder(
|
||||
{required this.currentTable,
|
||||
required this.referencedTable,
|
||||
required this.currentColumn,
|
||||
required this.referencedColumn});
|
||||
|
||||
/// The name of the alias that this join will use
|
||||
String get aliasedName {
|
||||
return referencedColumn.tableName;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant JoinBuilder other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.currentColumn == currentColumn &&
|
||||
other.referencedColumn == referencedColumn;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return currentColumn.hashCode ^ referencedColumn.hashCode;
|
||||
}
|
||||
|
||||
/// Build a join from this join builder
|
||||
Join buildJoin() {
|
||||
return leftOuterJoin(
|
||||
referencedTable, currentColumn.equalsExp(referencedColumn),
|
||||
useColumns: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// An interface for classes that hold join builders
|
||||
/// Typically used by classes whose composition requires joins
|
||||
/// to be created
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// categories.filter((f) => f.todos((f) => f.dueDate.isBefore(DateTime.now())))
|
||||
/// ```
|
||||
///
|
||||
/// In the above example, f.todos() returns a [ComposableFilter] object, which
|
||||
/// is a subclass of [HasJoinBuilders].
|
||||
/// This resulting where expression will require a join to be created
|
||||
/// between the `categories` and `todos` table.
|
||||
///
|
||||
/// This interface is used to ensure that the [ComposableFilter] object will have
|
||||
/// the information needed to create the join.
|
||||
@internal
|
||||
abstract interface class HasJoinBuilders {
|
||||
/// The join builders that are associated with this class
|
||||
Set<JoinBuilder> get joinBuilders;
|
||||
|
||||
/// Add a join builder to this class
|
||||
void addJoinBuilders(Set<JoinBuilder> builders) {
|
||||
joinBuilders.addAll(builders);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,579 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
part 'composer.dart';
|
||||
part 'filter.dart';
|
||||
part 'join.dart';
|
||||
part 'ordering.dart';
|
||||
|
||||
sealed class _StatementType<T extends Table, DT extends DataClass> {
|
||||
const _StatementType();
|
||||
}
|
||||
|
||||
class _SimpleResult<T extends Table, DT extends DataClass>
|
||||
extends _StatementType<T, DT> {
|
||||
final SimpleSelectStatement<T, DT> statement;
|
||||
const _SimpleResult(this.statement);
|
||||
}
|
||||
|
||||
class _JoinedResult<T extends Table, DT extends DataClass>
|
||||
extends _StatementType<T, DT> {
|
||||
final JoinedSelectStatement<T, DT> statement;
|
||||
|
||||
const _JoinedResult(this.statement);
|
||||
}
|
||||
|
||||
/// Defines a class that holds the state for a [BaseTableManager]
|
||||
///
|
||||
/// It holds the state for manager of [T] table in [DB] database, used to return [DT] data classes/rows.
|
||||
/// It holds the [FS] Filters and [OS] Orderings for the manager.
|
||||
///
|
||||
/// It also holds the [CI] and [CU] functions that are used to create companion builders for inserting and updating data.
|
||||
/// E.G Instead of `CategoriesCompanion.insert(name: "School")` you would use `(f) => f(name: "School")`
|
||||
///
|
||||
/// The [C] generic refers to the type of the child manager that will be created when a filter/ordering is applied
|
||||
class TableManagerState<
|
||||
DB extends GeneratedDatabase,
|
||||
T extends Table,
|
||||
DT extends DataClass,
|
||||
FS extends FilterComposer<DB, T>,
|
||||
OS extends OrderingComposer<DB, T>,
|
||||
C extends ProcessedTableManager<DB, T, DT, FS, OS, C, CI, CU>,
|
||||
CI extends Function,
|
||||
CU extends Function> {
|
||||
/// The database that the query will be exeCCted on
|
||||
final DB db;
|
||||
|
||||
/// The table that the query will be exeCCted on
|
||||
final T table;
|
||||
|
||||
/// The expression that will be applied to the query
|
||||
final Expression<bool>? filter;
|
||||
|
||||
/// A set of [OrderingBuilder] which will be used to apply
|
||||
/// [OrderingTerm]s to the statement when it's eventually built
|
||||
final Set<OrderingBuilder> orderingBuilders;
|
||||
|
||||
/// A set of [JoinBuilder] which will be used to create [Join]s
|
||||
/// that will be applied to the build statement
|
||||
final Set<JoinBuilder> joinBuilders;
|
||||
|
||||
/// Whether the query should return distinct results
|
||||
final bool? distinct;
|
||||
|
||||
/// If set, the maximum number of rows that will be returned
|
||||
final int? limit;
|
||||
|
||||
/// If set, the number of rows that will be skipped
|
||||
final int? offset;
|
||||
|
||||
/// The [FilterComposer] for this [TableManagerState]
|
||||
/// This class will be used to create filtering [Expression]s
|
||||
/// which will be applied to the statement when its eventually created
|
||||
final FS filteringComposer;
|
||||
|
||||
/// The [OrderingComposer] for this [TableManagerState]
|
||||
/// This class will be used to create [OrderingTerm]s
|
||||
/// which will be applied to the statement when its eventually created
|
||||
final OS orderingComposer;
|
||||
|
||||
/// This function is used internaly to return a new instance of the child manager
|
||||
final C Function(TableManagerState<DB, T, DT, FS, OS, C, CI, CU>)
|
||||
_getChildManagerBuilder;
|
||||
|
||||
/// This function is passed to the user to create a companion
|
||||
/// for inserting data into the table
|
||||
final CI _getInsertCompanionBuilder;
|
||||
|
||||
/// This function is passed to the user to create a companion
|
||||
/// for updating data in the table
|
||||
final CU _getUpdateCompanionBuilder;
|
||||
|
||||
/// Defines a class which holds the state for a table manager
|
||||
/// It contains the database instance, the table instance, and any filters/orderings that will be applied to the query
|
||||
/// This is held in a seperate class than the [BaseTableManager] so that the state can be passed down from the root manager to the lower level managers
|
||||
const TableManagerState({
|
||||
required this.db,
|
||||
required this.table,
|
||||
required this.filteringComposer,
|
||||
required this.orderingComposer,
|
||||
required C Function(TableManagerState<DB, T, DT, FS, OS, C, CI, CU>)
|
||||
getChildManagerBuilder,
|
||||
required CI getInsertCompanionBuilder,
|
||||
required CU getUpdateCompanionBuilder,
|
||||
this.filter,
|
||||
this.distinct,
|
||||
this.limit,
|
||||
this.offset,
|
||||
this.orderingBuilders = const {},
|
||||
this.joinBuilders = const {},
|
||||
}) : _getChildManagerBuilder = getChildManagerBuilder,
|
||||
_getInsertCompanionBuilder = getInsertCompanionBuilder,
|
||||
_getUpdateCompanionBuilder = getUpdateCompanionBuilder;
|
||||
|
||||
/// Copy this state with the given values
|
||||
TableManagerState<DB, T, DT, FS, OS, C, CI, CU> copyWith({
|
||||
bool? distinct,
|
||||
int? limit,
|
||||
int? offset,
|
||||
Expression<bool>? filter,
|
||||
Set<OrderingBuilder>? orderingBuilders,
|
||||
Set<JoinBuilder>? joinBuilders,
|
||||
}) {
|
||||
return TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: filteringComposer,
|
||||
orderingComposer: orderingComposer,
|
||||
getChildManagerBuilder: _getChildManagerBuilder,
|
||||
getInsertCompanionBuilder: _getInsertCompanionBuilder,
|
||||
getUpdateCompanionBuilder: _getUpdateCompanionBuilder,
|
||||
filter: filter ?? this.filter,
|
||||
joinBuilders: joinBuilders ?? this.joinBuilders,
|
||||
orderingBuilders: orderingBuilders ?? this.orderingBuilders,
|
||||
distinct: distinct ?? this.distinct,
|
||||
limit: limit ?? this.limit,
|
||||
offset: offset ?? this.offset,
|
||||
);
|
||||
}
|
||||
|
||||
/// Helper for getting the table that's casted as a TableInfo
|
||||
/// This is needed due to dart's limitations with generics
|
||||
TableInfo<T, DT> get _tableAsTableInfo => table as TableInfo<T, DT>;
|
||||
|
||||
/// Builds a select statement with the given target columns, or all columns if none are provided
|
||||
_StatementType<T, DT> _buildSelectStatement(
|
||||
{Iterable<Expression>? targetColumns}) {
|
||||
final joins = joinBuilders.map((e) => e.buildJoin()).toList();
|
||||
|
||||
// If there are no joins and we are returning all columns, we can use a simple select statement
|
||||
if (joins.isEmpty && targetColumns == null) {
|
||||
final simpleStatement =
|
||||
db.select(_tableAsTableInfo, distinct: distinct ?? false);
|
||||
|
||||
// Apply the expression to the statement
|
||||
if (filter != null) {
|
||||
simpleStatement.where((_) => filter!);
|
||||
}
|
||||
// Apply orderings and limits
|
||||
|
||||
simpleStatement
|
||||
.orderBy(orderingBuilders.map((e) => (_) => e.buildTerm()).toList());
|
||||
if (limit != null) {
|
||||
simpleStatement.limit(limit!, offset: offset);
|
||||
}
|
||||
|
||||
return _SimpleResult(simpleStatement);
|
||||
} else {
|
||||
JoinedSelectStatement<T, DT> joinedStatement;
|
||||
// If we are only selecting specific columns, we can use a selectOnly statement
|
||||
if (targetColumns != null) {
|
||||
joinedStatement =
|
||||
(db.selectOnly(_tableAsTableInfo, distinct: distinct ?? false)
|
||||
..addColumns(targetColumns));
|
||||
// Add the joins to the statement
|
||||
joinedStatement =
|
||||
joinedStatement.join(joins) as JoinedSelectStatement<T, DT>;
|
||||
} else {
|
||||
joinedStatement = db
|
||||
.select(_tableAsTableInfo, distinct: distinct ?? false)
|
||||
.join(joins) as JoinedSelectStatement<T, DT>;
|
||||
}
|
||||
// Apply the expression to the statement
|
||||
if (filter != null) {
|
||||
joinedStatement.where(filter!);
|
||||
}
|
||||
// Apply orderings and limits
|
||||
|
||||
joinedStatement
|
||||
.orderBy(orderingBuilders.map((e) => e.buildTerm()).toList());
|
||||
if (limit != null) {
|
||||
joinedStatement.limit(limit!, offset: offset);
|
||||
}
|
||||
|
||||
return _JoinedResult(joinedStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a select statement based on the manager state
|
||||
Selectable<DT> buildSelectStatement() {
|
||||
final result = _buildSelectStatement();
|
||||
return switch (result) {
|
||||
_SimpleResult() => result.statement,
|
||||
_JoinedResult() =>
|
||||
result.statement.map((p0) => p0.readTable(_tableAsTableInfo))
|
||||
};
|
||||
}
|
||||
|
||||
/// Build an update statement based on the manager state
|
||||
UpdateStatement<T, DT> buildUpdateStatement() {
|
||||
final UpdateStatement<T, DT> updateStatement;
|
||||
if (joinBuilders.isEmpty) {
|
||||
updateStatement = db.update(_tableAsTableInfo);
|
||||
if (filter != null) {
|
||||
updateStatement.where((_) => filter!);
|
||||
}
|
||||
} else {
|
||||
updateStatement = db.update(_tableAsTableInfo);
|
||||
for (var col in _tableAsTableInfo.primaryKey) {
|
||||
final subquery =
|
||||
_buildSelectStatement(targetColumns: [col]) as _JoinedResult<T, DT>;
|
||||
updateStatement.where((tbl) => col.isInQuery(subquery.statement));
|
||||
}
|
||||
}
|
||||
return updateStatement;
|
||||
}
|
||||
|
||||
/// Count the number of rows that would be returned by the built statement
|
||||
Future<int> count() {
|
||||
final count = countAll();
|
||||
final result =
|
||||
_buildSelectStatement(targetColumns: [count]) as _JoinedResult;
|
||||
return result.statement
|
||||
.map((row) => row.read(count)!)
|
||||
.get()
|
||||
.then((value) => value.firstOrNull ?? 0);
|
||||
}
|
||||
|
||||
/// Check if any rows exists using the built statement
|
||||
Future<bool> exists() async {
|
||||
final result = _buildSelectStatement();
|
||||
final BaseSelectStatement statement;
|
||||
switch (result) {
|
||||
case _SimpleResult():
|
||||
statement = result.statement;
|
||||
case _JoinedResult():
|
||||
statement = result.statement;
|
||||
}
|
||||
final query = existsQuery(statement);
|
||||
final existsStatement = db.selectOnly(_tableAsTableInfo)
|
||||
..addColumns([query]);
|
||||
return (await existsStatement
|
||||
.map((p0) => p0.read(query))
|
||||
.get()
|
||||
.then((value) {
|
||||
return value.firstOrNull ?? false;
|
||||
}));
|
||||
}
|
||||
|
||||
/// Build a delete statement based on the manager state
|
||||
DeleteStatement buildDeleteStatement() {
|
||||
final DeleteStatement deleteStatement;
|
||||
if (joinBuilders.isEmpty) {
|
||||
deleteStatement = db.delete(_tableAsTableInfo);
|
||||
if (filter != null) {
|
||||
deleteStatement.where((_) => filter!);
|
||||
}
|
||||
} else {
|
||||
deleteStatement = db.delete(_tableAsTableInfo);
|
||||
for (var col in _tableAsTableInfo.primaryKey) {
|
||||
final subquery =
|
||||
_buildSelectStatement(targetColumns: [col]) as _JoinedResult<T, DT>;
|
||||
deleteStatement.where((tbl) => col.isInQuery(subquery.statement));
|
||||
}
|
||||
}
|
||||
return deleteStatement;
|
||||
}
|
||||
}
|
||||
|
||||
/// Base class for all table managers
|
||||
/// Most of this classes functionality is kept in a seperate [TableManagerState] class
|
||||
/// This is so that the state can be passed down to lower level managers
|
||||
@internal
|
||||
abstract class BaseTableManager<
|
||||
DB extends GeneratedDatabase,
|
||||
T extends Table,
|
||||
DT extends DataClass,
|
||||
FS extends FilterComposer<DB, T>,
|
||||
OS extends OrderingComposer<DB, T>,
|
||||
C extends ProcessedTableManager<DB, T, DT, FS, OS, C, CI, CU>,
|
||||
CI extends Function,
|
||||
CU extends Function>
|
||||
implements
|
||||
MultiSelectable<DT>,
|
||||
SingleSelectable<DT>,
|
||||
SingleOrNullSelectable<DT> {
|
||||
/// The state for this manager
|
||||
final TableManagerState<DB, T, DT, FS, OS, C, CI, CU> $state;
|
||||
|
||||
/// Create a new [BaseTableManager] instance
|
||||
const BaseTableManager(this.$state);
|
||||
|
||||
/// Add a limit to the statement
|
||||
C limit(int limit, {int? offset}) {
|
||||
return $state
|
||||
._getChildManagerBuilder($state.copyWith(limit: limit, offset: offset));
|
||||
}
|
||||
|
||||
/// Add ordering to the statement
|
||||
C orderBy(ComposableOrdering Function(OS o) o) {
|
||||
final orderings = o($state.orderingComposer);
|
||||
return $state._getChildManagerBuilder($state.copyWith(
|
||||
orderingBuilders:
|
||||
$state.orderingBuilders.union(orderings.orderingBuilders),
|
||||
joinBuilders: $state.joinBuilders.union(orderings.joinBuilders)));
|
||||
}
|
||||
|
||||
/// Add a filter to the statement
|
||||
C filter(ComposableFilter Function(FS f) f) {
|
||||
final filter = f($state.filteringComposer);
|
||||
return $state._getChildManagerBuilder($state.copyWith(
|
||||
filter: $state.filter == null
|
||||
? filter.expression
|
||||
: filter.expression & $state.filter!,
|
||||
joinBuilders: $state.joinBuilders.union(filter.joinBuilders)));
|
||||
}
|
||||
|
||||
/// Writes all non-null fields from the entity into the columns of all rows
|
||||
/// that match the [filter] clause. Warning: That also means that, when you're
|
||||
/// not setting a where clause explicitly, this method will update all rows in
|
||||
/// the [$state.table].
|
||||
///
|
||||
/// The fields that are null on the entity object will not be changed by
|
||||
/// this operation, they will be ignored.
|
||||
///
|
||||
/// Returns the amount of rows that have been affected by this operation.
|
||||
///
|
||||
/// See also: [RootTableManager.replace], which does not require [filter] statements and
|
||||
/// supports setting fields back to null.
|
||||
Future<int> update(Insertable<DT> Function(CU o) f) =>
|
||||
$state.buildUpdateStatement().write(f($state._getUpdateCompanionBuilder));
|
||||
|
||||
/// Return the count of rows matched by the built statement
|
||||
/// When counting rows, the query will only count distinct rows by default
|
||||
Future<int> count([bool distinct = true]) {
|
||||
return $state.copyWith(distinct: true).count();
|
||||
}
|
||||
|
||||
/// Checks whether any rows exist
|
||||
Future<bool> exists() => $state.exists();
|
||||
|
||||
/// Deletes all rows matched by built statement
|
||||
///
|
||||
/// Returns the amount of rows that were deleted by this statement directly
|
||||
/// (not including additional rows that might be affected through triggers or
|
||||
/// foreign key constraints).
|
||||
Future<int> delete() => $state.buildDeleteStatement().go();
|
||||
|
||||
/// Executes this statement, like [get], but only returns one
|
||||
/// value. If the query returns no or too many rows, the returned future will
|
||||
/// complete with an error.
|
||||
///
|
||||
/// Be aware that this operation won't put a limit clause on this statement,
|
||||
/// if that's needed you would have to do use [limit]:
|
||||
/// You should only use this method if you know the query won't have more than
|
||||
/// one row, for instance because you used `limit(1)` or you know the filters
|
||||
/// you've applied will only match one row.
|
||||
///
|
||||
/// See also: [getSingleOrNull], which returns `null` instead of
|
||||
/// throwing if the query completes with no rows.
|
||||
///
|
||||
/// Uses the distinct flag to ensure that only distinct rows are returned
|
||||
@override
|
||||
Future<DT> getSingle() =>
|
||||
$state.copyWith(distinct: true).buildSelectStatement().getSingle();
|
||||
|
||||
/// Creates an auto-updating stream of this statement, similar to
|
||||
/// [watch]. However, it is assumed that the query will only emit
|
||||
/// one result, so instead of returning a `Stream<List<D>>`, this returns a
|
||||
/// `Stream<D>`. If, at any point, the query emits no or more than one rows,
|
||||
/// an error will be added to the stream instead.
|
||||
///
|
||||
/// Uses the distinct flag to ensure that only distinct rows are returned
|
||||
@override
|
||||
Stream<DT> watchSingle() =>
|
||||
$state.copyWith(distinct: true).buildSelectStatement().watchSingle();
|
||||
|
||||
/// Executes the statement and returns the first all rows as a list.
|
||||
///
|
||||
/// Use [limit] and [offset] to limit the number of rows returned
|
||||
/// An offset will only be applied if a limit is also set
|
||||
/// Set [distinct] to true to ensure that only distinct rows are returned
|
||||
@override
|
||||
Future<List<DT>> get({bool distinct = false, int? limit, int? offset}) =>
|
||||
$state
|
||||
.copyWith(distinct: distinct, limit: limit, offset: offset)
|
||||
.buildSelectStatement()
|
||||
.get();
|
||||
|
||||
/// Creates an auto-updating stream of the result that emits new items
|
||||
/// whenever any table used in this statement changes.
|
||||
///
|
||||
/// Use [limit] and [offset] to limit the number of rows returned
|
||||
/// An offset will only be applied if a limit is also set
|
||||
/// Set [distinct] to true to ensure that only distinct rows are returned
|
||||
@override
|
||||
Stream<List<DT>> watch({bool distinct = false, int? limit, int? offset}) =>
|
||||
$state
|
||||
.copyWith(distinct: distinct, limit: limit, offset: offset)
|
||||
.buildSelectStatement()
|
||||
.watch();
|
||||
|
||||
/// Executes this statement, like [get], but only returns one
|
||||
/// value. If the result too many values, this method will throw. If no
|
||||
/// row is returned, `null` will be returned instead.
|
||||
///
|
||||
/// See also: [getSingle], which can be used if the query will
|
||||
/// always evaluate to exactly one row.
|
||||
///
|
||||
/// Uses the distinct flag to ensure that only distinct rows are returned
|
||||
@override
|
||||
Future<DT?> getSingleOrNull() =>
|
||||
$state.copyWith(distinct: true).buildSelectStatement().getSingleOrNull();
|
||||
|
||||
/// Creates an auto-updating stream of this statement, similar to
|
||||
/// [watch]. However, it is assumed that the query will only
|
||||
/// emit one result, so instead of returning a `Stream<List<D>>`, this
|
||||
/// returns a `Stream<D?>`. If the query emits more than one row at
|
||||
/// some point, an error will be emitted to the stream instead.
|
||||
/// If the query emits zero rows at some point, `null` will be added
|
||||
/// to the stream instead.
|
||||
///
|
||||
/// Uses the distinct flag to ensure that only distinct rows are returned
|
||||
@override
|
||||
Stream<DT?> watchSingleOrNull() => $state
|
||||
.copyWith(distinct: true)
|
||||
.buildSelectStatement()
|
||||
.watchSingleOrNull();
|
||||
}
|
||||
|
||||
/// A table manager that exposes methods to a table manager that already has filters/orderings/limit applied
|
||||
// As of now this is identical to [BaseTableManager] but it's kept seperate for future extensibility
|
||||
class ProcessedTableManager<
|
||||
DB extends GeneratedDatabase,
|
||||
T extends Table,
|
||||
D extends DataClass,
|
||||
FS extends FilterComposer<DB, T>,
|
||||
OS extends OrderingComposer<DB, T>,
|
||||
C extends ProcessedTableManager<DB, T, D, FS, OS, C, CI, CU>,
|
||||
CI extends Function,
|
||||
CU extends Function>
|
||||
extends BaseTableManager<DB, T, D, FS, OS, C, CI, CU>
|
||||
implements
|
||||
MultiSelectable<D>,
|
||||
SingleSelectable<D>,
|
||||
SingleOrNullSelectable<D> {
|
||||
/// Create a new [ProcessedTableManager] instance
|
||||
const ProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
/// A table manager with top level function for creating, reading, updating, and deleting items
|
||||
abstract class RootTableManager<
|
||||
DB extends GeneratedDatabase,
|
||||
T extends Table,
|
||||
D extends DataClass,
|
||||
FS extends FilterComposer<DB, T>,
|
||||
OS extends OrderingComposer<DB, T>,
|
||||
C extends ProcessedTableManager<DB, T, D, FS, OS, C, CI, CU>,
|
||||
CI extends Function,
|
||||
CU extends Function> extends BaseTableManager<DB, T, D, FS, OS, C, CI, CU> {
|
||||
/// Create a new [RootTableManager] instance
|
||||
const RootTableManager(super.$state);
|
||||
|
||||
/// Creates a new row in the table using the given function
|
||||
///
|
||||
/// By default, an exception will be thrown if another row with the same
|
||||
/// primary key already exists. This behavior can be overridden with [mode],
|
||||
/// for instance by using [InsertMode.replace] or [InsertMode.insertOrIgnore].
|
||||
///
|
||||
/// To apply a partial or custom update in case of a conflict, you can also
|
||||
/// use an [upsert clause](https://sqlite.org/lang_UPSERT.html) by using
|
||||
/// [onConflict]. See [InsertStatement.insert] for more information.
|
||||
///
|
||||
/// By default, the [onConflict] clause will only consider the table's primary
|
||||
/// key. If you have additional columns with uniqueness constraints, you have
|
||||
/// to manually add them to the clause's [DoUpdate.target].
|
||||
///
|
||||
/// Returns the `rowid` of the inserted row. For tables with an auto-increment
|
||||
/// column, the `rowid` is the generated value of that column. The returned
|
||||
/// value can be inaccurate when [onConflict] is set and the insert behaved
|
||||
/// like an update.
|
||||
///
|
||||
/// If the table doesn't have a `rowid`, you can't rely on the return value.
|
||||
/// Still, the future will always complete with an error if the insert fails.
|
||||
Future<int> create(Insertable<D> Function(CI o) f,
|
||||
{InsertMode? mode, UpsertClause<T, D>? onConflict}) {
|
||||
return $state.db.into($state._tableAsTableInfo).insert(
|
||||
f($state._getInsertCompanionBuilder),
|
||||
mode: mode,
|
||||
onConflict: onConflict);
|
||||
}
|
||||
|
||||
/// Inserts a row into the table and returns it.
|
||||
///
|
||||
/// Depending on the [InsertMode] or the [DoUpdate] `onConflict` clause, the
|
||||
/// insert statement may not actually insert a row into the database. Since
|
||||
/// this function was declared to return a non-nullable row, it throws an
|
||||
/// exception in that case. Use [createReturningOrNull] when performing an
|
||||
/// insert with an insert mode like [InsertMode.insertOrIgnore] or when using
|
||||
/// a [DoUpdate] with a `where` clause clause.
|
||||
Future<D> createReturning(Insertable<D> Function(CI o) f,
|
||||
{InsertMode? mode, UpsertClause<T, D>? onConflict}) {
|
||||
return $state.db.into($state._tableAsTableInfo).insertReturning(
|
||||
f($state._getInsertCompanionBuilder),
|
||||
mode: mode,
|
||||
onConflict: onConflict);
|
||||
}
|
||||
|
||||
/// Inserts a row into the table and returns it.
|
||||
///
|
||||
/// When no row was inserted and no exception was thrown, for instance because
|
||||
/// [InsertMode.insertOrIgnore] was used or because the upsert clause had a
|
||||
/// `where` clause that didn't match, `null` is returned instead.
|
||||
Future<D?> createReturningOrNull(Insertable<D> Function(CI o) f,
|
||||
{InsertMode? mode, UpsertClause<T, D>? onConflict}) {
|
||||
return $state.db.into($state._tableAsTableInfo).insertReturningOrNull(
|
||||
f($state._getInsertCompanionBuilder),
|
||||
mode: mode,
|
||||
onConflict: onConflict);
|
||||
}
|
||||
|
||||
/// Create multiple rows in the table using the given function
|
||||
///
|
||||
/// All fields in a row that don't have a default value or auto-increment
|
||||
/// must be set and non-null. Otherwise, an [InvalidDataException] will be
|
||||
/// thrown.
|
||||
/// By default, an exception will be thrown if another row with the same
|
||||
/// primary key already exists. This behavior can be overridden with [mode],
|
||||
/// for instance by using [InsertMode.replace] or [InsertMode.insertOrIgnore].
|
||||
/// Using [bulkCreate] will not disable primary keys or any column constraint
|
||||
/// checks.
|
||||
/// [onConflict] can be used to create an upsert clause for engines that
|
||||
/// support it. For details and examples, see [InsertStatement.insert].
|
||||
Future<void> bulkCreate(Iterable<Insertable<D>> Function(CI o) f,
|
||||
{InsertMode? mode, UpsertClause<T, D>? onConflict}) {
|
||||
return $state.db.batch((b) => b.insertAll(
|
||||
$state._tableAsTableInfo, f($state._getInsertCompanionBuilder),
|
||||
mode: mode, onConflict: onConflict));
|
||||
}
|
||||
|
||||
/// Replaces the old version of [entity] that is stored in the database with
|
||||
/// the fields of the [entity] provided here. This implicitly applies a
|
||||
/// [filter] clause to rows with the same primary key as [entity], so that only
|
||||
/// the row representing outdated data will be replaced.
|
||||
///
|
||||
/// If [entity] has absent values (set to null on the [DataClass] or
|
||||
/// explicitly to absent on the [UpdateCompanion]), and a default value for
|
||||
/// the field exists, that default value will be used. Otherwise, the field
|
||||
/// will be reset to null. This behavior is different to [update], which simply
|
||||
/// ignores such fields without changing them in the database.
|
||||
///
|
||||
/// Returns true if a row was affected by this operation.
|
||||
Future<bool> replace(Insertable<D> entity) {
|
||||
return $state.db.update($state._tableAsTableInfo).replace(entity);
|
||||
}
|
||||
|
||||
/// Replace multiple rows in the table
|
||||
///
|
||||
/// If any of the [entities] has an absent value (set to null on the [DataClass] or
|
||||
/// explicitly to absent on the [UpdateCompanion]), and a default value for
|
||||
/// the field exists, that default value will be used. Otherwise, the field
|
||||
/// will be reset to null. This behavior is different to [update], which simply
|
||||
/// ignores such fields without changing them in the database.
|
||||
Future<void> bulkReplace(Iterable<Insertable<D>> entities) {
|
||||
return $state.db
|
||||
.batch((b) => b.replaceAll($state._tableAsTableInfo, entities));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
part of 'manager.dart';
|
||||
|
||||
/// Defines a class which is used to wrap a column to only expose ordering functions
|
||||
class ColumnOrderings<T extends Object> {
|
||||
/// This class is a wrapper on top of the generated column class
|
||||
///
|
||||
/// It's used to expose ordering functions for a column
|
||||
|
||||
ColumnOrderings(this.column);
|
||||
|
||||
/// Column that this [ColumnOrderings] wraps
|
||||
Expression<T> column;
|
||||
|
||||
/// Sort this column in ascending order
|
||||
///
|
||||
/// 10 -> 1 | Z -> A | Dec 31 -> Jan 1
|
||||
ComposableOrdering asc() =>
|
||||
ComposableOrdering({OrderingBuilder(OrderingMode.asc, column)});
|
||||
|
||||
/// Sort this column in descending order
|
||||
///
|
||||
/// 1 -> 10 | A -> Z | Jan 1 -> Dec 31
|
||||
ComposableOrdering desc() =>
|
||||
ComposableOrdering({OrderingBuilder(OrderingMode.desc, column)});
|
||||
}
|
||||
|
||||
/// Defines a class which will hold the information needed to create an ordering
|
||||
class OrderingBuilder {
|
||||
/// The mode of the ordering
|
||||
final OrderingMode mode;
|
||||
|
||||
/// The column that the ordering is applied to
|
||||
final Expression<Object> column;
|
||||
|
||||
/// Create a new ordering builder, will be used by the [TableManagerState] to create [OrderingTerm]s
|
||||
OrderingBuilder(this.mode, this.column);
|
||||
|
||||
@override
|
||||
bool operator ==(covariant OrderingBuilder other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.mode == mode && other.column == column;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => mode.hashCode ^ column.hashCode;
|
||||
|
||||
/// Build a join from this join builder
|
||||
OrderingTerm buildTerm() {
|
||||
return OrderingTerm(mode: mode, expression: column);
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a class that can be used to compose orderings for a column
|
||||
///
|
||||
/// Multiple orderings can be composed together using the `&` operator.
|
||||
/// The orderings will be executed from left to right.
|
||||
/// See [HasJoinBuilders] for more information
|
||||
/// on how joins are stored
|
||||
class ComposableOrdering extends HasJoinBuilders {
|
||||
/// The orderings that are being composed
|
||||
final Set<OrderingBuilder> orderingBuilders;
|
||||
@override
|
||||
final Set<JoinBuilder> joinBuilders;
|
||||
|
||||
/// Create a new [ComposableOrdering] for a column without any joins
|
||||
ComposableOrdering(this.orderingBuilders) : joinBuilders = {};
|
||||
|
||||
/// Create a new [ComposableOrdering] for a column with joins
|
||||
ComposableOrdering._(this.orderingBuilders, this.joinBuilders);
|
||||
|
||||
/// Combine two orderings with THEN
|
||||
ComposableOrdering operator &(ComposableOrdering other) {
|
||||
return ComposableOrdering._(orderingBuilders.union(other.orderingBuilders),
|
||||
joinBuilders.union(other.joinBuilders));
|
||||
}
|
||||
|
||||
/// Build a drift [OrderingTerm] from this ordering
|
||||
List<OrderingTerm> buildTerms() => orderingBuilders
|
||||
.map((e) => OrderingTerm(mode: e.mode, expression: e.column))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// The class that orchestrates the composition of orderings
|
||||
class OrderingComposer<DB extends GeneratedDatabase, T extends Table>
|
||||
extends Composer<DB, T> {
|
||||
/// Create an ordering composer with an empty state
|
||||
OrderingComposer(super.$db, super.$table);
|
||||
}
|
|
@ -40,3 +40,4 @@ dev_dependencies:
|
|||
shelf: ^1.3.0
|
||||
test_descriptor: ^2.0.1
|
||||
vm_service: ^14.0.0
|
||||
|
||||
|
|
|
@ -1657,6 +1657,7 @@ class MyView extends ViewInfo<MyView, MyViewData> implements HasResultSet {
|
|||
|
||||
abstract class _$CustomTablesDb extends GeneratedDatabase {
|
||||
_$CustomTablesDb(QueryExecutor e) : super(e);
|
||||
_$CustomTablesDbManager get managers => _$CustomTablesDbManager(this);
|
||||
late final NoIds noIds = NoIds(this);
|
||||
late final WithDefaults withDefaults = WithDefaults(this);
|
||||
late final WithConstraints withConstraints = WithConstraints(this);
|
||||
|
@ -1970,6 +1971,524 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
||||
}
|
||||
|
||||
class $WithDefaultsFilterComposer
|
||||
extends FilterComposer<_$CustomTablesDb, WithDefaults> {
|
||||
$WithDefaultsFilterComposer(super.db, super.table);
|
||||
ColumnFilters<String> get a => ColumnFilters($table.a);
|
||||
ColumnFilters<int> get b => ColumnFilters($table.b);
|
||||
}
|
||||
|
||||
class $WithDefaultsOrderingComposer
|
||||
extends OrderingComposer<_$CustomTablesDb, WithDefaults> {
|
||||
$WithDefaultsOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<String> get a => ColumnOrderings($table.a);
|
||||
ColumnOrderings<int> get b => ColumnOrderings($table.b);
|
||||
}
|
||||
|
||||
class $WithDefaultsProcessedTableManager extends ProcessedTableManager<
|
||||
_$CustomTablesDb,
|
||||
WithDefaults,
|
||||
WithDefault,
|
||||
$WithDefaultsFilterComposer,
|
||||
$WithDefaultsOrderingComposer,
|
||||
$WithDefaultsProcessedTableManager,
|
||||
$WithDefaultsInsertCompanionBuilder,
|
||||
$WithDefaultsUpdateCompanionBuilder> {
|
||||
const $WithDefaultsProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $WithDefaultsInsertCompanionBuilder = WithDefaultsCompanion Function({
|
||||
Value<String?> a,
|
||||
Value<int?> b,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $WithDefaultsUpdateCompanionBuilder = WithDefaultsCompanion Function({
|
||||
Value<String?> a,
|
||||
Value<int?> b,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $WithDefaultsTableManager extends RootTableManager<
|
||||
_$CustomTablesDb,
|
||||
WithDefaults,
|
||||
WithDefault,
|
||||
$WithDefaultsFilterComposer,
|
||||
$WithDefaultsOrderingComposer,
|
||||
$WithDefaultsProcessedTableManager,
|
||||
$WithDefaultsInsertCompanionBuilder,
|
||||
$WithDefaultsUpdateCompanionBuilder> {
|
||||
$WithDefaultsTableManager(_$CustomTablesDb db, WithDefaults table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $WithDefaultsFilterComposer(db, table),
|
||||
orderingComposer: $WithDefaultsOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$WithDefaultsProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<String?> a = const Value.absent(),
|
||||
Value<int?> b = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
WithDefaultsCompanion(
|
||||
a: a,
|
||||
b: b,
|
||||
rowid: rowid,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
Value<String?> a = const Value.absent(),
|
||||
Value<int?> b = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
WithDefaultsCompanion.insert(
|
||||
a: a,
|
||||
b: b,
|
||||
rowid: rowid,
|
||||
)));
|
||||
}
|
||||
|
||||
class $WithConstraintsFilterComposer
|
||||
extends FilterComposer<_$CustomTablesDb, WithConstraints> {
|
||||
$WithConstraintsFilterComposer(super.db, super.table);
|
||||
ColumnFilters<String> get a => ColumnFilters($table.a);
|
||||
ColumnFilters<int> get b => ColumnFilters($table.b);
|
||||
ColumnFilters<double> get c => ColumnFilters($table.c);
|
||||
}
|
||||
|
||||
class $WithConstraintsOrderingComposer
|
||||
extends OrderingComposer<_$CustomTablesDb, WithConstraints> {
|
||||
$WithConstraintsOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<String> get a => ColumnOrderings($table.a);
|
||||
ColumnOrderings<int> get b => ColumnOrderings($table.b);
|
||||
ColumnOrderings<double> get c => ColumnOrderings($table.c);
|
||||
}
|
||||
|
||||
class $WithConstraintsProcessedTableManager extends ProcessedTableManager<
|
||||
_$CustomTablesDb,
|
||||
WithConstraints,
|
||||
WithConstraint,
|
||||
$WithConstraintsFilterComposer,
|
||||
$WithConstraintsOrderingComposer,
|
||||
$WithConstraintsProcessedTableManager,
|
||||
$WithConstraintsInsertCompanionBuilder,
|
||||
$WithConstraintsUpdateCompanionBuilder> {
|
||||
const $WithConstraintsProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $WithConstraintsInsertCompanionBuilder = WithConstraintsCompanion
|
||||
Function({
|
||||
Value<String?> a,
|
||||
required int b,
|
||||
Value<double?> c,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $WithConstraintsUpdateCompanionBuilder = WithConstraintsCompanion
|
||||
Function({
|
||||
Value<String?> a,
|
||||
Value<int> b,
|
||||
Value<double?> c,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $WithConstraintsTableManager extends RootTableManager<
|
||||
_$CustomTablesDb,
|
||||
WithConstraints,
|
||||
WithConstraint,
|
||||
$WithConstraintsFilterComposer,
|
||||
$WithConstraintsOrderingComposer,
|
||||
$WithConstraintsProcessedTableManager,
|
||||
$WithConstraintsInsertCompanionBuilder,
|
||||
$WithConstraintsUpdateCompanionBuilder> {
|
||||
$WithConstraintsTableManager(_$CustomTablesDb db, WithConstraints table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $WithConstraintsFilterComposer(db, table),
|
||||
orderingComposer: $WithConstraintsOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$WithConstraintsProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<String?> a = const Value.absent(),
|
||||
Value<int> b = const Value.absent(),
|
||||
Value<double?> c = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
WithConstraintsCompanion(
|
||||
a: a,
|
||||
b: b,
|
||||
c: c,
|
||||
rowid: rowid,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
Value<String?> a = const Value.absent(),
|
||||
required int b,
|
||||
Value<double?> c = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
WithConstraintsCompanion.insert(
|
||||
a: a,
|
||||
b: b,
|
||||
c: c,
|
||||
rowid: rowid,
|
||||
)));
|
||||
}
|
||||
|
||||
class $ConfigTableFilterComposer
|
||||
extends FilterComposer<_$CustomTablesDb, ConfigTable> {
|
||||
$ConfigTableFilterComposer(super.db, super.table);
|
||||
ColumnFilters<String> get configKey => ColumnFilters($table.configKey);
|
||||
ColumnFilters<DriftAny> get configValue => ColumnFilters($table.configValue);
|
||||
ColumnFilters<int> get syncStateValue => ColumnFilters($table.syncState);
|
||||
ColumnWithTypeConverterFilters<SyncType?, SyncType, int> get syncState =>
|
||||
ColumnWithTypeConverterFilters($table.syncState);
|
||||
ColumnFilters<int> get syncStateImplicitValue =>
|
||||
ColumnFilters($table.syncStateImplicit);
|
||||
ColumnWithTypeConverterFilters<SyncType?, SyncType, int>
|
||||
get syncStateImplicit =>
|
||||
ColumnWithTypeConverterFilters($table.syncStateImplicit);
|
||||
}
|
||||
|
||||
class $ConfigTableOrderingComposer
|
||||
extends OrderingComposer<_$CustomTablesDb, ConfigTable> {
|
||||
$ConfigTableOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<String> get configKey => ColumnOrderings($table.configKey);
|
||||
ColumnOrderings<DriftAny> get configValue =>
|
||||
ColumnOrderings($table.configValue);
|
||||
ColumnOrderings<int> get syncState => ColumnOrderings($table.syncState);
|
||||
ColumnOrderings<int> get syncStateImplicit =>
|
||||
ColumnOrderings($table.syncStateImplicit);
|
||||
}
|
||||
|
||||
class $ConfigTableProcessedTableManager extends ProcessedTableManager<
|
||||
_$CustomTablesDb,
|
||||
ConfigTable,
|
||||
Config,
|
||||
$ConfigTableFilterComposer,
|
||||
$ConfigTableOrderingComposer,
|
||||
$ConfigTableProcessedTableManager,
|
||||
$ConfigTableInsertCompanionBuilder,
|
||||
$ConfigTableUpdateCompanionBuilder> {
|
||||
const $ConfigTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $ConfigTableInsertCompanionBuilder = ConfigCompanion Function({
|
||||
required String configKey,
|
||||
Value<DriftAny?> configValue,
|
||||
Value<SyncType?> syncState,
|
||||
Value<SyncType?> syncStateImplicit,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $ConfigTableUpdateCompanionBuilder = ConfigCompanion Function({
|
||||
Value<String> configKey,
|
||||
Value<DriftAny?> configValue,
|
||||
Value<SyncType?> syncState,
|
||||
Value<SyncType?> syncStateImplicit,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $ConfigTableTableManager extends RootTableManager<
|
||||
_$CustomTablesDb,
|
||||
ConfigTable,
|
||||
Config,
|
||||
$ConfigTableFilterComposer,
|
||||
$ConfigTableOrderingComposer,
|
||||
$ConfigTableProcessedTableManager,
|
||||
$ConfigTableInsertCompanionBuilder,
|
||||
$ConfigTableUpdateCompanionBuilder> {
|
||||
$ConfigTableTableManager(_$CustomTablesDb db, ConfigTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $ConfigTableFilterComposer(db, table),
|
||||
orderingComposer: $ConfigTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$ConfigTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<String> configKey = const Value.absent(),
|
||||
Value<DriftAny?> configValue = const Value.absent(),
|
||||
Value<SyncType?> syncState = const Value.absent(),
|
||||
Value<SyncType?> syncStateImplicit = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
ConfigCompanion(
|
||||
configKey: configKey,
|
||||
configValue: configValue,
|
||||
syncState: syncState,
|
||||
syncStateImplicit: syncStateImplicit,
|
||||
rowid: rowid,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
required String configKey,
|
||||
Value<DriftAny?> configValue = const Value.absent(),
|
||||
Value<SyncType?> syncState = const Value.absent(),
|
||||
Value<SyncType?> syncStateImplicit = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
ConfigCompanion.insert(
|
||||
configKey: configKey,
|
||||
configValue: configValue,
|
||||
syncState: syncState,
|
||||
syncStateImplicit: syncStateImplicit,
|
||||
rowid: rowid,
|
||||
)));
|
||||
}
|
||||
|
||||
class $MytableFilterComposer extends FilterComposer<_$CustomTablesDb, Mytable> {
|
||||
$MytableFilterComposer(super.db, super.table);
|
||||
ColumnFilters<int> get someid => ColumnFilters($table.someid);
|
||||
ColumnFilters<String> get sometext => ColumnFilters($table.sometext);
|
||||
ColumnFilters<bool> get isInserting => ColumnFilters($table.isInserting);
|
||||
ColumnFilters<DateTime> get somedate => ColumnFilters($table.somedate);
|
||||
}
|
||||
|
||||
class $MytableOrderingComposer
|
||||
extends OrderingComposer<_$CustomTablesDb, Mytable> {
|
||||
$MytableOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<int> get someid => ColumnOrderings($table.someid);
|
||||
ColumnOrderings<String> get sometext => ColumnOrderings($table.sometext);
|
||||
ColumnOrderings<bool> get isInserting => ColumnOrderings($table.isInserting);
|
||||
ColumnOrderings<DateTime> get somedate => ColumnOrderings($table.somedate);
|
||||
}
|
||||
|
||||
class $MytableProcessedTableManager extends ProcessedTableManager<
|
||||
_$CustomTablesDb,
|
||||
Mytable,
|
||||
MytableData,
|
||||
$MytableFilterComposer,
|
||||
$MytableOrderingComposer,
|
||||
$MytableProcessedTableManager,
|
||||
$MytableInsertCompanionBuilder,
|
||||
$MytableUpdateCompanionBuilder> {
|
||||
const $MytableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $MytableInsertCompanionBuilder = MytableCompanion Function({
|
||||
Value<int> someid,
|
||||
Value<String?> sometext,
|
||||
Value<bool?> isInserting,
|
||||
Value<DateTime?> somedate,
|
||||
});
|
||||
typedef $MytableUpdateCompanionBuilder = MytableCompanion Function({
|
||||
Value<int> someid,
|
||||
Value<String?> sometext,
|
||||
Value<bool?> isInserting,
|
||||
Value<DateTime?> somedate,
|
||||
});
|
||||
|
||||
class $MytableTableManager extends RootTableManager<
|
||||
_$CustomTablesDb,
|
||||
Mytable,
|
||||
MytableData,
|
||||
$MytableFilterComposer,
|
||||
$MytableOrderingComposer,
|
||||
$MytableProcessedTableManager,
|
||||
$MytableInsertCompanionBuilder,
|
||||
$MytableUpdateCompanionBuilder> {
|
||||
$MytableTableManager(_$CustomTablesDb db, Mytable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $MytableFilterComposer(db, table),
|
||||
orderingComposer: $MytableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) => $MytableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<int> someid = const Value.absent(),
|
||||
Value<String?> sometext = const Value.absent(),
|
||||
Value<bool?> isInserting = const Value.absent(),
|
||||
Value<DateTime?> somedate = const Value.absent(),
|
||||
}) =>
|
||||
MytableCompanion(
|
||||
someid: someid,
|
||||
sometext: sometext,
|
||||
isInserting: isInserting,
|
||||
somedate: somedate,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
Value<int> someid = const Value.absent(),
|
||||
Value<String?> sometext = const Value.absent(),
|
||||
Value<bool?> isInserting = const Value.absent(),
|
||||
Value<DateTime?> somedate = const Value.absent(),
|
||||
}) =>
|
||||
MytableCompanion.insert(
|
||||
someid: someid,
|
||||
sometext: sometext,
|
||||
isInserting: isInserting,
|
||||
somedate: somedate,
|
||||
)));
|
||||
}
|
||||
|
||||
class $EmailFilterComposer extends FilterComposer<_$CustomTablesDb, Email> {
|
||||
$EmailFilterComposer(super.db, super.table);
|
||||
ColumnFilters<String> get sender => ColumnFilters($table.sender);
|
||||
ColumnFilters<String> get title => ColumnFilters($table.title);
|
||||
ColumnFilters<String> get body => ColumnFilters($table.body);
|
||||
}
|
||||
|
||||
class $EmailOrderingComposer extends OrderingComposer<_$CustomTablesDb, Email> {
|
||||
$EmailOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<String> get sender => ColumnOrderings($table.sender);
|
||||
ColumnOrderings<String> get title => ColumnOrderings($table.title);
|
||||
ColumnOrderings<String> get body => ColumnOrderings($table.body);
|
||||
}
|
||||
|
||||
class $EmailProcessedTableManager extends ProcessedTableManager<
|
||||
_$CustomTablesDb,
|
||||
Email,
|
||||
EMail,
|
||||
$EmailFilterComposer,
|
||||
$EmailOrderingComposer,
|
||||
$EmailProcessedTableManager,
|
||||
$EmailInsertCompanionBuilder,
|
||||
$EmailUpdateCompanionBuilder> {
|
||||
const $EmailProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $EmailInsertCompanionBuilder = EmailCompanion Function({
|
||||
required String sender,
|
||||
required String title,
|
||||
required String body,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $EmailUpdateCompanionBuilder = EmailCompanion Function({
|
||||
Value<String> sender,
|
||||
Value<String> title,
|
||||
Value<String> body,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $EmailTableManager extends RootTableManager<
|
||||
_$CustomTablesDb,
|
||||
Email,
|
||||
EMail,
|
||||
$EmailFilterComposer,
|
||||
$EmailOrderingComposer,
|
||||
$EmailProcessedTableManager,
|
||||
$EmailInsertCompanionBuilder,
|
||||
$EmailUpdateCompanionBuilder> {
|
||||
$EmailTableManager(_$CustomTablesDb db, Email table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $EmailFilterComposer(db, table),
|
||||
orderingComposer: $EmailOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) => $EmailProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<String> sender = const Value.absent(),
|
||||
Value<String> title = const Value.absent(),
|
||||
Value<String> body = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
EmailCompanion(
|
||||
sender: sender,
|
||||
title: title,
|
||||
body: body,
|
||||
rowid: rowid,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
required String sender,
|
||||
required String title,
|
||||
required String body,
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
EmailCompanion.insert(
|
||||
sender: sender,
|
||||
title: title,
|
||||
body: body,
|
||||
rowid: rowid,
|
||||
)));
|
||||
}
|
||||
|
||||
class $WeirdTableFilterComposer
|
||||
extends FilterComposer<_$CustomTablesDb, WeirdTable> {
|
||||
$WeirdTableFilterComposer(super.db, super.table);
|
||||
ColumnFilters<int> get sqlClass => ColumnFilters($table.sqlClass);
|
||||
ColumnFilters<String> get textColumn => ColumnFilters($table.textColumn);
|
||||
}
|
||||
|
||||
class $WeirdTableOrderingComposer
|
||||
extends OrderingComposer<_$CustomTablesDb, WeirdTable> {
|
||||
$WeirdTableOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<int> get sqlClass => ColumnOrderings($table.sqlClass);
|
||||
ColumnOrderings<String> get textColumn => ColumnOrderings($table.textColumn);
|
||||
}
|
||||
|
||||
class $WeirdTableProcessedTableManager extends ProcessedTableManager<
|
||||
_$CustomTablesDb,
|
||||
WeirdTable,
|
||||
WeirdData,
|
||||
$WeirdTableFilterComposer,
|
||||
$WeirdTableOrderingComposer,
|
||||
$WeirdTableProcessedTableManager,
|
||||
$WeirdTableInsertCompanionBuilder,
|
||||
$WeirdTableUpdateCompanionBuilder> {
|
||||
const $WeirdTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $WeirdTableInsertCompanionBuilder = WeirdTableCompanion Function({
|
||||
required int sqlClass,
|
||||
required String textColumn,
|
||||
Value<int> rowid,
|
||||
});
|
||||
typedef $WeirdTableUpdateCompanionBuilder = WeirdTableCompanion Function({
|
||||
Value<int> sqlClass,
|
||||
Value<String> textColumn,
|
||||
Value<int> rowid,
|
||||
});
|
||||
|
||||
class $WeirdTableTableManager extends RootTableManager<
|
||||
_$CustomTablesDb,
|
||||
WeirdTable,
|
||||
WeirdData,
|
||||
$WeirdTableFilterComposer,
|
||||
$WeirdTableOrderingComposer,
|
||||
$WeirdTableProcessedTableManager,
|
||||
$WeirdTableInsertCompanionBuilder,
|
||||
$WeirdTableUpdateCompanionBuilder> {
|
||||
$WeirdTableTableManager(_$CustomTablesDb db, WeirdTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $WeirdTableFilterComposer(db, table),
|
||||
orderingComposer: $WeirdTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$WeirdTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<int> sqlClass = const Value.absent(),
|
||||
Value<String> textColumn = const Value.absent(),
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
WeirdTableCompanion(
|
||||
sqlClass: sqlClass,
|
||||
textColumn: textColumn,
|
||||
rowid: rowid,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
required int sqlClass,
|
||||
required String textColumn,
|
||||
Value<int> rowid = const Value.absent(),
|
||||
}) =>
|
||||
WeirdTableCompanion.insert(
|
||||
sqlClass: sqlClass,
|
||||
textColumn: textColumn,
|
||||
rowid: rowid,
|
||||
)));
|
||||
}
|
||||
|
||||
class _$CustomTablesDbManager {
|
||||
final _$CustomTablesDb _db;
|
||||
_$CustomTablesDbManager(this._db);
|
||||
$WithDefaultsTableManager get withDefaults =>
|
||||
$WithDefaultsTableManager(_db, _db.withDefaults);
|
||||
$WithConstraintsTableManager get withConstraints =>
|
||||
$WithConstraintsTableManager(_db, _db.withConstraints);
|
||||
$ConfigTableTableManager get config =>
|
||||
$ConfigTableTableManager(_db, _db.config);
|
||||
$MytableTableManager get mytable => $MytableTableManager(_db, _db.mytable);
|
||||
$EmailTableManager get email => $EmailTableManager(_db, _db.email);
|
||||
$WeirdTableTableManager get weirdTable =>
|
||||
$WeirdTableTableManager(_db, _db.weirdTable);
|
||||
}
|
||||
|
||||
typedef ReadMultiple$clause = OrderBy Function(ConfigTable config);
|
||||
typedef ReadDynamic$predicate = Expression<bool> Function(ConfigTable config);
|
||||
typedef TypeConverterVar$pred = Expression<bool> Function(ConfigTable config);
|
||||
|
|
|
@ -23,7 +23,7 @@ class TodosTable extends Table with AutoIncrement {
|
|||
TextColumn get content => text()();
|
||||
@JsonKey('target_date')
|
||||
DateTimeColumn get targetDate => dateTime().nullable().unique()();
|
||||
|
||||
@ReferenceName("todos")
|
||||
IntColumn get category => integer().references(Categories, #id).nullable()();
|
||||
|
||||
TextColumn get status => textEnum<TodoStatus>().nullable()();
|
||||
|
@ -87,6 +87,22 @@ class TableWithoutPK extends Table {
|
|||
text().map(const CustomConverter()).clientDefault(_uuid.v4)();
|
||||
}
|
||||
|
||||
class TableWithEveryColumnType extends Table with AutoIncrement {
|
||||
BoolColumn get aBool => boolean().nullable()();
|
||||
DateTimeColumn get aDateTime => dateTime().nullable()();
|
||||
TextColumn get aText => text().nullable()();
|
||||
IntColumn get anInt => integer().nullable()();
|
||||
Int64Column get anInt64 => int64().nullable()();
|
||||
RealColumn get aReal => real().nullable()();
|
||||
BlobColumn get aBlob => blob().nullable()();
|
||||
IntColumn get anIntEnum => intEnum<TodoStatus>().nullable()();
|
||||
TextColumn get aTextWithConverter => text()
|
||||
.named('insert')
|
||||
.map(const CustomJsonConverter())
|
||||
.nullable()
|
||||
.nullable()();
|
||||
}
|
||||
|
||||
class CustomRowClass {
|
||||
final int notReallyAnId;
|
||||
final double anotherName;
|
||||
|
@ -248,6 +264,7 @@ const uuidType = DialectAwareSqlType<UuidValue>.via(
|
|||
TableWithoutPK,
|
||||
PureDefaults,
|
||||
WithCustomType,
|
||||
TableWithEveryColumnType
|
||||
],
|
||||
views: [
|
||||
CategoryTodoCountView,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -184,6 +184,7 @@ class _SomeTableCompanion extends UpdateCompanion<_SomeTableData> {
|
|||
|
||||
abstract class _$_SomeDb extends GeneratedDatabase {
|
||||
_$_SomeDb(QueryExecutor e) : super(e);
|
||||
_$_SomeDbManager get managers => _$_SomeDbManager(this);
|
||||
late final $_SomeTableTable someTable = $_SomeTableTable(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
|
@ -191,3 +192,80 @@ abstract class _$_SomeDb extends GeneratedDatabase {
|
|||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [someTable];
|
||||
}
|
||||
|
||||
class $$_SomeTableTableFilterComposer
|
||||
extends FilterComposer<_$_SomeDb, $_SomeTableTable> {
|
||||
$$_SomeTableTableFilterComposer(super.db, super.table);
|
||||
ColumnFilters<int> get id => ColumnFilters($table.id);
|
||||
ColumnFilters<String> get name => ColumnFilters($table.name);
|
||||
}
|
||||
|
||||
class $$_SomeTableTableOrderingComposer
|
||||
extends OrderingComposer<_$_SomeDb, $_SomeTableTable> {
|
||||
$$_SomeTableTableOrderingComposer(super.db, super.table);
|
||||
ColumnOrderings<int> get id => ColumnOrderings($table.id);
|
||||
ColumnOrderings<String> get name => ColumnOrderings($table.name);
|
||||
}
|
||||
|
||||
class $$_SomeTableTableProcessedTableManager extends ProcessedTableManager<
|
||||
_$_SomeDb,
|
||||
$_SomeTableTable,
|
||||
_SomeTableData,
|
||||
$$_SomeTableTableFilterComposer,
|
||||
$$_SomeTableTableOrderingComposer,
|
||||
$$_SomeTableTableProcessedTableManager,
|
||||
$$_SomeTableTableInsertCompanionBuilder,
|
||||
$$_SomeTableTableUpdateCompanionBuilder> {
|
||||
const $$_SomeTableTableProcessedTableManager(super.$state);
|
||||
}
|
||||
|
||||
typedef $$_SomeTableTableInsertCompanionBuilder = _SomeTableCompanion Function({
|
||||
Value<int> id,
|
||||
Value<String?> name,
|
||||
});
|
||||
typedef $$_SomeTableTableUpdateCompanionBuilder = _SomeTableCompanion Function({
|
||||
Value<int> id,
|
||||
Value<String?> name,
|
||||
});
|
||||
|
||||
class $$_SomeTableTableTableManager extends RootTableManager<
|
||||
_$_SomeDb,
|
||||
$_SomeTableTable,
|
||||
_SomeTableData,
|
||||
$$_SomeTableTableFilterComposer,
|
||||
$$_SomeTableTableOrderingComposer,
|
||||
$$_SomeTableTableProcessedTableManager,
|
||||
$$_SomeTableTableInsertCompanionBuilder,
|
||||
$$_SomeTableTableUpdateCompanionBuilder> {
|
||||
$$_SomeTableTableTableManager(_$_SomeDb db, $_SomeTableTable table)
|
||||
: super(TableManagerState(
|
||||
db: db,
|
||||
table: table,
|
||||
filteringComposer: $$_SomeTableTableFilterComposer(db, table),
|
||||
orderingComposer: $$_SomeTableTableOrderingComposer(db, table),
|
||||
getChildManagerBuilder: (p0) =>
|
||||
$$_SomeTableTableProcessedTableManager(p0),
|
||||
getUpdateCompanionBuilder: ({
|
||||
Value<int> id = const Value.absent(),
|
||||
Value<String?> name = const Value.absent(),
|
||||
}) =>
|
||||
_SomeTableCompanion(
|
||||
id: id,
|
||||
name: name,
|
||||
),
|
||||
getInsertCompanionBuilder: ({
|
||||
Value<int> id = const Value.absent(),
|
||||
Value<String?> name = const Value.absent(),
|
||||
}) =>
|
||||
_SomeTableCompanion.insert(
|
||||
id: id,
|
||||
name: name,
|
||||
)));
|
||||
}
|
||||
|
||||
class _$_SomeDbManager {
|
||||
final _$_SomeDb _db;
|
||||
_$_SomeDbManager(this._db);
|
||||
$$_SomeTableTableTableManager get someTable =>
|
||||
$$_SomeTableTableTableManager(_db, _db.someTable);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,540 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../generated/todos.dart';
|
||||
import '../test_utils/test_utils.dart';
|
||||
|
||||
void main() {
|
||||
late TodoDb db;
|
||||
|
||||
setUp(() {
|
||||
db = TodoDb(testInMemoryDatabase());
|
||||
});
|
||||
|
||||
tearDown(() => db.close());
|
||||
|
||||
test('manager - query generic', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(5.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 1)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(3.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 3)))));
|
||||
|
||||
// Equals
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.equals(5.0))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal(3.0))
|
||||
.count(),
|
||||
completion(1));
|
||||
|
||||
// Not Equals - Exclude null (Default behavior)
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.not.equals(5.0))
|
||||
.count(),
|
||||
completion(1));
|
||||
|
||||
// In
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isIn([3.0, 5.0]))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Not In
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.not.isIn([3.0, 5.0]))
|
||||
.count(),
|
||||
completion(0));
|
||||
|
||||
// Null check
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isNull())
|
||||
.count(),
|
||||
completion(1));
|
||||
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.not.isNull())
|
||||
.count(),
|
||||
completion(2));
|
||||
});
|
||||
|
||||
test('manager - query number', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(5.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 1)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(3.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 3)))));
|
||||
|
||||
// More than
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isBiggerThan(3.0))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isBiggerOrEqualTo(3.0))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Less than
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isSmallerThan(5.0))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isSmallerOrEqualTo(5.0))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Between
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.isBetween(3.0, 5.0))
|
||||
.count(),
|
||||
completion(2));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aReal.not.isBetween(3.0, 5.0))
|
||||
.count(),
|
||||
completion(0));
|
||||
});
|
||||
|
||||
test('manager - query string', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("That homework Done"),
|
||||
));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("that MATH homework"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
));
|
||||
|
||||
// StartsWith
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aText.startsWith("that"))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// EndsWith
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aText.endsWith("done"))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Contains
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aText.contains("math"))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Make the database case sensitive
|
||||
await db.customStatement('PRAGMA case_sensitive_like = ON');
|
||||
|
||||
// StartsWith
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aText.startsWith("that", caseInsensitive: false))
|
||||
.count(),
|
||||
completion(1));
|
||||
|
||||
// EndsWith
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aText.endsWith("done", caseInsensitive: false))
|
||||
.count(),
|
||||
completion(1));
|
||||
|
||||
// Contains
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aText.contains("math", caseInsensitive: false))
|
||||
.count(),
|
||||
completion(1));
|
||||
});
|
||||
|
||||
test('manager - query int64', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
anInt64: Value(BigInt.from(5.0)),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 1)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
anInt64: Value(BigInt.from(3.0)),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 3)))));
|
||||
|
||||
// More than
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anInt64.isBiggerThan(BigInt.from(3.0)))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anInt64.isBiggerOrEqualTo(BigInt.from(3.0)))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Less than
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anInt64.isSmallerThan(BigInt.from(5.0)))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anInt64.isSmallerOrEqualTo(BigInt.from(5.0)))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Between
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter(
|
||||
(f) => f.anInt64.isBetween(BigInt.from(3.0), BigInt.from(5.0)))
|
||||
.count(),
|
||||
completion(2));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) =>
|
||||
f.anInt64.not.isBetween(BigInt.from(3.0), BigInt.from(5.0)))
|
||||
.count(),
|
||||
completion(0));
|
||||
});
|
||||
|
||||
test('manager - query bool', () async {
|
||||
await db.managers.users.create((o) => o(
|
||||
name: "John Doe",
|
||||
profilePicture: Uint8List(0),
|
||||
isAwesome: Value(true),
|
||||
creationTime: Value(DateTime.now().add(Duration(days: 1)))));
|
||||
await db.managers.users.create((o) => o(
|
||||
name: "Jane Doe1",
|
||||
profilePicture: Uint8List(0),
|
||||
isAwesome: Value(false),
|
||||
creationTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
await db.managers.users.create((o) => o(
|
||||
name: "Jane Doe2",
|
||||
profilePicture: Uint8List(0),
|
||||
isAwesome: Value(true),
|
||||
creationTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
|
||||
// False
|
||||
expect(db.managers.users.filter((f) => f.isAwesome.isFalse()).count(),
|
||||
completion(1));
|
||||
// True
|
||||
expect(db.managers.users.filter((f) => f.isAwesome.isTrue()).count(),
|
||||
completion(2));
|
||||
});
|
||||
|
||||
test('manager - query datetime', () async {
|
||||
final day1 = DateTime.now().add(Duration(days: 1));
|
||||
final day2 = DateTime.now().add(Duration(days: 2));
|
||||
final day3 = DateTime.now().add(Duration(days: 3));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(5.0),
|
||||
aDateTime: Value(day1)));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aDateTime: Value(day2)));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(3.0),
|
||||
aDateTime: Value(day3)));
|
||||
|
||||
// More than
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aDateTime.isAfter(day2))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aDateTime.isAfterOrOn(day2))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Less than
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aDateTime.isBefore(day2))
|
||||
.count(),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aDateTime.isBeforeOrOn(day2))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Between
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aDateTime.isBetween(day1, day2))
|
||||
.count(),
|
||||
completion(2));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.aDateTime.not.isBetween(day1, day2))
|
||||
.count(),
|
||||
completion(1));
|
||||
});
|
||||
|
||||
test('manager - query custom column', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open)));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open)));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.workInProgress)));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.done)));
|
||||
await db.managers.tableWithEveryColumnType
|
||||
.create((o) => o(aText: Value("Get that math homework done")));
|
||||
|
||||
// Equals
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anIntEnum.equals(TodoStatus.open))
|
||||
.count(),
|
||||
completion(2));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anIntEnum(TodoStatus.open))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.anIntEnum.not(TodoStatus.open))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// // Not Equals
|
||||
// expect(
|
||||
// db.managers.tableWithEveryColumnType
|
||||
// .filter((f) => f.anIntEnum.not.equals(TodoStatus.open))
|
||||
// .count(),
|
||||
// completion(2));
|
||||
|
||||
// // In
|
||||
// expect(
|
||||
// db.managers.tableWithEveryColumnType
|
||||
// .filter((f) =>
|
||||
// f.anIntEnum.isIn([TodoStatus.open, TodoStatus.workInProgress]))
|
||||
// .count(),
|
||||
// completion(3));
|
||||
|
||||
// // Not In
|
||||
// expect(
|
||||
// db.managers.tableWithEveryColumnType
|
||||
// .filter((f) => f.anIntEnum.not
|
||||
// .isIn([TodoStatus.open, TodoStatus.workInProgress]))
|
||||
// .count(),
|
||||
// completion(1));
|
||||
});
|
||||
|
||||
test('manager - filter related', () async {
|
||||
final schoolCategoryId = await db.managers.categories.create((o) =>
|
||||
o(priority: Value(CategoryPriority.high), description: "School"));
|
||||
final workCategoryId = await db.managers.categories.create(
|
||||
(o) => o(priority: Value(CategoryPriority.low), description: "Work"));
|
||||
|
||||
// School
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Get that math homework done",
|
||||
title: Value("Math Homework"),
|
||||
category: Value(schoolCategoryId),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 10)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Finish that report",
|
||||
title: Value("Report"),
|
||||
category: Value(schoolCategoryId),
|
||||
status: Value(TodoStatus.workInProgress),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 2, seconds: 10)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Get that english homework done",
|
||||
title: Value("English Homework"),
|
||||
category: Value(schoolCategoryId),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 15)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Finish that Book report",
|
||||
title: Value("Book Report"),
|
||||
category: Value(schoolCategoryId),
|
||||
status: Value(TodoStatus.done),
|
||||
targetDate:
|
||||
Value(DateTime.now().subtract(Duration(days: 2, seconds: 15)))));
|
||||
|
||||
// Work
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "File those reports",
|
||||
title: Value("File Reports"),
|
||||
category: Value(workCategoryId),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 20)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Clean the office",
|
||||
title: Value("Clean Office"),
|
||||
category: Value(workCategoryId),
|
||||
status: Value(TodoStatus.workInProgress),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 2, seconds: 20)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Nail that presentation",
|
||||
title: Value("Presentation"),
|
||||
category: Value(workCategoryId),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 25)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Take a break",
|
||||
title: Value("Break"),
|
||||
category: Value(workCategoryId),
|
||||
status: Value(TodoStatus.done),
|
||||
targetDate:
|
||||
Value(DateTime.now().subtract(Duration(days: 2, seconds: 25)))));
|
||||
|
||||
// Items with no category
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Get Whiteboard",
|
||||
title: Value("Whiteboard"),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 50)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
content: "Drink Water",
|
||||
title: Value("Water"),
|
||||
status: Value(TodoStatus.workInProgress),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 2, seconds: 50)))));
|
||||
|
||||
// item without title
|
||||
|
||||
// Equals
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.filter((f) => f.category(
|
||||
(f) => f.id(RowId(schoolCategoryId)),
|
||||
))
|
||||
.count(),
|
||||
completion(4));
|
||||
|
||||
// Not Equals
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.filter(
|
||||
(f) =>
|
||||
f.category((f) => f.id.not.equals(RowId(schoolCategoryId))),
|
||||
)
|
||||
.count(),
|
||||
completion(4));
|
||||
|
||||
// Multiple filters
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.filter((f) => f.category(
|
||||
(f) => f.id(RowId(schoolCategoryId)),
|
||||
))
|
||||
.filter((f) => f.status.equals(TodoStatus.open))
|
||||
.count(),
|
||||
completion(2));
|
||||
|
||||
// Multiple 2 related filters
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.filter((f) => f.category(
|
||||
(f) =>
|
||||
f.priority.equals(CategoryPriority.low) |
|
||||
f.descriptionInUpperCase.equals("SCHOOL"),
|
||||
))
|
||||
.count(),
|
||||
completion(8));
|
||||
|
||||
// Multiple use related filters twice
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.filter((f) =>
|
||||
f.category(
|
||||
(f) => f.priority.equals(CategoryPriority.low),
|
||||
) |
|
||||
f.category(
|
||||
(f) => f.descriptionInUpperCase.equals("SCHOOL"),
|
||||
))
|
||||
.count(),
|
||||
completion(8));
|
||||
// Use .filter multiple times
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.filter((f) => f.category(
|
||||
(f) => f.priority.equals(CategoryPriority.high),
|
||||
))
|
||||
.filter((f) => f.category(
|
||||
(f) => f.descriptionInUpperCase.equals("SCHOOL"),
|
||||
))
|
||||
.count(),
|
||||
completion(4));
|
||||
|
||||
// Use backreference
|
||||
expect(
|
||||
db.managers.categories
|
||||
.filter((f) => f.todos((f) => f.title.equals("Math Homework")))
|
||||
.getSingle()
|
||||
.then((value) => value.description),
|
||||
completion("School"));
|
||||
|
||||
// Nested backreference
|
||||
expect(
|
||||
db.managers.categories
|
||||
.filter((f) => f.todos((f) => f.category(
|
||||
(f) => f.todos((f) => f.title.equals("Math Homework")))))
|
||||
.getSingle()
|
||||
.then((value) => value.description),
|
||||
completion("School"));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../generated/todos.dart';
|
||||
import '../test_utils/test_utils.dart';
|
||||
|
||||
void main() {
|
||||
late TodoDb db;
|
||||
|
||||
setUp(() {
|
||||
db = TodoDb(testInMemoryDatabase());
|
||||
});
|
||||
|
||||
tearDown(() => db.close());
|
||||
|
||||
test('manager - order', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
id: Value(RowId(1)),
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(5.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 1)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(3.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 3)))));
|
||||
|
||||
// Equals
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.orderBy((o) => o.aDateTime.desc())
|
||||
.get()
|
||||
.then((value) => value[0].id),
|
||||
completion(3));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.orderBy((o) => o.aDateTime.asc())
|
||||
.get()
|
||||
.then((value) => value[0].id),
|
||||
completion(1));
|
||||
});
|
||||
|
||||
test('manager - order related', () async {
|
||||
final schoolCategoryId = await db.managers.categories.create((o) =>
|
||||
o(priority: Value(CategoryPriority.high), description: "School"));
|
||||
final workCategoryId = await db.managers.categories.create(
|
||||
(o) => o(priority: Value(CategoryPriority.low), description: "Work"));
|
||||
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
id: Value(RowId(1)),
|
||||
content: "Get that english homework done",
|
||||
title: Value("English Homework"),
|
||||
category: Value(workCategoryId),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 15)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
id: Value(RowId(2)),
|
||||
content: "Finish that Book report",
|
||||
title: Value("Book Report"),
|
||||
category: Value(workCategoryId),
|
||||
status: Value(TodoStatus.done),
|
||||
targetDate:
|
||||
Value(DateTime.now().subtract(Duration(days: 2, seconds: 15)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
id: Value(RowId(3)),
|
||||
content: "Get that math homework done",
|
||||
title: Value("Math Homework"),
|
||||
category: Value(schoolCategoryId),
|
||||
status: Value(TodoStatus.open),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 1, seconds: 10)))));
|
||||
await db.managers.todosTable.create((o) => o(
|
||||
id: Value(RowId(4)),
|
||||
content: "Finish that report",
|
||||
title: Value("Report"),
|
||||
category: Value(schoolCategoryId),
|
||||
status: Value(TodoStatus.workInProgress),
|
||||
targetDate: Value(DateTime.now().add(Duration(days: 2, seconds: 10)))));
|
||||
// Order by related
|
||||
expect(
|
||||
db.managers.todosTable
|
||||
.orderBy((o) => o.category((o) => o.id.asc()))
|
||||
.get()
|
||||
.then((value) => value.map((e) => e.id).toList()),
|
||||
completion([3, 4, 1, 2]));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../generated/todos.dart';
|
||||
import '../test_utils/test_utils.dart';
|
||||
|
||||
void main() {
|
||||
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
|
||||
late TodoDb db;
|
||||
|
||||
setUp(() {
|
||||
db = TodoDb(testInMemoryDatabase());
|
||||
});
|
||||
|
||||
tearDown(() => db.close());
|
||||
|
||||
test('manager - create', () async {
|
||||
// Initial count should be 0
|
||||
expect(db.managers.categories.count(), completion(0));
|
||||
|
||||
// Creating a row should return the id
|
||||
final create1 = db.managers.categories.create(
|
||||
(o) => o(priority: Value(CategoryPriority.high), description: "High"));
|
||||
expect(create1, completion(1));
|
||||
expect(db.managers.categories.count(), completion(1));
|
||||
|
||||
// Creating another row should increment the id
|
||||
final create2 = db.managers.categories.create(
|
||||
(o) => o(priority: Value(CategoryPriority.low), description: "Low"));
|
||||
expect(create2, completion(2));
|
||||
expect(db.managers.categories.count(), completion(2));
|
||||
|
||||
// Using an existing id should throw an exception
|
||||
final create3 = db.managers.categories.create((o) => o(
|
||||
priority: Value(CategoryPriority.medium),
|
||||
description: "Medium",
|
||||
id: Value(RowId(1))));
|
||||
expect(create3, throwsException);
|
||||
|
||||
// Using on conflict should not throw an exception
|
||||
// Only using DoNothing test that onConflict is being passed to the create method
|
||||
final create4 = db.managers.categories.create(
|
||||
(o) => o(
|
||||
priority: Value(CategoryPriority.medium),
|
||||
description: "Medium",
|
||||
id: Value(RowId(1))),
|
||||
onConflict: DoNothing());
|
||||
// The is incorrect when using onConflict
|
||||
expect(create4, completion(2));
|
||||
expect(db.managers.categories.count(), completion(2));
|
||||
|
||||
// Likewise, test that mode is passed to the create method
|
||||
final create5 = db.managers.categories.create(
|
||||
(o) => o(
|
||||
priority: Value(CategoryPriority.medium),
|
||||
description: "Medium",
|
||||
id: Value(RowId(1))),
|
||||
mode: InsertMode.insertOrIgnore);
|
||||
|
||||
// The is incorrect when using mode
|
||||
expect(create5, completion(2));
|
||||
expect(db.managers.categories.count(), completion(2));
|
||||
|
||||
// Test the other create methods
|
||||
final create6 = db.managers.categories.createReturning((o) =>
|
||||
o(priority: Value(CategoryPriority.high), description: "Other High"));
|
||||
expect(create6, completion(isA<Category>()));
|
||||
expect(db.managers.categories.count(), completion(3));
|
||||
|
||||
// Will return null because the description is not unique
|
||||
final create7 = db.managers.categories.createReturningOrNull(
|
||||
(o) => o(
|
||||
priority: Value(CategoryPriority.high),
|
||||
description: "High",
|
||||
),
|
||||
mode: InsertMode.insertOrIgnore);
|
||||
expect(create7, completion(null));
|
||||
|
||||
// Test batch create
|
||||
await db.managers.categories.bulkCreate((o) => [
|
||||
o(priority: Value(CategoryPriority.high), description: "Super High"),
|
||||
o(priority: Value(CategoryPriority.low), description: "Super Low"),
|
||||
o(
|
||||
priority: Value(CategoryPriority.medium),
|
||||
description: "Super Medium")
|
||||
]);
|
||||
expect(db.managers.categories.count(), completion(6));
|
||||
});
|
||||
|
||||
test('manager - update', () async {
|
||||
// Create a row
|
||||
final obj1 = await db.managers.categories.createReturning(
|
||||
(o) => o(priority: Value(CategoryPriority.low), description: "Low"));
|
||||
final obj2 = await db.managers.categories.createReturning((o) =>
|
||||
o(priority: Value(CategoryPriority.low), description: "Other Low"));
|
||||
|
||||
// Replace the row
|
||||
final update1 =
|
||||
db.managers.categories.replace(obj1.copyWith(description: "Hello"));
|
||||
expect(update1, completion(true));
|
||||
expect(
|
||||
db.managers.categories
|
||||
.filter(((f) => f.id(obj1.id)))
|
||||
.getSingle()
|
||||
.then((value) => value.description),
|
||||
completion("Hello"));
|
||||
|
||||
// Bulk Replace
|
||||
await db.managers.categories.bulkReplace([
|
||||
obj1.copyWith(description: "Hello"),
|
||||
obj2.copyWith(description: "World")
|
||||
]);
|
||||
expect(
|
||||
db.managers.categories
|
||||
.filter(((f) => f.id(obj1.id)))
|
||||
.getSingle()
|
||||
.then((value) => value.description),
|
||||
completion("Hello"));
|
||||
expect(
|
||||
db.managers.categories
|
||||
.filter(((f) => f.id(obj2.id)))
|
||||
.getSingle()
|
||||
.then((value) => value.description),
|
||||
completion("World"));
|
||||
|
||||
// Update All Rows
|
||||
final update2 = db.managers.categories
|
||||
.update((o) => o(priority: Value(CategoryPriority.high)));
|
||||
expect(update2, completion(2));
|
||||
|
||||
// Update a single row
|
||||
final update3 = db.managers.categories
|
||||
.filter(((f) => f.id(obj2.id)))
|
||||
.update((o) => o(description: Value("World")));
|
||||
expect(update3, completion(1));
|
||||
expect(
|
||||
db.managers.categories
|
||||
.filter(((f) => f.id(obj2.id)))
|
||||
.getSingle()
|
||||
.then((value) => value.description),
|
||||
completion("World"));
|
||||
});
|
||||
|
||||
test('manager - delete', () async {
|
||||
// Create a row
|
||||
final obj1 = await db.managers.categories.createReturning(
|
||||
(o) => o(priority: Value(CategoryPriority.low), description: "Low"));
|
||||
// ignore: unused_local_variable
|
||||
final obj2 = await db.managers.categories.createReturning((o) =>
|
||||
o(priority: Value(CategoryPriority.low), description: "Other Low"));
|
||||
|
||||
// Delete a single row
|
||||
final delete1 =
|
||||
db.managers.categories.filter(((f) => f.id(obj1.id))).delete();
|
||||
expect(delete1, completion(1));
|
||||
expect(db.managers.categories.count(), completion(1));
|
||||
|
||||
// Delete all rows
|
||||
final delete2 = db.managers.categories.delete();
|
||||
expect(delete2, completion(1));
|
||||
expect(db.managers.categories.count(), completion(0));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../generated/todos.dart';
|
||||
import '../test_utils/test_utils.dart';
|
||||
|
||||
void main() {
|
||||
late TodoDb db;
|
||||
|
||||
setUp(() {
|
||||
db = TodoDb(testInMemoryDatabase());
|
||||
});
|
||||
|
||||
tearDown(() => db.close());
|
||||
|
||||
test('processed manager', () async {
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(5.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 1)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 2)))));
|
||||
await db.managers.tableWithEveryColumnType.create((o) => o(
|
||||
aText: Value("Get that math homework done"),
|
||||
anIntEnum: Value(TodoStatus.open),
|
||||
aReal: Value(3.0),
|
||||
aDateTime: Value(DateTime.now().add(Duration(days: 3)))));
|
||||
// Test count
|
||||
expect(db.managers.tableWithEveryColumnType.count(), completion(3));
|
||||
// Test get
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.get()
|
||||
.then((value) => value.length),
|
||||
completion(3));
|
||||
// Test getSingle with limit
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.limit(1, offset: 1)
|
||||
.getSingle()
|
||||
.then((value) => value.id),
|
||||
completion(2));
|
||||
// Test filtered delete
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.id(RowId(2)))
|
||||
.delete(),
|
||||
completion(1));
|
||||
|
||||
// Test filtered update
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.id(RowId(1)))
|
||||
.update((o) => o(aReal: Value(10.0))),
|
||||
completion(1));
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.id(RowId(1)))
|
||||
.getSingle()
|
||||
.then((value) => value.aReal),
|
||||
completion(10.0));
|
||||
// Test filtered exists
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.id(RowId(1)))
|
||||
.exists(),
|
||||
completion(true));
|
||||
|
||||
// Test filtered count
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.id(RowId(1)))
|
||||
.count(),
|
||||
completion(1));
|
||||
// Test delte all
|
||||
expect(db.managers.tableWithEveryColumnType.delete(), completion(2));
|
||||
// Test exists - false
|
||||
expect(
|
||||
db.managers.tableWithEveryColumnType
|
||||
.filter((f) => f.id(RowId(1)))
|
||||
.exists(),
|
||||
completion(false));
|
||||
});
|
||||
}
|
|
@ -61,6 +61,10 @@ class DriftOptions {
|
|||
@JsonKey(name: 'generate_connect_constructor', defaultValue: false)
|
||||
final bool generateConnectConstructor;
|
||||
|
||||
/// Generate managers to assist with common database operations.
|
||||
@JsonKey(name: 'generate_manager', defaultValue: true)
|
||||
final bool generateManager;
|
||||
|
||||
@JsonKey(name: 'sqlite_modules', defaultValue: [])
|
||||
@Deprecated('Use effectiveModules instead')
|
||||
final List<SqlModule> modules;
|
||||
|
@ -128,6 +132,7 @@ class DriftOptions {
|
|||
this.useColumnNameAsJsonKeyWhenDefinedInMoorFile = true,
|
||||
this.useSqlColumnNameAsJsonKey = false,
|
||||
this.generateConnectConstructor = false,
|
||||
this.generateManager = true,
|
||||
this.dataClassToCompanions = true,
|
||||
this.generateMutableClasses = false,
|
||||
this.rawResultSetData = false,
|
||||
|
@ -156,6 +161,7 @@ class DriftOptions {
|
|||
required this.useColumnNameAsJsonKeyWhenDefinedInMoorFile,
|
||||
required this.useSqlColumnNameAsJsonKey,
|
||||
required this.generateConnectConstructor,
|
||||
required this.generateManager,
|
||||
required this.dataClassToCompanions,
|
||||
required this.generateMutableClasses,
|
||||
required this.rawResultSetData,
|
||||
|
|
|
@ -457,7 +457,6 @@ class ColumnParser {
|
|||
customConstraints: foundCustomConstraint,
|
||||
sourceForCustomConstraints: customConstraintSource,
|
||||
));
|
||||
|
||||
return PendingColumnInformation(
|
||||
DriftColumn(
|
||||
sqlType: columnType,
|
||||
|
@ -472,6 +471,7 @@ class ColumnParser {
|
|||
documentationComment: docString,
|
||||
constraints: foundConstraints,
|
||||
customConstraints: foundCustomConstraint,
|
||||
referenceName: _readReferenceName(element),
|
||||
),
|
||||
referencesColumnInSameTable: referencesColumnInSameTable,
|
||||
);
|
||||
|
@ -507,6 +507,22 @@ class ColumnParser {
|
|||
return object.computeConstantValue()!.getField('key')!.toStringValue();
|
||||
}
|
||||
|
||||
String? _readReferenceName(Element getter) {
|
||||
final annotations = getter.metadata;
|
||||
final object = annotations.firstWhereOrNull((e) {
|
||||
final value = e.computeConstantValue();
|
||||
final valueType = value?.type;
|
||||
|
||||
return valueType is InterfaceType &&
|
||||
isFromDrift(valueType) &&
|
||||
valueType.element.name == 'ReferenceName';
|
||||
});
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
return object.computeConstantValue()!.getField('name')!.toStringValue();
|
||||
}
|
||||
|
||||
Future<List<DriftColumnConstraint>> _driftConstraintsFromCustomConstraints({
|
||||
required bool isNullable,
|
||||
String? customConstraints,
|
||||
|
|
|
@ -69,6 +69,10 @@ class DriftColumn implements HasType {
|
|||
/// set.
|
||||
final AnnotatedDartCode? clientDefaultCode;
|
||||
|
||||
/// If this column references another column, this column will contain the name
|
||||
/// that the filters and orderings should use to denote the reverse direction
|
||||
final String? referenceName;
|
||||
|
||||
@override
|
||||
final AppliedTypeConverter? typeConverter;
|
||||
|
||||
|
@ -92,6 +96,7 @@ class DriftColumn implements HasType {
|
|||
this.documentationComment,
|
||||
this.constraints = const [],
|
||||
this.customConstraints,
|
||||
this.referenceName,
|
||||
bool foreignConverter = false,
|
||||
}) {
|
||||
if (typeConverter != null && !foreignConverter) {
|
||||
|
|
|
@ -226,6 +226,7 @@ class ElementSerializer {
|
|||
'clientDefaultCode': column.clientDefaultCode?.toJson(),
|
||||
'defaultArgument': column.defaultArgument?.toJson(),
|
||||
'overriddenJsonName': column.overriddenJsonName,
|
||||
'referenceName': column.referenceName,
|
||||
'documentationComment': column.documentationComment,
|
||||
'constraints': [
|
||||
for (final constraint in column.constraints)
|
||||
|
@ -773,6 +774,7 @@ class ElementDeserializer {
|
|||
? AnnotatedDartCode.fromJson(json['defaultArgument'] as Map)
|
||||
: null,
|
||||
overriddenJsonName: json['overriddenJsonName'] as String?,
|
||||
referenceName: json['referenceName'] as String?,
|
||||
documentationComment: json['documentationComment'] as String?,
|
||||
constraints: [
|
||||
for (final rawConstraint in json['constraints'] as List)
|
||||
|
|
|
@ -93,6 +93,7 @@ class GenerateUtilsCommand extends Command {
|
|||
final options = DriftOptions.fromJson({
|
||||
...cli.project.moorOptions.toJson(),
|
||||
...schema.options,
|
||||
'generate_manager': false,
|
||||
});
|
||||
|
||||
final writer = Writer(
|
||||
|
|
|
@ -20,6 +20,7 @@ DriftOptions _$DriftOptionsFromJson(Map json) => $checkedCreate(
|
|||
'use_column_name_as_json_key_when_defined_in_moor_file',
|
||||
'use_sql_column_name_as_json_key',
|
||||
'generate_connect_constructor',
|
||||
'generate_manager',
|
||||
'sqlite_modules',
|
||||
'sqlite',
|
||||
'sql',
|
||||
|
@ -57,6 +58,8 @@ DriftOptions _$DriftOptionsFromJson(Map json) => $checkedCreate(
|
|||
'use_sql_column_name_as_json_key', (v) => v as bool? ?? false),
|
||||
generateConnectConstructor: $checkedConvert(
|
||||
'generate_connect_constructor', (v) => v as bool? ?? false),
|
||||
generateManager:
|
||||
$checkedConvert('generate_manager', (v) => v as bool? ?? true),
|
||||
dataClassToCompanions: $checkedConvert(
|
||||
'data_class_to_companions', (v) => v as bool? ?? true),
|
||||
generateMutableClasses:
|
||||
|
@ -116,6 +119,7 @@ DriftOptions _$DriftOptionsFromJson(Map json) => $checkedCreate(
|
|||
'use_column_name_as_json_key_when_defined_in_moor_file',
|
||||
'useSqlColumnNameAsJsonKey': 'use_sql_column_name_as_json_key',
|
||||
'generateConnectConstructor': 'generate_connect_constructor',
|
||||
'generateManager': 'generate_manager',
|
||||
'dataClassToCompanions': 'data_class_to_companions',
|
||||
'generateMutableClasses': 'mutable_classes',
|
||||
'rawResultSetData': 'raw_result_set_data',
|
||||
|
@ -149,6 +153,7 @@ Map<String, dynamic> _$DriftOptionsToJson(DriftOptions instance) =>
|
|||
instance.useColumnNameAsJsonKeyWhenDefinedInMoorFile,
|
||||
'use_sql_column_name_as_json_key': instance.useSqlColumnNameAsJsonKey,
|
||||
'generate_connect_constructor': instance.generateConnectConstructor,
|
||||
'generate_manager': instance.generateManager,
|
||||
'sqlite_modules':
|
||||
instance.modules.map((e) => _$SqlModuleEnumMap[e]!).toList(),
|
||||
'sqlite': instance.sqliteAnalysisOptions?.toJson(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:drift/drift.dart' as drift;
|
||||
// ignore: implementation_imports
|
||||
import 'package:drift/src/runtime/executor/stream_queries.dart';
|
||||
import 'package:drift_dev/src/writer/manager_writer.dart';
|
||||
import 'package:drift_dev/src/writer/utils/memoized_getter.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
|
||||
|
@ -147,6 +148,17 @@ class DatabaseWriter {
|
|||
}
|
||||
}
|
||||
|
||||
// Write the main database manager & all the managers for tables
|
||||
if (scope.options.generateManager) {
|
||||
final managerWriter = ManagerWriter(scope.child(), dbScope, dbClassName);
|
||||
for (var table in elements.whereType<DriftTable>()) {
|
||||
managerWriter.addTable(table);
|
||||
}
|
||||
managerWriter.write();
|
||||
// Add getter for the manager to the database class
|
||||
firstLeaf.writeln(managerWriter.managerGetter);
|
||||
}
|
||||
|
||||
// Write implementation for query methods
|
||||
for (final query in input.availableRegularQueries) {
|
||||
QueryWriter(dbScope.child()).write(query);
|
||||
|
|
|
@ -0,0 +1,638 @@
|
|||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'package:drift_dev/src/analysis/results/results.dart';
|
||||
import 'package:drift_dev/src/writer/modules.dart';
|
||||
import 'package:drift_dev/src/writer/tables/update_companion_writer.dart';
|
||||
import 'package:drift_dev/src/writer/writer.dart';
|
||||
|
||||
abstract class _FilterWriter {
|
||||
/// The getter for the column on this table
|
||||
///
|
||||
/// E.G `id` in `table.id`
|
||||
final String fieldGetter;
|
||||
|
||||
/// The getter for the columns filter
|
||||
///
|
||||
/// E.G `id` in `f.id.equals(5)`
|
||||
final String filterName;
|
||||
|
||||
/// An abstract class for all filters
|
||||
_FilterWriter(this.filterName, {required this.fieldGetter});
|
||||
|
||||
/// Write the filter to a provider [TextEmitter]
|
||||
void writeFilter(TextEmitter leaf);
|
||||
}
|
||||
|
||||
class _RegularFilterWriter extends _FilterWriter {
|
||||
/// The type that this column is
|
||||
///
|
||||
/// E.G `int`, `String`, etc
|
||||
final String type;
|
||||
|
||||
/// A class used for writing `ColumnFilters` with regular types
|
||||
_RegularFilterWriter(super.filterName,
|
||||
{required super.fieldGetter, required this.type});
|
||||
|
||||
@override
|
||||
void writeFilter(TextEmitter leaf) {
|
||||
leaf
|
||||
..writeDriftRef("ColumnFilters")
|
||||
..write("<$type> get $filterName =>")
|
||||
..writeDriftRef("ColumnFilters")
|
||||
..write("(\$table.$fieldGetter);");
|
||||
}
|
||||
}
|
||||
|
||||
class _FilterWithConverterWriter extends _FilterWriter {
|
||||
/// The type that this column is
|
||||
///
|
||||
/// E.G `int`, `String`, etc
|
||||
final String type;
|
||||
|
||||
/// The type of the user provided converter
|
||||
///
|
||||
/// E.G `Color` etc
|
||||
final String converterType;
|
||||
|
||||
/// A class used for writing `ColumnFilters` with custom converters
|
||||
_FilterWithConverterWriter(super.filterName,
|
||||
{required super.fieldGetter,
|
||||
required this.type,
|
||||
required this.converterType});
|
||||
|
||||
@override
|
||||
void writeFilter(TextEmitter leaf) {
|
||||
final nonNullableConverterType = converterType.replaceFirst("?", "");
|
||||
leaf
|
||||
..writeDriftRef("ColumnWithTypeConverterFilters")
|
||||
..write(
|
||||
"<$converterType,$nonNullableConverterType,$type> get $filterName =>")
|
||||
..writeDriftRef("ColumnWithTypeConverterFilters")
|
||||
..writeln("(\$table.$fieldGetter);");
|
||||
}
|
||||
}
|
||||
|
||||
class _ReferencedFilterWriter extends _FilterWriter {
|
||||
/// The full function used to get the referenced table
|
||||
///
|
||||
/// E.G `\$db.resultSet<$CategoryTable>('categories')`
|
||||
/// or `\$db.categories`
|
||||
final String referencedTableField;
|
||||
|
||||
/// The getter for the column on the referenced table
|
||||
///
|
||||
/// E.G `id` in `table.id`
|
||||
final String referencedColumnGetter;
|
||||
|
||||
/// The name of the referenced table's filter composer
|
||||
///
|
||||
/// E.G `CategoryFilterComposer`
|
||||
final String referencedFilterComposer;
|
||||
|
||||
/// A class used for building filters for referenced tables
|
||||
_ReferencedFilterWriter(
|
||||
super.filterName, {
|
||||
required this.referencedTableField,
|
||||
required this.referencedColumnGetter,
|
||||
required this.referencedFilterComposer,
|
||||
required super.fieldGetter,
|
||||
});
|
||||
|
||||
@override
|
||||
void writeFilter(TextEmitter leaf) {
|
||||
leaf
|
||||
..writeDriftRef("ComposableFilter")
|
||||
..write(" $filterName(")
|
||||
..writeDriftRef("ComposableFilter")
|
||||
..writeln(" Function( $referencedFilterComposer f) f) {")
|
||||
..write("return \$composeWithJoins(")
|
||||
..writeln("\$db: \$db,")
|
||||
..writeln("\$table: \$table,")
|
||||
..writeln("referencedTable: $referencedTableField,")
|
||||
..writeln("getCurrentColumn: (f) => f.$fieldGetter,")
|
||||
..writeln("getReferencedColumn: (f) => f.$referencedColumnGetter,")
|
||||
..writeln(
|
||||
"getReferencedComposer: (db, table) => $referencedFilterComposer(db, table),")
|
||||
..writeln("builder: f);")
|
||||
..writeln("}");
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _OrderingWriter {
|
||||
/// The getter for the column on this table
|
||||
///
|
||||
/// E.G `id` in `table.id`
|
||||
final String fieldGetter;
|
||||
|
||||
/// The getter for the columns ordering
|
||||
///
|
||||
/// E.G `id` in `f.id.equals(5)`
|
||||
final String orderingName;
|
||||
|
||||
/// Abstract class for all orderings
|
||||
_OrderingWriter(this.orderingName, {required this.fieldGetter});
|
||||
|
||||
/// Write the ordering to a provider [TextEmitter]
|
||||
void writeOrdering(TextEmitter leaf);
|
||||
}
|
||||
|
||||
class _RegularOrderingWriter extends _OrderingWriter {
|
||||
/// The type that this column is
|
||||
///
|
||||
/// E.G `int`, `String`, etc
|
||||
final String type;
|
||||
|
||||
/// A class used for writing `ColumnOrderings` with regular types
|
||||
_RegularOrderingWriter(super.orderingName,
|
||||
{required super.fieldGetter, required this.type});
|
||||
|
||||
@override
|
||||
void writeOrdering(TextEmitter leaf) {
|
||||
leaf
|
||||
..writeDriftRef("ColumnOrderings")
|
||||
..write("<$type> get $orderingName =>")
|
||||
..writeDriftRef("ColumnOrderings")
|
||||
..write("(\$table.$fieldGetter);");
|
||||
}
|
||||
}
|
||||
|
||||
class _ReferencedOrderingWriter extends _OrderingWriter {
|
||||
/// The full function used to get the referenced table
|
||||
///
|
||||
/// E.G `\$db.resultSet<$CategoryTable>('categories')`
|
||||
/// or `\$db.categories`
|
||||
final String referencedTableField;
|
||||
|
||||
/// The getter for the column on the referenced table
|
||||
///
|
||||
/// E.G `id` in `table.id`
|
||||
final String referencedColumnGetter;
|
||||
|
||||
/// The name of the referenced table's ordering composer
|
||||
///
|
||||
/// E.G `CategoryOrderingComposer`
|
||||
final String referencedOrderingComposer;
|
||||
|
||||
/// A class used for building orderings for referenced tables
|
||||
_ReferencedOrderingWriter(super.orderingName,
|
||||
{required this.referencedTableField,
|
||||
required this.referencedColumnGetter,
|
||||
required this.referencedOrderingComposer,
|
||||
required super.fieldGetter});
|
||||
|
||||
@override
|
||||
void writeOrdering(TextEmitter leaf) {
|
||||
leaf
|
||||
..writeDriftRef("ComposableOrdering")
|
||||
..write(" $orderingName(")
|
||||
..writeDriftRef("ComposableOrdering")
|
||||
..writeln(" Function( $referencedOrderingComposer o) o) {")
|
||||
..write("return \$composeWithJoins(")
|
||||
..writeln("\$db: \$db,")
|
||||
..writeln("\$table: \$table,")
|
||||
..writeln("referencedTable: $referencedTableField,")
|
||||
..writeln("getCurrentColumn: (f) => f.$fieldGetter,")
|
||||
..writeln("getReferencedColumn: (f) => f.$referencedColumnGetter,")
|
||||
..writeln(
|
||||
"getReferencedComposer: (db, table) => $referencedOrderingComposer(db, table),")
|
||||
..writeln("builder: o);")
|
||||
..writeln("}");
|
||||
}
|
||||
}
|
||||
|
||||
class _ColumnManagerWriter {
|
||||
/// The getter for the field
|
||||
///
|
||||
/// E.G `id` in `table.id`
|
||||
final String fieldGetter;
|
||||
|
||||
/// List of filters for this column
|
||||
final List<_FilterWriter> filters;
|
||||
|
||||
/// List of orderings for this column
|
||||
final List<_OrderingWriter> orderings;
|
||||
|
||||
/// A class used for writing filters and orderings for columns
|
||||
_ColumnManagerWriter(this.fieldGetter)
|
||||
: filters = [],
|
||||
orderings = [];
|
||||
}
|
||||
|
||||
class _TableManagerWriter {
|
||||
/// The current table
|
||||
final DriftTable table;
|
||||
|
||||
/// Generation Scope
|
||||
final Scope scope;
|
||||
|
||||
/// Generation Scope for the entire database
|
||||
final Scope dbScope;
|
||||
|
||||
/// The name of the filter composer class
|
||||
///
|
||||
/// E.G `UserFilterComposer`
|
||||
String get filterComposer => '\$${table.entityInfoName}FilterComposer';
|
||||
|
||||
/// The name of the filter composer class
|
||||
///
|
||||
/// E.G `UserOrderingComposer`
|
||||
String get orderingComposer => '\$${table.entityInfoName}OrderingComposer';
|
||||
|
||||
/// The name of the processed table manager class
|
||||
///
|
||||
/// E.G `UserProcessedTableManager`
|
||||
String get processedTableManager =>
|
||||
'\$${table.entityInfoName}ProcessedTableManager';
|
||||
|
||||
/// The name of the root table manager class
|
||||
///
|
||||
/// E.G `UserTableManager`
|
||||
String get rootTableManager => '\$${table.entityInfoName}TableManager';
|
||||
|
||||
/// Name of the typedef for the insertCompanionBuilder
|
||||
///
|
||||
/// E.G. `insertCompanionBuilder`
|
||||
String get insertCompanionBuilderTypeDefName =>
|
||||
'\$${table.entityInfoName}InsertCompanionBuilder';
|
||||
|
||||
/// Name of the arguments for the updateCompanionBuilder
|
||||
///
|
||||
/// E.G. `updateCompanionBuilderTypeDef`
|
||||
String get updateCompanionBuilderTypeDefName =>
|
||||
'\$${table.entityInfoName}UpdateCompanionBuilder';
|
||||
|
||||
/// Table class name, this may be different from the entity name
|
||||
/// if modular generation is enabled
|
||||
/// E.G. `i5.$CategoriesTable`
|
||||
String get tableClassName => dbScope.dartCode(dbScope.entityInfoType(table));
|
||||
|
||||
/// Row class name, this may be different from the entity name
|
||||
/// if modular generation is enabled
|
||||
/// E.G. `i5.$Category`
|
||||
String get rowClassName => dbScope.dartCode(dbScope.writer.rowType(table));
|
||||
|
||||
/// Whether this table has a custom row class
|
||||
/// We use this row to determine if we should generate a manager for this table
|
||||
bool get hasCustomRowClass => table.existingRowClass != null;
|
||||
|
||||
/// The name of the database class
|
||||
///
|
||||
/// E.G. `i5.$GeneratedDatabase`
|
||||
final String databaseGenericName;
|
||||
|
||||
/// Writers for the columns of this table
|
||||
final List<_ColumnManagerWriter> columns;
|
||||
|
||||
/// Filters for back references
|
||||
final List<_ReferencedFilterWriter> backRefFilters;
|
||||
|
||||
_TableManagerWriter(
|
||||
this.table, this.scope, this.dbScope, this.databaseGenericName)
|
||||
: backRefFilters = [],
|
||||
columns = [];
|
||||
|
||||
void _writeFilterComposer(TextEmitter leaf) {
|
||||
leaf
|
||||
..write('class $filterComposer extends ')
|
||||
..writeDriftRef('FilterComposer')
|
||||
..writeln('<$databaseGenericName,$tableClassName> {')
|
||||
..writeln('$filterComposer(super.db, super.table);');
|
||||
for (var c in columns) {
|
||||
for (var f in c.filters) {
|
||||
f.writeFilter(leaf);
|
||||
}
|
||||
}
|
||||
for (var f in backRefFilters) {
|
||||
f.writeFilter(leaf);
|
||||
}
|
||||
leaf.writeln('}');
|
||||
}
|
||||
|
||||
void _writeOrderingComposer(TextEmitter leaf) {
|
||||
// Write the OrderingComposer
|
||||
leaf
|
||||
..write('class $orderingComposer extends ')
|
||||
..writeDriftRef('OrderingComposer')
|
||||
..writeln('<$databaseGenericName,$tableClassName> {')
|
||||
..writeln('$orderingComposer(super.db, super.table);');
|
||||
for (var c in columns) {
|
||||
for (var o in c.orderings) {
|
||||
o.writeOrdering(leaf);
|
||||
}
|
||||
}
|
||||
leaf.writeln('}');
|
||||
}
|
||||
|
||||
void _writeProcessedTableManager(TextEmitter leaf) {
|
||||
leaf
|
||||
..write('class $processedTableManager extends ')
|
||||
..writeDriftRef('ProcessedTableManager')
|
||||
..writeln(
|
||||
'<$databaseGenericName,$tableClassName,$rowClassName,$filterComposer,$orderingComposer,$processedTableManager,$insertCompanionBuilderTypeDefName,$updateCompanionBuilderTypeDefName> {')
|
||||
..writeln('const $processedTableManager(super.\$state);')
|
||||
..writeln('}');
|
||||
}
|
||||
|
||||
/// Build the builder for a companion class
|
||||
/// This is used to build the insert and update companions
|
||||
/// Returns a tuple with the typedef and the builder
|
||||
/// Use [isUpdate] to determine if the builder is for an update or insert companion
|
||||
(String, String) _companionBuilder(String typedefName,
|
||||
{required bool isUpdate}) {
|
||||
final companionClassName = scope.dartCode(scope.companionType(table));
|
||||
|
||||
final companionBuilderTypeDef =
|
||||
StringBuffer('typedef $typedefName = $companionClassName Function({');
|
||||
|
||||
final companionBuilderArguments = StringBuffer('({');
|
||||
|
||||
final StringBuffer companionBuilderBody;
|
||||
if (isUpdate) {
|
||||
companionBuilderBody = StringBuffer('=> $companionClassName(');
|
||||
} else {
|
||||
companionBuilderBody = StringBuffer('=> $companionClassName.insert(');
|
||||
}
|
||||
|
||||
for (final column in UpdateCompanionWriter(table, scope).columns) {
|
||||
final value = scope.drift('Value');
|
||||
final param = column.nameInDart;
|
||||
final typeName = scope.dartCode(scope.dartType(column));
|
||||
|
||||
companionBuilderBody.write('$param: $param,');
|
||||
|
||||
if (isUpdate) {
|
||||
// The update companion has no required fields, they are all defaulted to absent
|
||||
companionBuilderTypeDef.write('$value<$typeName> $param,');
|
||||
companionBuilderArguments
|
||||
.write('$value<$typeName> $param = const $value.absent(),');
|
||||
} else {
|
||||
// The insert compantion has some required arguments and some that are defaulted to absent
|
||||
if (!column.isImplicitRowId &&
|
||||
table.isColumnRequiredForInsert(column)) {
|
||||
companionBuilderTypeDef.write('required $typeName $param,');
|
||||
companionBuilderArguments.write('required $typeName $param,');
|
||||
} else {
|
||||
companionBuilderTypeDef.write('$value<$typeName> $param,');
|
||||
companionBuilderArguments
|
||||
.write('$value<$typeName> $param = const $value.absent(),');
|
||||
}
|
||||
}
|
||||
}
|
||||
companionBuilderTypeDef.write('});');
|
||||
companionBuilderArguments.write('})');
|
||||
companionBuilderBody.write(")");
|
||||
return (
|
||||
companionBuilderTypeDef.toString(),
|
||||
companionBuilderArguments.toString() + companionBuilderBody.toString()
|
||||
);
|
||||
}
|
||||
|
||||
void _writeRootTable(TextEmitter leaf) {
|
||||
final (insertCompanionBuilderTypeDef, insertCompanionBuilder) =
|
||||
_companionBuilder(insertCompanionBuilderTypeDefName, isUpdate: false);
|
||||
final (updateCompanionBuilderTypeDef, updateCompanionBuilder) =
|
||||
_companionBuilder(updateCompanionBuilderTypeDefName, isUpdate: true);
|
||||
|
||||
leaf.writeln(insertCompanionBuilderTypeDef);
|
||||
leaf.writeln(updateCompanionBuilderTypeDef);
|
||||
|
||||
leaf
|
||||
..write('class $rootTableManager extends ')
|
||||
..writeDriftRef('RootTableManager')
|
||||
..writeln(
|
||||
'<$databaseGenericName,$tableClassName,$rowClassName,$filterComposer,$orderingComposer,$processedTableManager,$insertCompanionBuilderTypeDefName,$updateCompanionBuilderTypeDefName> {')
|
||||
..writeln(
|
||||
'$rootTableManager($databaseGenericName db, $tableClassName table)')
|
||||
..writeln(": super(")
|
||||
..writeDriftRef("TableManagerState")
|
||||
..write(
|
||||
"""(db: db, table: table, filteringComposer:$filterComposer(db, table),orderingComposer:$orderingComposer(db, table),
|
||||
getChildManagerBuilder :(p0) => $processedTableManager(p0),getUpdateCompanionBuilder: $updateCompanionBuilder,
|
||||
getInsertCompanionBuilder:$insertCompanionBuilder));""")
|
||||
..writeln('}');
|
||||
}
|
||||
|
||||
/// Write the manager for this table, with all the filters and orderings
|
||||
void writeManager(TextEmitter leaf) {
|
||||
_writeFilterComposer(leaf);
|
||||
_writeOrderingComposer(leaf);
|
||||
_writeProcessedTableManager(leaf);
|
||||
_writeRootTable(leaf);
|
||||
}
|
||||
|
||||
String _referenceTable(DriftTable table) {
|
||||
if (scope.generationOptions.isModular) {
|
||||
final extension = scope.refUri(
|
||||
ModularAccessorWriter.modularSupport, 'ReadDatabaseContainer');
|
||||
final type = scope.dartCode(scope.entityInfoType(table));
|
||||
return "$extension(\$db).resultSet<$type>('${table.schemaName}')";
|
||||
} else {
|
||||
return '\$db.${table.dbGetterName}';
|
||||
}
|
||||
}
|
||||
|
||||
/// Add filters and orderings for the columns of this table
|
||||
void addFiltersAndOrderings(List<DriftTable> tables) {
|
||||
// Utility function to get the referenced table and column
|
||||
(DriftTable, DriftColumn)? getReferencedTableAndColumn(
|
||||
DriftColumn column, List<DriftTable> tables) {
|
||||
final referencedCol = column.constraints
|
||||
.whereType<ForeignKeyReference>()
|
||||
.firstOrNull
|
||||
?.otherColumn;
|
||||
if (referencedCol != null && referencedCol.owner is DriftTable) {
|
||||
final referencedTable = tables.firstWhere(
|
||||
(t) => t.entityInfoName == referencedCol.owner.entityInfoName);
|
||||
return (referencedTable, referencedCol);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Utility function to get the duplicates in a list
|
||||
List<String> duplicates(List<String> items) {
|
||||
final seen = <String>{};
|
||||
final duplicates = <String>[];
|
||||
for (var item in items) {
|
||||
if (!seen.add(item)) {
|
||||
duplicates.add(item);
|
||||
}
|
||||
}
|
||||
return duplicates;
|
||||
}
|
||||
|
||||
/// First add the filters and orderings for the columns
|
||||
/// of the current table
|
||||
for (var column in table.columns) {
|
||||
final c = _ColumnManagerWriter(column.nameInDart);
|
||||
|
||||
// The type that this column is (int, string, etc)
|
||||
final innerColumnType =
|
||||
scope.dartCode(scope.innerColumnType(column.sqlType));
|
||||
|
||||
// Get the referenced table and column if this column is a foreign key
|
||||
final referenced = getReferencedTableAndColumn(column, tables);
|
||||
final isForeignKey = referenced != null;
|
||||
|
||||
// If the column has a type converter, add a filter with a converter
|
||||
if (column.typeConverter != null) {
|
||||
final converterType = scope.dartCode(scope.writer.dartType(column));
|
||||
c.filters.add(_RegularFilterWriter("${c.fieldGetter}Value",
|
||||
type: innerColumnType, fieldGetter: c.fieldGetter));
|
||||
c.filters.add(_FilterWithConverterWriter(c.fieldGetter,
|
||||
converterType: converterType,
|
||||
fieldGetter: c.fieldGetter,
|
||||
type: innerColumnType));
|
||||
} else {
|
||||
c.filters.add(_RegularFilterWriter(
|
||||
c.fieldGetter + (isForeignKey ? "Id" : ""),
|
||||
type: innerColumnType,
|
||||
fieldGetter: c.fieldGetter));
|
||||
}
|
||||
|
||||
// Add the ordering for the column
|
||||
c.orderings.add(_RegularOrderingWriter(
|
||||
c.fieldGetter + (isForeignKey ? "Id" : ""),
|
||||
type: innerColumnType,
|
||||
fieldGetter: c.fieldGetter));
|
||||
|
||||
/// If this column is a foreign key to another table, add a filter and ordering
|
||||
/// for the referenced table
|
||||
if (referenced != null) {
|
||||
final (referencedTable, referencedCol) = referenced;
|
||||
final referencedTableNames = _TableManagerWriter(
|
||||
referencedTable, scope, dbScope, databaseGenericName);
|
||||
final referencedColumnNames =
|
||||
_ColumnManagerWriter(referencedCol.nameInDart);
|
||||
final referencedTableField = _referenceTable(referencedTable);
|
||||
|
||||
c.filters.add(_ReferencedFilterWriter(c.fieldGetter,
|
||||
fieldGetter: c.fieldGetter,
|
||||
referencedColumnGetter: referencedColumnNames.fieldGetter,
|
||||
referencedFilterComposer: referencedTableNames.filterComposer,
|
||||
referencedTableField: referencedTableField));
|
||||
c.orderings.add(_ReferencedOrderingWriter(c.fieldGetter,
|
||||
fieldGetter: c.fieldGetter,
|
||||
referencedColumnGetter: referencedColumnNames.fieldGetter,
|
||||
referencedOrderingComposer: referencedTableNames.orderingComposer,
|
||||
referencedTableField: referencedTableField));
|
||||
}
|
||||
columns.add(c);
|
||||
}
|
||||
|
||||
// Iterate over all other tables to find back references
|
||||
for (var ot in tables) {
|
||||
for (var oc in ot.columns) {
|
||||
// Check if the column is a foreign key to the current table
|
||||
final reference = getReferencedTableAndColumn(oc, tables);
|
||||
if (reference != null &&
|
||||
reference.$1.entityInfoName == table.entityInfoName) {
|
||||
final referencedTableNames =
|
||||
_TableManagerWriter(ot, scope, dbScope, databaseGenericName);
|
||||
final referencedColumnNames = _ColumnManagerWriter(oc.nameInDart);
|
||||
final referencedTableField = _referenceTable(ot);
|
||||
|
||||
final filterName = oc.referenceName ??
|
||||
"${referencedTableNames.table.dbGetterName}Refs";
|
||||
|
||||
backRefFilters.add(_ReferencedFilterWriter(filterName,
|
||||
fieldGetter: reference.$2.nameInDart,
|
||||
referencedColumnGetter: referencedColumnNames.fieldGetter,
|
||||
referencedFilterComposer: referencedTableNames.filterComposer,
|
||||
referencedTableField: referencedTableField));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the filters and orderings that have duplicates
|
||||
final duplicatedFilterNames = duplicates(columns
|
||||
.map((e) => e.filters.map((e) => e.filterName))
|
||||
.expand((e) => e)
|
||||
.toList() +
|
||||
backRefFilters.map((e) => e.filterName).toList());
|
||||
final duplicatedOrderingNames = duplicates(columns
|
||||
.map((e) => e.orderings.map((e) => e.orderingName))
|
||||
.expand((e) => e)
|
||||
.toList());
|
||||
if (duplicatedFilterNames.isNotEmpty ||
|
||||
duplicatedOrderingNames.isNotEmpty) {
|
||||
print(
|
||||
"The code generator encountered an issue while attempting to create filters/orderings for $tableClassName manager. The following filters/orderings were not created ${(duplicatedFilterNames + duplicatedOrderingNames).toSet()}. Use the @ReferenceName() annotation to resolve this issue.");
|
||||
// Remove the duplicates
|
||||
for (var c in columns) {
|
||||
c.filters
|
||||
.removeWhere((e) => duplicatedFilterNames.contains(e.filterName));
|
||||
c.orderings.removeWhere(
|
||||
(e) => duplicatedOrderingNames.contains(e.orderingName));
|
||||
}
|
||||
backRefFilters
|
||||
.removeWhere((e) => duplicatedFilterNames.contains(e.filterName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ManagerWriter {
|
||||
final Scope _scope;
|
||||
final Scope _dbScope;
|
||||
final String _dbClassName;
|
||||
late final List<DriftTable> _addedTables;
|
||||
|
||||
/// Class used to write a manager for a database
|
||||
ManagerWriter(this._scope, this._dbScope, this._dbClassName) {
|
||||
_addedTables = [];
|
||||
}
|
||||
|
||||
/// Add a table to the manager
|
||||
void addTable(DriftTable table) {
|
||||
_addedTables.add(table);
|
||||
}
|
||||
|
||||
/// The generic of the database that the manager will use
|
||||
/// Will be `GeneratedDatabase` if modular generation is enabled
|
||||
/// or the name of the database class if not
|
||||
String get databaseGenericName {
|
||||
if (_scope.generationOptions.isModular) {
|
||||
return _scope.drift("GeneratedDatabase");
|
||||
} else {
|
||||
return _dbClassName;
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of the manager class
|
||||
String get databaseManagerName => '${_dbClassName}Manager';
|
||||
|
||||
/// The getter for the manager that will be added to the database
|
||||
String get managerGetter {
|
||||
return '$databaseManagerName get managers => $databaseManagerName(this);';
|
||||
}
|
||||
|
||||
/// Write the manager to a provider [TextEmitter]
|
||||
void write() {
|
||||
final leaf = _scope.leaf();
|
||||
|
||||
// create the manager class for each table
|
||||
final tableWriters = <_TableManagerWriter>[];
|
||||
for (var table in _addedTables) {
|
||||
tableWriters.add(
|
||||
_TableManagerWriter(table, _scope, _dbScope, databaseGenericName)
|
||||
..addFiltersAndOrderings(_addedTables));
|
||||
}
|
||||
|
||||
// Remove ones that have custom row classes
|
||||
tableWriters.removeWhere((t) => t.hasCustomRowClass);
|
||||
|
||||
// Write each tables manager to the leaf and append the getter to the main manager
|
||||
final tableManagerGetters = StringBuffer();
|
||||
for (var table in tableWriters) {
|
||||
table.writeManager(leaf);
|
||||
tableManagerGetters.writeln(
|
||||
"${table.rootTableManager} get ${table.table.dbGetterName} => ${table.rootTableManager}(_db, _db.${table.table.dbGetterName});");
|
||||
}
|
||||
|
||||
// Write the main manager class
|
||||
leaf
|
||||
..writeln('class $databaseManagerName{')
|
||||
..writeln('final $_dbClassName _db;')
|
||||
..writeln('$databaseManagerName(this._db);')
|
||||
..writeln(tableManagerGetters)
|
||||
..writeln('}');
|
||||
}
|
||||
}
|
|
@ -46,7 +46,6 @@ abstract class TableOrViewWriter {
|
|||
final typeName =
|
||||
emitter.dartCode(emitter.writer.converterType(converter));
|
||||
final code = emitter.dartCode(converter.expression);
|
||||
|
||||
buffer.write('static $typeName ${converter.fieldName} = $code;');
|
||||
|
||||
// Generate wrappers for non-nullable type converters that are applied to
|
||||
|
|
|
@ -5,7 +5,6 @@ import 'package:analyzer/file_system/memory_file_system.dart';
|
|||
import 'package:build/build.dart';
|
||||
import 'package:build_test/build_test.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
|
@ -409,10 +408,7 @@ class _GeneratesConstDataClasses extends Matcher {
|
|||
|
||||
final parsed = parseFile(
|
||||
path: '/foo.dart',
|
||||
featureSet: FeatureSet.fromEnableFlags2(
|
||||
sdkLanguageVersion: Version(2, 12, 0),
|
||||
flags: const [],
|
||||
),
|
||||
featureSet: FeatureSet.latestLanguageVersion(),
|
||||
resourceProvider: resourceProvider,
|
||||
throwIfDiagnostics: true,
|
||||
).unit;
|
||||
|
|
|
@ -18,9 +18,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
|
|
@ -32,9 +32,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -257,9 +258,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -475,9 +477,10 @@ class Notes extends Table
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
|
|
|
@ -21,9 +21,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
|
|
@ -21,9 +21,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -179,9 +180,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
|
|
@ -23,9 +23,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -181,9 +182,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
|
|
@ -29,9 +29,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -218,9 +219,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
|
|
@ -32,9 +32,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -250,9 +251,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
|
|
@ -32,9 +32,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -250,9 +251,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -603,9 +605,10 @@ class Notes extends Table
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
|
|
|
@ -32,9 +32,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -254,9 +255,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -607,9 +609,10 @@ class Notes extends Table
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
|
|
|
@ -32,9 +32,10 @@ class Users extends Table with TableInfo<Users, UsersData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -257,9 +258,10 @@ class Groups extends Table with TableInfo<Groups, GroupsData> {
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
|
@ -475,9 +477,10 @@ class Notes extends Table
|
|||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
|
|
Loading…
Reference in New Issue