sqlparser: Make InsertSource an AstNode

This commit is contained in:
Simon Binder 2020-06-15 17:45:28 +02:00
parent 7ae3783473
commit 5c6331e486
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
5 changed files with 84 additions and 26 deletions

View File

@ -2,7 +2,7 @@
- Breaking: Made `RecursiveVisitor.visit`, `visitList` and `visitExcept` an extension on `AstVisitor`.
- Support the transformer pattern to modify ast nodes
- Breaking: `FrameBoundary`, `DeleteTarget`, `UpdateTarget` and `InsertTarget` are no longer constant
- Breaking: `FrameBoundary`, `DeleteTarget`, `UpdateTarget`, `DefaultValues` and `InsertTarget` are no longer constant
- Support parsing and analyzing `CREATE VIEW` statements (see `SchemaFromCreateTable.readView`).
Thanks to [@mqus](https://github.com/mqus) for their contribution!

View File

@ -48,13 +48,13 @@ class InsertStatement extends CrudStatement {
}
@override
Iterable<AstNode> get childNodes sync* {
if (withClause != null) yield withClause;
yield table;
yield* targetColumns;
yield* source.childNodes;
if (upsert != null) yield upsert;
}
Iterable<AstNode> get childNodes => [
if (withClause != null) withClause,
table,
...targetColumns,
source,
if (upsert != null) upsert
];
@override
bool contentEquals(InsertStatement other) {
@ -62,12 +62,7 @@ class InsertStatement extends CrudStatement {
}
}
// todo: Should be an AstNode
abstract class InsertSource {
Iterable<AstNode> get childNodes;
const InsertSource();
abstract class InsertSource extends AstNode {
T when<T>(
{T Function(ValuesSource) isValues,
T Function(SelectInsertSource) isSelect,
@ -92,22 +87,57 @@ class ValuesSource extends InsertSource {
@override
Iterable<AstNode> get childNodes => values;
@override
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
return visitor.visitValuesSource(this, arg);
}
@override
bool contentEquals(ValuesSource other) => true;
@override
void transformChildren<A>(Transformer<A> transformer, A arg) {
transformer.transformChildren(values, this, arg);
}
}
/// Inserts the rows returned by [stmt].
class SelectInsertSource extends InsertSource {
final BaseSelectStatement stmt;
BaseSelectStatement stmt;
SelectInsertSource(this.stmt);
@override
Iterable<AstNode> get childNodes => [stmt];
@override
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
return visitor.visitSelectInsertSource(this, arg);
}
@override
bool contentEquals(SelectInsertSource other) => true;
@override
void transformChildren<A>(Transformer<A> transformer, A arg) {
stmt = transformer.transformChild(stmt, this, arg);
}
}
/// Use `DEFAULT VALUES` for an insert statement.
class DefaultValues extends InsertSource {
const DefaultValues();
@override
Iterable<AstNode> get childNodes => const [];
@override
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
return visitor.visitDefaultValues(this, arg);
}
@override
bool contentEquals(DefaultValues other) => true;
@override
void transformChildren<A>(Transformer<A> transformer, A arg) {}
}

View File

@ -34,6 +34,10 @@ abstract class AstVisitor<A, R> {
R visitSetComponent(SetComponent e, A arg);
R visitValuesSource(ValuesSource e, A arg);
R visitSelectInsertSource(SelectInsertSource e, A arg);
R visitDefaultValues(DefaultValues e, A arg);
R visitColumnDefinition(ColumnDefinition e, A arg);
R visitColumnConstraint(ColumnConstraint e, A arg);
R visitTableConstraint(TableConstraint e, A arg);
@ -257,6 +261,25 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
return defaultNode(e, arg);
}
@override
R visitValuesSource(ValuesSource e, A arg) {
return defaultInsertSource(e, arg);
}
@override
R visitSelectInsertSource(SelectInsertSource e, A arg) {
return defaultInsertSource(e, arg);
}
@override
R visitDefaultValues(DefaultValues e, A arg) {
return defaultInsertSource(e, arg);
}
R defaultInsertSource(InsertSource e, A arg) {
return defaultNode(e, arg);
}
@override
R visitColumnDefinition(ColumnDefinition e, A arg) {
return defaultNode(e, arg);

View File

@ -667,18 +667,23 @@ mixin CrudParser on ParserBase {
InsertSource _insertSource() {
if (_matchOne(TokenType.$values)) {
final first = _previous;
final values = <Tuple>[];
do {
// it will be a tuple, we don't turn on "orSubQuery"
values.add(_consumeTuple() as Tuple);
} while (_matchOne(TokenType.comma));
return ValuesSource(values);
return ValuesSource(values)..setSpan(first, _previous);
} else if (_matchOne(TokenType.$default)) {
final first = _previous;
_consume(TokenType.$values, 'Expected DEFAULT VALUES');
return const DefaultValues();
return DefaultValues()..setSpan(first, _previous);
} else {
final first = _previous;
return SelectInsertSource(
_fullSelect() ?? _error('Expeced a select statement'));
_fullSelect() ?? _error('Expeced a select statement'),
)..setSpan(first, _previous);
}
}

View File

@ -33,7 +33,7 @@ void main() {
mode: InsertMode.insert,
table: TableReference('tbl', null),
targetColumns: const [],
source: const DefaultValues(),
source: DefaultValues(),
),
);
});
@ -63,7 +63,7 @@ void main() {
InsertStatement(
table: TableReference('tbl'),
targetColumns: const [],
source: const DefaultValues(),
source: DefaultValues(),
upsert: UpsertClause(action: DoNothing()),
),
);
@ -75,7 +75,7 @@ void main() {
InsertStatement(
table: TableReference('tbl'),
targetColumns: const [],
source: const DefaultValues(),
source: DefaultValues(),
upsert: UpsertClause(
onColumns: [
IndexedColumn(Reference(columnName: 'foo')),
@ -96,7 +96,7 @@ void main() {
InsertStatement(
table: TableReference('tbl'),
targetColumns: const [],
source: const DefaultValues(),
source: DefaultValues(),
upsert: UpsertClause(
onColumns: [
IndexedColumn(Reference(columnName: 'foo')),
@ -119,7 +119,7 @@ void main() {
InsertStatement(
table: TableReference('tbl'),
targetColumns: const [],
source: const DefaultValues(),
source: DefaultValues(),
upsert: UpsertClause(
action: DoUpdate(
[
@ -140,7 +140,7 @@ void main() {
InsertStatement(
table: TableReference('tbl'),
targetColumns: const [],
source: const DefaultValues(),
source: DefaultValues(),
upsert: UpsertClause(
action: DoUpdate(
[