mirror of https://github.com/AMT-Cheif/drift.git
add tests, fix custom type
This commit is contained in:
parent
14335b5d3d
commit
cdd11c8e40
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue