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, ), ),