mirror of https://github.com/AMT-Cheif/drift.git
Start with transformers in sqlparser
This commit is contained in:
parent
01e5a47189
commit
fee32fc302
|
@ -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!
|
||||
|
||||
|
|
|
@ -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<A>(Transformer<A> 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.
|
||||
|
|
|
@ -17,6 +17,12 @@ class Limit extends AstNode implements LimitBase {
|
|||
return visitor.visitLimit(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
count = transformer.transformChild(count, this, arg);
|
||||
offset = transformer.transformNullableChild(offset, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [count, if (offset != null) offset];
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ class OrderBy extends AstNode implements OrderByBase {
|
|||
return visitor.visitOrderBy(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(terms, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
expression = transformer.transformChild(expression, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [expression];
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ part of '../ast.dart';
|
|||
class UpsertClause extends AstNode implements HasWhereClause {
|
||||
final List<IndexedColumn> /*?*/ 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<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(onColumns, this, arg);
|
||||
where = transformer.transformNullableChild(where, this, arg);
|
||||
action = transformer.transformChild(action, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes {
|
||||
return [
|
||||
|
@ -35,6 +42,9 @@ class DoNothing extends UpsertAction {
|
|||
return visitor.visitDoNothing(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
|
@ -45,7 +55,7 @@ class DoNothing extends UpsertAction {
|
|||
class DoUpdate extends UpsertAction implements HasWhereClause {
|
||||
final List<SetComponent> 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<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(set, this, arg);
|
||||
where = transformer.transformNullableChild(where, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [...set, if (where != null) where];
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@ class WithClause extends AstNode {
|
|||
return visitor.visitWithClause(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(ctes, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<String> 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<A>(Transformer<A> transformer, A arg) {
|
||||
as = transformer.transformChild(as, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [as];
|
||||
|
||||
|
|
|
@ -60,6 +60,9 @@ class TableReference extends TableOrSubquery
|
|||
return other.tableName == tableName && other.as == as;
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> get childNodes => [statement];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<Join> joins;
|
||||
|
||||
JoinClause({@required this.primary, @required this.joins});
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
primary = transformer.transformChild(primary, this, arg);
|
||||
transformer.transformChildren(joins, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||
return visitor.visitJoin(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> get childNodes => [parameters];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
parameters = transformer.transformChild(parameters, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get visibleToChildren => false;
|
||||
|
||||
|
|
|
@ -21,6 +21,11 @@ class Tuple extends Expression {
|
|||
return visitor.visitTuple(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(expressions, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Expression> get childNodes => expressions;
|
||||
|
||||
|
|
|
@ -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 <window-name>` 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<A>(Transformer<A> transformer, A arg) {
|
||||
parameters = transformer.transformChild(parameters, this, arg);
|
||||
filter = transformer.transformNullableChild(filter, this, arg);
|
||||
windowDefinition =
|
||||
transformer.transformNullableChild(windowDefinition, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes {
|
||||
return [
|
||||
|
@ -65,6 +73,7 @@ class AggregateExpression extends Expression
|
|||
/// `WINDOW <name> AS <window-defn>`. 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<Expression> 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<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(partitionBy, this, arg);
|
||||
orderBy = transformer.transformNullableChild(orderBy, this, arg);
|
||||
frameSpec = transformer.transformChild(frameSpec, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||
return visitor.visitFrameSpec(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
part of '../ast.dart';
|
||||
|
||||
class CaseExpression extends Expression {
|
||||
final Expression base; // can be null
|
||||
Expression /*?*/ base;
|
||||
final List<WhenComponent> 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<A>(Transformer<A> transformer, A arg) {
|
||||
base = transformer.transformNullableChild(base, this, arg);
|
||||
transformer.transformChildren(whens, this, arg);
|
||||
elseExpr = transformer.transformNullableChild(elseExpr, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
when = transformer.transformChild(when, this, arg);
|
||||
then = transformer.transformChild(then, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [when, then];
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ part of '../ast.dart';
|
|||
|
||||
/// A `CAST(<expr> AS <type>)` 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<A>(Transformer<A> transformer, A arg) {
|
||||
operand = transformer.transformChild(operand, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [operand];
|
||||
|
||||
|
|
|
@ -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<A>(Transformer<A> transformer, A arg) {
|
||||
parameters = transformer.transformChild(parameters, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes {
|
||||
return [parameters];
|
||||
|
@ -57,6 +62,9 @@ class StarFunctionParameter extends FunctionParameters {
|
|||
return visitor.visitStarFunctionParameter(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => const Iterable.empty();
|
||||
|
||||
|
@ -77,6 +85,11 @@ class ExprFunctionParameters extends FunctionParameters {
|
|||
return visitor.visitExpressionFunctionParameters(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(parameters, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
List<AstNode> get childNodes => parameters;
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@ abstract class Literal<T> extends Expression {
|
|||
@override
|
||||
final Iterable<AstNode> childNodes = const <AstNode>[];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Literal with value $value';
|
||||
|
|
|
@ -20,6 +20,9 @@ class Reference extends Expression with ReferenceOwner {
|
|||
return visitor.visitReference(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
|
|
|
@ -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<A>(Transformer<A> transformer, A arg) {
|
||||
inner = transformer.transformChild(inner, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
left = transformer.transformChild(left, this, arg);
|
||||
right = transformer.transformChild(right, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
left = transformer.transformChild(left, this, arg);
|
||||
right = transformer.transformChild(right, this, arg);
|
||||
escape = transformer.transformNullableChild(escape, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
left = transformer.transformChild(left, this, arg);
|
||||
right = transformer.transformChild(right, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
operand = transformer.transformChild(operand, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
check = transformer.transformChild(check, this, arg);
|
||||
lower = transformer.transformChild(lower, this, arg);
|
||||
upper = transformer.transformChild(upper, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Expression> 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<Expression> get childNodes => [left, inside];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<A>(Transformer<A> transformer, A arg) {
|
||||
expression = transformer.transformChild(expression, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [expression];
|
||||
|
||||
|
|
|
@ -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<A>(Transformer<A> transformer, A arg) {
|
||||
select = transformer.transformChild(select, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
select = transformer.transformChild(select, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [select];
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ class NumberedVariable extends Expression with Variable {
|
|||
return visitor.visitNumberedVariable(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
|
@ -38,6 +41,9 @@ class ColonNamedVariable extends Expression with Variable {
|
|||
return visitor.visitNamedVariable(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [];
|
||||
|
||||
|
|
|
@ -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<StatementParameter> 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<A>(Transformer<A> transformer, A arg) {
|
||||
statement = transformer.transformChild(statement, this, arg);
|
||||
if (parameters != null) {
|
||||
transformer.transformChildren(parameters, this, arg);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<AstNode> get childNodes => [variable];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
variable = transformer.transformChild(variable, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
bool contentEquals(VariableTypeHint other) {
|
||||
return other.typeName == typeName;
|
||||
|
|
|
@ -13,6 +13,9 @@ class ImportStatement extends Statement implements PartOfMoorFile {
|
|||
return visitor.visitMoorImportStatement(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
final Iterable<AstNode> childNodes = const [];
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ abstract class DartPlaceholder extends AstNode {
|
|||
@override
|
||||
final Iterable<AstNode> childNodes = const Iterable.empty();
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||
return visitor.visitDartPlaceholder(this, arg);
|
||||
|
|
|
@ -17,6 +17,11 @@ class MoorFile extends AstNode {
|
|||
return visitor.visitMoorFile(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(statements, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => statements;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ class NestedStarResultColumn extends ResultColumn {
|
|||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
bool contentEquals(NestedStarResultColumn other) {
|
||||
return other.tableName == tableName;
|
||||
|
|
|
@ -20,6 +20,11 @@ class ColumnDefinition extends AstNode {
|
|||
return visitor.visitColumnDefinition(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(constraints, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => constraints;
|
||||
|
||||
|
@ -102,6 +107,9 @@ class NotNull extends ColumnConstraint {
|
|||
@override
|
||||
final Iterable<AstNode> childNodes = const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
bool _equalToConstraint(NotNull other) => onConflict == other.onConflict;
|
||||
}
|
||||
|
@ -118,6 +126,9 @@ class PrimaryKeyColumn extends ColumnConstraint {
|
|||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
bool _equalToConstraint(PrimaryKeyColumn other) {
|
||||
return other.autoIncrement == autoIncrement &&
|
||||
|
@ -134,6 +145,9 @@ class UniqueColumn extends ColumnConstraint {
|
|||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> get childNodes => [expression];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> get childNodes => [expression];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> childNodes = const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> get childNodes => [clause];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> childNodes = const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<A>(Transformer<A> transformer, A arg) {}
|
||||
}
|
||||
|
|
|
@ -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<Reference> columnNames;
|
||||
final ReferenceAction onDelete;
|
||||
final ReferenceAction onUpdate;
|
||||
|
@ -19,6 +19,12 @@ class ForeignKeyClause extends AstNode {
|
|||
return visitor.visitForeignKeyClause(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
foreignTable = transformer.transformChild(foreignTable, this, arg);
|
||||
transformer.transformChildren(columnNames, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [foreignTable, ...columnNames];
|
||||
|
||||
|
@ -66,25 +72,35 @@ class KeyClause extends TableConstraint {
|
|||
return other.isPrimaryKey == isPrimaryKey && other.onConflict == onConflict;
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(indexedColumns, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
expression = transformer.transformChild(expression, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [expression];
|
||||
}
|
||||
|
||||
class ForeignKeyTableConstraint extends TableConstraint {
|
||||
final List<Reference> 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<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(columns, this, arg);
|
||||
clause = transformer.transformChild(clause, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [...columns, clause];
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@ class Block extends AstNode {
|
|||
return visitor.visitBlock(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(statements, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => statements;
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ class CreateIndexStatement extends Statement
|
|||
final bool ifNotExists;
|
||||
IdentifierToken nameToken;
|
||||
|
||||
final TableReference on;
|
||||
TableReference on;
|
||||
final List<IndexedColumn> 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<A>(Transformer<A> transformer, A arg) {
|
||||
on = transformer.transformChild(on, this, arg);
|
||||
transformer.transformChildren(columns, this, arg);
|
||||
where = transformer.transformNullableChild(where, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<AstNode> get childNodes => [expression];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
expression = transformer.transformChild(expression, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
bool contentEquals(IndexedColumn other) => other.ordering == ordering;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,12 @@ class CreateTableStatement extends TableInducingStatement {
|
|||
return visitor.visitCreateTableStatement(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(columns, this, arg);
|
||||
transformer.transformChildren(tableConstraints, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [...columns, ...tableConstraints];
|
||||
|
||||
|
@ -83,6 +89,9 @@ class CreateVirtualTableStatement extends TableInducingStatement {
|
|||
return visitor.visitCreateVirtualTableStatement(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
|
|
|
@ -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<A>(Transformer<A> transformer, A arg) {
|
||||
onTable = transformer.transformChild(onTable, this, arg);
|
||||
when = transformer.transformNullableChild(when, this, arg);
|
||||
action = transformer.transformChild(action, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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
|
||||
|
|
|
@ -7,7 +7,7 @@ class CreateViewStatement extends Statement implements CreatingStatement {
|
|||
final String viewName;
|
||||
IdentifierToken viewNameToken;
|
||||
|
||||
final BaseSelectStatement query;
|
||||
BaseSelectStatement query;
|
||||
|
||||
final List<String> columns;
|
||||
|
||||
|
@ -25,6 +25,11 @@ class CreateViewStatement extends Statement implements CreatingStatement {
|
|||
return visitor.visitCreateViewStatement(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
query = transformer.transformChild(query, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [query];
|
||||
|
||||
|
|
|
@ -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<A>(Transformer<A> transformer, A arg) {
|
||||
withClause = transformer.transformNullableChild(withClause, this, arg);
|
||||
from = transformer.transformChild(from, this, arg);
|
||||
where = transformer.transformNullableChild(where, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [
|
||||
if (withClause != null) withClause,
|
||||
|
|
|
@ -12,10 +12,10 @@ enum InsertMode {
|
|||
|
||||
class InsertStatement extends CrudStatement {
|
||||
final InsertMode mode;
|
||||
final TableReference table;
|
||||
TableReference table;
|
||||
final List<Reference> targetColumns;
|
||||
final InsertSource source;
|
||||
final UpsertClause upsert;
|
||||
InsertSource source;
|
||||
UpsertClause upsert;
|
||||
|
||||
List<Column> get resolvedTargetColumns {
|
||||
if (targetColumns.isNotEmpty) {
|
||||
|
@ -40,6 +40,13 @@ class InsertStatement extends CrudStatement {
|
|||
return visitor.visitInsertStatement(this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
withClause = transformer.transformNullableChild(withClause, this, arg);
|
||||
table = transformer.transformChild(table, this, arg);
|
||||
transformer.transformChildren(targetColumns, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<AstNode> get childNodes;
|
||||
|
||||
|
|
|
@ -17,15 +17,15 @@ class SelectStatement extends BaseSelectStatement
|
|||
implements StatementWithWhere, SelectStatementNoCompound {
|
||||
final bool distinct;
|
||||
final List<ResultColumn> columns;
|
||||
final Queryable /*?*/ from;
|
||||
Queryable /*?*/ from;
|
||||
|
||||
@override
|
||||
final Expression where;
|
||||
final GroupBy groupBy;
|
||||
Expression where;
|
||||
GroupBy groupBy;
|
||||
final List<NamedWindowDeclaration> 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<A>(Transformer<A> 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<AstNode> get childNodes {
|
||||
return [
|
||||
|
@ -65,7 +77,7 @@ class SelectStatement extends BaseSelectStatement
|
|||
}
|
||||
|
||||
class CompoundSelectStatement extends BaseSelectStatement {
|
||||
final SelectStatementNoCompound base;
|
||||
SelectStatementNoCompound base;
|
||||
final List<CompoundSelectPart> 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<A>(Transformer<A> 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<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(values, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => values;
|
||||
|
||||
|
@ -132,6 +156,9 @@ class StarResultColumn extends ResultColumn {
|
|||
@override
|
||||
Iterable<AstNode> get childNodes => const [];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<AstNode> get childNodes => [expression];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> 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<Expression> 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<A>(Transformer<A> transformer, A arg) {
|
||||
transformer.transformChildren(by, this, arg);
|
||||
transformer.transformChild(having, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
select = transformer.transformChild(select, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
bool contentEquals(CompoundSelectPart other) => mode == other.mode;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@ const Map<TokenType, FailureMode> _tokensToMode = {
|
|||
|
||||
class UpdateStatement extends CrudStatement implements StatementWithWhere {
|
||||
final FailureMode or;
|
||||
final TableReference table;
|
||||
TableReference table;
|
||||
final List<SetComponent> 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<A>(Transformer<A> 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<AstNode> 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<A>(Transformer<A> transformer, A arg) {
|
||||
column = transformer.transformChild(column, this, arg);
|
||||
expression = transformer.transformChild(expression, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [column, expression];
|
||||
|
||||
|
|
|
@ -467,6 +467,11 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
|
|||
}
|
||||
}
|
||||
|
||||
class Transformer<A> extends RecursiveVisitor<A, AstNode /*?*/ > {
|
||||
@override
|
||||
AstNode defaultNode(AstNode e, A arg) => e..transformChildren(this, arg);
|
||||
}
|
||||
|
||||
extension VisitChildrenExtension<A, R> on AstVisitor<A, R> {
|
||||
/// Visits the node [e] by calling [AstNode.accept].
|
||||
R visit(AstNode e, A arg) => e.accept(this, arg);
|
||||
|
@ -496,3 +501,39 @@ extension VisitChildrenExtension<A, R> on AstVisitor<A, R> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TransformerUtils<A> on Transformer<A> {
|
||||
AstNode transform(AstNode e, A arg) => visit(e, arg);
|
||||
|
||||
T transformChild<T extends AstNode>(T child, AstNode parent, A arg) {
|
||||
final transformed = transform(child, arg)..parent = parent;
|
||||
return transformed as T;
|
||||
}
|
||||
|
||||
T /*?*/ transformNullableChild<T extends AstNode>(
|
||||
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<AstNode> children, AstNode parent, A arg) {
|
||||
final newChildren = <AstNode>[];
|
||||
|
||||
for (final child in children) {
|
||||
final transformed = transform(child, arg);
|
||||
if (transformed != null) {
|
||||
newChildren.add(transformed..parent = parent);
|
||||
}
|
||||
}
|
||||
|
||||
children
|
||||
..clear()
|
||||
..addAll(newChildren);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -790,7 +790,7 @@ mixin CrudParser on ParserBase {
|
|||
} else {
|
||||
// <expr> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -32,7 +32,7 @@ final Map<String, Expression> _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<String, Expression> _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,
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue