diff --git a/sqlparser/CHANGELOG.md b/sqlparser/CHANGELOG.md
index 50c7d1e4..a7087774 100644
--- a/sqlparser/CHANGELOG.md
+++ b/sqlparser/CHANGELOG.md
@@ -1,6 +1,8 @@
## 0.10.0
- Breaking: Made `RecursiveVisitor.visit`, `visitList` and `visitExcept` an extension on `AstVisitor`.
+- Support the transformer pattern to modify ast nodes
+- Breaking: `FrameBoundary` is no longer constant
- Support parsing and analyzing `CREATE VIEW` statements (see `SchemaFromCreateTable.readView`).
Thanks to [@mqus](https://github.com/mqus) for their contribution!
diff --git a/sqlparser/lib/src/ast/ast.dart b/sqlparser/lib/src/ast/ast.dart
index 214b61eb..06562df1 100644
--- a/sqlparser/lib/src/ast/ast.dart
+++ b/sqlparser/lib/src/ast/ast.dart
@@ -146,6 +146,10 @@ abstract class AstNode with HasMetaMixin implements SyntacticEntity {
return accept(visitor, null);
}
+ /// Transforms children of this node by invoking [transformer] with the
+ /// argument [arg].
+ void transformChildren(Transformer transformer, A arg);
+
/// Whether the content of this node is equal to the [other] node of the same
/// type. The "content" refers to anything stored only in this node, children
/// are ignored.
diff --git a/sqlparser/lib/src/ast/clauses/limit.dart b/sqlparser/lib/src/ast/clauses/limit.dart
index 0060ec94..ee86c033 100644
--- a/sqlparser/lib/src/ast/clauses/limit.dart
+++ b/sqlparser/lib/src/ast/clauses/limit.dart
@@ -17,6 +17,12 @@ class Limit extends AstNode implements LimitBase {
return visitor.visitLimit(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ count = transformer.transformChild(count, this, arg);
+ offset = transformer.transformNullableChild(offset, this, arg);
+ }
+
@override
Iterable get childNodes => [count, if (offset != null) offset];
diff --git a/sqlparser/lib/src/ast/clauses/ordering.dart b/sqlparser/lib/src/ast/clauses/ordering.dart
index a8d84664..681d1033 100644
--- a/sqlparser/lib/src/ast/clauses/ordering.dart
+++ b/sqlparser/lib/src/ast/clauses/ordering.dart
@@ -19,6 +19,11 @@ class OrderBy extends AstNode implements OrderByBase {
return visitor.visitOrderBy(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(terms, this, arg);
+ }
+
@override
Iterable get childNodes => terms;
@@ -31,8 +36,8 @@ class OrderBy extends AstNode implements OrderByBase {
enum OrderingMode { ascending, descending }
class OrderingTerm extends AstNode implements OrderingTermBase {
- final Expression expression;
- final OrderingMode orderingMode;
+ Expression expression;
+ OrderingMode orderingMode;
OrderingMode get resolvedOrderingMode =>
orderingMode ?? OrderingMode.ascending;
@@ -44,6 +49,11 @@ class OrderingTerm extends AstNode implements OrderingTermBase {
return visitor.visitOrderingTerm(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
Iterable get childNodes => [expression];
diff --git a/sqlparser/lib/src/ast/clauses/upsert.dart b/sqlparser/lib/src/ast/clauses/upsert.dart
index 47fbe824..ac554128 100644
--- a/sqlparser/lib/src/ast/clauses/upsert.dart
+++ b/sqlparser/lib/src/ast/clauses/upsert.dart
@@ -3,9 +3,9 @@ part of '../ast.dart';
class UpsertClause extends AstNode implements HasWhereClause {
final List /*?*/ onColumns;
@override
- final Expression where;
+ Expression where;
- final UpsertAction action;
+ UpsertAction action;
UpsertClause({this.onColumns, this.where, @required this.action});
@@ -14,6 +14,13 @@ class UpsertClause extends AstNode implements HasWhereClause {
return visitor.visitUpsertClause(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(onColumns, this, arg);
+ where = transformer.transformNullableChild(where, this, arg);
+ action = transformer.transformChild(action, this, arg);
+ }
+
@override
Iterable get childNodes {
return [
@@ -35,6 +42,9 @@ class DoNothing extends UpsertAction {
return visitor.visitDoNothing(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
Iterable get childNodes => const [];
@@ -45,7 +55,7 @@ class DoNothing extends UpsertAction {
class DoUpdate extends UpsertAction implements HasWhereClause {
final List set;
@override
- final Expression where;
+ Expression where;
DoUpdate(this.set, {this.where});
@@ -54,6 +64,12 @@ class DoUpdate extends UpsertAction implements HasWhereClause {
return visitor.visitDoUpdate(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(set, this, arg);
+ where = transformer.transformNullableChild(where, this, arg);
+ }
+
@override
Iterable get childNodes => [...set, if (where != null) where];
diff --git a/sqlparser/lib/src/ast/clauses/with.dart b/sqlparser/lib/src/ast/clauses/with.dart
index 77ad614d..4990b05c 100644
--- a/sqlparser/lib/src/ast/clauses/with.dart
+++ b/sqlparser/lib/src/ast/clauses/with.dart
@@ -15,6 +15,11 @@ class WithClause extends AstNode {
return visitor.visitWithClause(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(ctes, this, arg);
+ }
+
@override
Iterable get childNodes => ctes;
@@ -29,7 +34,7 @@ class CommonTableExpression extends AstNode with ResultSet {
/// `cnt(x) AS (...)`, contains the column names (`['x']`, in that case).
/// Otherwise null.
final List columnNames;
- final BaseSelectStatement as;
+ BaseSelectStatement as;
Token asToken;
IdentifierToken tableNameToken;
@@ -44,6 +49,11 @@ class CommonTableExpression extends AstNode with ResultSet {
return visitor.visitCommonTableExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ as = transformer.transformChild(as, this, arg);
+ }
+
@override
Iterable get childNodes => [as];
diff --git a/sqlparser/lib/src/ast/common/queryables.dart b/sqlparser/lib/src/ast/common/queryables.dart
index 53a651da..21b0b967 100644
--- a/sqlparser/lib/src/ast/common/queryables.dart
+++ b/sqlparser/lib/src/ast/common/queryables.dart
@@ -60,6 +60,9 @@ class TableReference extends TableOrSubquery
return other.tableName == tableName && other.as == as;
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
ResultSet get resultSet {
return resolved as ResultSet;
@@ -74,13 +77,18 @@ class TableReference extends TableOrSubquery
class SelectStatementAsSource extends TableOrSubquery implements Renamable {
@override
final String as;
- final BaseSelectStatement statement;
+ BaseSelectStatement statement;
SelectStatementAsSource({@required this.statement, this.as});
@override
Iterable get childNodes => [statement];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ statement = transformer.transformChild(statement, this, arg);
+ }
+
@override
bool contentEquals(SelectStatementAsSource other) {
return other.as == as;
@@ -89,11 +97,17 @@ class SelectStatementAsSource extends TableOrSubquery implements Renamable {
/// https://www.sqlite.org/syntax/join-clause.html
class JoinClause extends Queryable {
- final TableOrSubquery primary;
+ TableOrSubquery primary;
final List joins;
JoinClause({@required this.primary, @required this.joins});
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ primary = transformer.transformChild(primary, this, arg);
+ transformer.transformChildren(joins, this, arg);
+ }
+
@override
Iterable get childNodes => [primary, ...joins];
@@ -115,7 +129,7 @@ enum JoinOperator {
class Join extends AstNode {
final bool natural;
final JoinOperator operator;
- final TableOrSubquery query;
+ TableOrSubquery query;
final JoinConstraint /*?*/ constraint;
Join(
@@ -157,13 +171,23 @@ class Join extends AstNode {
R accept(AstVisitor visitor, A arg) {
return visitor.visitJoin(this, arg);
}
+
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ query = transformer.transformChild(query, this, arg);
+ if (constraint is OnConstraint) {
+ final onConstraint = constraint as OnConstraint;
+ onConstraint.expression =
+ transformer.transformChild(onConstraint.expression, this, arg);
+ }
+ }
}
/// https://www.sqlite.org/syntax/join-constraint.html
abstract class JoinConstraint {}
class OnConstraint extends JoinConstraint {
- final Expression expression;
+ Expression expression;
OnConstraint({@required this.expression});
}
@@ -182,7 +206,7 @@ class TableValuedFunction extends Queryable
final String as;
@override
- final FunctionParameters parameters;
+ FunctionParameters parameters;
@override
ResultSet resultSet;
@@ -192,6 +216,11 @@ class TableValuedFunction extends Queryable
@override
Iterable get childNodes => [parameters];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ parameters = transformer.transformChild(parameters, this, arg);
+ }
+
@override
bool get visibleToChildren => false;
diff --git a/sqlparser/lib/src/ast/common/tuple.dart b/sqlparser/lib/src/ast/common/tuple.dart
index 39103b7e..904ae01d 100644
--- a/sqlparser/lib/src/ast/common/tuple.dart
+++ b/sqlparser/lib/src/ast/common/tuple.dart
@@ -21,6 +21,11 @@ class Tuple extends Expression {
return visitor.visitTuple(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(expressions, this, arg);
+ }
+
@override
List get childNodes => expressions;
diff --git a/sqlparser/lib/src/ast/expressions/aggregate.dart b/sqlparser/lib/src/ast/expressions/aggregate.dart
index 1cc1992b..6f1f01ec 100644
--- a/sqlparser/lib/src/ast/expressions/aggregate.dart
+++ b/sqlparser/lib/src/ast/expressions/aggregate.dart
@@ -8,8 +8,8 @@ class AggregateExpression extends Expression
String get name => function.identifier;
@override
- final FunctionParameters parameters;
- final Expression filter;
+ FunctionParameters parameters;
+ Expression filter;
@override
Referencable resolved;
@@ -24,7 +24,7 @@ class AggregateExpression extends Expression
/// this field will be null. Either [windowDefinition] or [windowName] are
/// null. The resolved [WindowDefinition] is available in [over] in either
/// case.
- final WindowDefinition windowDefinition;
+ WindowDefinition windowDefinition;
/// An aggregate expression can be written as `OVER ` instead of
/// declaring its own [windowDefinition]. Either [windowDefinition] or
@@ -46,6 +46,14 @@ class AggregateExpression extends Expression
return visitor.visitAggregateExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ parameters = transformer.transformChild(parameters, this, arg);
+ filter = transformer.transformNullableChild(filter, this, arg);
+ windowDefinition =
+ transformer.transformNullableChild(windowDefinition, this, arg);
+ }
+
@override
Iterable get childNodes {
return [
@@ -65,6 +73,7 @@ class AggregateExpression extends Expression
/// `WINDOW AS `. It can be referenced from an
/// [AggregateExpression] if it uses the same name.
class NamedWindowDeclaration with Referencable {
+ // todo: Should be an ast node
final String name;
final WindowDefinition definition;
@@ -74,8 +83,8 @@ class NamedWindowDeclaration with Referencable {
class WindowDefinition extends AstNode {
final String baseWindowName;
final List partitionBy;
- final OrderByBase orderBy;
- final FrameSpec frameSpec;
+ OrderByBase orderBy;
+ FrameSpec frameSpec;
WindowDefinition(
{this.baseWindowName,
@@ -88,6 +97,13 @@ class WindowDefinition extends AstNode {
return visitor.visitWindowDefinition(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(partitionBy, this, arg);
+ orderBy = transformer.transformNullableChild(orderBy, this, arg);
+ frameSpec = transformer.transformChild(frameSpec, this, arg);
+ }
+
@override
Iterable get childNodes =>
[...partitionBy, if (orderBy != null) orderBy, frameSpec];
@@ -101,21 +117,32 @@ class WindowDefinition extends AstNode {
class FrameSpec extends AstNode {
final FrameType type;
final ExcludeMode excludeMode;
- final FrameBoundary start;
- final FrameBoundary end;
+ FrameBoundary start;
+ FrameBoundary end;
FrameSpec({
this.type = FrameType.range,
- this.start = const FrameBoundary.unboundedPreceding(),
- this.end = const FrameBoundary.currentRow(),
+ FrameBoundary start,
+ FrameBoundary end,
this.excludeMode = ExcludeMode.noOthers,
- });
+ }) : start = start ?? FrameBoundary.unboundedPreceding(),
+ end = end ?? FrameBoundary.currentRow();
@override
R accept(AstVisitor visitor, A arg) {
return visitor.visitFrameSpec(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ if (start.isExpressionOffset) {
+ start.offset = transformer.transformChild(start.offset, this, arg);
+ }
+ if (end.isExpressionOffset) {
+ end.offset = transformer.transformChild(end.offset, this, arg);
+ }
+ }
+
@override
Iterable get childNodes => [
if (start.isExpressionOffset) start.offset,
@@ -164,7 +191,7 @@ class FrameBoundary {
/// The (integer) expression that specifies the amount of rows to include
/// before or after the row being processed.
- final Expression offset;
+ Expression offset;
/// Whether this boundary refers to a row before the current row.
final bool preceding;
@@ -180,18 +207,18 @@ class FrameBoundary {
/// Whether this boundary only refers to the current row.
bool get isCurrentRow => _type == _BoundaryType.currentRow;
- const FrameBoundary._(this._type, this.preceding, {this.offset});
+ FrameBoundary._(this._type, this.preceding, {this.offset});
- const FrameBoundary.unboundedPreceding()
+ FrameBoundary.unboundedPreceding()
: this._(_BoundaryType.unboundedOffset, true);
- const FrameBoundary.unboundedFollowing()
+ FrameBoundary.unboundedFollowing()
: this._(_BoundaryType.unboundedOffset, false);
- const FrameBoundary.currentRow() : this._(_BoundaryType.currentRow, false);
+ FrameBoundary.currentRow() : this._(_BoundaryType.currentRow, false);
- const FrameBoundary.preceding(Expression amount)
+ FrameBoundary.preceding(Expression amount)
: this._(_BoundaryType.exprOffset, true, offset: amount);
- const FrameBoundary.following(Expression amount)
+ FrameBoundary.following(Expression amount)
: this._(_BoundaryType.exprOffset, false, offset: amount);
@override
@@ -207,7 +234,8 @@ class FrameBoundary {
// lint bug: https://github.com/dart-lang/linter/issues/1397
final typedOther = other as FrameBoundary; // ignore: test_types_in_equals
return typedOther._type == _type &&
- typedOther.offset.contentEquals(offset) &&
+ (typedOther.offset == null && offset == null ||
+ typedOther.offset.contentEquals(offset)) &&
typedOther.preceding == preceding;
}
}
diff --git a/sqlparser/lib/src/ast/expressions/case.dart b/sqlparser/lib/src/ast/expressions/case.dart
index 80a7c689..593a5af7 100644
--- a/sqlparser/lib/src/ast/expressions/case.dart
+++ b/sqlparser/lib/src/ast/expressions/case.dart
@@ -1,9 +1,9 @@
part of '../ast.dart';
class CaseExpression extends Expression {
- final Expression base; // can be null
+ Expression /*?*/ base;
final List whens;
- final Expression elseExpr;
+ Expression /*?*/ elseExpr;
CaseExpression({this.base, @required this.whens, this.elseExpr});
@@ -12,6 +12,13 @@ class CaseExpression extends Expression {
return visitor.visitCaseExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ base = transformer.transformNullableChild(base, this, arg);
+ transformer.transformChildren(whens, this, arg);
+ elseExpr = transformer.transformNullableChild(elseExpr, this, arg);
+ }
+
@override
Iterable get childNodes =>
[if (base != null) base, ...whens, if (elseExpr != null) elseExpr];
@@ -21,8 +28,8 @@ class CaseExpression extends Expression {
}
class WhenComponent extends AstNode {
- final Expression when;
- final Expression then;
+ Expression when;
+ Expression then;
WhenComponent({this.when, this.then});
@@ -31,6 +38,12 @@ class WhenComponent extends AstNode {
return visitor.visitWhen(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ when = transformer.transformChild(when, this, arg);
+ then = transformer.transformChild(then, this, arg);
+ }
+
@override
Iterable get childNodes => [when, then];
diff --git a/sqlparser/lib/src/ast/expressions/cast.dart b/sqlparser/lib/src/ast/expressions/cast.dart
index 08a3e593..6ba8a9b9 100644
--- a/sqlparser/lib/src/ast/expressions/cast.dart
+++ b/sqlparser/lib/src/ast/expressions/cast.dart
@@ -2,7 +2,7 @@ part of '../ast.dart';
/// A `CAST( AS )` expression.
class CastExpression extends Expression {
- final Expression operand;
+ Expression operand;
final String typeName;
CastExpression(this.operand, this.typeName);
@@ -12,6 +12,11 @@ class CastExpression extends Expression {
return visitor.visitCastExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ operand = transformer.transformChild(operand, this, arg);
+ }
+
@override
Iterable get childNodes => [operand];
diff --git a/sqlparser/lib/src/ast/expressions/function.dart b/sqlparser/lib/src/ast/expressions/function.dart
index 32a1aebf..b8948fa9 100644
--- a/sqlparser/lib/src/ast/expressions/function.dart
+++ b/sqlparser/lib/src/ast/expressions/function.dart
@@ -22,7 +22,7 @@ class FunctionExpression extends Expression
@override
final String name;
@override
- final FunctionParameters parameters;
+ FunctionParameters parameters;
FunctionExpression({@required this.name, @required this.parameters});
@@ -31,6 +31,11 @@ class FunctionExpression extends Expression
return visitor.visitFunction(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ parameters = transformer.transformChild(parameters, this, arg);
+ }
+
@override
Iterable get childNodes {
return [parameters];
@@ -57,6 +62,9 @@ class StarFunctionParameter extends FunctionParameters {
return visitor.visitStarFunctionParameter(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
Iterable get childNodes => const Iterable.empty();
@@ -77,6 +85,11 @@ class ExprFunctionParameters extends FunctionParameters {
return visitor.visitExpressionFunctionParameters(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(parameters, this, arg);
+ }
+
@override
List get childNodes => parameters;
diff --git a/sqlparser/lib/src/ast/expressions/literals.dart b/sqlparser/lib/src/ast/expressions/literals.dart
index 6d282b8c..b4a7a87c 100644
--- a/sqlparser/lib/src/ast/expressions/literals.dart
+++ b/sqlparser/lib/src/ast/expressions/literals.dart
@@ -11,6 +11,9 @@ abstract class Literal extends Expression {
@override
final Iterable childNodes = const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
String toString() {
return 'Literal with value $value';
diff --git a/sqlparser/lib/src/ast/expressions/reference.dart b/sqlparser/lib/src/ast/expressions/reference.dart
index ea9f256f..a9d446e3 100644
--- a/sqlparser/lib/src/ast/expressions/reference.dart
+++ b/sqlparser/lib/src/ast/expressions/reference.dart
@@ -20,6 +20,9 @@ class Reference extends Expression with ReferenceOwner {
return visitor.visitReference(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
Iterable get childNodes => const [];
diff --git a/sqlparser/lib/src/ast/expressions/simple.dart b/sqlparser/lib/src/ast/expressions/simple.dart
index 6fb49cf9..1a23c8c6 100644
--- a/sqlparser/lib/src/ast/expressions/simple.dart
+++ b/sqlparser/lib/src/ast/expressions/simple.dart
@@ -2,7 +2,7 @@ part of '../ast.dart';
class UnaryExpression extends Expression {
final Token operator;
- final Expression inner;
+ Expression inner;
UnaryExpression(this.operator, this.inner);
@@ -11,6 +11,11 @@ class UnaryExpression extends Expression {
return visitor.visitUnaryExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ inner = transformer.transformChild(inner, this, arg);
+ }
+
@override
Iterable get childNodes => [inner];
@@ -43,8 +48,8 @@ class CollateExpression extends UnaryExpression {
class BinaryExpression extends Expression {
final Token operator;
- final Expression left;
- final Expression right;
+ Expression left;
+ Expression right;
BinaryExpression(this.left, this.operator, this.right);
@@ -53,6 +58,12 @@ class BinaryExpression extends Expression {
return visitor.visitBinaryExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ left = transformer.transformChild(left, this, arg);
+ right = transformer.transformChild(right, this, arg);
+ }
+
@override
Iterable get childNodes => [left, right];
@@ -66,9 +77,9 @@ class BinaryExpression extends Expression {
class StringComparisonExpression extends Expression {
final bool not;
final Token operator;
- final Expression left;
- final Expression right;
- final Expression escape;
+ Expression left;
+ Expression right;
+ Expression escape;
StringComparisonExpression(
{this.not = false,
@@ -82,6 +93,13 @@ class StringComparisonExpression extends Expression {
return visitor.visitStringComparison(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ left = transformer.transformChild(left, this, arg);
+ right = transformer.transformChild(right, this, arg);
+ escape = transformer.transformNullableChild(escape, this, arg);
+ }
+
@override
Iterable get childNodes => [left, right, if (escape != null) escape];
@@ -92,8 +110,8 @@ class StringComparisonExpression extends Expression {
/// `(NOT)? $left IS $right`
class IsExpression extends Expression {
final bool negated;
- final Expression left;
- final Expression right;
+ Expression left;
+ Expression right;
IsExpression(this.negated, this.left, this.right);
@@ -102,6 +120,12 @@ class IsExpression extends Expression {
return visitor.visitIsExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ left = transformer.transformChild(left, this, arg);
+ right = transformer.transformChild(right, this, arg);
+ }
+
@override
Iterable get childNodes => [left, right];
@@ -112,7 +136,7 @@ class IsExpression extends Expression {
}
class IsNullExpression extends Expression {
- final Expression operand;
+ Expression operand;
/// When true, this is a `NOT NULL` expression.
final bool negated;
@@ -124,6 +148,11 @@ class IsNullExpression extends Expression {
return visitor.visitIsNullExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ operand = transformer.transformChild(operand, this, arg);
+ }
+
@override
Iterable get childNodes => [operand];
@@ -136,9 +165,9 @@ class IsNullExpression extends Expression {
/// `$check BETWEEN $lower AND $upper`
class BetweenExpression extends Expression {
final bool not;
- final Expression check;
- final Expression lower;
- final Expression upper;
+ Expression check;
+ Expression lower;
+ Expression upper;
BetweenExpression({this.not = false, this.check, this.lower, this.upper});
@@ -147,6 +176,13 @@ class BetweenExpression extends Expression {
return visitor.visitBetweenExpression(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ check = transformer.transformChild(check, this, arg);
+ lower = transformer.transformChild(lower, this, arg);
+ upper = transformer.transformChild(upper, this, arg);
+ }
+
@override
List get childNodes => [check, lower, upper];
@@ -157,13 +193,13 @@ class BetweenExpression extends Expression {
/// `$left$ IN $inside`.
class InExpression extends Expression {
final bool not;
- final Expression left;
+ Expression left;
/// The right-hand part: Contains the set of values [left] will be tested
/// against. From the sqlite grammar, we support [Tuple] and a [SubQuery].
/// We also support a [Variable] as syntax sugar - it will be expanded into a
/// tuple of variables at runtime.
- final Expression inside;
+ Expression inside;
InExpression({this.not = false, @required this.left, @required this.inside})
: assert(inside is Tuple || inside is Variable || inside is SubQuery);
@@ -176,16 +212,19 @@ class InExpression extends Expression {
@override
List get childNodes => [left, inside];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ left = transformer.transformChild(left, this, arg);
+ inside = transformer.transformChild(inside, this, arg);
+ }
+
@override
bool contentEquals(InExpression other) => other.not == not;
}
-// todo we might be able to remove a hack in the parser at _in() if we make
-// parentheses a subclass of tuples
-
class Parentheses extends Expression {
final Token openingLeft;
- final Expression expression;
+ Expression expression;
final Token closingRight;
Parentheses(this.openingLeft, this.expression, this.closingRight) {
@@ -197,6 +236,11 @@ class Parentheses extends Expression {
return visitor.visitParentheses(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
Iterable get childNodes => [expression];
diff --git a/sqlparser/lib/src/ast/expressions/subquery.dart b/sqlparser/lib/src/ast/expressions/subquery.dart
index 2b235994..c156c224 100644
--- a/sqlparser/lib/src/ast/expressions/subquery.dart
+++ b/sqlparser/lib/src/ast/expressions/subquery.dart
@@ -3,7 +3,7 @@ part of '../ast.dart';
/// A subquery, which is an expression. It is expected that the inner query
/// only returns one column and one row.
class SubQuery extends Expression {
- final BaseSelectStatement select;
+ BaseSelectStatement select;
SubQuery({this.select});
@@ -12,6 +12,11 @@ class SubQuery extends Expression {
return visitor.visitSubQuery(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ select = transformer.transformChild(select, this, arg);
+ }
+
@override
Iterable get childNodes => [select];
@@ -20,7 +25,7 @@ class SubQuery extends Expression {
}
class ExistsExpression extends Expression {
- final BaseSelectStatement select;
+ BaseSelectStatement select;
ExistsExpression({@required this.select});
@@ -29,6 +34,11 @@ class ExistsExpression extends Expression {
return visitor.visitExists(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ select = transformer.transformChild(select, this, arg);
+ }
+
@override
Iterable get childNodes => [select];
diff --git a/sqlparser/lib/src/ast/expressions/variables.dart b/sqlparser/lib/src/ast/expressions/variables.dart
index e2a02fd0..74642fc2 100644
--- a/sqlparser/lib/src/ast/expressions/variables.dart
+++ b/sqlparser/lib/src/ast/expressions/variables.dart
@@ -18,6 +18,9 @@ class NumberedVariable extends Expression with Variable {
return visitor.visitNumberedVariable(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
Iterable get childNodes => const [];
@@ -38,6 +41,9 @@ class ColonNamedVariable extends Expression with Variable {
return visitor.visitNamedVariable(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
Iterable get childNodes => [];
diff --git a/sqlparser/lib/src/ast/moor/declared_statement.dart b/sqlparser/lib/src/ast/moor/declared_statement.dart
index cb655c80..79cf7b9f 100644
--- a/sqlparser/lib/src/ast/moor/declared_statement.dart
+++ b/sqlparser/lib/src/ast/moor/declared_statement.dart
@@ -4,7 +4,7 @@ part of '../ast.dart';
/// followed by a colon and the query to run.
class DeclaredStatement extends Statement implements PartOfMoorFile {
final DeclaredStatementIdentifier identifier;
- final CrudStatement statement;
+ CrudStatement statement;
final List parameters;
/// The desired result class name, if set.
@@ -25,6 +25,14 @@ class DeclaredStatement extends Statement implements PartOfMoorFile {
return visitor.visitMoorDeclaredStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ statement = transformer.transformChild(statement, this, arg);
+ if (parameters != null) {
+ transformer.transformChildren(parameters, this, arg);
+ }
+ }
+
@override
Iterable get childNodes =>
[statement, if (parameters != null) ...parameters];
@@ -101,7 +109,7 @@ abstract class StatementParameter extends AstNode {
/// in the query will then be resolved to the type set here. This is useful for
/// cases in which the resolver doesn't yield acceptable results.
class VariableTypeHint extends StatementParameter {
- final Variable variable;
+ Variable variable;
final String typeName;
Token as;
@@ -111,6 +119,11 @@ class VariableTypeHint extends StatementParameter {
@override
Iterable get childNodes => [variable];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ variable = transformer.transformChild(variable, this, arg);
+ }
+
@override
bool contentEquals(VariableTypeHint other) {
return other.typeName == typeName;
diff --git a/sqlparser/lib/src/ast/moor/import_statement.dart b/sqlparser/lib/src/ast/moor/import_statement.dart
index b7553404..6e05528b 100644
--- a/sqlparser/lib/src/ast/moor/import_statement.dart
+++ b/sqlparser/lib/src/ast/moor/import_statement.dart
@@ -13,6 +13,9 @@ class ImportStatement extends Statement implements PartOfMoorFile {
return visitor.visitMoorImportStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
final Iterable childNodes = const [];
diff --git a/sqlparser/lib/src/ast/moor/inline_dart.dart b/sqlparser/lib/src/ast/moor/inline_dart.dart
index ad2f638c..ddb048b8 100644
--- a/sqlparser/lib/src/ast/moor/inline_dart.dart
+++ b/sqlparser/lib/src/ast/moor/inline_dart.dart
@@ -23,6 +23,9 @@ abstract class DartPlaceholder extends AstNode {
@override
final Iterable childNodes = const Iterable.empty();
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
R accept(AstVisitor visitor, A arg) {
return visitor.visitDartPlaceholder(this, arg);
diff --git a/sqlparser/lib/src/ast/moor/moor_file.dart b/sqlparser/lib/src/ast/moor/moor_file.dart
index 07ab465f..0278efad 100644
--- a/sqlparser/lib/src/ast/moor/moor_file.dart
+++ b/sqlparser/lib/src/ast/moor/moor_file.dart
@@ -17,6 +17,11 @@ class MoorFile extends AstNode {
return visitor.visitMoorFile(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(statements, this, arg);
+ }
+
@override
Iterable get childNodes => statements;
diff --git a/sqlparser/lib/src/ast/moor/nested_star_result_column.dart b/sqlparser/lib/src/ast/moor/nested_star_result_column.dart
index 19c134ab..33ed717e 100644
--- a/sqlparser/lib/src/ast/moor/nested_star_result_column.dart
+++ b/sqlparser/lib/src/ast/moor/nested_star_result_column.dart
@@ -14,6 +14,9 @@ class NestedStarResultColumn extends ResultColumn {
@override
Iterable get childNodes => const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
bool contentEquals(NestedStarResultColumn other) {
return other.tableName == tableName;
diff --git a/sqlparser/lib/src/ast/schema/column_definition.dart b/sqlparser/lib/src/ast/schema/column_definition.dart
index 122f50ab..a3b146e6 100644
--- a/sqlparser/lib/src/ast/schema/column_definition.dart
+++ b/sqlparser/lib/src/ast/schema/column_definition.dart
@@ -20,6 +20,11 @@ class ColumnDefinition extends AstNode {
return visitor.visitColumnDefinition(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(constraints, this, arg);
+ }
+
@override
Iterable get childNodes => constraints;
@@ -102,6 +107,9 @@ class NotNull extends ColumnConstraint {
@override
final Iterable childNodes = const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
bool _equalToConstraint(NotNull other) => onConflict == other.onConflict;
}
@@ -118,6 +126,9 @@ class PrimaryKeyColumn extends ColumnConstraint {
@override
Iterable get childNodes => const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
bool _equalToConstraint(PrimaryKeyColumn other) {
return other.autoIncrement == autoIncrement &&
@@ -134,6 +145,9 @@ class UniqueColumn extends ColumnConstraint {
@override
Iterable get childNodes => const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
bool _equalToConstraint(UniqueColumn other) {
return other.onConflict == onConflict;
@@ -141,25 +155,35 @@ class UniqueColumn extends ColumnConstraint {
}
class CheckColumn extends ColumnConstraint {
- final Expression expression;
+ Expression expression;
CheckColumn(String name, this.expression) : super(name);
@override
Iterable get childNodes => [expression];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
bool _equalToConstraint(CheckColumn other) => true;
}
class Default extends ColumnConstraint {
- final Expression expression;
+ Expression expression;
Default(String name, this.expression) : super(name);
@override
Iterable get childNodes => [expression];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
bool _equalToConstraint(Default other) => true;
}
@@ -172,12 +196,15 @@ class CollateConstraint extends ColumnConstraint {
@override
final Iterable childNodes = const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
bool _equalToConstraint(CollateConstraint other) => true;
}
class ForeignKeyColumnConstraint extends ColumnConstraint {
- final ForeignKeyClause clause;
+ ForeignKeyClause clause;
ForeignKeyColumnConstraint(String name, this.clause) : super(name);
@@ -186,6 +213,11 @@ class ForeignKeyColumnConstraint extends ColumnConstraint {
@override
Iterable get childNodes => [clause];
+
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ clause = transformer.transformChild(clause, this, arg);
+ }
}
/// A `MAPPED BY` constraint, which is only parsed for moor files. It can be
@@ -203,6 +235,9 @@ class MappedBy extends ColumnConstraint {
@override
final Iterable childNodes = const [];
+
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
}
/// A `JSON KEY xyz` constraint which, which is only parsed for moor files.
@@ -222,4 +257,7 @@ class JsonKey extends ColumnConstraint {
bool _equalToConstraint(JsonKey other) {
return other.jsonKey == jsonKey;
}
+
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
}
diff --git a/sqlparser/lib/src/ast/schema/table_definition.dart b/sqlparser/lib/src/ast/schema/table_definition.dart
index c480d191..e5843ad6 100644
--- a/sqlparser/lib/src/ast/schema/table_definition.dart
+++ b/sqlparser/lib/src/ast/schema/table_definition.dart
@@ -3,7 +3,7 @@ part of '../ast.dart';
enum ReferenceAction { setNull, setDefault, cascade, restrict, noAction }
class ForeignKeyClause extends AstNode {
- final TableReference foreignTable;
+ TableReference foreignTable;
final List columnNames;
final ReferenceAction onDelete;
final ReferenceAction onUpdate;
@@ -19,6 +19,12 @@ class ForeignKeyClause extends AstNode {
return visitor.visitForeignKeyClause(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ foreignTable = transformer.transformChild(foreignTable, this, arg);
+ transformer.transformChildren(columnNames, this, arg);
+ }
+
@override
Iterable get childNodes => [foreignTable, ...columnNames];
@@ -66,25 +72,35 @@ class KeyClause extends TableConstraint {
return other.isPrimaryKey == isPrimaryKey && other.onConflict == onConflict;
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(indexedColumns, this, arg);
+ }
+
@override
Iterable get childNodes => indexedColumns;
}
class CheckTable extends TableConstraint {
- final Expression expression;
+ Expression expression;
CheckTable(String name, this.expression) : super(name);
@override
bool _constraintEquals(CheckTable other) => true;
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
Iterable get childNodes => [expression];
}
class ForeignKeyTableConstraint extends TableConstraint {
final List columns;
- final ForeignKeyClause clause;
+ ForeignKeyClause clause;
ForeignKeyTableConstraint(String name,
{@required this.columns, @required this.clause})
@@ -93,6 +109,12 @@ class ForeignKeyTableConstraint extends TableConstraint {
@override
bool _constraintEquals(ForeignKeyTableConstraint other) => true;
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(columns, this, arg);
+ clause = transformer.transformChild(clause, this, arg);
+ }
+
@override
Iterable get childNodes => [...columns, clause];
}
diff --git a/sqlparser/lib/src/ast/statements/block.dart b/sqlparser/lib/src/ast/statements/block.dart
index 982eda4d..1c235d12 100644
--- a/sqlparser/lib/src/ast/statements/block.dart
+++ b/sqlparser/lib/src/ast/statements/block.dart
@@ -13,6 +13,11 @@ class Block extends AstNode {
return visitor.visitBlock(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(statements, this, arg);
+ }
+
@override
Iterable get childNodes => statements;
diff --git a/sqlparser/lib/src/ast/statements/create_index.dart b/sqlparser/lib/src/ast/statements/create_index.dart
index 08a78619..2409a617 100644
--- a/sqlparser/lib/src/ast/statements/create_index.dart
+++ b/sqlparser/lib/src/ast/statements/create_index.dart
@@ -7,10 +7,10 @@ class CreateIndexStatement extends Statement
final bool ifNotExists;
IdentifierToken nameToken;
- final TableReference on;
+ TableReference on;
final List columns;
@override
- final Expression where;
+ Expression where;
CreateIndexStatement(
{@required this.indexName,
@@ -28,6 +28,13 @@ class CreateIndexStatement extends Statement
return visitor.visitCreateIndexStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ on = transformer.transformChild(on, this, arg);
+ transformer.transformChildren(columns, this, arg);
+ where = transformer.transformNullableChild(where, this, arg);
+ }
+
@override
Iterable get childNodes =>
[on, ...columns, if (where != null) where];
@@ -45,7 +52,7 @@ class CreateIndexStatement extends Statement
class IndexedColumn extends AstNode {
/// The expression on which the index should be created. Most commonly a
/// [Reference], for simple column names.
- final Expression expression;
+ Expression expression;
// nullable
final OrderingMode ordering;
@@ -59,6 +66,11 @@ class IndexedColumn extends AstNode {
@override
Iterable get childNodes => [expression];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
bool contentEquals(IndexedColumn other) => other.ordering == ordering;
}
diff --git a/sqlparser/lib/src/ast/statements/create_table.dart b/sqlparser/lib/src/ast/statements/create_table.dart
index 32906ca4..d13235c9 100644
--- a/sqlparser/lib/src/ast/statements/create_table.dart
+++ b/sqlparser/lib/src/ast/statements/create_table.dart
@@ -43,6 +43,12 @@ class CreateTableStatement extends TableInducingStatement {
return visitor.visitCreateTableStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(columns, this, arg);
+ transformer.transformChildren(tableConstraints, this, arg);
+ }
+
@override
Iterable get childNodes => [...columns, ...tableConstraints];
@@ -83,6 +89,9 @@ class CreateVirtualTableStatement extends TableInducingStatement {
return visitor.visitCreateVirtualTableStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
Iterable get childNodes => const [];
diff --git a/sqlparser/lib/src/ast/statements/create_trigger.dart b/sqlparser/lib/src/ast/statements/create_trigger.dart
index 4dcb74f1..2888f3c9 100644
--- a/sqlparser/lib/src/ast/statements/create_trigger.dart
+++ b/sqlparser/lib/src/ast/statements/create_trigger.dart
@@ -9,10 +9,10 @@ class CreateTriggerStatement extends Statement implements CreatingStatement {
final TriggerMode mode;
final TriggerTarget target;
- final TableReference onTable;
+ TableReference onTable;
- final Expression when;
- final Block action;
+ Expression when;
+ Block action;
CreateTriggerStatement(
{this.ifNotExists = false,
@@ -31,6 +31,13 @@ class CreateTriggerStatement extends Statement implements CreatingStatement {
return visitor.visitCreateTriggerStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ onTable = transformer.transformChild(onTable, this, arg);
+ when = transformer.transformNullableChild(when, this, arg);
+ action = transformer.transformChild(action, this, arg);
+ }
+
@override
Iterable get childNodes sync* {
if (target is UpdateTarget) yield* (target as UpdateTarget).columnNames;
@@ -50,6 +57,7 @@ class CreateTriggerStatement extends Statement implements CreatingStatement {
enum TriggerMode { before, after, insteadOf }
+// todo: Should be an AstNode
abstract class TriggerTarget {
const TriggerTarget._();
@override
diff --git a/sqlparser/lib/src/ast/statements/create_view.dart b/sqlparser/lib/src/ast/statements/create_view.dart
index f323aeee..72aece36 100644
--- a/sqlparser/lib/src/ast/statements/create_view.dart
+++ b/sqlparser/lib/src/ast/statements/create_view.dart
@@ -7,7 +7,7 @@ class CreateViewStatement extends Statement implements CreatingStatement {
final String viewName;
IdentifierToken viewNameToken;
- final BaseSelectStatement query;
+ BaseSelectStatement query;
final List columns;
@@ -25,6 +25,11 @@ class CreateViewStatement extends Statement implements CreatingStatement {
return visitor.visitCreateViewStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ query = transformer.transformChild(query, this, arg);
+ }
+
@override
Iterable get childNodes => [query];
diff --git a/sqlparser/lib/src/ast/statements/delete.dart b/sqlparser/lib/src/ast/statements/delete.dart
index cb80750a..837fe37b 100644
--- a/sqlparser/lib/src/ast/statements/delete.dart
+++ b/sqlparser/lib/src/ast/statements/delete.dart
@@ -1,9 +1,9 @@
part of '../ast.dart';
class DeleteStatement extends CrudStatement implements StatementWithWhere {
- final TableReference from;
+ TableReference from;
@override
- final Expression where;
+ Expression where;
DeleteStatement({WithClause withClause, @required this.from, this.where})
: super._(withClause);
@@ -13,6 +13,13 @@ class DeleteStatement extends CrudStatement implements StatementWithWhere {
return visitor.visitDeleteStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ withClause = transformer.transformNullableChild(withClause, this, arg);
+ from = transformer.transformChild(from, this, arg);
+ where = transformer.transformNullableChild(where, this, arg);
+ }
+
@override
Iterable get childNodes => [
if (withClause != null) withClause,
diff --git a/sqlparser/lib/src/ast/statements/insert.dart b/sqlparser/lib/src/ast/statements/insert.dart
index 04861d83..d33237ce 100644
--- a/sqlparser/lib/src/ast/statements/insert.dart
+++ b/sqlparser/lib/src/ast/statements/insert.dart
@@ -12,10 +12,10 @@ enum InsertMode {
class InsertStatement extends CrudStatement {
final InsertMode mode;
- final TableReference table;
+ TableReference table;
final List targetColumns;
- final InsertSource source;
- final UpsertClause upsert;
+ InsertSource source;
+ UpsertClause upsert;
List get resolvedTargetColumns {
if (targetColumns.isNotEmpty) {
@@ -40,6 +40,13 @@ class InsertStatement extends CrudStatement {
return visitor.visitInsertStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ withClause = transformer.transformNullableChild(withClause, this, arg);
+ table = transformer.transformChild(table, this, arg);
+ transformer.transformChildren(targetColumns, this, arg);
+ }
+
@override
Iterable get childNodes sync* {
if (withClause != null) yield withClause;
@@ -55,6 +62,7 @@ class InsertStatement extends CrudStatement {
}
}
+// todo: Should be an AstNode
abstract class InsertSource {
Iterable get childNodes;
diff --git a/sqlparser/lib/src/ast/statements/select.dart b/sqlparser/lib/src/ast/statements/select.dart
index f0162691..6714e18b 100644
--- a/sqlparser/lib/src/ast/statements/select.dart
+++ b/sqlparser/lib/src/ast/statements/select.dart
@@ -17,15 +17,15 @@ class SelectStatement extends BaseSelectStatement
implements StatementWithWhere, SelectStatementNoCompound {
final bool distinct;
final List columns;
- final Queryable /*?*/ from;
+ Queryable /*?*/ from;
@override
- final Expression where;
- final GroupBy groupBy;
+ Expression where;
+ GroupBy groupBy;
final List windowDeclarations;
- final OrderByBase orderBy;
- final LimitBase limit;
+ OrderByBase orderBy;
+ LimitBase limit;
SelectStatement(
{WithClause withClause,
@@ -44,6 +44,18 @@ class SelectStatement extends BaseSelectStatement
return visitor.visitSelectStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ withClause = transformer.transformNullableChild(withClause, this, arg);
+ transformer.transformChildren(columns, this, arg);
+ from = transformer.transformNullableChild(from, this, arg);
+ where = transformer.transformNullableChild(where, this, arg);
+ groupBy = transformer.transformNullableChild(groupBy, this, arg);
+// transformer.transformChildren(windowDeclarations, this, arg);
+ limit = transformer.transformNullableChild(limit, this, arg);
+ orderBy = transformer.transformNullableChild(orderBy, this, arg);
+ }
+
@override
Iterable get childNodes {
return [
@@ -65,7 +77,7 @@ class SelectStatement extends BaseSelectStatement
}
class CompoundSelectStatement extends BaseSelectStatement {
- final SelectStatementNoCompound base;
+ SelectStatementNoCompound base;
final List additional;
// the grammar under https://www.sqlite.org/syntax/compound-select-stmt.html
@@ -88,6 +100,13 @@ class CompoundSelectStatement extends BaseSelectStatement {
return visitor.visitCompoundSelectStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ withClause = transformer.transformNullableChild(withClause, this, arg);
+ base = transformer.transformChild(base, this, arg);
+ transformer.transformChildren(additional, this, arg);
+ }
+
@override
bool contentEquals(CompoundSelectStatement other) {
// this class doesn't contain anything but child nodes
@@ -108,6 +127,11 @@ class ValuesSelectStatement extends BaseSelectStatement
return visitor.visitValuesSelectStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(values, this, arg);
+ }
+
@override
Iterable get childNodes => values;
@@ -132,6 +156,9 @@ class StarResultColumn extends ResultColumn {
@override
Iterable get childNodes => const [];
+ @override
+ void transformChildren(Transformer transformer, A arg) {}
+
@override
bool contentEquals(StarResultColumn other) {
return other.tableName == tableName;
@@ -140,7 +167,7 @@ class StarResultColumn extends ResultColumn {
class ExpressionResultColumn extends ResultColumn
implements Renamable, Referencable {
- final Expression expression;
+ Expression expression;
@override
final String as;
@@ -152,6 +179,11 @@ class ExpressionResultColumn extends ResultColumn
@override
Iterable get childNodes => [expression];
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
bool contentEquals(ExpressionResultColumn other) {
return other.as == as;
@@ -161,7 +193,7 @@ class ExpressionResultColumn extends ResultColumn
class GroupBy extends AstNode {
/// The list of expressions that form the partition
final List by;
- final Expression having;
+ Expression having;
GroupBy({@required this.by, this.having});
@@ -170,6 +202,12 @@ class GroupBy extends AstNode {
return visitor.visitGroupBy(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ transformer.transformChildren(by, this, arg);
+ transformer.transformChild(having, this, arg);
+ }
+
@override
Iterable get childNodes => [...by, if (having != null) having];
@@ -188,7 +226,7 @@ enum CompoundSelectMode {
class CompoundSelectPart extends AstNode {
final CompoundSelectMode mode;
- final SelectStatementNoCompound select;
+ SelectStatementNoCompound select;
/// The first token of this statement, so either union, intersect or except.
Token firstModeToken;
@@ -206,6 +244,11 @@ class CompoundSelectPart extends AstNode {
return visitor.visitCompoundSelectPart(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ select = transformer.transformChild(select, this, arg);
+ }
+
@override
bool contentEquals(CompoundSelectPart other) => mode == other.mode;
}
diff --git a/sqlparser/lib/src/ast/statements/update.dart b/sqlparser/lib/src/ast/statements/update.dart
index 3f721537..da37b295 100644
--- a/sqlparser/lib/src/ast/statements/update.dart
+++ b/sqlparser/lib/src/ast/statements/update.dart
@@ -18,10 +18,10 @@ const Map _tokensToMode = {
class UpdateStatement extends CrudStatement implements StatementWithWhere {
final FailureMode or;
- final TableReference table;
+ TableReference table;
final List set;
@override
- final Expression where;
+ Expression where;
UpdateStatement(
{WithClause withClause,
@@ -36,6 +36,14 @@ class UpdateStatement extends CrudStatement implements StatementWithWhere {
return visitor.visitUpdateStatement(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ withClause = transformer.transformNullableChild(withClause, this, arg);
+ table = transformer.transformChild(table, this, arg);
+ transformer.transformChildren(set, this, arg);
+ where = transformer.transformChild(where, this, arg);
+ }
+
@override
Iterable get childNodes => [
if (withClause != null) withClause,
@@ -55,8 +63,8 @@ class UpdateStatement extends CrudStatement implements StatementWithWhere {
}
class SetComponent extends AstNode {
- final Reference column;
- final Expression expression;
+ Reference column;
+ Expression expression;
SetComponent({@required this.column, @required this.expression});
@@ -65,6 +73,12 @@ class SetComponent extends AstNode {
return visitor.visitSetComponent(this, arg);
}
+ @override
+ void transformChildren(Transformer transformer, A arg) {
+ column = transformer.transformChild(column, this, arg);
+ expression = transformer.transformChild(expression, this, arg);
+ }
+
@override
Iterable get childNodes => [column, expression];
diff --git a/sqlparser/lib/src/ast/visitor.dart b/sqlparser/lib/src/ast/visitor.dart
index b7db74bd..6191ad8e 100644
--- a/sqlparser/lib/src/ast/visitor.dart
+++ b/sqlparser/lib/src/ast/visitor.dart
@@ -467,6 +467,11 @@ class RecursiveVisitor implements AstVisitor {
}
}
+class Transformer extends RecursiveVisitor {
+ @override
+ AstNode defaultNode(AstNode e, A arg) => e..transformChildren(this, arg);
+}
+
extension VisitChildrenExtension on AstVisitor {
/// Visits the node [e] by calling [AstNode.accept].
R visit(AstNode e, A arg) => e.accept(this, arg);
@@ -496,3 +501,39 @@ extension VisitChildrenExtension on AstVisitor {
}
}
}
+
+extension TransformerUtils on Transformer {
+ AstNode transform(AstNode e, A arg) => visit(e, arg);
+
+ T transformChild(T child, AstNode parent, A arg) {
+ final transformed = transform(child, arg)..parent = parent;
+ return transformed as T;
+ }
+
+ T /*?*/ transformNullableChild(
+ T /*?*/ child,
+ AstNode parent,
+ A arg,
+ ) {
+ if (child == null) return null;
+
+ final transformed = transform(child, arg);
+ transformed?.parent = parent;
+ return transformed as T;
+ }
+
+ void transformChildren(List children, AstNode parent, A arg) {
+ final newChildren = [];
+
+ for (final child in children) {
+ final transformed = transform(child, arg);
+ if (transformed != null) {
+ newChildren.add(transformed..parent = parent);
+ }
+ }
+
+ children
+ ..clear()
+ ..addAll(newChildren);
+ }
+}
diff --git a/sqlparser/lib/src/reader/parser/crud.dart b/sqlparser/lib/src/reader/parser/crud.dart
index 4a916ba4..9f1ae338 100644
--- a/sqlparser/lib/src/reader/parser/crud.dart
+++ b/sqlparser/lib/src/reader/parser/crud.dart
@@ -790,7 +790,7 @@ mixin CrudParser on ParserBase {
} else {
// FOLLOWING is not supported in the short-hand syntax
start = _frameBoundary(isStartBounds: true, parseExprFollowing: false);
- end = const FrameBoundary.currentRow();
+ end = FrameBoundary.currentRow();
}
var exclude = ExcludeMode.noOthers;
@@ -821,17 +821,17 @@ mixin CrudParser on ParserBase {
// the CURRENT ROW boundary is supported for all modes
if (_matchOne(TokenType.current)) {
_consume(TokenType.row, 'Expected ROW to finish CURRENT ROW boundary');
- return const FrameBoundary.currentRow();
+ return FrameBoundary.currentRow();
}
if (_matchOne(TokenType.unbounded)) {
// if this is a start boundary, only UNBOUNDED PRECEDING makes sense.
// Otherwise, only UNBOUNDED FOLLOWING makes sense
if (isStartBounds) {
_consume(TokenType.preceding, 'Expected UNBOUNDED PRECEDING');
- return const FrameBoundary.unboundedPreceding();
+ return FrameBoundary.unboundedPreceding();
} else {
_consume(TokenType.following, 'Expected UNBOUNDED FOLLOWING');
- return const FrameBoundary.unboundedFollowing();
+ return FrameBoundary.unboundedFollowing();
}
}
diff --git a/sqlparser/test/analysis/reference_resolver_test.dart b/sqlparser/test/analysis/reference_resolver_test.dart
index 7b7e8b51..a06d12fb 100644
--- a/sqlparser/test/analysis/reference_resolver_test.dart
+++ b/sqlparser/test/analysis/reference_resolver_test.dart
@@ -172,7 +172,7 @@ SELECT row_number() OVER wnd FROM demo
partitionBy: [Reference(columnName: 'content')],
frameSpec: FrameSpec(
type: FrameType.groups,
- start: const FrameBoundary.currentRow(),
+ start: FrameBoundary.currentRow(),
excludeMode: ExcludeMode.ties,
),
),
diff --git a/sqlparser/test/parser/partition_test.dart b/sqlparser/test/parser/partition_test.dart
index 30d0b6d6..48e42cbd 100644
--- a/sqlparser/test/parser/partition_test.dart
+++ b/sqlparser/test/parser/partition_test.dart
@@ -32,7 +32,7 @@ final Map _testCases = {
],
frameSpec: FrameSpec(
type: FrameType.groups,
- start: const FrameBoundary.unboundedPreceding(),
+ start: FrameBoundary.unboundedPreceding(),
end: FrameBoundary.following(
NumericLiteral(3, token(TokenType.numberLiteral)),
),
@@ -47,8 +47,8 @@ final Map _testCases = {
windowDefinition: WindowDefinition(
frameSpec: FrameSpec(
type: FrameType.range,
- start: const FrameBoundary.currentRow(),
- end: const FrameBoundary.currentRow(),
+ start: FrameBoundary.currentRow(),
+ end: FrameBoundary.currentRow(),
excludeMode: ExcludeMode.noOthers,
),
),