Use extensions methods for Dart query api (#195)

This commit is contained in:
Simon Binder 2019-11-06 12:16:55 +01:00
parent e3d3bcd99e
commit 77cc6b2d88
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
15 changed files with 77 additions and 66 deletions

View File

@ -116,7 +116,7 @@ class Database extends _$Database {
return transaction(() async { return transaction(() async {
final id = user.id; final id = user.id;
await (delete(friendships) await (delete(friendships)
..where((f) => or(f.firstUser.equals(id), f.secondUser.equals(id)))) ..where((f) => f.firstUser.equals(id) | f.secondUser.equals(id)))
.go(); .go();
if (fail) { if (fail) {

View File

@ -5,36 +5,24 @@ part of 'dsl.dart';
abstract class Column<T, S extends SqlType<T>> extends Expression<T, S> {} abstract class Column<T, S extends SqlType<T>> extends Expression<T, S> {}
/// A column that stores int values. /// A column that stores int values.
abstract class IntColumn extends Column<int, IntType> implements IntExpression { abstract class IntColumn extends Column<int, IntType> {}
}
/// A column that stores boolean values. Booleans will be stored as an integer /// A column that stores boolean values. Booleans will be stored as an integer
/// that can either be 0 (false) or 1 (true). /// that can either be 0 (false) or 1 (true).
abstract class BoolColumn extends Column<bool, BoolType> {} abstract class BoolColumn extends Column<bool, BoolType> {}
/// A column that stores text. /// A column that stores text.
abstract class TextColumn extends Column<String, StringType> { abstract class TextColumn extends Column<String, StringType> {}
/// Whether this column matches the given pattern. For details on what patters
/// are valid and how they are interpreted, check out
/// [this tutorial](http://www.sqlitetutorial.net/sqlite-like/).
Expression<bool, BoolType> like(String regex);
/// Uses the given [collate] sequence when comparing this column to other
/// values.
Expression<String, StringType> collate(Collate collate);
}
/// A column that stores a [DateTime]. Times will be stored as unix timestamp /// A column that stores a [DateTime]. Times will be stored as unix timestamp
/// and will thus have a second accuracy. /// and will thus have a second accuracy.
abstract class DateTimeColumn extends Column<DateTime, DateTimeType> abstract class DateTimeColumn extends Column<DateTime, DateTimeType> {}
implements DateTimeExpression {}
/// A column that stores arbitrary blobs of data as a [Uint8List]. /// A column that stores arbitrary blobs of data as a [Uint8List].
abstract class BlobColumn extends Column<Uint8List, BlobType> {} abstract class BlobColumn extends Column<Uint8List, BlobType> {}
/// A column that stores floating point numeric values. /// A column that stores floating point numeric values.
abstract class RealColumn extends Column<double, RealType> abstract class RealColumn extends Column<double, RealType> {}
implements DoubleExpression {}
/// A column builder is used to specify which columns should appear in a table. /// A column builder is used to specify which columns should appear in a table.
/// All of the methods defined in this class and its subclasses are not meant to /// All of the methods defined in this class and its subclasses are not meant to
@ -94,9 +82,10 @@ class ColumnBuilder<
/// has been specified. /// has been specified.
/// ///
/// Note: Unless most other methods used to declare tables, the parameter /// Note: Unless most other methods used to declare tables, the parameter
/// [e] which denotes the default expression, doesn't have to be constant. /// [e] which denotes the default expression, doesn't have to be a Dart
/// Particularly, you can use methods like [and], [or] and [not] to form /// constant.
/// expressions here. /// Particularly, you can use operators like those defined in
/// [BooleanExpressionOperators] to form expressions here.
/// ///
/// If you need a column that just stores a static default value, you could /// If you need a column that just stores a static default value, you could
/// use this method with a [Constant]: /// use this method with a [Constant]:

View File

@ -470,6 +470,7 @@ abstract class GeneratedDatabase extends DatabaseConnectionUser
/// A [Type] can't be sent across isolates. Instances of this class shouldn't /// A [Type] can't be sent across isolates. Instances of this class shouldn't
/// be sent over isolates either, so let's keep a reference to a [Type] that /// be sent over isolates either, so let's keep a reference to a [Type] that
/// definitely prohibits this. /// definitely prohibits this.
// ignore: unused_field
final Type _$dontSendThisOverIsolates = Null; final Type _$dontSendThisOverIsolates = Null;
/// Used by generated code /// Used by generated code

View File

@ -1,19 +1,45 @@
part of '../query_builder.dart'; part of '../query_builder.dart';
/// Returns an expression that is true iff both [a] and [b] are true. /// Returns an expression that is true iff both [a] and [b] are true.
///
/// This is now deprecated. Instead of `and(a, b)`, use `a & b`.
@Deprecated('Use the operator on BooleanExpressionOperators instead')
Expression<bool, BoolType> and( Expression<bool, BoolType> and(
Expression<bool, BoolType> a, Expression<bool, BoolType> b) => Expression<bool, BoolType> a, Expression<bool, BoolType> b) =>
_AndExpression(a, b); _AndExpression(a, b);
/// Returns an expression that is true iff [a], [b] or both are true. /// Returns an expression that is true iff [a], [b] or both are true.
///
/// This is now deprecated. Instead of `or(a, b)`, use `a | b`;
@Deprecated('Use the operator on BooleanExpressionOperators instead')
Expression<bool, BoolType> or( Expression<bool, BoolType> or(
Expression<bool, BoolType> a, Expression<bool, BoolType> b) => Expression<bool, BoolType> a, Expression<bool, BoolType> b) =>
_OrExpression(a, b); _OrExpression(a, b);
/// Returns an expression that is true iff [a] is not true. /// Returns an expression that is true iff [a] is not true.
///
/// This is now deprecated. Instead of `not(a)`, prefer to use `a.not()` now.
@Deprecated('Use BooleanExpressionOperators.not() as a extension instead')
Expression<bool, BoolType> not(Expression<bool, BoolType> a) => Expression<bool, BoolType> not(Expression<bool, BoolType> a) =>
_NotExpression(a); _NotExpression(a);
/// Defines operations on boolean values.
extension BooleanExpressionOperators on Expression<bool, BoolType> {
/// Negates this boolean expression. The returned expression is true if
/// `this` is false, and vice versa.
Expression<bool, BoolType> not() => _NotExpression(this);
/// Returns an expression that is true iff both `this` and [other] are true.
Expression<bool, BoolType> operator &(Expression<bool, BoolType> other) {
return _AndExpression(this, other);
}
/// Returns an expression that is true if `this` or [other] are true.
Expression<bool, BoolType> operator |(Expression<bool, BoolType> other) {
return _OrExpression(this, other);
}
}
class _AndExpression extends _InfixOperator<bool, BoolType> { class _AndExpression extends _InfixOperator<bool, BoolType> {
@override @override
Expression<bool, BoolType> left, right; Expression<bool, BoolType> left, right;

View File

@ -1,23 +1,8 @@
part of '../query_builder.dart'; part of '../query_builder.dart';
// todo: Can we replace these classes with an extension on expression? /// Defines extension functions to express comparisons in sql
extension ComparableExpr<DT, ST extends SqlType<DT>, Comparable>
/// An [Expression] that operates on ints. Declared as a class so that we can on Expression<DT, ST> {
/// mixin [ComparableExpr].
abstract class IntExpression extends Expression<int, IntType>
implements ComparableExpr<int, IntType> {}
/// An [Expression] that operates on doubles. Declared as a class so that we can
/// mixin [ComparableExpr].
abstract class DoubleExpression extends Expression<double, RealType>
implements ComparableExpr<double, RealType> {}
/// An [Expression] that operates on datetimes. Declared as a class so that we
/// can mixin [ComparableExpr].
abstract class DateTimeExpression extends Expression<DateTime, DateTimeType>
implements ComparableExpr<DateTime, DateTimeType> {}
mixin ComparableExpr<DT, ST extends SqlType<DT>> on Expression<DT, ST> {
/// Returns an expression that is true if this expression is strictly bigger /// Returns an expression that is true if this expression is strictly bigger
/// than the other expression. /// than the other expression.
Expression<bool, BoolType> isBiggerThan(Expression<DT, ST> other) { Expression<bool, BoolType> isBiggerThan(Expression<DT, ST> other) {

View File

@ -32,17 +32,16 @@ Expression<int, IntType> second(Expression<DateTime, DateTimeType> date) =>
/// A sql expression that evaluates to the current date represented as a unix /// A sql expression that evaluates to the current date represented as a unix
/// timestamp. The hour, minute and second fields will be set to 0. /// timestamp. The hour, minute and second fields will be set to 0.
const DateTimeExpression currentDate = const Expression<DateTime, DateTimeType> currentDate =
_CustomDateTimeExpression("strftime('%s', CURRENT_DATE)"); _CustomDateTimeExpression("strftime('%s', CURRENT_DATE)");
/// A sql expression that evaluates to the current date and time, similar to /// A sql expression that evaluates to the current date and time, similar to
/// [DateTime.now]. Timestamps are stored with a second accuracy. /// [DateTime.now]. Timestamps are stored with a second accuracy.
const DateTimeExpression currentDateAndTime = const Expression<DateTime, DateTimeType> currentDateAndTime =
_CustomDateTimeExpression("strftime('%s', CURRENT_TIMESTAMP)"); _CustomDateTimeExpression("strftime('%s', CURRENT_TIMESTAMP)");
class _CustomDateTimeExpression extends CustomExpression<DateTime, DateTimeType> class _CustomDateTimeExpression
with ComparableExpr extends CustomExpression<DateTime, DateTimeType> {
implements DateTimeExpression {
const _CustomDateTimeExpression(String content) : super(content); const _CustomDateTimeExpression(String content) : super(content);
} }

View File

@ -1,5 +1,21 @@
part of '../query_builder.dart'; part of '../query_builder.dart';
/// Defines methods that operate on a column storing [String] values.
extension StringExpressionOperators on Column<String, StringType> {
/// Whether this column matches the given pattern. For details on what patters
/// are valid and how they are interpreted, check out
/// [this tutorial](http://www.sqlitetutorial.net/sqlite-like/).
Expression<bool, BoolType> like(String regex) {
return _LikeOperator(this, Variable.withString(regex));
}
/// Uses the given [collate] sequence when comparing this column to other
/// values.
Expression<String, StringType> collate(Collate collate) {
return _CollateOperator(this, collate);
}
}
/// A `text LIKE pattern` expression that will be true if the first expression /// A `text LIKE pattern` expression that will be true if the first expression
/// matches the pattern given by the second expression. /// matches the pattern given by the second expression.
class _LikeOperator extends Expression<bool, BoolType> { class _LikeOperator extends Expression<bool, BoolType> {

View File

@ -2,7 +2,10 @@
// at runtime. // at runtime.
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:moor/moor.dart'; // todo we're hiding the extensions because the analyzer complains about
// ambigous extensions (once via import, once via part of), even though they're
// the same. We should probably file a bug report.
import 'package:moor/moor.dart' hide BooleanExpressionOperators;
import 'package:moor/sqlite_keywords.dart'; import 'package:moor/sqlite_keywords.dart';
import 'package:moor/src/runtime/executor/stream_queries.dart'; import 'package:moor/src/runtime/executor/stream_queries.dart';
import 'package:moor/src/utils/single_transformer.dart'; import 'package:moor/src/utils/single_transformer.dart';

View File

@ -124,15 +124,6 @@ class GeneratedTextColumn extends GeneratedColumn<String, StringType>
}) : super(name, tableName, nullable, }) : super(name, tableName, nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue); $customConstraints: $customConstraints, defaultValue: defaultValue);
@override
Expression<bool, BoolType> like(String pattern) =>
_LikeOperator(this, Variable<String, StringType>(pattern));
@override
Expression<String, StringType> collate(Collate collate) {
return _CollateOperator(this, collate);
}
@override @override
final String typeName = 'VARCHAR'; final String typeName = 'VARCHAR';
@ -175,7 +166,6 @@ class GeneratedBoolColumn extends GeneratedColumn<bool, BoolType>
/// Implementation for [IntColumn] /// Implementation for [IntColumn]
class GeneratedIntColumn extends GeneratedColumn<int, IntType> class GeneratedIntColumn extends GeneratedColumn<int, IntType>
with ComparableExpr
implements IntColumn { implements IntColumn {
/// Whether this column was declared to be a primary key via a column /// Whether this column was declared to be a primary key via a column
/// constraint. The only way to do this in Dart is with /// constraint. The only way to do this in Dart is with
@ -223,7 +213,6 @@ class GeneratedIntColumn extends GeneratedColumn<int, IntType>
/// Implementation for [DateTimeColumn]. /// Implementation for [DateTimeColumn].
class GeneratedDateTimeColumn extends GeneratedColumn<DateTime, DateTimeType> class GeneratedDateTimeColumn extends GeneratedColumn<DateTime, DateTimeType>
with ComparableExpr
implements DateTimeColumn { implements DateTimeColumn {
/// Used by generated code. /// Used by generated code.
GeneratedDateTimeColumn( GeneratedDateTimeColumn(
@ -254,7 +243,6 @@ class GeneratedBlobColumn extends GeneratedColumn<Uint8List, BlobType>
/// Implementation for [RealColumn] /// Implementation for [RealColumn]
class GeneratedRealColumn extends GeneratedColumn<double, RealType> class GeneratedRealColumn extends GeneratedColumn<double, RealType>
with ComparableExpr
implements RealColumn { implements RealColumn {
/// Used by generated code /// Used by generated code
GeneratedRealColumn( GeneratedRealColumn(

View File

@ -184,7 +184,7 @@ mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
if (whereExpr == null) { if (whereExpr == null) {
whereExpr = Where(predicate); whereExpr = Where(predicate);
} else { } else {
whereExpr = Where(and(whereExpr.predicate, predicate)); whereExpr = Where(whereExpr.predicate & predicate);
} }
} }
@ -221,7 +221,7 @@ mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
if (predicate == null) { if (predicate == null) {
predicate = comparison; predicate = comparison;
} else { } else {
predicate = and(predicate, comparison); predicate = predicate & comparison;
} }
} }

View File

@ -85,7 +85,7 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
if (whereExpr == null) { if (whereExpr == null) {
whereExpr = Where(predicate); whereExpr = Where(predicate);
} else { } else {
whereExpr = Where(and(whereExpr.predicate, predicate)); whereExpr = Where(whereExpr.predicate & predicate);
} }
} }

View File

@ -23,6 +23,10 @@ abstract class SqlType<T> {
T mapFromDatabaseResponse(dynamic response); T mapFromDatabaseResponse(dynamic response);
} }
/// A marker interface for [SqlType]s that can be compared using the comparison
/// operators in sql.
abstract class ComparableType {}
/// A mapper for boolean values in sql. Booleans are represented as integers, /// A mapper for boolean values in sql. Booleans are represented as integers,
/// where 0 means false and any other value means true. /// where 0 means false and any other value means true.
class BoolType extends SqlType<bool> { class BoolType extends SqlType<bool> {
@ -77,7 +81,7 @@ class StringType extends SqlType<String> {
} }
/// Maps [int] values from and to sql /// Maps [int] values from and to sql
class IntType extends SqlType<int> { class IntType extends SqlType<int> implements ComparableType {
/// Constant constructor used by the type system /// Constant constructor used by the type system
const IntType(); const IntType();
@ -94,7 +98,7 @@ class IntType extends SqlType<int> {
} }
/// Maps [DateTime] values from and to sql /// Maps [DateTime] values from and to sql
class DateTimeType extends SqlType<DateTime> { class DateTimeType extends SqlType<DateTime> implements ComparableType {
/// Constant constructor used by the type system /// Constant constructor used by the type system
const DateTimeType(); const DateTimeType();
@ -123,7 +127,7 @@ class DateTimeType extends SqlType<DateTime> {
} }
/// Maps [Uint8List] values from and to sql /// Maps [Uint8List] values from and to sql
class BlobType extends SqlType<Uint8List> { class BlobType extends SqlType<Uint8List> implements ComparableType {
/// Constant constructor used by the type system /// Constant constructor used by the type system
const BlobType(); const BlobType();
@ -142,7 +146,7 @@ class BlobType extends SqlType<Uint8List> {
} }
/// Maps [double] values from and to sql /// Maps [double] values from and to sql
class RealType extends SqlType<double> { class RealType extends SqlType<double> implements ComparableType {
/// Constant constructor used by the type system /// Constant constructor used by the type system
const RealType(); const RealType();

View File

@ -9,7 +9,7 @@ authors:
maintainer: Simon Binder (@simolus3) maintainer: Simon Binder (@simolus3)
environment: environment:
sdk: '>=2.3.0 <3.0.0' sdk: '>=2.6.0 <3.0.0'
dependencies: dependencies:
meta: ^1.0.0 meta: ^1.0.0

View File

@ -28,7 +28,7 @@ void main() {
test('for complex components', () async { test('for complex components', () async {
await (db.delete(db.users) await (db.delete(db.users)
..where((u) => or(not(u.isAwesome), u.id.isSmallerThanValue(100)))) ..where((u) => u.isAwesome.not() | u.id.isSmallerThanValue(100)))
.go(); .go();
verify(executor.runDelete( verify(executor.runDelete(

View File

@ -66,7 +66,7 @@ void main() {
test('with complex predicates', () { test('with complex predicates', () {
(db.select(db.users) (db.select(db.users)
..where((u) => ..where((u) =>
and(not(u.name.equals('Dash')), (u.id.isBiggerThanValue(12))))) u.name.equals('Dash').not() & u.id.isBiggerThanValue(12)))
.get(); .get();
verify(executor.runSelect( verify(executor.runSelect(