diff --git a/sqlparser/lib/src/ast/ast.dart b/sqlparser/lib/src/ast/ast.dart index 18900994..fca95be9 100644 --- a/sqlparser/lib/src/ast/ast.dart +++ b/sqlparser/lib/src/ast/ast.dart @@ -1,9 +1,9 @@ -import 'package:collection/collection.dart'; import 'package:meta/meta.dart'; import 'package:source_span/source_span.dart'; import 'package:sqlparser/src/analysis/analysis.dart'; import 'package:sqlparser/src/reader/syntactic_entity.dart'; import 'package:sqlparser/src/reader/tokenizer/token.dart'; +import 'package:sqlparser/src/utils/ast_equality.dart'; import 'package:sqlparser/src/utils/meta.dart'; part 'clauses/limit.dart'; @@ -167,7 +167,16 @@ abstract class AstNode with HasMetaMixin implements SyntacticEntity { /// 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. - bool contentEquals(covariant AstNode other); + @nonVirtual + bool contentEquals(AstNode other) { + final checker = EqualityEnforcingVisitor(this, considerChildren: false); + try { + checker.visit(other, null); + return true; + } on NotEqualException { + return false; + } + } @override String toString() { diff --git a/sqlparser/lib/src/ast/clauses/limit.dart b/sqlparser/lib/src/ast/clauses/limit.dart index 3ce25a78..0f7b60d5 100644 --- a/sqlparser/lib/src/ast/clauses/limit.dart +++ b/sqlparser/lib/src/ast/clauses/limit.dart @@ -33,7 +33,4 @@ class Limit extends AstNode implements LimitBase { // If using a comma, the count is followed by an optional offset return [count, if (offset != null) offset]; } - - @override - bool contentEquals(Limit other) => true; } diff --git a/sqlparser/lib/src/ast/clauses/ordering.dart b/sqlparser/lib/src/ast/clauses/ordering.dart index 3c0f1c50..839336a1 100644 --- a/sqlparser/lib/src/ast/clauses/ordering.dart +++ b/sqlparser/lib/src/ast/clauses/ordering.dart @@ -26,11 +26,6 @@ class OrderBy extends AstNode implements OrderByBase { @override Iterable get childNodes => terms; - - @override - bool contentEquals(OrderBy other) { - return true; - } } enum OrderingMode { ascending, descending } @@ -59,9 +54,4 @@ class OrderingTerm extends AstNode implements OrderingTermBase { @override Iterable get childNodes => [expression]; - - @override - bool contentEquals(OrderingTerm other) { - return other.orderingMode == orderingMode && other.nulls == nulls; - } } diff --git a/sqlparser/lib/src/ast/clauses/upsert.dart b/sqlparser/lib/src/ast/clauses/upsert.dart index ac554128..b84fa047 100644 --- a/sqlparser/lib/src/ast/clauses/upsert.dart +++ b/sqlparser/lib/src/ast/clauses/upsert.dart @@ -29,9 +29,6 @@ class UpsertClause extends AstNode implements HasWhereClause { action, ]; } - - @override - bool contentEquals(UpsertClause other) => true; } abstract class UpsertAction extends AstNode {} @@ -47,9 +44,6 @@ class DoNothing extends UpsertAction { @override Iterable get childNodes => const []; - - @override - bool contentEquals(DoNothing other) => true; } class DoUpdate extends UpsertAction implements HasWhereClause { @@ -72,7 +66,4 @@ class DoUpdate extends UpsertAction implements HasWhereClause { @override Iterable get childNodes => [...set, if (where != null) where]; - - @override - bool contentEquals(DoUpdate other) => true; } diff --git a/sqlparser/lib/src/ast/clauses/with.dart b/sqlparser/lib/src/ast/clauses/with.dart index 4990b05c..6296e213 100644 --- a/sqlparser/lib/src/ast/clauses/with.dart +++ b/sqlparser/lib/src/ast/clauses/with.dart @@ -22,9 +22,6 @@ class WithClause extends AstNode { @override Iterable get childNodes => ctes; - - @override - bool contentEquals(WithClause other) => other.recursive == recursive; } class CommonTableExpression extends AstNode with ResultSet { @@ -57,11 +54,6 @@ class CommonTableExpression extends AstNode with ResultSet { @override Iterable get childNodes => [as]; - @override - bool contentEquals(CommonTableExpression other) { - return other.cteTableName == cteTableName; - } - @override List get resolvedColumns { final columnsOfSelect = as.resolvedColumns; diff --git a/sqlparser/lib/src/ast/common/queryables.dart b/sqlparser/lib/src/ast/common/queryables.dart index f2b79641..9ec76e2d 100644 --- a/sqlparser/lib/src/ast/common/queryables.dart +++ b/sqlparser/lib/src/ast/common/queryables.dart @@ -55,11 +55,6 @@ class TableReference extends TableOrSubquery return visitor.visitTableReference(this, arg); } - @override - bool contentEquals(TableReference other) { - return other.tableName == tableName && other.as == as; - } - @override void transformChildren(Transformer transformer, A arg) {} @@ -93,11 +88,6 @@ class SelectStatementAsSource extends TableOrSubquery implements Renamable { void transformChildren(Transformer transformer, A arg) { statement = transformer.transformChild(statement, this, arg); } - - @override - bool contentEquals(SelectStatementAsSource other) { - return other.as == as; - } } /// https://www.sqlite.org/syntax/join-clause.html @@ -120,11 +110,6 @@ class JoinClause extends Queryable { @override Iterable get childNodes => [primary, ...joins]; - - @override - bool contentEquals(JoinClause other) { - return true; // equality is defined by child nodes - } } enum JoinOperator { @@ -156,27 +141,6 @@ class Join extends AstNode { ]; } - @override - bool contentEquals(Join other) { - if (other.natural != natural || other.operator != operator) { - return false; - } - - if (constraint is OnConstraint) { - return other.constraint is OnConstraint; - } else if (constraint is UsingConstraint) { - final typedConstraint = constraint as UsingConstraint; - if (other.constraint is! UsingConstraint) { - return false; - } - final typedOther = other.constraint as UsingConstraint; - - return const ListEquality() - .equals(typedConstraint.columnNames, typedOther.columnNames); - } - return true; - } - @override R accept(AstVisitor visitor, A arg) { return visitor.visitJoin(this, arg); @@ -238,9 +202,4 @@ class TableValuedFunction extends Queryable @override bool get visibleToChildren => false; - - @override - bool contentEquals(TableValuedFunction other) { - return other.name == name; - } } diff --git a/sqlparser/lib/src/ast/common/tuple.dart b/sqlparser/lib/src/ast/common/tuple.dart index 904ae01d..7bc1e020 100644 --- a/sqlparser/lib/src/ast/common/tuple.dart +++ b/sqlparser/lib/src/ast/common/tuple.dart @@ -28,7 +28,4 @@ class Tuple extends Expression { @override List get childNodes => expressions; - - @override - bool contentEquals(Tuple other) => true; } diff --git a/sqlparser/lib/src/ast/expressions/aggregate.dart b/sqlparser/lib/src/ast/expressions/aggregate.dart index 6f1f01ec..baabbfca 100644 --- a/sqlparser/lib/src/ast/expressions/aggregate.dart +++ b/sqlparser/lib/src/ast/expressions/aggregate.dart @@ -62,11 +62,6 @@ class AggregateExpression extends Expression if (windowDefinition != null) windowDefinition, ]; } - - @override - bool contentEquals(AggregateExpression other) { - return other.name == name && other.windowName == windowName; - } } /// A window declaration that appears in a `SELECT` statement like @@ -107,11 +102,6 @@ class WindowDefinition extends AstNode { @override Iterable get childNodes => [...partitionBy, if (orderBy != null) orderBy, frameSpec]; - - @override - bool contentEquals(WindowDefinition other) { - return other.baseWindowName == baseWindowName; - } } class FrameSpec extends AstNode { @@ -148,14 +138,6 @@ class FrameSpec extends AstNode { if (start.isExpressionOffset) start.offset, if (end.isExpressionOffset) end.offset, ]; - - @override - bool contentEquals(FrameSpec other) { - return other.type == type && - other.excludeMode == excludeMode && - other.start == start && - other.end == end; - } } /// Defines how a [FrameBoundary] count rows or groups. See diff --git a/sqlparser/lib/src/ast/expressions/case.dart b/sqlparser/lib/src/ast/expressions/case.dart index 593a5af7..991d25e2 100644 --- a/sqlparser/lib/src/ast/expressions/case.dart +++ b/sqlparser/lib/src/ast/expressions/case.dart @@ -22,9 +22,6 @@ class CaseExpression extends Expression { @override Iterable get childNodes => [if (base != null) base, ...whens, if (elseExpr != null) elseExpr]; - - @override - bool contentEquals(CaseExpression other) => true; } class WhenComponent extends AstNode { @@ -46,7 +43,4 @@ class WhenComponent extends AstNode { @override Iterable get childNodes => [when, then]; - - @override - bool contentEquals(WhenComponent other) => true; } diff --git a/sqlparser/lib/src/ast/expressions/cast.dart b/sqlparser/lib/src/ast/expressions/cast.dart index 6ba8a9b9..9ead345f 100644 --- a/sqlparser/lib/src/ast/expressions/cast.dart +++ b/sqlparser/lib/src/ast/expressions/cast.dart @@ -19,9 +19,4 @@ class CastExpression extends Expression { @override Iterable get childNodes => [operand]; - - @override - bool contentEquals(CastExpression other) { - return other.typeName == typeName; - } } diff --git a/sqlparser/lib/src/ast/expressions/function.dart b/sqlparser/lib/src/ast/expressions/function.dart index b8948fa9..9df44d8b 100644 --- a/sqlparser/lib/src/ast/expressions/function.dart +++ b/sqlparser/lib/src/ast/expressions/function.dart @@ -40,11 +40,6 @@ class FunctionExpression extends Expression Iterable get childNodes { return [parameters]; } - - @override - bool contentEquals(FunctionExpression other) { - return other.name == name; - } } /// Marker interface for anything that can be inside the parentheses after a @@ -67,11 +62,6 @@ class StarFunctionParameter extends FunctionParameters { @override Iterable get childNodes => const Iterable.empty(); - - @override - bool contentEquals(StarFunctionParameter other) { - return true; - } } class ExprFunctionParameters extends FunctionParameters { @@ -92,9 +82,4 @@ class ExprFunctionParameters extends FunctionParameters { @override List get childNodes => parameters; - - @override - bool contentEquals(ExprFunctionParameters other) { - return other.distinct == distinct; - } } diff --git a/sqlparser/lib/src/ast/expressions/literals.dart b/sqlparser/lib/src/ast/expressions/literals.dart index a6570d74..bc563a6e 100644 --- a/sqlparser/lib/src/ast/expressions/literals.dart +++ b/sqlparser/lib/src/ast/expressions/literals.dart @@ -30,9 +30,6 @@ class NullLiteral extends Literal { R accept(AstVisitor visitor, A arg) { return visitor.visitNullLiteral(this, arg); } - - @override - bool contentEquals(NullLiteral other) => true; } class NumericLiteral extends Literal { @@ -47,9 +44,6 @@ class NumericLiteral extends Literal { R accept(AstVisitor visitor, A arg) { return visitor.visitNumericLiteral(this, arg); } - - @override - bool contentEquals(NumericLiteral other) => other.value == value; } class BooleanLiteral extends Literal { @@ -67,11 +61,6 @@ class BooleanLiteral extends Literal { R accept(AstVisitor visitor, A arg) { return visitor.visitBooleanLiteral(this, arg); } - - @override - bool contentEquals(BooleanLiteral other) { - return other.value == value; - } } class StringLiteral extends Literal { @@ -91,11 +80,6 @@ class StringLiteral extends Literal { R accept(AstVisitor visitor, A arg) { return visitor.visitStringLiteral(this, arg); } - - @override - bool contentEquals(StringLiteral other) { - return other.isBinary == isBinary && other.value == value; - } } enum TimeConstantKind { currentTime, currentDate, currentTimestamp } @@ -110,11 +94,6 @@ class TimeConstantLiteral extends Literal { return visitor.visitTimeConstantLiteral(this, arg); } - @override - bool contentEquals(TimeConstantLiteral other) { - return other.kind == kind; - } - @override dynamic get value => throw UnimplementedError('TimeConstantLiteral.value'); } diff --git a/sqlparser/lib/src/ast/expressions/reference.dart b/sqlparser/lib/src/ast/expressions/reference.dart index a9d446e3..672a722c 100644 --- a/sqlparser/lib/src/ast/expressions/reference.dart +++ b/sqlparser/lib/src/ast/expressions/reference.dart @@ -26,11 +26,6 @@ class Reference extends Expression with ReferenceOwner { @override Iterable get childNodes => const []; - @override - bool contentEquals(Reference other) { - return other.tableName == tableName && other.columnName == columnName; - } - @override String toString() { if (tableName != null) { diff --git a/sqlparser/lib/src/ast/expressions/simple.dart b/sqlparser/lib/src/ast/expressions/simple.dart index 5335dc0b..07c9d9e8 100644 --- a/sqlparser/lib/src/ast/expressions/simple.dart +++ b/sqlparser/lib/src/ast/expressions/simple.dart @@ -18,11 +18,6 @@ class UnaryExpression extends Expression { @override Iterable get childNodes => [inner]; - - @override - bool contentEquals(UnaryExpression other) { - return other.operator.type == operator.type; - } } class CollateExpression extends UnaryExpression { @@ -40,12 +35,6 @@ class CollateExpression extends UnaryExpression { R accept(AstVisitor visitor, A arg) { return visitor.visitCollateExpression(this, arg); } - - @override - bool contentEquals(CollateExpression other) { - return super.contentEquals(other) && - other.collateFunction.type == collateFunction.type; - } } class BinaryExpression extends Expression { @@ -68,11 +57,6 @@ class BinaryExpression extends Expression { @override Iterable get childNodes => [left, right]; - - @override - bool contentEquals(BinaryExpression other) { - return other.operator.type == operator.type; - } } /// A like, glob, match or regexp expression. @@ -104,9 +88,6 @@ class StringComparisonExpression extends Expression { @override Iterable get childNodes => [left, right, if (escape != null) escape]; - - @override - bool contentEquals(StringComparisonExpression other) => other.not == not; } /// `(NOT)? $left IS $right` @@ -130,11 +111,6 @@ class IsExpression extends Expression { @override Iterable get childNodes => [left, right]; - - @override - bool contentEquals(IsExpression other) { - return other.negated == negated; - } } class IsNullExpression extends Expression { @@ -157,11 +133,6 @@ class IsNullExpression extends Expression { @override Iterable get childNodes => [operand]; - - @override - bool contentEquals(IsNullExpression other) { - return other.negated == negated; - } } /// `$check BETWEEN $lower AND $upper` @@ -187,9 +158,6 @@ class BetweenExpression extends Expression { @override List get childNodes => [check, lower, upper]; - - @override - bool contentEquals(BetweenExpression other) => other.not == not; } /// `$left$ IN $inside`. @@ -219,9 +187,6 @@ class InExpression extends Expression { left = transformer.transformChild(left, this, arg); inside = transformer.transformChild(inside, this, arg); } - - @override - bool contentEquals(InExpression other) => other.not == not; } class Parentheses extends Expression { @@ -245,7 +210,4 @@ class Parentheses extends Expression { @override Iterable get childNodes => [expression]; - - @override - bool contentEquals(Parentheses other) => true; } diff --git a/sqlparser/lib/src/ast/expressions/subquery.dart b/sqlparser/lib/src/ast/expressions/subquery.dart index c156c224..02a22af3 100644 --- a/sqlparser/lib/src/ast/expressions/subquery.dart +++ b/sqlparser/lib/src/ast/expressions/subquery.dart @@ -19,9 +19,6 @@ class SubQuery extends Expression { @override Iterable get childNodes => [select]; - - @override - bool contentEquals(SubQuery other) => true; } class ExistsExpression extends Expression { @@ -41,7 +38,4 @@ class ExistsExpression extends Expression { @override Iterable get childNodes => [select]; - - @override - bool contentEquals(ExistsExpression other) => true; } diff --git a/sqlparser/lib/src/ast/expressions/variables.dart b/sqlparser/lib/src/ast/expressions/variables.dart index 74642fc2..92de30c6 100644 --- a/sqlparser/lib/src/ast/expressions/variables.dart +++ b/sqlparser/lib/src/ast/expressions/variables.dart @@ -23,11 +23,6 @@ class NumberedVariable extends Expression with Variable { @override Iterable get childNodes => const []; - - @override - bool contentEquals(NumberedVariable other) { - return other.explicitIndex == explicitIndex; - } } class ColonNamedVariable extends Expression with Variable { @@ -46,9 +41,4 @@ class ColonNamedVariable extends Expression with Variable { @override Iterable get childNodes => []; - - @override - bool contentEquals(ColonNamedVariable other) { - return other.name == name; - } } diff --git a/sqlparser/lib/src/ast/moor/declared_statement.dart b/sqlparser/lib/src/ast/moor/declared_statement.dart index e5e48b35..4af58c97 100644 --- a/sqlparser/lib/src/ast/moor/declared_statement.dart +++ b/sqlparser/lib/src/ast/moor/declared_statement.dart @@ -36,11 +36,6 @@ class DeclaredStatement extends Statement implements PartOfMoorFile { @override Iterable get childNodes => [statement, if (parameters != null) ...parameters]; - - @override - bool contentEquals(DeclaredStatement other) { - return other.identifier == identifier && other.as == as; - } } /// How a statement was declared in a moor file. @@ -123,11 +118,6 @@ class VariableTypeHint extends StatementParameter { void transformChildren(Transformer transformer, A arg) { variable = transformer.transformChild(variable, this, arg); } - - @override - bool contentEquals(VariableTypeHint other) { - return other.typeName == typeName; - } } /// Set a default value for a dart placeholder. @@ -150,11 +140,6 @@ class DartPlaceholderDefaultValue extends StatementParameter { @override Iterable get childNodes => [defaultValue]; - @override - bool contentEquals(DartPlaceholderDefaultValue other) { - return other.variableName == variableName; - } - @override void transformChildren(Transformer transformer, A arg) { defaultValue = transformer.transformChild(defaultValue, this, arg); diff --git a/sqlparser/lib/src/ast/moor/import_statement.dart b/sqlparser/lib/src/ast/moor/import_statement.dart index 6e05528b..0a5f3929 100644 --- a/sqlparser/lib/src/ast/moor/import_statement.dart +++ b/sqlparser/lib/src/ast/moor/import_statement.dart @@ -18,9 +18,4 @@ class ImportStatement extends Statement implements PartOfMoorFile { @override final Iterable childNodes = const []; - - @override - bool contentEquals(ImportStatement other) { - return other.importedFile == importedFile; - } } diff --git a/sqlparser/lib/src/ast/moor/inline_dart.dart b/sqlparser/lib/src/ast/moor/inline_dart.dart index ddb048b8..492f4e3a 100644 --- a/sqlparser/lib/src/ast/moor/inline_dart.dart +++ b/sqlparser/lib/src/ast/moor/inline_dart.dart @@ -31,13 +31,6 @@ abstract class DartPlaceholder extends AstNode { return visitor.visitDartPlaceholder(this, arg); } - bool _dartEquals(covariant DartPlaceholder other) => true; - - @override - bool contentEquals(DartPlaceholder other) { - return other.name == name && other._dartEquals(other); - } - T when( {T Function(DartExpressionPlaceholder) isExpression, T Function(DartLimitPlaceholder) isLimit, diff --git a/sqlparser/lib/src/ast/moor/moor_file.dart b/sqlparser/lib/src/ast/moor/moor_file.dart index 0278efad..f9a050d6 100644 --- a/sqlparser/lib/src/ast/moor/moor_file.dart +++ b/sqlparser/lib/src/ast/moor/moor_file.dart @@ -28,7 +28,4 @@ class MoorFile extends AstNode { /// Returns the imports defined in this file. Iterable get imports => childNodes.whereType(); - - @override - bool contentEquals(MoorFile other) => true; } 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 5986a255..3873c3ff 100644 --- a/sqlparser/lib/src/ast/moor/nested_star_result_column.dart +++ b/sqlparser/lib/src/ast/moor/nested_star_result_column.dart @@ -17,11 +17,6 @@ class NestedStarResultColumn extends ResultColumn { @override void transformChildren(Transformer transformer, A arg) {} - @override - bool contentEquals(NestedStarResultColumn other) { - return other.tableName == tableName; - } - @override R accept(AstVisitor visitor, A arg) { return visitor.visitMoorNestedStarResultColumn(this, arg); diff --git a/sqlparser/lib/src/ast/schema/column_definition.dart b/sqlparser/lib/src/ast/schema/column_definition.dart index b5bf5534..b827f902 100644 --- a/sqlparser/lib/src/ast/schema/column_definition.dart +++ b/sqlparser/lib/src/ast/schema/column_definition.dart @@ -28,11 +28,6 @@ class ColumnDefinition extends AstNode { @override Iterable get childNodes => constraints; - @override - bool contentEquals(ColumnDefinition other) { - return other.columnName == columnName && other.typeName == typeName; - } - /// Finds a constraint of type [T], or null, if none is set. T findConstraint() { final typedConstraints = constraints.whereType().iterator; @@ -87,14 +82,6 @@ abstract class ColumnConstraint extends AstNode { throw Exception('Did not expect $runtimeType as a ColumnConstraint'); } } - - @visibleForOverriding - bool _equalToConstraint(covariant ColumnConstraint other); - - @override - bool contentEquals(ColumnConstraint other) { - return other.name == name && _equalToConstraint(other); - } } enum ConflictClause { rollback, abort, fail, ignore, replace } @@ -105,9 +92,6 @@ class NullColumnConstraint extends ColumnConstraint { NullColumnConstraint(String name, {this.$null}) : super(name); - @override - bool _equalToConstraint(NullColumnConstraint other) => true; - @override Iterable get childNodes => const Iterable.empty(); @@ -128,9 +112,6 @@ class NotNull extends ColumnConstraint { @override void transformChildren(Transformer transformer, A arg) {} - - @override - bool _equalToConstraint(NotNull other) => onConflict == other.onConflict; } class PrimaryKeyColumn extends ColumnConstraint { @@ -147,13 +128,6 @@ class PrimaryKeyColumn extends ColumnConstraint { @override void transformChildren(Transformer transformer, A arg) {} - - @override - bool _equalToConstraint(PrimaryKeyColumn other) { - return other.autoIncrement == autoIncrement && - other.mode == mode && - other.onConflict == onConflict; - } } class UniqueColumn extends ColumnConstraint { @@ -166,11 +140,6 @@ class UniqueColumn extends ColumnConstraint { @override void transformChildren(Transformer transformer, A arg) {} - - @override - bool _equalToConstraint(UniqueColumn other) { - return other.onConflict == onConflict; - } } class CheckColumn extends ColumnConstraint { @@ -185,9 +154,6 @@ class CheckColumn extends ColumnConstraint { void transformChildren(Transformer transformer, A arg) { expression = transformer.transformChild(expression, this, arg); } - - @override - bool _equalToConstraint(CheckColumn other) => true; } class Default extends ColumnConstraint { @@ -202,9 +168,6 @@ class Default extends ColumnConstraint { void transformChildren(Transformer transformer, A arg) { expression = transformer.transformChild(expression, this, arg); } - - @override - bool _equalToConstraint(Default other) => true; } class CollateConstraint extends ColumnConstraint { @@ -217,9 +180,6 @@ class CollateConstraint extends ColumnConstraint { @override void transformChildren(Transformer transformer, A arg) {} - - @override - bool _equalToConstraint(CollateConstraint other) => true; } class ForeignKeyColumnConstraint extends ColumnConstraint { @@ -227,9 +187,6 @@ class ForeignKeyColumnConstraint extends ColumnConstraint { ForeignKeyColumnConstraint(String name, this.clause) : super(name); - @override - bool _equalToConstraint(ForeignKeyColumnConstraint other) => true; - @override Iterable get childNodes => [clause]; @@ -247,11 +204,6 @@ class MappedBy extends ColumnConstraint { MappedBy(String name, this.mapper) : super(name); - @override - bool _equalToConstraint(MappedBy other) { - return other.mapper.dartCode == mapper.dartCode; - } - @override final Iterable childNodes = const []; @@ -272,11 +224,6 @@ class JsonKey extends ColumnConstraint { JsonKey(String name, this.jsonNameToken) : super(name); - @override - 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 bdf4a044..b4faad01 100644 --- a/sqlparser/lib/src/ast/schema/table_definition.dart +++ b/sqlparser/lib/src/ast/schema/table_definition.dart @@ -35,11 +35,6 @@ class ForeignKeyClause extends AstNode { ...columnNames, if (deferrable != null) deferrable, ]; - - @override - bool contentEquals(ForeignKeyClause other) { - return other.onDelete == onDelete && other.onUpdate == onUpdate; - } } enum InitialDeferrableMode { @@ -69,11 +64,6 @@ class DeferrableClause extends AstNode { @override Iterable get childNodes => const Iterable.empty(); - @override - bool contentEquals(DeferrableClause other) { - return other.not == not && other.declaredInitially == declaredInitially; - } - @override void transformChildren(Transformer transformer, A arg) {} } @@ -89,13 +79,7 @@ abstract class TableConstraint extends AstNode { return visitor.visitTableConstraint(this, arg); } - @override - bool contentEquals(TableConstraint other) { - return other.name == name && _constraintEquals(other); - } - - @visibleForOverriding - bool _constraintEquals(covariant TableConstraint other); + bool constraintEquals(covariant TableConstraint other); } class KeyClause extends TableConstraint { @@ -112,7 +96,7 @@ class KeyClause extends TableConstraint { : super(name); @override - bool _constraintEquals(KeyClause other) { + bool constraintEquals(KeyClause other) { return other.isPrimaryKey == isPrimaryKey && other.onConflict == onConflict; } @@ -131,7 +115,7 @@ class CheckTable extends TableConstraint { CheckTable(String name, this.expression) : super(name); @override - bool _constraintEquals(CheckTable other) => true; + bool constraintEquals(CheckTable other) => true; @override void transformChildren(Transformer transformer, A arg) { @@ -151,7 +135,7 @@ class ForeignKeyTableConstraint extends TableConstraint { : super(name); @override - bool _constraintEquals(ForeignKeyTableConstraint other) => true; + bool constraintEquals(ForeignKeyTableConstraint other) => true; @override void transformChildren(Transformer transformer, A arg) { diff --git a/sqlparser/lib/src/ast/statements/block.dart b/sqlparser/lib/src/ast/statements/block.dart index 1c235d12..f0bc2f13 100644 --- a/sqlparser/lib/src/ast/statements/block.dart +++ b/sqlparser/lib/src/ast/statements/block.dart @@ -20,7 +20,4 @@ class Block extends AstNode { @override Iterable get childNodes => statements; - - @override - bool contentEquals(Block other) => true; } diff --git a/sqlparser/lib/src/ast/statements/create_index.dart b/sqlparser/lib/src/ast/statements/create_index.dart index 2409a617..4f3e1848 100644 --- a/sqlparser/lib/src/ast/statements/create_index.dart +++ b/sqlparser/lib/src/ast/statements/create_index.dart @@ -38,11 +38,6 @@ class CreateIndexStatement extends Statement @override Iterable get childNodes => [on, ...columns, if (where != null) where]; - - @override - bool contentEquals(CreateIndexStatement other) { - return other.indexName == indexName; - } } /// Note that this class matches the productions listed at https://www.sqlite.org/syntax/indexed-column.html @@ -70,7 +65,4 @@ class IndexedColumn extends AstNode { 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 d13235c9..13eac967 100644 --- a/sqlparser/lib/src/ast/statements/create_table.dart +++ b/sqlparser/lib/src/ast/statements/create_table.dart @@ -51,14 +51,6 @@ class CreateTableStatement extends TableInducingStatement { @override Iterable get childNodes => [...columns, ...tableConstraints]; - - @override - bool contentEquals(CreateTableStatement other) { - return other.ifNotExists == ifNotExists && - other.tableName == tableName && - other.withoutRowId == withoutRowId && - other.overriddenDataClassName == overriddenDataClassName; - } } class CreateVirtualTableStatement extends TableInducingStatement { @@ -94,12 +86,4 @@ class CreateVirtualTableStatement extends TableInducingStatement { @override Iterable get childNodes => const []; - - @override - bool contentEquals(CreateVirtualTableStatement other) { - return other.ifNotExists == ifNotExists && - other.tableName == tableName && - other.moduleName == moduleName && - const ListEquality().equals(other.argumentContent, argumentContent); - } } diff --git a/sqlparser/lib/src/ast/statements/create_trigger.dart b/sqlparser/lib/src/ast/statements/create_trigger.dart index 69bab03d..14da7c3e 100644 --- a/sqlparser/lib/src/ast/statements/create_trigger.dart +++ b/sqlparser/lib/src/ast/statements/create_trigger.dart @@ -46,13 +46,6 @@ class CreateTriggerStatement extends Statement implements CreatingStatement { if (when != null) when, action, ]; - - @override - bool contentEquals(CreateTriggerStatement other) { - return other.ifNotExists == ifNotExists && - other.triggerName == triggerName && - other.mode == mode; - } } enum TriggerMode { before, after, insteadOf } @@ -74,9 +67,6 @@ abstract class TriggerTarget extends AstNode { /// Whether this target introduces the "old" table reference in the sub-scope /// of the create trigger statement. bool get introducesOld; - - @override - bool contentEquals(TriggerTarget other) => true; } class DeleteTarget extends TriggerTarget { diff --git a/sqlparser/lib/src/ast/statements/create_view.dart b/sqlparser/lib/src/ast/statements/create_view.dart index 72aece36..7566fbdb 100644 --- a/sqlparser/lib/src/ast/statements/create_view.dart +++ b/sqlparser/lib/src/ast/statements/create_view.dart @@ -32,11 +32,4 @@ class CreateViewStatement extends Statement implements CreatingStatement { @override Iterable get childNodes => [query]; - - @override - bool contentEquals(CreateViewStatement other) { - return other.ifNotExists == ifNotExists && - other.viewName == viewName && - const ListEquality().equals(other.columns, columns); - } } diff --git a/sqlparser/lib/src/ast/statements/delete.dart b/sqlparser/lib/src/ast/statements/delete.dart index 4cd04ed1..cb16c049 100644 --- a/sqlparser/lib/src/ast/statements/delete.dart +++ b/sqlparser/lib/src/ast/statements/delete.dart @@ -30,7 +30,4 @@ class DeleteStatement extends CrudStatement from, if (where != null) where, ]; - - @override - bool contentEquals(DeleteStatement other) => true; } diff --git a/sqlparser/lib/src/ast/statements/insert.dart b/sqlparser/lib/src/ast/statements/insert.dart index 10730f3c..904be723 100644 --- a/sqlparser/lib/src/ast/statements/insert.dart +++ b/sqlparser/lib/src/ast/statements/insert.dart @@ -56,11 +56,6 @@ class InsertStatement extends CrudStatement implements HasPrimarySource { source, if (upsert != null) upsert ]; - - @override - bool contentEquals(InsertStatement other) { - return other.mode == mode && other.source.runtimeType == source.runtimeType; - } } abstract class InsertSource extends AstNode { @@ -94,9 +89,6 @@ class ValuesSource extends InsertSource { return visitor.visitValuesSource(this, arg); } - @override - bool contentEquals(ValuesSource other) => true; - @override void transformChildren(Transformer transformer, A arg) { transformer.transformChildren(values, this, arg); @@ -117,9 +109,6 @@ class SelectInsertSource extends InsertSource { return visitor.visitSelectInsertSource(this, arg); } - @override - bool contentEquals(SelectInsertSource other) => true; - @override void transformChildren(Transformer transformer, A arg) { stmt = transformer.transformChild(stmt, this, arg); @@ -136,9 +125,6 @@ class DefaultValues extends InsertSource { return visitor.visitDefaultValues(this, arg); } - @override - bool contentEquals(DefaultValues other) => true; - @override void transformChildren(Transformer transformer, A arg) {} } diff --git a/sqlparser/lib/src/ast/statements/invalid.dart b/sqlparser/lib/src/ast/statements/invalid.dart index be910062..0597447e 100644 --- a/sqlparser/lib/src/ast/statements/invalid.dart +++ b/sqlparser/lib/src/ast/statements/invalid.dart @@ -10,9 +10,6 @@ class InvalidStatement extends Statement { @override Iterable get childNodes => const Iterable.empty(); - @override - bool contentEquals(InvalidStatement other) => true; - @override void transformChildren(Transformer transformer, A arg) {} } diff --git a/sqlparser/lib/src/ast/statements/select.dart b/sqlparser/lib/src/ast/statements/select.dart index 26ed5f95..f3d95e10 100644 --- a/sqlparser/lib/src/ast/statements/select.dart +++ b/sqlparser/lib/src/ast/statements/select.dart @@ -72,11 +72,6 @@ class SelectStatement extends BaseSelectStatement if (orderBy != null) orderBy, ]; } - - @override - bool contentEquals(SelectStatement other) { - return other.distinct == distinct; - } } class CompoundSelectStatement extends BaseSelectStatement { @@ -109,12 +104,6 @@ class CompoundSelectStatement extends BaseSelectStatement { 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 - return true; - } } /// A select statement of the form `VALUES (expr-list), ..., (expr-list-N)`. @@ -137,9 +126,6 @@ class ValuesSelectStatement extends BaseSelectStatement @override Iterable get childNodes => values; - - @override - bool contentEquals(ValuesSelectStatement other) => true; } abstract class ResultColumn extends AstNode {} @@ -157,11 +143,6 @@ class StarResultColumn extends ResultColumn { @override void transformChildren(Transformer transformer, A arg) {} - @override - bool contentEquals(StarResultColumn other) { - return other.tableName == tableName; - } - @override R accept(AstVisitor visitor, A arg) { return visitor.visitStarResultColumn(this, arg); @@ -191,11 +172,6 @@ class ExpressionResultColumn extends ResultColumn R accept(AstVisitor visitor, A arg) { return visitor.visitExpressionResultColumn(this, arg); } - - @override - bool contentEquals(ExpressionResultColumn other) { - return other.as == as; - } } class GroupBy extends AstNode { @@ -218,11 +194,6 @@ class GroupBy extends AstNode { @override Iterable get childNodes => [...by, if (having != null) having]; - - @override - bool contentEquals(GroupBy other) { - return true; // Defined via child nodes - } } enum CompoundSelectMode { @@ -256,7 +227,4 @@ class CompoundSelectPart extends AstNode { 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 a39da958..577b0ab9 100644 --- a/sqlparser/lib/src/ast/statements/update.dart +++ b/sqlparser/lib/src/ast/statements/update.dart @@ -54,11 +54,6 @@ class UpdateStatement extends CrudStatement if (where != null) where, ]; - @override - bool contentEquals(UpdateStatement other) { - return other.or == or; - } - static FailureMode failureModeFromToken(TokenType token) { return _tokensToMode[token]; } @@ -83,7 +78,4 @@ class SetComponent extends AstNode { @override Iterable get childNodes => [column, expression]; - - @override - bool contentEquals(SetComponent other) => true; } diff --git a/sqlparser/lib/src/utils/ast_equality.dart b/sqlparser/lib/src/utils/ast_equality.dart index 3c647872..d55111c6 100644 --- a/sqlparser/lib/src/utils/ast_equality.dart +++ b/sqlparser/lib/src/utils/ast_equality.dart @@ -1,16 +1,693 @@ +import 'package:collection/collection.dart'; import 'package:sqlparser/src/ast/ast.dart'; +/// Visitor enforcing the equality of two ast nodes. +class EqualityEnforcingVisitor implements AstVisitor { + // The current ast node. Visitor methods will compare the node they receive to + // this one. + AstNode _current; + // Whether to check for deep equality too. + final bool _considerChildren; + + /// Creates a visitor enforcing equality to the given node. + /// + /// The [visit] methods of this visitor will throw an [NotEqualException] + /// if they receive a node that is different to the node passed here. + /// + /// When [considerChildren] is true (the default), it also considers child + /// nodes, thus enforcing deep equality. + EqualityEnforcingVisitor(this._current, {bool considerChildren = true}) + : _considerChildren = considerChildren; + + void _check(AstNode childOfCurrent, AstNode childOfOther) { + if (identical(childOfCurrent, childOfOther)) return; + + if ((childOfCurrent == null) != (childOfOther == null)) { + throw NotEqualException('$childOfCurrent and $childOfOther'); + } + + // Both non nullable here + final savedCurrent = _current; + _current = childOfCurrent; + visit(childOfOther, null); + _current = savedCurrent; + } + + void _checkChildren(AstNode other) { + if (!_considerChildren) return; + + final currentChildren = _current.childNodes.iterator; + final otherChildren = other.childNodes.iterator; + + // always move both iterators + while (currentChildren.moveNext() & otherChildren.moveNext()) { + _check(currentChildren.current, otherChildren.current); + } + + if (currentChildren.moveNext() || otherChildren.moveNext()) { + throw NotEqualException( + "$_current and $other don't have an equal amount of children"); + } + } + + Null /*Never*/ _notEqual(AstNode other) { + throw NotEqualException('$_current and $other'); + } + + T _currentAs(T context) { + final current = _current; + if (current is T) return current; + + _notEqual(context); + return null; + } + + void _assert(bool contentEqual, AstNode context) { + if (!contentEqual) _notEqual(context); + } + + @override + void visitAggregateExpression(AggregateExpression e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name && current.windowName == e.windowName, e); + _checkChildren(e); + } + + @override + void visitBetweenExpression(BetweenExpression e, void arg) { + final current = _currentAs(e); + _assert(current.not == e.not, e); + _checkChildren(e); + } + + @override + void visitBinaryExpression(BinaryExpression e, void arg) { + final current = _currentAs(e); + _assert(current.operator.type == e.operator.type, e); + _checkChildren(e); + } + + @override + void visitBlock(Block block, void arg) { + _currentAs(block); + _checkChildren(block); + } + + @override + void visitBooleanLiteral(BooleanLiteral e, void arg) { + final current = _currentAs(e); + _assert(current.value == e.value, e); + _checkChildren(e); + } + + @override + void visitCaseExpression(CaseExpression e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitCastExpression(CastExpression e, void arg) { + final current = _currentAs(e); + _assert(current.typeName == e.typeName, e); + _checkChildren(e); + } + + @override + void visitCollateExpression(CollateExpression e, void arg) { + final current = _currentAs(e); + _assert(current.collateFunction.type == e.collateFunction.type, e); + _checkChildren(e); + } + + @override + void visitColumnConstraint(ColumnConstraint e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name, e); + + if (e is NotNull) { + _assert(current is NotNull && current.onConflict == e.onConflict, e); + } else if (e is PrimaryKeyColumn) { + _assert( + current is PrimaryKeyColumn && + current.autoIncrement == e.autoIncrement && + current.mode == e.mode && + current.onConflict == e.onConflict, + e); + } else if (e is UniqueColumn) { + _assert(current is UniqueColumn && current.onConflict == e.onConflict, e); + } else if (e is CheckColumn) { + _assert(current is CheckColumn, e); + } else if (e is MappedBy) { + _assert( + current is MappedBy && current.mapper.dartCode == e.mapper.dartCode, + e); + } else if (e is JsonKey) { + _assert(current is JsonKey && current.jsonKey == e.jsonKey, e); + } else { + _assert(current.runtimeType == e.runtimeType, e); + } + + _checkChildren(e); + } + + @override + void visitColumnDefinition(ColumnDefinition e, void arg) { + final current = _currentAs(e); + _assert( + current.columnName == e.columnName && current.typeName == e.typeName, + e); + _checkChildren(e); + } + + @override + void visitCommonTableExpression(CommonTableExpression e, void arg) { + final current = _currentAs(e); + _assert(current.cteTableName == e.cteTableName, e); + _checkChildren(e); + } + + @override + void visitCompoundSelectPart(CompoundSelectPart e, void arg) { + final current = _currentAs(e); + _assert(current.mode == e.mode, e); + _checkChildren(e); + } + + @override + void visitCompoundSelectStatement(CompoundSelectStatement e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitCreateIndexStatement(CreateIndexStatement e, void arg) { + final current = _currentAs(e); + _assert( + current.indexName == e.indexName && + current.unique == e.unique && + current.ifNotExists == e.ifNotExists, + e); + _checkChildren(e); + } + + @override + void visitCreateTableStatement(CreateTableStatement e, void arg) { + final current = _currentAs(e); + _assert( + current.ifNotExists == e.ifNotExists && + current.tableName == e.tableName && + current.withoutRowId == e.withoutRowId && + current.overriddenDataClassName == e.overriddenDataClassName, + e); + _checkChildren(e); + } + + @override + void visitCreateTriggerStatement(CreateTriggerStatement e, void arg) { + final current = _currentAs(e); + _assert( + current.ifNotExists == e.ifNotExists && + current.triggerName == e.triggerName && + current.mode == e.mode, + e); + _checkChildren(e); + } + + @override + void visitCreateViewStatement(CreateViewStatement e, void arg) { + final current = _currentAs(e); + _assert( + current.ifNotExists == e.ifNotExists && + current.viewName == e.viewName && + const ListEquality().equals(current.columns, e.columns), + e); + _checkChildren(e); + } + + @override + void visitCreateVirtualTableStatement( + CreateVirtualTableStatement e, void arg) { + final current = _currentAs(e); + _assert( + current.ifNotExists == e.ifNotExists && + current.tableName == e.tableName && + current.moduleName == e.moduleName && + const ListEquality() + .equals(current.argumentContent, e.argumentContent), + e); + _checkChildren(e); + } + + @override + void visitDartPlaceholder(DartPlaceholder e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name && current.runtimeType == e.runtimeType, e); + _checkChildren(e); + } + + @override + void visitDefaultValues(DefaultValues e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitDeferrableClause(DeferrableClause e, void arg) { + final current = _currentAs(e); + _assert( + current.not == e.not && + current.declaredInitially == e.declaredInitially, + e); + _checkChildren(e); + } + + @override + void visitDeleteStatement(DeleteStatement e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitDeleteTriggerTarget(DeleteTarget e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitDoNothing(DoNothing e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitDoUpdate(DoUpdate e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitExists(ExistsExpression e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitExpressionFunctionParameters(ExprFunctionParameters e, void arg) { + final current = _currentAs(e); + _assert(current.distinct == e.distinct, e); + _checkChildren(e); + } + + @override + void visitExpressionResultColumn(ExpressionResultColumn e, void arg) { + final current = _currentAs(e); + _assert(current.as == e.as, e); + _checkChildren(e); + } + + @override + void visitForeignKeyClause(ForeignKeyClause e, void arg) { + final current = _currentAs(e); + _assert( + current.onDelete == e.onDelete && current.onUpdate == e.onUpdate, e); + _checkChildren(e); + } + + @override + void visitFrameSpec(FrameSpec e, void arg) { + final current = _currentAs(e); + _assert( + current.type == e.type && + current.excludeMode == e.excludeMode && + current.start == e.start && + e.end == e.end, + e); + _checkChildren(e); + } + + @override + void visitFunction(FunctionExpression e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name, e); + _checkChildren(e); + } + + @override + void visitGroupBy(GroupBy e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitInExpression(InExpression e, void arg) { + final current = _currentAs(e); + _assert(current.not == e.not, e); + _checkChildren(e); + } + + @override + void visitIndexedColumn(IndexedColumn e, void arg) { + final current = _currentAs(e); + _assert(current.ordering == e.ordering, e); + _checkChildren(e); + } + + @override + void visitInsertStatement(InsertStatement e, void arg) { + final current = _currentAs(e); + _assert(current.mode == e.mode, e); + _checkChildren(e); + } + + @override + void visitInsertTriggerTarget(InsertTarget e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitInvalidStatement(InvalidStatement e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitIsExpression(IsExpression e, void arg) { + final current = _currentAs(e); + _assert(current.negated == e.negated, e); + _checkChildren(e); + } + + @override + void visitIsNullExpression(IsNullExpression e, void arg) { + final current = _currentAs(e); + _assert(current.negated == e.negated, e); + _checkChildren(e); + } + + @override + void visitJoin(Join e, void arg) { + final current = _currentAs(e); + + if (current.natural != e.natural || current.operator != e.operator) { + _notEqual(e); + } + + final constraint = current.constraint; + if (constraint is OnConstraint) { + _assert(e.constraint is OnConstraint, e); + } else if (constraint is UsingConstraint) { + if (e.constraint is! UsingConstraint) { + _notEqual(e); + } + final typedOther = e.constraint as UsingConstraint; + + _assert( + const ListEquality() + .equals(constraint.columnNames, typedOther.columnNames), + e); + } + + _checkChildren(e); + } + + @override + void visitJoinClause(JoinClause e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitLimit(Limit e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitMoorDeclaredStatement(DeclaredStatement e, void arg) { + final current = _currentAs(e); + _assert(current.identifier == e.identifier && current.as == e.as, e); + _checkChildren(e); + } + + @override + void visitMoorFile(MoorFile e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitMoorImportStatement(ImportStatement e, void arg) { + final current = _currentAs(e); + _assert(current.importedFile == e.importedFile, e); + _checkChildren(e); + } + + @override + void visitMoorNestedStarResultColumn(NestedStarResultColumn e, void arg) { + final current = _currentAs(e); + _assert(current.tableName == e.tableName, e); + _checkChildren(e); + } + + @override + void visitMoorStatementParameter(StatementParameter e, void arg) { + if (e is VariableTypeHint) { + final current = _currentAs(e); + _assert(current.typeName == e.typeName, e); + } else if (e is DartPlaceholderDefaultValue) { + final current = _currentAs(e); + _assert(current.variableName == e.variableName, e); + } + + _checkChildren(e); + } + + @override + void visitNamedVariable(ColonNamedVariable e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name, e); + _checkChildren(e); + } + + @override + void visitNullLiteral(NullLiteral e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitNumberedVariable(NumberedVariable e, void arg) { + final current = _currentAs(e); + _assert(current.explicitIndex == e.explicitIndex, e); + _checkChildren(e); + } + + @override + void visitNumericLiteral(NumericLiteral e, void arg) { + final current = _currentAs(e); + _assert(current.value == e.value, e); + _checkChildren(e); + } + + @override + void visitOrderBy(OrderBy e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitOrderingTerm(OrderingTerm e, void arg) { + final current = _currentAs(e); + _assert( + current.orderingMode == e.orderingMode && current.nulls == e.nulls, e); + _checkChildren(e); + } + + @override + void visitParentheses(Parentheses e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitReference(Reference e, void arg) { + final current = _currentAs(e); + _assert( + current.tableName == e.tableName && current.columnName == e.columnName, + e); + _checkChildren(e); + } + + @override + void visitSelectInsertSource(SelectInsertSource e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitSelectStatement(SelectStatement e, void arg) { + final current = _currentAs(e); + _assert(current.distinct == e.distinct, e); + _checkChildren(e); + } + + @override + void visitSelectStatementAsSource(SelectStatementAsSource e, void arg) { + final current = _currentAs(e); + _assert(current.as == e.as, e); + _checkChildren(e); + } + + @override + void visitSetComponent(SetComponent e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitStarFunctionParameter(StarFunctionParameter e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitStarResultColumn(StarResultColumn e, void arg) { + final current = _currentAs(e); + _assert(current.tableName == e.tableName, e); + _checkChildren(e); + } + + @override + void visitStringComparison(StringComparisonExpression e, void arg) { + final current = _currentAs(e); + _assert(current.not == e.not, e); + _checkChildren(e); + } + + @override + void visitStringLiteral(StringLiteral e, void arg) { + final current = _currentAs(e); + _assert(current.value == e.value, e); + _checkChildren(e); + } + + @override + void visitSubQuery(SubQuery e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitTableConstraint(TableConstraint e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name && e.constraintEquals(current), e); + _checkChildren(e); + } + + @override + void visitTableReference(TableReference e, void arg) { + final current = _currentAs(e); + _assert(current.tableName == e.tableName && current.as == e.as, e); + _checkChildren(e); + } + + @override + void visitTableValuedFunction(TableValuedFunction e, void arg) { + final current = _currentAs(e); + _assert(current.name == e.name, e); + _checkChildren(e); + } + + @override + void visitTimeConstantLiteral(TimeConstantLiteral e, void arg) { + final current = _currentAs(e); + _assert(current.kind == e.kind, e); + _checkChildren(e); + } + + @override + void visitTuple(Tuple e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitUnaryExpression(UnaryExpression e, void arg) { + final current = _currentAs(e); + _assert(current.operator.type == e.operator.type, e); + _checkChildren(e); + } + + @override + void visitUpdateStatement(UpdateStatement e, void arg) { + final current = _currentAs(e); + _assert(current.or == e.or, e); + _checkChildren(e); + } + + @override + void visitUpdateTriggerTarget(UpdateTarget e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitUpsertClause(UpsertClause e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitValuesSelectStatement(ValuesSelectStatement e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitValuesSource(ValuesSource e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitWhen(WhenComponent e, void arg) { + _currentAs(e); + _checkChildren(e); + } + + @override + void visitWindowDefinition(WindowDefinition e, void arg) { + final current = _currentAs(e); + _assert(current.baseWindowName == e.baseWindowName, e); + _checkChildren(e); + } + + @override + void visitWithClause(WithClause e, void arg) { + final current = _currentAs(e); + _assert(current.recursive == e.recursive, e); + _checkChildren(e); + } +} + /// Checks whether [a] and [b] are equal. If they aren't, throws an exception. void enforceEqual(AstNode a, AstNode b) { - if (a.runtimeType != b.runtimeType) { - throw ArgumentError('Not equal: First was $a, second $b'); - } + EqualityEnforcingVisitor(a).visit(b, null); +} - if (!a.contentEquals(b)) { - throw ArgumentError('Content not equal: $a and $b'); - } +/// Thrown by the [EqualityEnforcingVisitor] when two nodes were determined to +/// be non-equal. +class NotEqualException implements Exception { + final String message; - return enforceEqualIterable(a.childNodes, b.childNodes); + NotEqualException(this.message); + + @override + String toString() { + return 'Not equal: $message'; + } } void enforceEqualIterable(Iterable a, Iterable b) {