/
join.dart
108 lines (93 loc) · 3.52 KB
/
join.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
part of '../query_builder.dart';
/// A type for a [Join] (e.g. inner, outer).
enum _JoinType {
/// Perform an inner join, see the [innerJoin] function for details.
inner,
/// Perform a (left) outer join, see also [leftOuterJoin]
leftOuter,
/// Perform a full cross join, see also [crossJoin].
cross
}
const Map<_JoinType, String> _joinKeywords = {
_JoinType.inner: 'INNER',
_JoinType.leftOuter: 'LEFT OUTER',
_JoinType.cross: 'CROSS',
};
/// Used internally by drift when calling [SimpleSelectStatement.join].
///
/// You should use [innerJoin], [leftOuterJoin] or [crossJoin] to obtain a
/// [Join] instance.
class Join<T extends HasResultSet, D> extends Component {
/// The [_JoinType] of this join.
final _JoinType _type;
/// The [TableInfo] that will be added to the query
final HasResultSet table;
/// For joins that aren't [_JoinType.cross], contains an additional predicate
/// that must be matched for the join.
final Expression<bool>? on;
/// Whether [table] should appear in the result set (defaults to true).
/// Default value can be changed by `includeJoinedTableColumns` in
/// `selectOnly` statements.
///
/// It can be useful to exclude some tables. Sometimes, tables are used in a
/// join only to run aggregate functions on them.
final bool? includeInResult;
/// Constructs a [Join] by providing the relevant fields. [on] is optional for
/// [_JoinType.cross].
Join._(this._type, this.table, this.on, {this.includeInResult}) {
if (table is! ResultSetImplementation<T, D>) {
throw ArgumentError(
'Invalid table parameter. You must provide the table reference from '
'generated database object.',
'table');
}
}
@override
void writeInto(GenerationContext context) {
context.buffer.write(_joinKeywords[_type]);
context.buffer.write(' JOIN ');
final resultSet = table as ResultSetImplementation<T, D>;
context.writeResultSet(resultSet);
if (_type != _JoinType.cross) {
context.buffer.write(' ON ');
on!.writeInto(context);
}
}
}
/// Creates a sql inner join that can be used in [SimpleSelectStatement.join].
///
/// {@template drift_join_include_results}
/// The optional [useColumns] parameter (defaults to true) can be used to
/// exclude the [other] table from the result set. When set to false,
/// [TypedResult.readTable] will return `null` for that table.
/// {@endtemplate}
///
/// See also:
/// - https://drift.simonbinder.eu/docs/advanced-features/joins/#joins
/// - http://www.sqlitetutorial.net/sqlite-inner-join/
Join innerJoin(HasResultSet other, Expression<bool> on, {bool? useColumns}) {
return Join._(_JoinType.inner, other, on, includeInResult: useColumns);
}
/// Creates a sql left outer join that can be used in
/// [SimpleSelectStatement.join].
///
/// {@macro drift_join_include_results}
///
/// See also:
/// - https://drift.simonbinder.eu/docs/advanced-features/joins/#joins
/// - http://www.sqlitetutorial.net/sqlite-left-join/
Join leftOuterJoin(HasResultSet other, Expression<bool> on,
{bool? useColumns}) {
return Join._(_JoinType.leftOuter, other, on, includeInResult: useColumns);
}
/// Creates a sql cross join that can be used in
/// [SimpleSelectStatement.join].
///
/// {@macro drift_join_include_results}
///
/// See also:
/// - https://drift.simonbinder.eu/docs/advanced-features/joins/#joins
/// - http://www.sqlitetutorial.net/sqlite-cross-join/
Join crossJoin(HasResultSet other, {bool? useColumns}) {
return Join._(_JoinType.cross, other, null, includeInResult: useColumns);
}