mirror of https://github.com/AMT-Cheif/drift.git
Support calling join on a JoinedSelectStatement
This commit is contained in:
parent
727ab4d88a
commit
a37a653e43
|
@ -133,7 +133,7 @@ mixin QueryEngine on DatabaseConnectionUser {
|
|||
bool distinct = false,
|
||||
}) {
|
||||
return JoinedSelectStatement<T, R>(
|
||||
_resolvedEngine, table, const [], distinct, false);
|
||||
_resolvedEngine, table, [], distinct, false);
|
||||
}
|
||||
|
||||
/// Starts a [DeleteStatement] that can be used to delete rows from a table.
|
||||
|
|
|
@ -14,4 +14,13 @@ class Where extends Component {
|
|||
context.buffer.write('WHERE ');
|
||||
predicate.writeInto(context);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => predicate.hashCode * 7;
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
other is Where && other.predicate == predicate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,26 @@ class _AggregateExpression<D, S extends SqlType<D>> extends Expression<D, S> {
|
|||
context.buffer.write(')');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return $mrjf($mrjc(functionName.hashCode,
|
||||
$mrjc(distinct.hashCode, $mrjc(parameter.hashCode, filter.hashCode))));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (!identical(this, other) && other.runtimeType != runtimeType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore: test_types_in_equals
|
||||
final typedOther = other as _AggregateExpression;
|
||||
return typedOther.functionName == functionName &&
|
||||
typedOther.distinct == distinct &&
|
||||
typedOther.parameter == parameter &&
|
||||
typedOther.filter == filter;
|
||||
}
|
||||
}
|
||||
|
||||
class _StarFunctionParameter implements FunctionParameter {
|
||||
|
|
|
@ -12,6 +12,9 @@ abstract class FunctionParameter implements Component {}
|
|||
/// Any sql expression that evaluates to some generic value. This does not
|
||||
/// include queries (which might evaluate to multiple values) but individual
|
||||
/// columns, functions and operators.
|
||||
///
|
||||
/// It's important that all subclasses properly implement [hashCode] and
|
||||
/// [==].
|
||||
abstract class Expression<D, T extends SqlType<D>>
|
||||
implements FunctionParameter {
|
||||
/// Constant constructor so that subclasses can be constant.
|
||||
|
|
|
@ -60,6 +60,7 @@ class SimpleSelectStatement<T extends Table, D extends DataClass>
|
|||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
/// - https://moor.simonbinder.eu/docs/advanced-features/joins/#joins
|
||||
/// - [innerJoin], [leftOuterJoin] and [crossJoin], which can be used to
|
||||
/// construct a [Join].
|
||||
/// - [DatabaseConnectionUser.alias], which can be used to build statements
|
||||
|
|
|
@ -12,11 +12,7 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
|
|||
JoinedSelectStatement(
|
||||
QueryEngine database, TableInfo<FirstT, FirstD> table, this._joins,
|
||||
[this.distinct = false, this._includeMainTableInResult = true])
|
||||
: super(database, table) {
|
||||
// use all columns across all tables as result column for this query
|
||||
_selectedColumns.addAll(
|
||||
_queriedTables(true).expand((t) => t.$columns).cast<Expression>());
|
||||
}
|
||||
: super(database, table);
|
||||
|
||||
/// Whether to generate a `SELECT DISTINCT` query that will remove duplicate
|
||||
/// rows from the result set.
|
||||
|
@ -60,6 +56,10 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
|
|||
|
||||
@override
|
||||
void writeStartPart(GenerationContext ctx) {
|
||||
// use all columns across all tables as result column for this query
|
||||
_selectedColumns.insertAll(
|
||||
0, _queriedTables(true).expand((t) => t.$columns).cast<Expression>());
|
||||
|
||||
ctx.hasMultipleTables = true;
|
||||
ctx.buffer..write(_beginOfSelect(distinct))..write(' ');
|
||||
|
||||
|
@ -74,8 +74,8 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
|
|||
chosenAlias = '${column.tableName}.${column.$name}';
|
||||
} else {
|
||||
chosenAlias = 'c$i';
|
||||
_columnAliases[column] = chosenAlias;
|
||||
}
|
||||
_columnAliases[column] = chosenAlias;
|
||||
|
||||
column.writeInto(ctx);
|
||||
ctx.buffer..write(' AS "')..write(chosenAlias)..write('"');
|
||||
|
@ -145,6 +145,23 @@ class JoinedSelectStatement<FirstT extends Table, FirstD extends DataClass>
|
|||
_selectedColumns.addAll(expressions);
|
||||
}
|
||||
|
||||
/// Adds more joined tables to this [JoinedSelectStatement].
|
||||
///
|
||||
/// Always returns the same instance.
|
||||
///
|
||||
/// See also:
|
||||
/// - https://moor.simonbinder.eu/docs/advanced-features/joins/#joins
|
||||
/// - [SimpleSelectStatement.join], which is used for the first join
|
||||
/// - [innerJoin], [leftOuterJoin] and [crossJoin], which can be used to
|
||||
/// construct a [Join].
|
||||
/// - [DatabaseConnectionUser.alias], which can be used to build statements
|
||||
/// that refer to the same table multiple times.
|
||||
// ignore: avoid_returning_this
|
||||
JoinedSelectStatement join(List<Join> joins) {
|
||||
_joins.addAll(joins);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Groups the result by values in [expressions].
|
||||
///
|
||||
/// An optional [having] attribute can be set to exclude certain groups.
|
||||
|
|
|
@ -225,6 +225,42 @@ void main() {
|
|||
expect(result, 3.0);
|
||||
});
|
||||
|
||||
test('join on JoinedSelectStatement', () async {
|
||||
final categories = db.categories;
|
||||
final todos = db.todosTable;
|
||||
|
||||
final query = db.selectOnly(categories).join([
|
||||
innerJoin(
|
||||
todos,
|
||||
todos.category.equalsExp(categories.id),
|
||||
useColumns: false,
|
||||
)
|
||||
]);
|
||||
query
|
||||
..addColumns([categories.id, todos.id.count()])
|
||||
..groupBy([categories.id]);
|
||||
|
||||
when(executor.runSelect(any, any)).thenAnswer((_) async {
|
||||
return [
|
||||
{
|
||||
'categories.id': 2,
|
||||
'c1': 10,
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
final result = await query.getSingle();
|
||||
|
||||
verify(executor.runSelect(
|
||||
'SELECT categories.id AS "categories.id", COUNT(todos.id) AS "c1" '
|
||||
'FROM categories INNER JOIN todos ON todos.category = categories.id '
|
||||
'GROUP BY categories.id;',
|
||||
[]));
|
||||
|
||||
expect(result.read(categories.id), equals(2));
|
||||
expect(result.read(todos.id.count()), equals(10));
|
||||
});
|
||||
|
||||
test('injects custom error message when a table is used multiple times',
|
||||
() async {
|
||||
when(executor.runSelect(any, any)).thenAnswer((_) => Future.error('nah'));
|
||||
|
|
Loading…
Reference in New Issue