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 /// Use an extention to add more filters to any column type
/// ///
/// ```dart /// ```dart
/// extension on FilterComposer<DateTime>{ /// extension on ColumnFilters<DateTime>{
/// FitlerBuilder after2000() => isAfter(DateTime(2000)); /// ComposableFilter after2000() => isAfter(DateTime(2000));
///} ///}
/// ``` /// ```
const ColumnFilters(this.column); const ColumnFilters(this.column, [this.inverted = false]);
/// Column that this [ColumnFilters] wraps /// Column that this [ColumnFilters] wraps
final Expression<T> column; final Expression<T> column;
/// Create a filter that checks if the column is null. /// If true, all filters will be inverted
ComposableFilter isNull() => ComposableFilter(column.isNull()); final bool inverted;
/// Create a filter that checks if the column is not null. /// Returns a copy of these column filters where all the filters are inverted
ComposableFilter isNotNull() => ComposableFilter(column.isNotNull()); /// ```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. /// 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. /// Create a filter that checks if the column is in a list of values.
ComposableFilter isIn(Iterable<T> values) => ComposableFilter isIn(Iterable<T> values) =>
ComposableFilter(column.isIn(values)); ComposableFilter(column.isIn(values), inverted: inverted);
/// Create a filter that checks if the column is not in a list of values.
ComposableFilter isNotIn(Iterable<T> values) =>
ComposableFilter(column.isNotIn(values));
/// Shortcut for [equals] /// Shortcut for [equals]
ComposableFilter call(T value) => ComposableFilter(column.equals(value)); ComposableFilter call(T value) => equals(value);
} }
enum _StringFilterTypes { contains, startsWith, endsWith } 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 /// 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 /// Setting [caseInsensitive] to false will have no effect unless the database in configured to use
/// case sensitive like expressions. /// case sensitive like expressions.
/// ///
/// See https://www.sqlitetutorial.net/sqlite-like/ for more information on how /// See https://www.sqlitetutorial.net/sqlite-like/ for more information on how
/// to the like expression works. /// to the like expression works.
/// {@endtemplate}
ComposableFilter contains(T value, {bool caseInsensitive = true}) { ComposableFilter contains(T value, {bool caseInsensitive = true}) {
return ComposableFilter( 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 /// 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}) { ComposableFilter startsWith(T value, {bool caseInsensitive = true}) {
return ComposableFilter(_buildExpression( return ComposableFilter(
_StringFilterTypes.startsWith, value, caseInsensitive)); _buildExpression(_StringFilterTypes.startsWith, value, caseInsensitive),
inverted: inverted);
} }
/// Create a filter to check if the this text column ends with a substring /// 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}) { ComposableFilter endsWith(T value, {bool caseInsensitive = true}) {
return ComposableFilter( return ComposableFilter(
_buildExpression(_StringFilterTypes.endsWith, value, caseInsensitive)); _buildExpression(_StringFilterTypes.endsWith, value, caseInsensitive),
inverted: inverted);
} }
} }
/// Built in filters for bool columns /// Built in filters for bool columns
extension BoolFilters on ColumnFilters<bool> { extension BoolFilters on ColumnFilters<bool> {
/// Create a filter to check if the column is bigger than a value /// 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 /// 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 /// Built in filters for int/double columns
extension NumFilters<T extends num> on ColumnFilters<T> { extension NumFilters<T extends num> on ColumnFilters<T> {
/// Create a filter to check if the column is bigger than a value /// Create a filter to check if the column is bigger than a value
ComposableFilter isBiggerThan(T 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 /// Create a filter to check if the column is small than a value
ComposableFilter isSmallerThan(T 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 /// Create a filter to check if the column is bigger or equal to a value
ComposableFilter isBiggerOrEqualTo(T 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 /// Create a filter to check if the column is small or equal to a value
ComposableFilter isSmallerOrEqualTo(T 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 /// 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 /// 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 /// E.G isBetween(1, 3) will return true for 1, 2, and 3
ComposableFilter isBetween(T lower, T higher) => ComposableFilter isBetween(T lower, T higher) =>
ComposableFilter(column.isBetweenValues(lower, higher)); ComposableFilter(column.isBetweenValues(lower, higher),
inverted: inverted);
/// 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();
} }
/// Built in filters for BigInt columns /// Built in filters for BigInt columns
extension BigIntFilters<T extends BigInt> on ColumnFilters<T> { extension BigIntFilters<T extends BigInt> on ColumnFilters<T> {
/// Create a filter to check if the column is bigger than a value /// Create a filter to check if the column is bigger than a value
ComposableFilter isBiggerThan(T 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 /// Create a filter to check if the column is small than a value
ComposableFilter isSmallerThan(T 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 /// Create a filter to check if the column is bigger or equal to a value
ComposableFilter isBiggerOrEqualTo(T 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 /// Create a filter to check if the column is small or equal to a value
ComposableFilter isSmallerOrEqualTo(T 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 /// 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 /// 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 /// E.G isBetween(1, 3) will return true for 1, 2, and 3
ComposableFilter isBetween(T lower, T higher) => ComposableFilter isBetween(T lower, T higher) =>
ComposableFilter(column.isBetweenValues(lower, higher)); ComposableFilter(column.isBetweenValues(lower, higher),
inverted: inverted);
/// 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();
} }
/// Built in filters for DateTime columns /// Built in filters for DateTime columns
extension DateFilters<T extends DateTime> on ColumnFilters<T> { extension DateFilters<T extends DateTime> on ColumnFilters<T> {
/// Create a filter to check if the column is after a [DateTime] /// Create a filter to check if the column is after a [DateTime]
ComposableFilter isAfter(T value) => 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] /// Create a filter to check if the column is before a [DateTime]
ComposableFilter isBefore(T value) => 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] /// Create a filter to check if the column is on or after a [DateTime]
ComposableFilter isAfterOrOn(T value) => 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] /// Create a filter to check if the column is before or on a [DateTime]
ComposableFilter isBeforeOrOn(T value) => 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 /// 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 /// 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 /// E.G isBetween(1, 3) will return true for 1, 2, and 3
ComposableFilter isBetween(T lower, T higher) => ComposableFilter isBetween(T lower, T higher) =>
ComposableFilter(column.isBetweenValues(lower, higher)); ComposableFilter(column.isBetweenValues(lower, higher),
inverted: inverted);
/// 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();
} }
/// Defines a class which is used to wrap a column with a type converter to only expose filter functions /// 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\ /// 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 /// 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. /// 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. /// Get the actual value from the custom type
ComposableFilter isNotNull() => ComposableFilter(column.isNotNull()); 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. /// Create a filter that checks if the column equals a value.
ComposableFilter equals(CUSTOM value) => ComposableFilter equals(CustomTypeNonNullable value) {
ComposableFilter(column.equalsValue(value)); return ComposableFilter(column.equals(_customTypeToSql(value)),
inverted: inverted);
}
/// Shortcut for [equals] /// Shortcut for [equals]
ComposableFilter call(CUSTOM value) => ComposableFilter call(CustomTypeNonNullable value) => equals(value);
ComposableFilter(column.equalsValue(value));
/// Create a filter that checks if the column is in a list of values. /// Create a filter that checks if the column is in a list of values.
ComposableFilter isIn(Iterable<CUSTOM> values) => ComposableFilter isIn(Iterable<CustomTypeNonNullable> values) =>
ComposableFilter(column.isInValues(values)); ComposableFilter(column.isIn(values.map(_customTypeToSql).toList()),
inverted: inverted);
/// Create a filter that checks if the column is not in a list of values.
ComposableFilter isNotIn(Iterable<CUSTOM> values) =>
ComposableFilter(column.isNotInValues(values));
} }
/// This class is wrapper on the expression class /// This class is wrapper on the expression class
@ -247,10 +282,13 @@ class ComposableFilter extends HasJoinBuilders {
final Set<JoinBuilder> joinBuilders; final Set<JoinBuilder> joinBuilders;
/// The expression that will be applied to the query /// 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 /// 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 /// Create a new [ComposableFilter] for a column with joins
ComposableFilter._(this.expression, this.joinBuilders); ComposableFilter._(this.expression, this.joinBuilders);
@ -270,14 +308,6 @@ class ComposableFilter extends HasJoinBuilders {
joinBuilders.union(other.joinBuilders), 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 /// The class that orchestrates the composition of filtering

View File

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

View File

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

View File

@ -5,134 +5,12 @@ import '../generated/todos.dart';
import '../test_utils/test_utils.dart'; import '../test_utils/test_utils.dart';
void main() { void main() {
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
late TodoDb db; late TodoDb db;
setUp(() { setUp(() {
db = TodoDb(testInMemoryDatabase()); 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()); tearDown(() => db.close());
test('manager - query generic', () async { test('manager - query generic', () async {
@ -162,6 +40,14 @@ void main() {
.filter((f) => f.aReal(3.0)) .filter((f) => f.aReal(3.0))
.count(), .count(),
completion(1)); completion(1));
// Not Equals - Exclude null (Default behavior)
expect(
db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.not.equals(5.0))
.count(),
completion(1));
// In // In
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
@ -172,7 +58,7 @@ void main() {
// Not In // Not In
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.isNotIn([3.0, 5.0])) .filter((f) => f.aReal.not.isIn([3.0, 5.0]))
.count(), .count(),
completion(0)); completion(0));
@ -182,9 +68,10 @@ void main() {
.filter((f) => f.aReal.isNull()) .filter((f) => f.aReal.isNull())
.count(), .count(),
completion(1)); completion(1));
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.isNotNull()) .filter((f) => f.aReal.not.isNull())
.count(), .count(),
completion(2)); completion(2));
}); });
@ -237,7 +124,7 @@ void main() {
completion(2)); completion(2));
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.filter((f) => f.aReal.isNotBetween(3.0, 5.0)) .filter((f) => f.aReal.not.isBetween(3.0, 5.0))
.count(), .count(),
completion(0)); completion(0));
}); });
@ -351,7 +238,7 @@ void main() {
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.filter((f) => .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(), .count(),
completion(0)); completion(0));
}); });
@ -432,7 +319,7 @@ void main() {
completion(2)); completion(2));
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.filter((f) => f.aDateTime.isNotBetween(day1, day2)) .filter((f) => f.aDateTime.not.isBetween(day1, day2))
.count(), .count(),
completion(1)); completion(1));
}); });
@ -450,6 +337,8 @@ void main() {
await db.managers.tableWithEveryColumnType.create((o) => o( await db.managers.tableWithEveryColumnType.create((o) => o(
aText: Value("Get that math homework done"), aText: Value("Get that math homework done"),
anIntEnum: Value(TodoStatus.done))); anIntEnum: Value(TodoStatus.done)));
await db.managers.tableWithEveryColumnType
.create((o) => o(aText: Value("Get that math homework done")));
// Equals // Equals
expect( expect(
@ -463,20 +352,172 @@ void main() {
.count(), .count(),
completion(2)); completion(2));
// In
expect( expect(
db.managers.tableWithEveryColumnType db.managers.tableWithEveryColumnType
.filter((f) => .filter((f) => f.anIntEnum.not(TodoStatus.open))
f.anIntEnum.isIn([TodoStatus.open, TodoStatus.workInProgress]))
.count(), .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( expect(
db.managers.tableWithEveryColumnType db.managers.todosTable
.filter((f) => f.anIntEnum .filter((f) => f.category(
.isNotIn([TodoStatus.open, TodoStatus.workInProgress])) (f) => f.id(RowId(schoolCategoryId)),
))
.count(), .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 @override
void writeFilter(TextEmitter leaf) { void writeFilter(TextEmitter leaf) {
final nonNullableConverterType = converterType.replaceFirst("?", "");
leaf leaf
..writeDriftRef("ColumnWithTypeConverterFilters") ..writeDriftRef("ColumnWithTypeConverterFilters")
..write("<$converterType,$type> get $filterName =>") ..write(
"<$converterType,$nonNullableConverterType,$type> get $filterName =>")
..writeDriftRef("ColumnWithTypeConverterFilters") ..writeDriftRef("ColumnWithTypeConverterFilters")
..writeln("(\$table.$fieldGetter);"); ..writeln("(\$table.$fieldGetter);");
} }