mirror of https://github.com/AMT-Cheif/drift.git
Parse more than ON CONFLICT clause
This commit is contained in:
parent
cf9ea89681
commit
c9f8af346d
|
@ -1,5 +1,7 @@
|
|||
## 0.15.0-dev
|
||||
|
||||
- __Breaking__: Change `InsertStatement.upsert` to a list of upsert clauses
|
||||
- Support multiple upsert clauses
|
||||
- Support `FROM` clauses in `UPDATE` statements
|
||||
- Support `MATERIALIZED`/`NOT MATERIALIZED` hints in common table expressions
|
||||
- Add `BuiltInMathExtension` which corresponds to the `-DSQLITE_ENABLE_MATH_FUNCTIONS`
|
||||
|
|
|
@ -102,7 +102,7 @@ class TypeResolver extends RecursiveVisitor<TypeExpectation, void> {
|
|||
},
|
||||
);
|
||||
|
||||
visitNullable(e.upsert, const NoTypeExpectation());
|
||||
visitList(e.upsert, const NoTypeExpectation());
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -7,9 +7,9 @@ import 'node.dart';
|
|||
import 'statements/create_index.dart';
|
||||
import 'statements/select.dart';
|
||||
import 'statements/statement.dart';
|
||||
import 'statements/update.dart';
|
||||
import 'visitor.dart';
|
||||
|
||||
export 'clauses/upsert.dart';
|
||||
export 'node.dart';
|
||||
export 'statements/block.dart';
|
||||
export 'statements/create_index.dart';
|
||||
|
@ -27,7 +27,6 @@ export 'visitor.dart';
|
|||
// todo: Split up this mega-library
|
||||
part 'clauses/limit.dart';
|
||||
part 'clauses/ordering.dart';
|
||||
part 'clauses/upsert.dart';
|
||||
part 'clauses/with.dart';
|
||||
part 'common/queryables.dart';
|
||||
part 'common/renamable.dart';
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
part of '../ast.dart';
|
||||
import '../ast.dart'; // todo: Remove this import
|
||||
import '../node.dart';
|
||||
import '../statements/create_index.dart' show IndexedColumn;
|
||||
|
||||
class UpsertClause extends AstNode implements HasWhereClause {
|
||||
final List<IndexedColumn>? onColumns;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import '../../analysis/analysis.dart';
|
||||
import '../ast.dart'; // todo: Remove this import
|
||||
import '../clauses/upsert.dart';
|
||||
import '../node.dart';
|
||||
import '../visitor.dart';
|
||||
import 'statement.dart';
|
||||
|
@ -20,7 +21,7 @@ class InsertStatement extends CrudStatement implements HasPrimarySource {
|
|||
TableReference? table;
|
||||
final List<Reference> targetColumns;
|
||||
InsertSource source;
|
||||
UpsertClause? upsert;
|
||||
final List<UpsertClause> upsert;
|
||||
|
||||
List<Column?>? get resolvedTargetColumns {
|
||||
if (targetColumns.isNotEmpty) {
|
||||
|
@ -37,7 +38,7 @@ class InsertStatement extends CrudStatement implements HasPrimarySource {
|
|||
required this.table,
|
||||
required this.targetColumns,
|
||||
required this.source,
|
||||
this.upsert})
|
||||
this.upsert = const []})
|
||||
: super(withClause);
|
||||
|
||||
@override
|
||||
|
@ -58,7 +59,7 @@ class InsertStatement extends CrudStatement implements HasPrimarySource {
|
|||
table!,
|
||||
...targetColumns,
|
||||
source,
|
||||
if (upsert != null) upsert!
|
||||
...upsert,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -584,9 +584,9 @@ extension VisitChildrenExtension<A, R> on AstVisitor<A, R?> {
|
|||
}
|
||||
|
||||
/// Visits all [nodes] in sequence.
|
||||
R? visitList(Iterable<AstNode?> nodes, A arg) {
|
||||
R? visitList(Iterable<AstNode> nodes, A arg) {
|
||||
for (final node in nodes) {
|
||||
node!.accept(this, arg);
|
||||
node.accept(this, arg);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1538,7 +1538,10 @@ class Parser {
|
|||
'Expected clpsing parenthesis after column list');
|
||||
}
|
||||
final source = _insertSource();
|
||||
final upsert = _upsertClauseOrNull();
|
||||
final upsert = <UpsertClause>[];
|
||||
while (_check(TokenType.on)) {
|
||||
upsert.add(_upsertClause());
|
||||
}
|
||||
|
||||
return InsertStatement(
|
||||
withClause: withClause,
|
||||
|
@ -1572,10 +1575,8 @@ class Parser {
|
|||
}
|
||||
}
|
||||
|
||||
UpsertClause? _upsertClauseOrNull() {
|
||||
if (!_matchOne(TokenType.on)) return null;
|
||||
|
||||
final first = _previous;
|
||||
UpsertClause _upsertClause() {
|
||||
final first = _consume(TokenType.on);
|
||||
_consume(TokenType.conflict, 'Expected CONFLICT keyword for upsert clause');
|
||||
|
||||
List<IndexedColumn>? indexedColumns;
|
||||
|
|
|
@ -715,7 +715,7 @@ class NodeSqlBuilder extends AstVisitor<void, void> {
|
|||
}
|
||||
|
||||
visit(e.source, arg);
|
||||
visitNullable(e.upsert, arg);
|
||||
_join(e.upsert, '');
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -64,7 +64,7 @@ void main() {
|
|||
table: TableReference('tbl'),
|
||||
targetColumns: const [],
|
||||
source: DefaultValues(),
|
||||
upsert: UpsertClause(action: DoNothing()),
|
||||
upsert: [UpsertClause(action: DoNothing())],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -76,7 +76,8 @@ void main() {
|
|||
table: TableReference('tbl'),
|
||||
targetColumns: const [],
|
||||
source: DefaultValues(),
|
||||
upsert: UpsertClause(
|
||||
upsert: [
|
||||
UpsertClause(
|
||||
onColumns: [
|
||||
IndexedColumn(Reference(columnName: 'foo')),
|
||||
IndexedColumn(
|
||||
|
@ -86,6 +87,7 @@ void main() {
|
|||
],
|
||||
action: DoNothing(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -97,7 +99,8 @@ void main() {
|
|||
table: TableReference('tbl'),
|
||||
targetColumns: const [],
|
||||
source: DefaultValues(),
|
||||
upsert: UpsertClause(
|
||||
upsert: [
|
||||
UpsertClause(
|
||||
onColumns: [
|
||||
IndexedColumn(Reference(columnName: 'foo')),
|
||||
IndexedColumn(Reference(columnName: 'bar')),
|
||||
|
@ -109,6 +112,7 @@ void main() {
|
|||
),
|
||||
action: DoNothing(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -120,16 +124,19 @@ void main() {
|
|||
table: TableReference('tbl'),
|
||||
targetColumns: const [],
|
||||
source: DefaultValues(),
|
||||
upsert: UpsertClause(
|
||||
upsert: [
|
||||
UpsertClause(
|
||||
action: DoUpdate(
|
||||
[
|
||||
SetComponent(
|
||||
column: Reference(columnName: 'foo'),
|
||||
expression: NumericLiteral(2, token(TokenType.numberLiteral)),
|
||||
expression:
|
||||
NumericLiteral(2, token(TokenType.numberLiteral)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -141,12 +148,14 @@ void main() {
|
|||
table: TableReference('tbl'),
|
||||
targetColumns: const [],
|
||||
source: DefaultValues(),
|
||||
upsert: UpsertClause(
|
||||
upsert: [
|
||||
UpsertClause(
|
||||
action: DoUpdate(
|
||||
[
|
||||
SetComponent(
|
||||
column: Reference(columnName: 'foo'),
|
||||
expression: NumericLiteral(2, token(TokenType.numberLiteral)),
|
||||
expression:
|
||||
NumericLiteral(2, token(TokenType.numberLiteral)),
|
||||
),
|
||||
],
|
||||
where: NumberedVariable(
|
||||
|
@ -154,6 +163,36 @@ void main() {
|
|||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('having more than one clause', () {
|
||||
testStatement(
|
||||
'$prefix (foo) DO NOTHING ON CONFLICT (bar) DO UPDATE SET x = 2',
|
||||
InsertStatement(
|
||||
table: TableReference('tbl'),
|
||||
targetColumns: const [],
|
||||
source: DefaultValues(),
|
||||
upsert: [
|
||||
UpsertClause(
|
||||
onColumns: [IndexedColumn(Reference(columnName: 'foo'))],
|
||||
action: DoNothing(),
|
||||
),
|
||||
UpsertClause(
|
||||
onColumns: [IndexedColumn(Reference(columnName: 'bar'))],
|
||||
action: DoUpdate(
|
||||
[
|
||||
SetComponent(
|
||||
column: Reference(columnName: 'x'),
|
||||
expression:
|
||||
NumericLiteral(2, token(TokenType.numberLiteral)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -247,6 +247,12 @@ CREATE UNIQUE INDEX my_idx ON t1 (c1, c2, c3) WHERE c1 < c3;
|
|||
testFormat('INSERT INTO foo VALUES (1, 2, 3) '
|
||||
'ON CONFLICT DO UPDATE SET a = b, c = d WHERE d < a;');
|
||||
});
|
||||
|
||||
test('upsert - multiple clauses', () {
|
||||
testFormat('INSERT INTO foo VALUES (1, 2, 3) '
|
||||
'ON CONFLICT DO NOTHING '
|
||||
'ON CONFLICT DO UPDATE SET a = b, c = d WHERE d < a;');
|
||||
});
|
||||
});
|
||||
|
||||
group('update', () {
|
||||
|
|
Loading…
Reference in New Issue