mirror of https://github.com/AMT-Cheif/drift.git
Use custom types for comparisons
This commit is contained in:
parent
ad856314c2
commit
615a1d7ad8
|
@ -1,3 +1,7 @@
|
|||
## 2.15.0-dev
|
||||
|
||||
- Methods in the query builder API now respect custom types.
|
||||
|
||||
## 2.14.1
|
||||
|
||||
- Fix `WasmProbeResult.open` ignoring the `ìnitializeDatabase` callback.
|
||||
|
|
|
@ -11,7 +11,7 @@ extension ComparableExpr<DT extends Comparable<dynamic>> on Expression<DT> {
|
|||
/// Returns an expression that is true if this expression is strictly bigger
|
||||
/// than the other value.
|
||||
Expression<bool> isBiggerThanValue(DT other) {
|
||||
return isBiggerThan(Variable(other));
|
||||
return isBiggerThan(variable(other));
|
||||
}
|
||||
|
||||
/// Returns an expression that is true if this expression is bigger than or
|
||||
|
@ -23,7 +23,7 @@ extension ComparableExpr<DT extends Comparable<dynamic>> on Expression<DT> {
|
|||
/// Returns an expression that is true if this expression is bigger than or
|
||||
/// equal to he other value.
|
||||
Expression<bool> isBiggerOrEqualValue(DT other) {
|
||||
return isBiggerOrEqual(Variable(other));
|
||||
return isBiggerOrEqual(variable(other));
|
||||
}
|
||||
|
||||
/// Returns an expression that is true if this expression is strictly smaller
|
||||
|
@ -35,7 +35,7 @@ extension ComparableExpr<DT extends Comparable<dynamic>> on Expression<DT> {
|
|||
/// Returns an expression that is true if this expression is strictly smaller
|
||||
/// than the other value.
|
||||
Expression<bool> isSmallerThanValue(DT other) =>
|
||||
isSmallerThan(Variable(other));
|
||||
isSmallerThan(variable(other));
|
||||
|
||||
/// Returns an expression that is true if this expression is smaller than or
|
||||
/// equal to he other expression.
|
||||
|
@ -46,7 +46,7 @@ extension ComparableExpr<DT extends Comparable<dynamic>> on Expression<DT> {
|
|||
/// Returns an expression that is true if this expression is smaller than or
|
||||
/// equal to he other value.
|
||||
Expression<bool> isSmallerOrEqualValue(DT other) {
|
||||
return isSmallerOrEqual(Variable(other));
|
||||
return isSmallerOrEqual(variable(other));
|
||||
}
|
||||
|
||||
/// Returns an expression evaluating to true if this expression is between
|
||||
|
@ -67,8 +67,8 @@ extension ComparableExpr<DT extends Comparable<dynamic>> on Expression<DT> {
|
|||
Expression<bool> isBetweenValues(DT lower, DT higher, {bool not = false}) {
|
||||
return _BetweenExpression(
|
||||
target: this,
|
||||
lower: Variable<DT>(lower),
|
||||
higher: Variable<DT>(higher),
|
||||
lower: variable(lower),
|
||||
higher: variable(higher),
|
||||
not: not,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,17 +24,27 @@ class CustomExpression<D extends Object> extends Expression<D> {
|
|||
@override
|
||||
final Precedence precedence;
|
||||
|
||||
final CustomSqlType<D>? _customSqlType;
|
||||
|
||||
/// Constructs a custom expression by providing the raw sql [content].
|
||||
const CustomExpression(this.content,
|
||||
{this.watchedTables = const [], this.precedence = Precedence.unknown})
|
||||
: _dialectSpecificContent = null;
|
||||
const CustomExpression(
|
||||
this.content, {
|
||||
this.watchedTables = const [],
|
||||
this.precedence = Precedence.unknown,
|
||||
CustomSqlType<D>? customType,
|
||||
}) : _dialectSpecificContent = null,
|
||||
_customSqlType = customType;
|
||||
|
||||
/// Constructs a custom expression providing the raw SQL in [content] depending
|
||||
/// on the SQL dialect when this expression is built.
|
||||
const CustomExpression.dialectSpecific(Map<SqlDialect, String> content,
|
||||
{this.watchedTables = const [], this.precedence = Precedence.unknown})
|
||||
: _dialectSpecificContent = content,
|
||||
content = '';
|
||||
const CustomExpression.dialectSpecific(
|
||||
Map<SqlDialect, String> content, {
|
||||
this.watchedTables = const [],
|
||||
this.precedence = Precedence.unknown,
|
||||
CustomSqlType<D>? customType,
|
||||
}) : _dialectSpecificContent = content,
|
||||
content = '',
|
||||
_customSqlType = customType;
|
||||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
|
@ -53,6 +63,9 @@ class CustomExpression<D extends Object> extends Expression<D> {
|
|||
@override
|
||||
int get hashCode => content.hashCode * 3;
|
||||
|
||||
@override
|
||||
BaseSqlType<D> get driftSqlType => _customSqlType ?? super.driftSqlType;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other.runtimeType == runtimeType &&
|
||||
|
|
|
@ -21,6 +21,7 @@ const Expression<DateTime> currentDate = _DependingOnDateTimeExpression(
|
|||
'strftime',
|
||||
[Constant('%s'), _currentDateLiteral],
|
||||
),
|
||||
null,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ abstract class Expression<D extends Object> implements FunctionParameter {
|
|||
/// nullable values and translates to a direct `=` comparison in SQL.
|
||||
/// To compare this column to `null`, use [isValue].
|
||||
Expression<bool> equals(D compare) =>
|
||||
_Comparison.equal(this, Variable<D>(compare));
|
||||
_Comparison.equal(this, variable(compare));
|
||||
|
||||
/// Compares the value of this column to [compare] or `null`.
|
||||
///
|
||||
|
@ -81,8 +81,8 @@ abstract class Expression<D extends Object> implements FunctionParameter {
|
|||
/// in sql, use [cast].
|
||||
///
|
||||
/// This method is used internally by drift.
|
||||
Expression<D2> dartCast<D2 extends Object>() {
|
||||
return _DartCastExpression<D, D2>(this);
|
||||
Expression<D2> dartCast<D2 extends Object>({CustomSqlType<D2>? customType}) {
|
||||
return _DartCastExpression<D, D2>(this, customType);
|
||||
}
|
||||
|
||||
/// Generates a `CAST(expression AS TYPE)` expression.
|
||||
|
@ -106,7 +106,7 @@ abstract class Expression<D extends Object> implements FunctionParameter {
|
|||
/// Dart. When this expression and [value] are both non-null, this is the same
|
||||
/// as [equals]. Two `NULL` values are considered equal as well.
|
||||
Expression<bool> isValue(D value) {
|
||||
return isExp(Variable<D>(value));
|
||||
return isExp(variable(value));
|
||||
}
|
||||
|
||||
/// Generates an `IS NOT` expression in SQL, comparing this expression with
|
||||
|
@ -114,7 +114,7 @@ abstract class Expression<D extends Object> implements FunctionParameter {
|
|||
///
|
||||
/// This the inverse of [isValue].
|
||||
Expression<bool> isNotValue(D value) {
|
||||
return isNotExp(Variable<D>(value));
|
||||
return isNotExp(variable(value));
|
||||
}
|
||||
|
||||
/// Expression that is true if the inner expression resolves to a null value.
|
||||
|
@ -147,13 +147,13 @@ abstract class Expression<D extends Object> implements FunctionParameter {
|
|||
/// An expression that is true if `this` resolves to any of the values in
|
||||
/// [values].
|
||||
Expression<bool> isIn(Iterable<D> values) {
|
||||
return isInExp([for (final value in values) Variable<D>(value)]);
|
||||
return isInExp([for (final value in values) variable(value)]);
|
||||
}
|
||||
|
||||
/// An expression that is true if `this` does not resolve to any of the values
|
||||
/// in [values].
|
||||
Expression<bool> isNotIn(Iterable<D> values) {
|
||||
return isNotInExp([for (final value in values) Variable<D>(value)]);
|
||||
return isNotInExp([for (final value in values) variable(value)]);
|
||||
}
|
||||
|
||||
/// An expression that evaluates to `true` if this expression resolves to a
|
||||
|
@ -478,8 +478,12 @@ class _UnaryMinus<DT extends Object> extends Expression<DT> {
|
|||
class _DartCastExpression<D1 extends Object, D2 extends Object>
|
||||
extends Expression<D2> {
|
||||
final Expression<D1> inner;
|
||||
final CustomSqlType<D2>? _customSqlType;
|
||||
|
||||
const _DartCastExpression(this.inner);
|
||||
const _DartCastExpression(this.inner, this._customSqlType);
|
||||
|
||||
@override
|
||||
BaseSqlType<D2> get driftSqlType => _customSqlType ?? super.driftSqlType;
|
||||
|
||||
@override
|
||||
Precedence get precedence => inner.precedence;
|
||||
|
|
|
@ -3,6 +3,7 @@ library;
|
|||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../types/mapping.dart';
|
||||
import 'query_builder.dart';
|
||||
|
||||
/// Internal utilities for building queries that aren't exported.
|
||||
|
@ -46,3 +47,15 @@ extension WriteDefinition on GenerationContext {
|
|||
return sql.values.first; // Fallback
|
||||
}
|
||||
}
|
||||
|
||||
/// Utilities to derive other expressions with a type compatible to `this`
|
||||
/// expression.
|
||||
extension WithTypes<T extends Object> on Expression<T> {
|
||||
/// Creates a variable with a matching [driftSqlType].
|
||||
Variable<T> variable(T? value) {
|
||||
return switch (driftSqlType) {
|
||||
CustomSqlType<T> custom => Variable(value, custom),
|
||||
_ => Variable(value),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ class GeneratedColumn<T extends Object> extends Column<T> {
|
|||
}
|
||||
|
||||
Variable _evaluateClientDefault() {
|
||||
return Variable<T>(clientDefault!());
|
||||
return variable(clientDefault!());
|
||||
}
|
||||
|
||||
/// A value for [additionalChecks] validating allowed text lengths.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: drift
|
||||
description: Drift is a reactive library to store relational data in Dart and Flutter applications.
|
||||
version: 2.14.1
|
||||
version: 2.15.0-dev
|
||||
repository: https://github.com/simolus3/drift
|
||||
homepage: https://drift.simonbinder.eu/
|
||||
issue_tracker: https://github.com/simolus3/drift/issues
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../../test_utils/test_utils.dart';
|
||||
|
||||
void main() {
|
||||
const a = CustomExpression('a',
|
||||
customType: _NegatedIntType(), precedence: Precedence.primary);
|
||||
|
||||
test('equals', () {
|
||||
expect(a.equals(123), generates('a = ?', [-123]));
|
||||
});
|
||||
|
||||
test('is', () {
|
||||
expect(a.isValue(42), generates('a IS ?', [-42]));
|
||||
expect(a.isNotValue(42), generates('a IS NOT ?', [-42]));
|
||||
|
||||
expect(a.isIn([1, 2, 3]), generates('a IN (?, ?, ?)', [-1, -2, -3]));
|
||||
expect(a.isNotIn([1, 2, 3]), generates('a NOT IN (?, ?, ?)', [-1, -2, -3]));
|
||||
});
|
||||
|
||||
test('comparison', () {
|
||||
expect(a.isSmallerThanValue(42), generates('a < ?', [-42]));
|
||||
expect(a.isSmallerOrEqualValue(42), generates('a <= ?', [-42]));
|
||||
|
||||
expect(a.isBiggerThanValue(42), generates('a > ?', [-42]));
|
||||
expect(a.isBiggerOrEqualValue(42), generates('a >= ?', [-42]));
|
||||
|
||||
expect(
|
||||
a.isBetweenValues(12, 24), generates('a BETWEEN ? AND ?', [-12, -24]));
|
||||
expect(a.isBetweenValues(12, 24, not: true),
|
||||
generates('a NOT BETWEEN ? AND ?', [-12, -24]));
|
||||
});
|
||||
|
||||
test('cast', () {
|
||||
expect(Variable.withInt(10).cast<int>(const _NegatedIntType()),
|
||||
generates('CAST(? AS custom_int)', [10]));
|
||||
});
|
||||
|
||||
test('dartCast', () {
|
||||
final exp =
|
||||
Variable.withInt(10).dartCast<int>(customType: const _NegatedIntType());
|
||||
|
||||
expect(exp, generates('?', [10]));
|
||||
expect(exp.driftSqlType, isA<_NegatedIntType>());
|
||||
});
|
||||
}
|
||||
|
||||
class _NegatedIntType implements CustomSqlType<int> {
|
||||
const _NegatedIntType();
|
||||
|
||||
@override
|
||||
String mapToSqlLiteral(int dartValue) {
|
||||
return '-$dartValue';
|
||||
}
|
||||
|
||||
@override
|
||||
Object mapToSqlParameter(int dartValue) {
|
||||
return -dartValue;
|
||||
}
|
||||
|
||||
@override
|
||||
int read(Object fromSql) {
|
||||
return -(fromSql as int);
|
||||
}
|
||||
|
||||
@override
|
||||
String sqlTypeName(GenerationContext context) {
|
||||
return 'custom_int';
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ dependencies:
|
|||
io: ^1.0.3
|
||||
|
||||
# Drift-specific analysis and apis
|
||||
drift: '>=2.14.0 <2.15.0'
|
||||
drift: '>=2.15.0 <2.16.0'
|
||||
sqlite3: '>=0.1.6 <3.0.0'
|
||||
sqlparser: '^0.33.0'
|
||||
|
||||
|
|
Loading…
Reference in New Issue