1) Apply Limit to Single Getting

2) Move Distict to positional arg
3) Add limit as a positional arg
4) Fix _tests.dart to _test.dart for CI
5) Move all methods to base - Remove all()
This commit is contained in:
Moshe Dicker 2024-04-17 13:04:47 -04:00
parent f17c251126
commit 4c7f7402c1
5 changed files with 82 additions and 68 deletions

View File

@ -283,24 +283,28 @@ class TableManagerState<
/// This is so that the state can be passed down to lower level managers /// This is so that the state can be passed down to lower level managers
@internal @internal
abstract class BaseTableManager< abstract class BaseTableManager<
DB extends GeneratedDatabase, DB extends GeneratedDatabase,
T extends Table, T extends Table,
DT extends DataClass, DT extends DataClass,
FS extends FilterComposer<DB, T>, FS extends FilterComposer<DB, T>,
OS extends OrderingComposer<DB, T>, OS extends OrderingComposer<DB, T>,
C extends ProcessedTableManager<DB, T, DT, FS, OS, C, CI, CU>, C extends ProcessedTableManager<DB, T, DT, FS, OS, C, CI, CU>,
CI extends Function, CI extends Function,
CU extends Function> { CU extends Function>
implements
MultiSelectable<DT>,
SingleSelectable<DT>,
SingleOrNullSelectable<DT> {
/// The state for this manager /// The state for this manager
final TableManagerState<DB, T, DT, FS, OS, C, CI, CU> $state; final TableManagerState<DB, T, DT, FS, OS, C, CI, CU> $state;
/// Create a new [BaseTableManager] instance /// Create a new [BaseTableManager] instance
const BaseTableManager(this.$state); const BaseTableManager(this.$state);
/// Set the distinct flag on the statement to true /// Add a limit to the statement
/// This will ensure that only distinct rows are returned C limit(int limit, {int? offset}) {
C distict() { return $state
return $state._getChildManagerBuilder($state.copyWith(distinct: true)); ._getChildManagerBuilder($state.copyWith(limit: limit, offset: offset));
} }
/// Add ordering to the statement /// Add ordering to the statement
@ -322,12 +326,6 @@ abstract class BaseTableManager<
joinBuilders: $state.joinBuilders.union(filter.joinBuilders))); joinBuilders: $state.joinBuilders.union(filter.joinBuilders)));
} }
/// Add a limit to the statement
C limit(int limit, {int? offset}) {
return $state
._getChildManagerBuilder($state.copyWith(limit: limit, offset: offset));
}
/// Writes all non-null fields from the entity into the columns of all rows /// 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 /// 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 /// not setting a where clause explicitly, this method will update all rows in
@ -351,25 +349,6 @@ abstract class BaseTableManager<
/// Checks whether any rows exist /// Checks whether any rows exist
Future<bool> exists() => $state.exists(); Future<bool> exists() => $state.exists();
}
/// A table manager that can be used to select rows from a table
abstract 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);
/// Deletes all rows matched by built statement /// Deletes all rows matched by built statement
/// ///
@ -390,25 +369,47 @@ abstract class ProcessedTableManager<
/// ///
/// See also: [getSingleOrNull], which returns `null` instead of /// See also: [getSingleOrNull], which returns `null` instead of
/// throwing if the query completes with no rows. /// throwing if the query completes with no rows.
///
/// Uses the distinct flag to ensure that only distinct rows are returned
@override @override
Future<D> getSingle() => $state.buildSelectStatement().getSingle(); Future<DT> getSingle() =>
$state.copyWith(distinct: true).buildSelectStatement().getSingle();
/// Creates an auto-updating stream of this statement, similar to /// Creates an auto-updating stream of this statement, similar to
/// [watch]. However, it is assumed that the query will only emit /// [watch]. However, it is assumed that the query will only emit
/// one result, so instead of returning a `Stream<List<D>>`, this returns a /// 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, /// `Stream<D>`. If, at any point, the query emits no or more than one rows,
/// an error will be added to the stream instead. /// an error will be added to the stream instead.
///
/// Uses the distinct flag to ensure that only distinct rows are returned
@override @override
Stream<D> watchSingle() => $state.buildSelectStatement().watchSingle(); Stream<DT> watchSingle() =>
$state.copyWith(distinct: true).buildSelectStatement().watchSingle();
/// Executes the statement and returns the first all rows as a list. /// 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 @override
Future<List<D>> get() => $state.buildSelectStatement().get(); 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 /// Creates an auto-updating stream of the result that emits new items
/// whenever any table used in this statement changes. /// 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 @override
Stream<List<D>> watch() => $state.buildSelectStatement().watch(); 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 /// Executes this statement, like [get], but only returns one
/// value. If the result too many values, this method will throw. If no /// value. If the result too many values, this method will throw. If no
@ -416,9 +417,11 @@ abstract class ProcessedTableManager<
/// ///
/// See also: [getSingle], which can be used if the query will /// See also: [getSingle], which can be used if the query will
/// always evaluate to exactly one row. /// always evaluate to exactly one row.
///
/// Uses the distinct flag to ensure that only distinct rows are returned
@override @override
Future<D?> getSingleOrNull() => Future<DT?> getSingleOrNull() =>
$state.buildSelectStatement().getSingleOrNull(); $state.copyWith(distinct: true).buildSelectStatement().getSingleOrNull();
/// Creates an auto-updating stream of this statement, similar to /// Creates an auto-updating stream of this statement, similar to
/// [watch]. However, it is assumed that the query will only /// [watch]. However, it is assumed that the query will only
@ -427,9 +430,33 @@ abstract class ProcessedTableManager<
/// some point, an error will be emitted to the stream instead. /// some point, an error will be emitted to the stream instead.
/// If the query emits zero rows at some point, `null` will be added /// If the query emits zero rows at some point, `null` will be added
/// to the stream instead. /// to the stream instead.
///
/// Uses the distinct flag to ensure that only distinct rows are returned
@override @override
Stream<D?> watchSingleOrNull() => Stream<DT?> watchSingleOrNull() => $state
$state.buildSelectStatement().watchSingleOrNull(); .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 /// A table manager with top level function for creating, reading, updating, and deleting items
@ -445,16 +472,6 @@ abstract class RootTableManager<
/// Create a new [RootTableManager] instance /// Create a new [RootTableManager] instance
const RootTableManager(super.$state); const RootTableManager(super.$state);
/// 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.db.delete($state._tableAsTableInfo).go();
/// Select all rows from the table
C all() => $state._getChildManagerBuilder($state);
/// Creates a new row in the table using the given function /// Creates a new row in the table using the given function
/// ///
/// By default, an exception will be thrown if another row with the same /// By default, an exception will be thrown if another row with the same

View File

@ -533,7 +533,6 @@ void main() {
db.managers.categories db.managers.categories
.filter((f) => f.todos((f) => f.category( .filter((f) => f.todos((f) => f.category(
(f) => f.todos((f) => f.title.equals("Math Homework"))))) (f) => f.todos((f) => f.title.equals("Math Homework")))))
.distict()
.getSingle() .getSingle()
.then((value) => value.description), .then((value) => value.description),
completion("School")); completion("School"));

View File

@ -16,19 +16,19 @@ void main() {
test('manager - create', () async { test('manager - create', () async {
// Initial count should be 0 // Initial count should be 0
expect(db.managers.categories.all().count(), completion(0)); expect(db.managers.categories.count(), completion(0));
// Creating a row should return the id // Creating a row should return the id
final create1 = db.managers.categories.create( final create1 = db.managers.categories.create(
(o) => o(priority: Value(CategoryPriority.high), description: "High")); (o) => o(priority: Value(CategoryPriority.high), description: "High"));
expect(create1, completion(1)); expect(create1, completion(1));
expect(db.managers.categories.all().count(), completion(1)); expect(db.managers.categories.count(), completion(1));
// Creating another row should increment the id // Creating another row should increment the id
final create2 = db.managers.categories.create( final create2 = db.managers.categories.create(
(o) => o(priority: Value(CategoryPriority.low), description: "Low")); (o) => o(priority: Value(CategoryPriority.low), description: "Low"));
expect(create2, completion(2)); expect(create2, completion(2));
expect(db.managers.categories.all().count(), completion(2)); expect(db.managers.categories.count(), completion(2));
// Using an existing id should throw an exception // Using an existing id should throw an exception
final create3 = db.managers.categories.create((o) => o( final create3 = db.managers.categories.create((o) => o(
@ -47,7 +47,7 @@ void main() {
onConflict: DoNothing()); onConflict: DoNothing());
// The is incorrect when using onConflict // The is incorrect when using onConflict
expect(create4, completion(2)); expect(create4, completion(2));
expect(db.managers.categories.all().count(), completion(2)); expect(db.managers.categories.count(), completion(2));
// Likewise, test that mode is passed to the create method // Likewise, test that mode is passed to the create method
final create5 = db.managers.categories.create( final create5 = db.managers.categories.create(
@ -59,13 +59,13 @@ void main() {
// The is incorrect when using mode // The is incorrect when using mode
expect(create5, completion(2)); expect(create5, completion(2));
expect(db.managers.categories.all().count(), completion(2)); expect(db.managers.categories.count(), completion(2));
// Test the other create methods // Test the other create methods
final create6 = db.managers.categories.createReturning((o) => final create6 = db.managers.categories.createReturning((o) =>
o(priority: Value(CategoryPriority.high), description: "Other High")); o(priority: Value(CategoryPriority.high), description: "Other High"));
expect(create6, completion(isA<Category>())); expect(create6, completion(isA<Category>()));
expect(db.managers.categories.all().count(), completion(3)); expect(db.managers.categories.count(), completion(3));
// Will return null because the description is not unique // Will return null because the description is not unique
final create7 = db.managers.categories.createReturningOrNull( final create7 = db.managers.categories.createReturningOrNull(
@ -84,7 +84,7 @@ void main() {
priority: Value(CategoryPriority.medium), priority: Value(CategoryPriority.medium),
description: "Super Medium") description: "Super Medium")
]); ]);
expect(db.managers.categories.all().count(), completion(6)); expect(db.managers.categories.count(), completion(6));
}); });
test('manager - update', () async { test('manager - update', () async {
@ -135,11 +135,11 @@ void main() {
final delete1 = final delete1 =
db.managers.categories.filter(((f) => f.id(obj1.id))).delete(); db.managers.categories.filter(((f) => f.id(obj1.id))).delete();
expect(delete1, completion(1)); expect(delete1, completion(1));
expect(db.managers.categories.all().count(), completion(1)); expect(db.managers.categories.count(), completion(1));
// Delete all rows // Delete all rows
final delete2 = db.managers.categories.delete(); final delete2 = db.managers.categories.delete();
expect(delete2, completion(1)); expect(delete2, completion(1));
expect(db.managers.categories.all().count(), completion(0)); expect(db.managers.categories.count(), completion(0));
}); });
} }

View File

@ -29,18 +29,16 @@ void main() {
aReal: Value(3.0), aReal: Value(3.0),
aDateTime: Value(DateTime.now().add(Duration(days: 3))))); aDateTime: Value(DateTime.now().add(Duration(days: 3)))));
// Test count // Test count
expect(db.managers.tableWithEveryColumnType.all().count(), completion(3)); expect(db.managers.tableWithEveryColumnType.count(), completion(3));
// Test get // Test get
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.all()
.get() .get()
.then((value) => value.length), .then((value) => value.length),
completion(3)); completion(3));
// Test getSingle with limit // Test getSingle with limit
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.all()
.limit(1, offset: 1) .limit(1, offset: 1)
.getSingle() .getSingle()
.then((value) => value.id), .then((value) => value.id),