mirror of https://github.com/AMT-Cheif/drift.git
Implement order-by clauses for select statements
This commit is contained in:
parent
a26f84ceaf
commit
e018f6d725
|
@ -4,6 +4,7 @@ export 'package:sally/src/dsl/table.dart';
|
|||
export 'package:sally/src/dsl/columns.dart';
|
||||
export 'package:sally/src/dsl/database.dart';
|
||||
|
||||
export 'package:sally/src/runtime/components/order_by.dart';
|
||||
export 'package:sally/src/runtime/executor/executor.dart';
|
||||
export 'package:sally/src/runtime/executor/type_system.dart';
|
||||
export 'package:sally/src/runtime/expressions/comparable.dart';
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:sally/src/runtime/components/component.dart';
|
||||
import 'package:sally/src/runtime/expressions/expression.dart';
|
||||
|
||||
enum OrderingMode {
|
||||
/// Ascending ordering mode (lowest items first)
|
||||
asc,
|
||||
/// Descending ordering mode (highest items first)
|
||||
desc
|
||||
}
|
||||
|
||||
const _modeToString = {
|
||||
OrderingMode.asc: 'ASC',
|
||||
OrderingMode.desc: 'DESC',
|
||||
};
|
||||
|
||||
/// A single term in a [OrderBy] clause. The priority of this term is determined
|
||||
/// by its position in [OrderBy.terms].
|
||||
class OrderingTerm extends Component {
|
||||
|
||||
/// The expression after which the ordering should happen
|
||||
final Expression expression;
|
||||
/// The ordering mode (ascending or descending).
|
||||
final OrderingMode mode;
|
||||
|
||||
OrderingTerm({@required this.expression, this.mode = OrderingMode.asc});
|
||||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
expression.writeInto(context);
|
||||
context.writeWhitespace();
|
||||
context.buffer.write(_modeToString[mode]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// An order-by clause as part of a select statement. The clause can consist
|
||||
/// of multiple [OrderingTerm]s, with the first terms being more important and
|
||||
/// the later terms only being considered if the first term considers two rows
|
||||
/// equal.
|
||||
class OrderBy extends Component {
|
||||
|
||||
final List<OrderingTerm> terms;
|
||||
|
||||
OrderBy(this.terms);
|
||||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
var first = true;
|
||||
|
||||
context.buffer.write('ORDER BY ');
|
||||
|
||||
for (var term in terms) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
context.buffer.write(', ');
|
||||
}
|
||||
|
||||
term.writeInto(context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:sally/src/runtime/components/component.dart';
|
||||
import 'package:sally/src/runtime/components/limit.dart';
|
||||
import 'package:sally/src/runtime/components/order_by.dart';
|
||||
import 'package:sally/src/runtime/components/where.dart';
|
||||
import 'package:sally/src/runtime/executor/executor.dart';
|
||||
import 'package:sally/src/runtime/expressions/bools.dart';
|
||||
|
@ -20,6 +21,8 @@ abstract class Query<Table, DataClass> {
|
|||
@protected
|
||||
Where whereExpr;
|
||||
@protected
|
||||
OrderBy orderByExpr;
|
||||
@protected
|
||||
Limit limitExpr;
|
||||
|
||||
/// Subclasses must override this and write the part of the statement that
|
||||
|
@ -53,6 +56,13 @@ abstract class Query<Table, DataClass> {
|
|||
needsWhitespace = true;
|
||||
}
|
||||
|
||||
if (orderByExpr != null) {
|
||||
if (needsWhitespace) ctx.writeWhitespace();
|
||||
|
||||
orderByExpr.writeInto(ctx);
|
||||
needsWhitespace = true;
|
||||
}
|
||||
|
||||
if (limitExpr != null) {
|
||||
if (needsWhitespace) ctx.writeWhitespace();
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import 'package:sally/sally.dart';
|
||||
import 'package:sally/src/runtime/components/component.dart';
|
||||
import 'package:sally/src/runtime/components/limit.dart';
|
||||
import 'package:sally/src/runtime/executor/executor.dart';
|
||||
import 'package:sally/src/runtime/statements/query.dart';
|
||||
import 'package:sally/src/runtime/structure/table_info.dart';
|
||||
|
||||
typedef OrderingTerm OrderClauseGenerator<T>(T tbl);
|
||||
|
||||
class SelectStatement<T, D> extends Query<T, D> {
|
||||
SelectStatement(GeneratedDatabase database, TableInfo<T, D> table)
|
||||
: super(database, table);
|
||||
|
@ -30,6 +33,13 @@ class SelectStatement<T, D> extends Query<T, D> {
|
|||
limitExpr = Limit(limit, offset);
|
||||
}
|
||||
|
||||
/// Orders the result by the given clauses. The clauses coming first in the
|
||||
/// list have a higher priority, the later clauses are only considered if the
|
||||
/// first clause considers two rows to be equal.
|
||||
void orderBy(List<OrderClauseGenerator<T>> clauses) {
|
||||
orderByExpr = OrderBy(clauses.map((t) => t(table.asDslTable)).toList());
|
||||
}
|
||||
|
||||
/// Creates an auto-updating stream that emits new items whenever this table
|
||||
/// changes.
|
||||
Stream<List<D>> watch() {
|
||||
|
|
|
@ -31,6 +31,17 @@ void main() {
|
|||
.runSelect('SELECT * FROM users WHERE name LIKE ?;', ['Dash%']));
|
||||
});
|
||||
|
||||
test('with order-by clauses', () async {
|
||||
await (db.select(db.users)
|
||||
..orderBy([
|
||||
(u) => OrderingTerm(expression: u.isAwesome, mode: OrderingMode.desc),
|
||||
(u) => OrderingTerm(expression: u.id)
|
||||
])).get();
|
||||
|
||||
verify(executor.runSelect('SELECT * FROM users ORDER BY '
|
||||
'(is_awesome = 1) DESC, id ASC;', argThat(isEmpty)));
|
||||
});
|
||||
|
||||
test('with complex predicates', () {
|
||||
(db.select(db.users)
|
||||
..where((u) =>
|
||||
|
|
Loading…
Reference in New Issue