mirror of https://github.com/AMT-Cheif/drift.git
Add caseMatch to build CASE WHEN
This commit is contained in:
parent
a3a64419b8
commit
58fdda482f
|
@ -1,3 +1,7 @@
|
|||
## 4.3.0-dev
|
||||
|
||||
- Add `CASE WHEN` expressions with the `caseMatch` method on `Expression`
|
||||
|
||||
## 4.2.1
|
||||
|
||||
- Deprecate `readBool`, `readString`, `readInt`, `readDouble`, `readDateTime`
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../query_builder.dart';
|
||||
|
||||
/// A `CASE WHEN` expression in sqlite.
|
||||
///
|
||||
/// This class supports when expressions with or without a base expression.
|
||||
@internal
|
||||
class CaseWhenExpression<T> extends Expression<T?> {
|
||||
/// The optional base expression. If it's set, the keys in [whenThen] will be
|
||||
/// compared to this expression.
|
||||
final Expression? base;
|
||||
|
||||
/// The when entries for this expression. This expression will evaluate to the
|
||||
/// value of the entry with a matching key.
|
||||
final List<MapEntry<Expression, Expression>> whenThen;
|
||||
|
||||
/// The expression to use if no entry in [whenThen] matched.
|
||||
final Expression<T?>? orElse;
|
||||
|
||||
/// Creates a `CASE WHEN` expression from the independent components.
|
||||
CaseWhenExpression(this.base, this.whenThen, this.orElse);
|
||||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
context.buffer.write('CASE ');
|
||||
base?.writeInto(context);
|
||||
|
||||
for (final entry in whenThen) {
|
||||
context.buffer.write(' WHEN ');
|
||||
entry.key.writeInto(context);
|
||||
context.buffer.write(' THEN ');
|
||||
entry.value.writeInto(context);
|
||||
}
|
||||
|
||||
final orElse = this.orElse;
|
||||
if (orElse != null) {
|
||||
context.buffer.write(' ELSE ');
|
||||
orElse.writeInto(context);
|
||||
}
|
||||
|
||||
context.buffer.write(' END');
|
||||
}
|
||||
}
|
|
@ -86,9 +86,47 @@ abstract class Expression<D> implements FunctionParameter {
|
|||
return _InSelectExpression(select, this, true);
|
||||
}
|
||||
|
||||
/// A `CASE WHEN` construct using the current expression as a base.
|
||||
///
|
||||
/// The expression on which [caseMatch] is invoked will be used as a base and
|
||||
/// compared against the keys in [when]. If an equal key is found in the map,
|
||||
/// the expression returned evaluates to the respective value.
|
||||
/// If no matching keys are found in [when], the [orElse] expression is
|
||||
/// evaluated and returned. If no [orElse] expression is provided, `NULL` will
|
||||
/// be returned instead.
|
||||
///
|
||||
/// For example, consider this expression mapping numerical weekdays to their
|
||||
/// name:
|
||||
///
|
||||
/// ```dart
|
||||
/// final weekday = myTable.createdOnWeekDay;
|
||||
/// weekday.caseMatch<String>(
|
||||
/// when: {
|
||||
/// Constant(1): Constant('Monday'),
|
||||
/// Constant(2): Constant('Tuesday'),
|
||||
/// Constant(3): Constant('Wednesday'),
|
||||
/// Constant(4): Constant('Thursday'),
|
||||
/// Constant(5): Constant('Friday'),
|
||||
/// Constant(6): Constant('Saturday'),
|
||||
/// Constant(7): Constant('Sunday'),
|
||||
/// },
|
||||
/// orElse: Constant('(unknown)'),
|
||||
/// );
|
||||
/// ```
|
||||
Expression<T?> caseMatch<T>({
|
||||
required Map<Expression<D>, Expression<T?>> when,
|
||||
Expression<T?>? orElse,
|
||||
}) {
|
||||
if (when.isEmpty) {
|
||||
throw ArgumentError.value(when, 'when', 'Must not be empty');
|
||||
}
|
||||
|
||||
return CaseWhenExpression<T>(this, when.entries.toList(), orElse);
|
||||
}
|
||||
|
||||
/// Writes this expression into the [GenerationContext], assuming that there's
|
||||
/// an outer expression with [precedence]. If the [Expression.precedence] of
|
||||
/// `this` expression is lower, it will be wrapped in
|
||||
/// `this` expression is lower, it will be wrap}ped in
|
||||
///
|
||||
/// See also:
|
||||
/// - [Component.writeInto], which doesn't take any precedence relation into
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
// hidden because of https://github.com/dart-lang/sdk/issues/39262
|
||||
import 'package:moor/moor.dart'
|
||||
hide BooleanExpressionOperators, DateTimeExpressions, TableInfoUtils;
|
||||
|
@ -11,12 +12,15 @@ import 'package:moor/src/runtime/executor/stream_queries.dart';
|
|||
import 'package:moor/src/runtime/types/sql_types.dart';
|
||||
import 'package:moor/src/utils/single_transformer.dart';
|
||||
|
||||
// New files should not be part of this mega library, which we're trying to
|
||||
// split up.
|
||||
import 'expressions/case_when.dart';
|
||||
|
||||
part 'components/group_by.dart';
|
||||
part 'components/join.dart';
|
||||
part 'components/limit.dart';
|
||||
part 'components/order_by.dart';
|
||||
part 'components/where.dart';
|
||||
|
||||
part 'expressions/aggregate.dart';
|
||||
part 'expressions/algebra.dart';
|
||||
part 'expressions/bools.dart';
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import 'package:moor/moor.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../data/utils/expect_generated.dart';
|
||||
|
||||
void main() {
|
||||
const x = CustomExpression<String>('x');
|
||||
const y = CustomExpression<int>('y');
|
||||
|
||||
test('WHEN without ELSE', () {
|
||||
expect(
|
||||
x.caseMatch<int>(when: {
|
||||
const Constant('a'): const Constant(1),
|
||||
const Constant('b'): const Constant(2),
|
||||
}),
|
||||
generates("CASE x WHEN 'a' THEN 1 WHEN 'b' THEN 2 END"),
|
||||
);
|
||||
});
|
||||
|
||||
test('WHEN with ELSE', () {
|
||||
expect(
|
||||
x.caseMatch<int>(
|
||||
when: {
|
||||
const Constant('a'): const Constant(1),
|
||||
},
|
||||
orElse: y,
|
||||
),
|
||||
generates("CASE x WHEN 'a' THEN 1 ELSE y END"),
|
||||
);
|
||||
});
|
||||
|
||||
test('does not allow empty WHEN map', () {
|
||||
expect(() => x.caseMatch(when: const {}), throwsA(isA<ArgumentError>()));
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue