add tests, fix custom type

This commit is contained in:
Moshe Dicker 2024-04-16 14:48:43 -04:00
parent 14335b5d3d
commit cdd11c8e40
5 changed files with 309 additions and 235 deletions

View File

@ -9,35 +9,44 @@ class ColumnFilters<T extends Object> {
/// Use an extention to add more filters to any column type
///
/// ```dart
/// extension on FilterComposer<DateTime>{
/// FitlerBuilder after2000() => isAfter(DateTime(2000));
/// extension on ColumnFilters<DateTime>{
/// ComposableFilter after2000() => isAfter(DateTime(2000));
///}
/// ```
const ColumnFilters(this.column);
const ColumnFilters(this.column, [this.inverted = false]);
/// Column that this [ColumnFilters] wraps
final Expression<T> column;
/// Create a filter that checks if the column is null.
ComposableFilter isNull() => ComposableFilter(column.isNull());
/// If true, all filters will be inverted
final bool inverted;
/// Create a filter that checks if the column is not null.
ComposableFilter isNotNull() => ComposableFilter(column.isNotNull());
/// 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));
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));
/// Create a filter that checks if the column is not in a list of values.
ComposableFilter isNotIn(Iterable<T> values) =>
ComposableFilter(column.isNotIn(values));
ComposableFilter(column.isIn(values), inverted: inverted);
/// Shortcut for [equals]
ComposableFilter call(T value) => ComposableFilter(column.equals(value));
ComposableFilter call(T value) => equals(value);
}
enum _StringFilterTypes { contains, startsWith, endsWith }
@ -76,165 +85,191 @@ extension StringFilters<T extends String> on ColumnFilters<String> {
}
/// Create a filter to check if the this text column contains a substring
/// {@template drift.manager.likeCaseSensitivity}
///
/// 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.
/// {@endtemplate}
ComposableFilter contains(T value, {bool caseInsensitive = true}) {
return ComposableFilter(
_buildExpression(_StringFilterTypes.contains, value, caseInsensitive));
_buildExpression(_StringFilterTypes.contains, value, caseInsensitive),
inverted: inverted);
}
/// Create a filter to check if the this text column starts with a substring
/// {@macro drift.manager.likeCaseSensitivity}
///
/// 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));
return ComposableFilter(
_buildExpression(_StringFilterTypes.startsWith, value, caseInsensitive),
inverted: inverted);
}
/// Create a filter to check if the this text column ends with a substring
/// {@macro drift.manager.likeCaseSensitivity}
///
/// 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));
_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));
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));
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));
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));
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));
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));
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));
/// Create a filter to check if the column is not between two values
/// This is done inclusively, so the column will not be equal to the lower or higher value
/// E.G isNotBetween(1, 3) will return false for 1, 2, and 3
ComposableFilter isNotBetween(T lower, T higher) =>
isBetween(lower, higher)._invert();
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));
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));
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));
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));
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));
/// Create a filter to check if the column is not between two values
/// This is done inclusively, so the column will not be equal to the lower or higher value
/// E.G isNotBetween(1, 3) will return false for 1, 2, and 3
ComposableFilter isNotBetween(T lower, T higher) =>
isBetween(lower, higher)._invert();
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));
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));
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));
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));
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));
/// Create a filter to check if the column is not between 2 [DateTime]s
/// This is done inclusively, so the column will not be equal to the lower or higher value
/// E.G isNotBetween(1, 3) will return false for 1, 2, and 3
ComposableFilter isNotBetween(T lower, T higher) =>
isBetween(lower, higher)._invert();
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
class ColumnWithTypeConverterFilters<CUSTOM, T extends Object> {
// [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);
const ColumnWithTypeConverterFilters(this.column, [this.inverted = false]);
/// If true, all filters will be inverted
final bool inverted;
/// Column that this [ColumnWithTypeConverterFilters] wraps
final GeneratedColumnWithTypeConverter<CUSTOM, T> column;
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());
ComposableFilter isNull() =>
ComposableFilter(column.isNull(), inverted: inverted);
/// Create a filter that checks if the column is not null.
ComposableFilter isNotNull() => ComposableFilter(column.isNotNull());
/// 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(CUSTOM value) =>
ComposableFilter(column.equalsValue(value));
ComposableFilter equals(CustomTypeNonNullable value) {
return ComposableFilter(column.equals(_customTypeToSql(value)),
inverted: inverted);
}
/// Shortcut for [equals]
ComposableFilter call(CUSTOM value) =>
ComposableFilter(column.equalsValue(value));
ComposableFilter call(CustomTypeNonNullable value) => equals(value);
/// Create a filter that checks if the column is in a list of values.
ComposableFilter isIn(Iterable<CUSTOM> values) =>
ComposableFilter(column.isInValues(values));
/// Create a filter that checks if the column is not in a list of values.
ComposableFilter isNotIn(Iterable<CUSTOM> values) =>
ComposableFilter(column.isNotInValues(values));
ComposableFilter isIn(Iterable<CustomTypeNonNullable> values) =>
ComposableFilter(column.isIn(values.map(_customTypeToSql).toList()),
inverted: inverted);
}
/// This class is wrapper on the expression class
@ -247,10 +282,13 @@ class ComposableFilter extends HasJoinBuilders {
final Set<JoinBuilder> joinBuilders;
/// The expression that will be applied to the query
final Expression<bool> expression;
late final Expression<bool> expression;
/// Create a new [ComposableFilter] for a column without any joins
ComposableFilter(this.expression) : joinBuilders = {};
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);
@ -270,14 +308,6 @@ class ComposableFilter extends HasJoinBuilders {
joinBuilders.union(other.joinBuilders),
);
}
/// Returns a copy of this filter with the expression reversed
ComposableFilter _invert() {
return ComposableFilter._(
expression.not(),
joinBuilders,
);
}
}
/// The class that orchestrates the composition of filtering

View File

@ -2139,12 +2139,13 @@ class $ConfigTableFilterComposer
ColumnFilters<String> get configKey => ColumnFilters($table.configKey);
ColumnFilters<DriftAny> get configValue => ColumnFilters($table.configValue);
ColumnFilters<int> get syncStateValue => ColumnFilters($table.syncState);
ColumnWithTypeConverterFilters<SyncType?, int> get syncState =>
ColumnWithTypeConverterFilters<SyncType?, SyncType, int> get syncState =>
ColumnWithTypeConverterFilters($table.syncState);
ColumnFilters<int> get syncStateImplicitValue =>
ColumnFilters($table.syncStateImplicit);
ColumnWithTypeConverterFilters<SyncType?, int> get syncStateImplicit =>
ColumnWithTypeConverterFilters($table.syncStateImplicit);
ColumnWithTypeConverterFilters<SyncType?, SyncType, int>
get syncStateImplicit =>
ColumnWithTypeConverterFilters($table.syncStateImplicit);
}
class $ConfigTableOrderingComposer

View File

@ -2502,12 +2502,12 @@ class $$CategoriesTableFilterComposer
extends FilterComposer<_$TodoDb, $CategoriesTable> {
$$CategoriesTableFilterComposer(super.db, super.table);
ColumnFilters<int> get idValue => ColumnFilters($table.id);
ColumnWithTypeConverterFilters<RowId, int> get id =>
ColumnWithTypeConverterFilters<RowId, RowId, int> get id =>
ColumnWithTypeConverterFilters($table.id);
ColumnFilters<String> get description => ColumnFilters($table.description);
ColumnFilters<int> get priorityValue => ColumnFilters($table.priority);
ColumnWithTypeConverterFilters<CategoryPriority, int> get priority =>
ColumnWithTypeConverterFilters($table.priority);
ColumnWithTypeConverterFilters<CategoryPriority, CategoryPriority, int>
get priority => ColumnWithTypeConverterFilters($table.priority);
ColumnFilters<String> get descriptionInUpperCase =>
ColumnFilters($table.descriptionInUpperCase);
ComposableFilter todosTableRefs(
@ -2600,7 +2600,7 @@ class $$TodosTableTableFilterComposer
extends FilterComposer<_$TodoDb, $TodosTableTable> {
$$TodosTableTableFilterComposer(super.db, super.table);
ColumnFilters<int> get idValue => ColumnFilters($table.id);
ColumnWithTypeConverterFilters<RowId, int> get id =>
ColumnWithTypeConverterFilters<RowId, RowId, int> get id =>
ColumnWithTypeConverterFilters($table.id);
ColumnFilters<String> get title => ColumnFilters($table.title);
ColumnFilters<String> get content => ColumnFilters($table.content);
@ -2620,7 +2620,7 @@ class $$TodosTableTableFilterComposer
}
ColumnFilters<String> get statusValue => ColumnFilters($table.status);
ColumnWithTypeConverterFilters<TodoStatus?, String> get status =>
ColumnWithTypeConverterFilters<TodoStatus?, TodoStatus, String> get status =>
ColumnWithTypeConverterFilters($table.status);
}
@ -2731,7 +2731,7 @@ class $$TodosTableTableTableManager extends RootTableManager<
class $$UsersTableFilterComposer extends FilterComposer<_$TodoDb, $UsersTable> {
$$UsersTableFilterComposer(super.db, super.table);
ColumnFilters<int> get idValue => ColumnFilters($table.id);
ColumnWithTypeConverterFilters<RowId, int> get id =>
ColumnWithTypeConverterFilters<RowId, RowId, int> get id =>
ColumnWithTypeConverterFilters($table.id);
ColumnFilters<String> get name => ColumnFilters($table.name);
ColumnFilters<bool> get isAwesome => ColumnFilters($table.isAwesome);
@ -2907,8 +2907,8 @@ class $$PureDefaultsTableFilterComposer
extends FilterComposer<_$TodoDb, $PureDefaultsTable> {
$$PureDefaultsTableFilterComposer(super.db, super.table);
ColumnFilters<String> get txtValue => ColumnFilters($table.txt);
ColumnWithTypeConverterFilters<MyCustomObject?, String> get txt =>
ColumnWithTypeConverterFilters($table.txt);
ColumnWithTypeConverterFilters<MyCustomObject?, MyCustomObject, String>
get txt => ColumnWithTypeConverterFilters($table.txt);
}
class $$PureDefaultsTableOrderingComposer
@ -3049,7 +3049,7 @@ class $$TableWithEveryColumnTypeTableFilterComposer
extends FilterComposer<_$TodoDb, $TableWithEveryColumnTypeTable> {
$$TableWithEveryColumnTypeTableFilterComposer(super.db, super.table);
ColumnFilters<int> get idValue => ColumnFilters($table.id);
ColumnWithTypeConverterFilters<RowId, int> get id =>
ColumnWithTypeConverterFilters<RowId, RowId, int> get id =>
ColumnWithTypeConverterFilters($table.id);
ColumnFilters<bool> get aBool => ColumnFilters($table.aBool);
ColumnFilters<DateTime> get aDateTime => ColumnFilters($table.aDateTime);
@ -3059,11 +3059,11 @@ class $$TableWithEveryColumnTypeTableFilterComposer
ColumnFilters<double> get aReal => ColumnFilters($table.aReal);
ColumnFilters<Uint8List> get aBlob => ColumnFilters($table.aBlob);
ColumnFilters<int> get anIntEnumValue => ColumnFilters($table.anIntEnum);
ColumnWithTypeConverterFilters<TodoStatus?, int> get anIntEnum =>
ColumnWithTypeConverterFilters<TodoStatus?, TodoStatus, int> get anIntEnum =>
ColumnWithTypeConverterFilters($table.anIntEnum);
ColumnFilters<String> get aTextWithConverterValue =>
ColumnFilters($table.aTextWithConverter);
ColumnWithTypeConverterFilters<MyCustomObject?, String>
ColumnWithTypeConverterFilters<MyCustomObject?, MyCustomObject, String>
get aTextWithConverter =>
ColumnWithTypeConverterFilters($table.aTextWithConverter);
}

View File

@ -5,134 +5,12 @@ import '../generated/todos.dart';
import '../test_utils/test_utils.dart';
void main() {
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
late TodoDb db;
setUp(() {
db = TodoDb(testInMemoryDatabase());
});
// // Create a dataset for the tests
// schoolId = await db.managers.categories.create((o) =>
// o(priority: Value(CategoryPriority.high), description: "School"));
// workId = await db.managers.categories.create(
// (o) => o(priority: Value(CategoryPriority.low), description: "Work"));
// homeId = await db.managers.categories.create((o) =>
// o(priority: Value(CategoryPriority.medium), description: "Home"));
// otherId = await db.managers.categories.create(
// (o) => o(priority: Value(CategoryPriority.high), description: "Other"));
// // School
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: Value("Get that math homework done"),
// title: Value("Math Homework"),
// category: Value(schoolId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1,seconds: 10)))));
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Finish that report",
// title: Value("Report"),
// category: Value(workId),
// anIntEnum: Value(TodoStatus.workInProgress),
// aDateTime: Value(DateTime.now().add(Duration(days: 2,seconds: 10)))));
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Get that english homework done",
// title: Value("English Homework"),
// category: Value(schoolId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1,seconds: 15)))));
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Finish that Book report",
// title: Value("Book Report"),
// category: Value(workId),
// anIntEnum: Value(TodoStatus.done),
// aDateTime: Value(DateTime.now().subtract(Duration(days: 2,seconds: 15)))));
// // Work
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "File those reports",
// title: Value("File Reports"),
// category: Value(workId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 20)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Clean the office",
// title: Value("Clean Office"),
// category: Value(workId),
// anIntEnum: Value(TodoStatus.workInProgress),
// aDateTime: Value(DateTime.now().add(Duration(days: 2, seconds: 20)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Nail that presentation",
// title: Value("Presentation"),
// category: Value(workId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 25)))));
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Take a break",
// title: Value("Break"),
// category: Value(workId),
// anIntEnum: Value(TodoStatus.done),
// aDateTime: Value(DateTime.now().subtract(Duration(days: 2, seconds: 25)))));
// // Work
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Take out the trash",
// title: Value("Trash"),
// category: Value(homeId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 30)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Mow the lawn",
// title: Value("Lawn"),
// category: Value(homeId),
// anIntEnum: Value(TodoStatus.workInProgress),
// aDateTime: Value(DateTime.now().add(Duration(days: 2, seconds: 30)))));
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Fix the sink",
// title: Value("Sink"),
// category: Value(homeId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 35)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Paint the walls",
// title: Value("Paint"),
// category: Value(homeId),
// anIntEnum: Value(TodoStatus.done),
// aDateTime: Value(DateTime.now().subtract(Duration(days: 2, seconds: 35)))));
// // Other
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Get groceries",
// title: Value("Groceries"),
// category: Value(otherId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 40)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Pick up the kids",
// title: Value("Kids"),
// category: Value(otherId),
// anIntEnum: Value(TodoStatus.workInProgress),
// aDateTime: Value(DateTime.now().add(Duration(days: 2, seconds: 40)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Take the dog for a walk",
// title: Value("Dog"),
// category: Value(otherId),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 45)))));
// // Items with no category
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Get Whiteboard",
// title: Value("Whiteboard"),
// anIntEnum: Value(TodoStatus.open),
// aDateTime: Value(DateTime.now().add(Duration(days: 1, seconds: 50)))););
// await db.managers.tableWithEveryColumnType.create((o) => o(
// aText: "Drink Water",
// title: Value("Water"),
// anIntEnum: Value(TodoStatus.workInProgress),
// aDateTime: Value(DateTime.now().add(Duration(days: 2, seconds: 50)))));
// });
tearDown(() => db.close());
test('manager - query generic', () async {
@ -162,6 +40,14 @@ void main() {
.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
@ -172,7 +58,7 @@ void main() {
// Not In
expect(
db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.isNotIn([3.0, 5.0]))
.filter((f) => f.aReal.not.isIn([3.0, 5.0]))
.count(),
completion(0));
@ -182,9 +68,10 @@ void main() {
.filter((f) => f.aReal.isNull())
.count(),
completion(1));
expect(
db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.isNotNull())
.filter((f) => f.aReal.not.isNull())
.count(),
completion(2));
});
@ -237,7 +124,7 @@ void main() {
completion(2));
expect(
db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.isNotBetween(3.0, 5.0))
.filter((f) => f.aReal.not.isBetween(3.0, 5.0))
.count(),
completion(0));
});
@ -351,7 +238,7 @@ void main() {
expect(
db.managers.tableWithEveryColumnType
.filter((f) =>
f.anInt64.isNotBetween(BigInt.from(3.0), BigInt.from(5.0)))
f.anInt64.not.isBetween(BigInt.from(3.0), BigInt.from(5.0)))
.count(),
completion(0));
});
@ -432,7 +319,7 @@ void main() {
completion(2));
expect(
db.managers.tableWithEveryColumnType
.filter((f) => f.aDateTime.isNotBetween(day1, day2))
.filter((f) => f.aDateTime.not.isBetween(day1, day2))
.count(),
completion(1));
});
@ -450,6 +337,8 @@ void main() {
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(
@ -463,20 +352,172 @@ void main() {
.count(),
completion(2));
// In
expect(
db.managers.tableWithEveryColumnType
.filter((f) =>
f.anIntEnum.isIn([TodoStatus.open, TodoStatus.workInProgress]))
.filter((f) => f.anIntEnum.not(TodoStatus.open))
.count(),
completion(3));
completion(2));
// Not In
// // 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.tableWithEveryColumnType
.filter((f) => f.anIntEnum
.isNotIn([TodoStatus.open, TodoStatus.workInProgress]))
db.managers.todosTable
.filter((f) => f.category(
(f) => f.id(RowId(schoolCategoryId)),
))
.count(),
completion(1));
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));
});
}

View File

@ -61,9 +61,11 @@ class _FilterWithConverterWriter extends _FilterWriter {
@override
void writeFilter(TextEmitter leaf) {
final nonNullableConverterType = converterType.replaceFirst("?", "");
leaf
..writeDriftRef("ColumnWithTypeConverterFilters")
..write("<$converterType,$type> get $filterName =>")
..write(
"<$converterType,$nonNullableConverterType,$type> get $filterName =>")
..writeDriftRef("ColumnWithTypeConverterFilters")
..writeln("(\$table.$fieldGetter);");
}