2020-08-21 07:44:17 -07:00
|
|
|
/// Library to convert AST nodes back to text.
|
|
|
|
///
|
|
|
|
/// See the [NodeToText] extension for details.
|
|
|
|
library utils.node_to_text;
|
|
|
|
|
|
|
|
import 'package:charcode/charcode.dart';
|
|
|
|
import 'package:sqlparser/sqlparser.dart';
|
|
|
|
|
2021-01-23 12:03:03 -08:00
|
|
|
class NodeSqlBuilder extends AstVisitor<void, void> {
|
|
|
|
final StringSink buffer;
|
2021-01-24 03:27:53 -08:00
|
|
|
|
|
|
|
/// Whether we need to insert a space before writing the next identifier.
|
|
|
|
bool needsSpace = false;
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2021-01-23 12:03:03 -08:00
|
|
|
NodeSqlBuilder([StringSink? buffer]) : buffer = buffer ?? StringBuffer();
|
|
|
|
|
2021-01-24 03:27:53 -08:00
|
|
|
/// Writes a space character if [needsSpace] is set.
|
|
|
|
///
|
|
|
|
/// This also resets [needsSpace] to `false`.
|
|
|
|
void spaceIfNeeded() {
|
|
|
|
if (needsSpace) {
|
|
|
|
needsSpace = false;
|
|
|
|
_space();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-05 05:28:19 -08:00
|
|
|
bool isKeyword(String lexeme) {
|
|
|
|
return isKeywordLexeme(lexeme);
|
|
|
|
}
|
|
|
|
|
2023-07-27 02:16:58 -07:00
|
|
|
String escapeIdentifier(String identifier) {
|
|
|
|
return '"$identifier"';
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
2022-03-08 01:58:40 -08:00
|
|
|
void visitAggregateFunctionInvocation(
|
|
|
|
AggregateFunctionInvocation e, void arg) {
|
2023-01-20 09:14:37 -08:00
|
|
|
symbol(e.name, spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.parameters, arg);
|
2023-10-24 13:32:39 -07:00
|
|
|
visitNullable(e.orderBy, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.filter != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.filter);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.where);
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(e.filter!, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2022-03-08 01:58:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitWindowFunctionInvocation(WindowFunctionInvocation e, void arg) {
|
|
|
|
visitAggregateFunctionInvocation(e, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.windowDefinition != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.over);
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(e.windowDefinition!, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
} else if (e.windowName != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.over);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.windowName!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
@override
|
|
|
|
void visitBeginTransaction(BeginTransactionStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.begin);
|
2021-09-08 13:53:57 -07:00
|
|
|
|
|
|
|
switch (e.mode) {
|
|
|
|
case TransactionMode.none:
|
|
|
|
break;
|
|
|
|
case TransactionMode.deferred:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.deferred);
|
2021-09-08 13:53:57 -07:00
|
|
|
break;
|
|
|
|
case TransactionMode.immediate:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.immediate);
|
2021-09-08 13:53:57 -07:00
|
|
|
break;
|
|
|
|
case TransactionMode.exclusive:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.exclusive);
|
2021-09-08 13:53:57 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitBetweenExpression(BetweenExpression e, void arg) {
|
|
|
|
visit(e.check, arg);
|
|
|
|
|
|
|
|
if (e.not) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.between);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.lower, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.and);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.upper, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitBinaryExpression(BinaryExpression e, void arg) {
|
|
|
|
visit(e.left, arg);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
final operatorSymbol = const {
|
2020-08-21 07:44:17 -07:00
|
|
|
TokenType.doublePipe: '||',
|
|
|
|
TokenType.star: '*',
|
|
|
|
TokenType.slash: '/',
|
|
|
|
TokenType.percent: '%',
|
|
|
|
TokenType.plus: '+',
|
|
|
|
TokenType.minus: '-',
|
|
|
|
TokenType.shiftLeft: '<<',
|
|
|
|
TokenType.shiftRight: '>>',
|
2020-08-22 03:36:36 -07:00
|
|
|
TokenType.ampersand: '&',
|
2020-08-21 07:44:17 -07:00
|
|
|
TokenType.pipe: '|',
|
|
|
|
TokenType.less: '<',
|
|
|
|
TokenType.lessEqual: '<=',
|
|
|
|
TokenType.more: '>',
|
|
|
|
TokenType.moreEqual: '>=',
|
|
|
|
TokenType.equal: '=',
|
|
|
|
TokenType.doubleEqual: '==',
|
|
|
|
TokenType.exclamationEqual: '!=',
|
|
|
|
TokenType.lessMore: '<>',
|
2022-02-23 13:06:42 -08:00
|
|
|
TokenType.dashRangle: '->',
|
|
|
|
TokenType.dashRangleRangle: '->>',
|
2020-08-21 07:44:17 -07:00
|
|
|
}[e.operator.type];
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
if (operatorSymbol != null) {
|
|
|
|
symbol(operatorSymbol, spaceBefore: true, spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
} else {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(e.operator.type);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.right, arg);
|
|
|
|
}
|
|
|
|
|
2021-09-09 09:05:03 -07:00
|
|
|
void _writeStatements(Iterable<Statement> statements) {
|
|
|
|
for (final stmt in statements) {
|
|
|
|
visit(stmt, null);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(';');
|
2021-09-09 09:05:03 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitBlock(Block block, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.begin);
|
2021-09-09 09:05:03 -07:00
|
|
|
_writeStatements(block.statements);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.end);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitBooleanLiteral(BooleanLiteral e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(e.value ? TokenType.$true : TokenType.$false);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCaseExpression(CaseExpression e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$case);
|
2020-08-21 07:44:17 -07:00
|
|
|
visitNullable(e.base, arg);
|
|
|
|
visitList(e.whens, arg);
|
|
|
|
|
|
|
|
final elseExpr = e.elseExpr;
|
|
|
|
if (elseExpr != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$else);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(elseExpr, arg);
|
|
|
|
}
|
2020-08-22 03:36:36 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.end);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCastExpression(CastExpression e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.cast);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.operand, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(e.typeName, spaceBefore: true);
|
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCollateExpression(CollateExpression e, void arg) {
|
|
|
|
visit(e.inner, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.collate);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.collation);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitColumnConstraint(ColumnConstraint e, void arg) {
|
|
|
|
if (e.name != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.constraint);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.name!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2023-01-05 14:04:36 -08:00
|
|
|
e.when(
|
|
|
|
primaryKey: (primaryKey) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.primary);
|
|
|
|
keyword(TokenType.key);
|
2023-01-05 14:04:36 -08:00
|
|
|
_orderingMode(primaryKey.mode);
|
|
|
|
_conflictClause(primaryKey.onConflict);
|
2023-01-06 06:10:03 -08:00
|
|
|
if (primaryKey.autoIncrement) keyword(TokenType.autoincrement);
|
2023-01-05 14:04:36 -08:00
|
|
|
},
|
|
|
|
notNull: (notNull) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
|
|
|
keyword(TokenType.$null);
|
2023-01-05 14:04:36 -08:00
|
|
|
_conflictClause(notNull.onConflict);
|
|
|
|
},
|
2023-12-12 12:46:58 -08:00
|
|
|
nullable: (nullable) {
|
|
|
|
keyword(TokenType.$null);
|
|
|
|
},
|
2023-01-05 14:04:36 -08:00
|
|
|
unique: (unique) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.unique);
|
2023-01-05 14:04:36 -08:00
|
|
|
_conflictClause(unique.onConflict);
|
|
|
|
},
|
|
|
|
check: (check) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.check);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2023-01-05 14:04:36 -08:00
|
|
|
visit(check.expression, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2023-01-05 14:04:36 -08:00
|
|
|
},
|
|
|
|
isDefault: (def) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$default);
|
2023-01-05 14:04:36 -08:00
|
|
|
final expr = def.expression;
|
|
|
|
if (expr is Literal) {
|
|
|
|
visit(expr, arg);
|
|
|
|
} else {
|
|
|
|
symbol('(', spaceBefore: true);
|
|
|
|
visit(expr, arg);
|
|
|
|
symbol(')', spaceAfter: true);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
collate: (collate) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.collate);
|
2023-01-05 14:04:36 -08:00
|
|
|
identifier(collate.collation);
|
|
|
|
},
|
|
|
|
foreignKey: (foreignKey) {
|
|
|
|
visit(foreignKey.clause, arg);
|
|
|
|
},
|
|
|
|
generatedAs: (generatedAs) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.generated);
|
|
|
|
keyword(TokenType.always);
|
|
|
|
keyword(TokenType.as);
|
2021-11-07 13:10:08 -08:00
|
|
|
|
2023-01-05 14:04:36 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
|
|
|
visit(generatedAs.expression, arg);
|
|
|
|
symbol(')', spaceAfter: true);
|
2021-11-07 13:10:08 -08:00
|
|
|
|
2023-01-05 14:04:36 -08:00
|
|
|
if (generatedAs.stored) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.stored);
|
2023-01-05 14:04:36 -08:00
|
|
|
} else {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.virtual);
|
2023-01-05 14:04:36 -08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
mappedBy: (mappedBy) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.mapped);
|
|
|
|
keyword(TokenType.by);
|
2023-01-05 14:04:36 -08:00
|
|
|
dartCode(mappedBy.mapper.dartCode);
|
|
|
|
},
|
|
|
|
);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitColumnDefinition(ColumnDefinition e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.columnName);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.typeName != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(e.typeName!, spaceAfter: true, spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visitList(e.constraints, arg);
|
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
@override
|
|
|
|
void visitCommitStatement(CommitStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.commit);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitCommonTableExpression(CommonTableExpression e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.cteTableName);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.columnNames != null) {
|
2022-10-29 08:30:18 -07:00
|
|
|
symbol('(', spaceBefore: true);
|
|
|
|
|
|
|
|
var first = true;
|
|
|
|
for (final columnName in e.columnNames!) {
|
|
|
|
if (!first) {
|
|
|
|
symbol(',', spaceAfter: true);
|
|
|
|
}
|
|
|
|
|
|
|
|
identifier(columnName, spaceBefore: !first, spaceAfter: false);
|
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-03-13 05:00:06 -08:00
|
|
|
switch (e.materializationHint) {
|
|
|
|
case MaterializationHint.notMaterialized:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
|
|
|
keyword(TokenType.materialized);
|
2021-03-13 05:00:06 -08:00
|
|
|
break;
|
|
|
|
case MaterializationHint.materialized:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.materialized);
|
2021-03-13 05:00:06 -08:00
|
|
|
break;
|
|
|
|
case null:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.as, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCompoundSelectPart(CompoundSelectPart e, void arg) {
|
|
|
|
switch (e.mode) {
|
|
|
|
case CompoundSelectMode.union:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.union);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case CompoundSelectMode.unionAll:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.union);
|
|
|
|
keyword(TokenType.all);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case CompoundSelectMode.intersect:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.intersect);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case CompoundSelectMode.except:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.except);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.select, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCompoundSelectStatement(CompoundSelectStatement e, void arg) {
|
|
|
|
visitNullable(e.withClause, arg);
|
|
|
|
visit(e.base, arg);
|
|
|
|
visitList(e.additional, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCreateIndexStatement(CreateIndexStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.create);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.unique) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.unique);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$index);
|
2020-08-21 07:44:17 -07:00
|
|
|
_ifNotExists(e.ifNotExists);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.indexName);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.on, arg);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.columns, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
_where(e.where);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCreateTableStatement(CreateTableStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.create);
|
|
|
|
keyword(TokenType.table);
|
2020-08-21 07:44:17 -07:00
|
|
|
_ifNotExists(e.ifNotExists);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.tableName);
|
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
_join([...e.columns, ...e.tableConstraints], ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.withoutRowId) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.without);
|
|
|
|
keyword(TokenType.rowid);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2021-08-28 07:28:29 -07:00
|
|
|
|
|
|
|
if (e.isStrict) {
|
2021-11-11 05:40:41 -08:00
|
|
|
if (e.withoutRowId) symbol(',');
|
2021-08-28 07:28:29 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.strict);
|
2021-08-28 07:28:29 -07:00
|
|
|
}
|
2023-04-23 07:21:31 -07:00
|
|
|
|
|
|
|
e.driftTableName?.accept(this, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCreateTriggerStatement(CreateTriggerStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.create);
|
|
|
|
keyword(TokenType.trigger);
|
2020-08-21 07:44:17 -07:00
|
|
|
_ifNotExists(e.ifNotExists);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.triggerName);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
switch (e.mode) {
|
|
|
|
case TriggerMode.before:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.before);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TriggerMode.after:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.after);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TriggerMode.insteadOf:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.instead);
|
|
|
|
keyword(TokenType.of);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Can happen if e.mode == null
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.target, arg);
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.onTable, arg);
|
|
|
|
|
|
|
|
if (e.when != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.when);
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(e.when!, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.action, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCreateViewStatement(CreateViewStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.create);
|
|
|
|
keyword(TokenType.view);
|
2020-08-21 07:44:17 -07:00
|
|
|
_ifNotExists(e.ifNotExists);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.viewName);
|
2024-03-08 09:13:50 -08:00
|
|
|
e.driftTableName?.accept(this, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.columns != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
|
|
|
symbol(e.columns!.join(','));
|
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.query, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitCreateVirtualTableStatement(
|
|
|
|
CreateVirtualTableStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.create);
|
|
|
|
keyword(TokenType.virtual);
|
|
|
|
keyword(TokenType.table);
|
2020-08-21 07:44:17 -07:00
|
|
|
_ifNotExists(e.ifNotExists);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.tableName);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.using);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.moduleName);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(${e.argumentContent.join(', ')})');
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
2022-02-26 12:38:28 -08:00
|
|
|
void visitDriftSpecificNode(DriftSpecificNode e, void arg) {
|
2021-09-08 14:20:45 -07:00
|
|
|
if (e is DartPlaceholder) {
|
2022-10-23 09:13:40 -07:00
|
|
|
e.when(
|
2023-01-06 06:10:03 -08:00
|
|
|
isLimit: (_) => keyword(TokenType.limit),
|
2022-10-23 09:13:40 -07:00
|
|
|
isOrderBy: (_) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.order);
|
|
|
|
keyword(TokenType.by);
|
2022-10-23 09:13:40 -07:00
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(r'$', spaceBefore: true);
|
|
|
|
symbol(e.name, spaceAfter: true);
|
2021-09-08 14:20:45 -07:00
|
|
|
} else if (e is DeclaredStatement) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.identifier.name);
|
2021-09-08 14:20:45 -07:00
|
|
|
|
|
|
|
if (e.parameters.isNotEmpty) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2021-09-08 14:20:45 -07:00
|
|
|
_join(e.parameters, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2021-09-08 14:20:45 -07:00
|
|
|
}
|
|
|
|
|
2022-12-26 10:17:17 -08:00
|
|
|
visitNullable(e.as, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(':', spaceAfter: true);
|
2021-09-08 14:20:45 -07:00
|
|
|
visit(e.statement, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(';');
|
2022-02-26 12:38:28 -08:00
|
|
|
} else if (e is DriftFile) {
|
2021-09-08 14:20:45 -07:00
|
|
|
for (final stmt in e.statements) {
|
|
|
|
visit(stmt, arg);
|
|
|
|
buffer.write('\n');
|
|
|
|
needsSpace = false;
|
|
|
|
}
|
|
|
|
} else if (e is ImportStatement) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.import);
|
2021-09-08 14:20:45 -07:00
|
|
|
_stringLiteral(e.importedFile);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(';', spaceAfter: true);
|
2021-09-08 14:20:45 -07:00
|
|
|
} else if (e is StatementParameter) {
|
|
|
|
if (e is VariableTypeHint) {
|
2023-01-06 06:10:03 -08:00
|
|
|
if (e.isRequired) keyword(TokenType.required);
|
2021-09-08 14:20:45 -07:00
|
|
|
|
|
|
|
visit(e.variable, arg);
|
|
|
|
final typeName = e.typeName;
|
|
|
|
if (typeName != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(typeName, spaceBefore: true, spaceAfter: true);
|
2021-09-08 14:20:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (e.orNull) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.or);
|
|
|
|
keyword(TokenType.$null);
|
2021-09-08 14:20:45 -07:00
|
|
|
}
|
|
|
|
} else if (e is DartPlaceholderDefaultValue) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('\$${e.variableName}', spaceAfter: true);
|
|
|
|
symbol('=', spaceBefore: true, spaceAfter: true);
|
2021-09-08 14:20:45 -07:00
|
|
|
visit(e.defaultValue, arg);
|
|
|
|
} else {
|
|
|
|
throw AssertionError('Unknown StatementParameter: $e');
|
|
|
|
}
|
2022-02-26 12:38:28 -08:00
|
|
|
} else if (e is DriftTableName) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(e.useExistingDartClass ? TokenType.$with : TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.overriddenDataClassName);
|
2023-04-23 07:21:31 -07:00
|
|
|
final constructor = e.constructorName;
|
|
|
|
if (constructor != null) {
|
|
|
|
symbol('.');
|
|
|
|
identifier(constructor);
|
|
|
|
}
|
2021-09-08 14:20:45 -07:00
|
|
|
} else if (e is NestedStarResultColumn) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.tableName);
|
|
|
|
symbol('.**', spaceAfter: true);
|
2022-01-23 08:08:32 -08:00
|
|
|
} else if (e is NestedQueryColumn) {
|
2022-12-27 08:04:38 -08:00
|
|
|
symbol('LIST(', spaceBefore: true);
|
2022-01-23 08:08:32 -08:00
|
|
|
visit(e.select, arg);
|
|
|
|
symbol(')', spaceAfter: true);
|
2022-12-27 08:04:38 -08:00
|
|
|
|
|
|
|
if (e.as != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2022-12-27 08:04:38 -08:00
|
|
|
identifier(e.as!);
|
|
|
|
}
|
2021-09-09 09:05:03 -07:00
|
|
|
} else if (e is TransactionBlock) {
|
|
|
|
visit(e.begin, arg);
|
|
|
|
_writeStatements(e.innerStatements);
|
|
|
|
visit(e.commit, arg);
|
2021-09-08 14:20:45 -07:00
|
|
|
}
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitDefaultValues(DefaultValues e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$default);
|
|
|
|
keyword(TokenType.$values);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitDeferrableClause(DeferrableClause e, void arg) {
|
|
|
|
if (e.not) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.deferrable);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
switch (e.declaredInitially) {
|
|
|
|
case InitialDeferrableMode.deferred:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.initially);
|
|
|
|
keyword(TokenType.deferred);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case InitialDeferrableMode.immediate:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.initially);
|
|
|
|
keyword(TokenType.immediate);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// declaredInitially == null, don't do anything
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitDeleteStatement(DeleteStatement e, void arg) {
|
|
|
|
visitNullable(e.withClause, arg);
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.delete);
|
2021-03-13 03:02:35 -08:00
|
|
|
_from(e.from);
|
2020-08-21 07:44:17 -07:00
|
|
|
_where(e.where);
|
2021-03-30 14:24:28 -07:00
|
|
|
visitNullable(e.returning, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitDeleteTriggerTarget(DeleteTarget e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.delete);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitDoNothing(DoNothing e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.nothing);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitDoUpdate(DoUpdate e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.update);
|
|
|
|
keyword(TokenType.set);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.set, ',');
|
|
|
|
_where(e.where);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitExists(ExistsExpression e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.exists);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.select, null);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitExpressionFunctionParameters(ExprFunctionParameters e, void arg) {
|
|
|
|
if (e.distinct) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.distinct);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
_join(e.parameters, ',');
|
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
@override
|
|
|
|
void visitExpressionResultColumn(ExpressionResultColumn e, void arg) {
|
|
|
|
visit(e.expression, arg);
|
2023-01-05 14:04:36 -08:00
|
|
|
visitNullable(e.mappedBy, arg);
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
if (e.as != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.as!);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitForeignKeyClause(ForeignKeyClause e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.references);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.foreignTable, arg);
|
|
|
|
|
|
|
|
if (e.columnNames.isNotEmpty) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.columnNames, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void referenceAction(ReferenceAction action) {
|
|
|
|
switch (action) {
|
|
|
|
case ReferenceAction.setNull:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.set);
|
|
|
|
keyword(TokenType.$null);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ReferenceAction.setDefault:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.set);
|
|
|
|
keyword(TokenType.$default);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ReferenceAction.cascade:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.cascade);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ReferenceAction.restrict:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.restrict);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ReferenceAction.noAction:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.no);
|
|
|
|
keyword(TokenType.action);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.onUpdate != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
|
|
|
keyword(TokenType.update);
|
2020-12-11 01:53:17 -08:00
|
|
|
referenceAction(e.onUpdate!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
if (e.onDelete != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
|
|
|
keyword(TokenType.delete);
|
2020-12-11 01:53:17 -08:00
|
|
|
referenceAction(e.onDelete!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visitNullable(e.deferrable, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitFrameSpec(FrameSpec e, void arg) {
|
|
|
|
void frameBoundary(FrameBoundary boundary) {
|
|
|
|
void precedingOrFollowing(bool preceding) {
|
|
|
|
if (boundary.isUnbounded) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.unbounded);
|
2020-08-22 03:36:36 -07:00
|
|
|
} else {
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(boundary.offset!, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2020-08-22 03:36:36 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(preceding ? TokenType.preceding : TokenType.following);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (boundary.isCurrentRow) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.current);
|
|
|
|
keyword(TokenType.row);
|
2020-08-21 07:44:17 -07:00
|
|
|
} else if (boundary.preceding) {
|
|
|
|
precedingOrFollowing(true);
|
|
|
|
} else {
|
|
|
|
precedingOrFollowing(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2020-08-21 07:44:17 -07:00
|
|
|
FrameType.range: TokenType.range,
|
|
|
|
FrameType.rows: TokenType.rows,
|
|
|
|
FrameType.groups: TokenType.groups,
|
2020-12-11 01:53:17 -08:00
|
|
|
}[e.type!]!);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.between);
|
2020-12-11 01:53:17 -08:00
|
|
|
frameBoundary(e.start);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.and);
|
2020-12-11 01:53:17 -08:00
|
|
|
frameBoundary(e.end);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.excludeMode != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.exclude);
|
2020-12-11 01:53:17 -08:00
|
|
|
switch (e.excludeMode!) {
|
2020-08-21 07:44:17 -07:00
|
|
|
case ExcludeMode.noOthers:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.no);
|
|
|
|
keyword(TokenType.others);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ExcludeMode.currentRow:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.current);
|
|
|
|
keyword(TokenType.row);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ExcludeMode.group:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.group);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case ExcludeMode.ties:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.ties);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitFunction(FunctionExpression e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.name);
|
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.parameters, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitGroupBy(GroupBy e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.group);
|
|
|
|
keyword(TokenType.by);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
_join(e.by, ',');
|
|
|
|
|
|
|
|
if (e.having != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.having);
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(e.having!, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
@override
|
|
|
|
void visitIndexedColumn(IndexedColumn e, void arg) {
|
|
|
|
visit(e.expression, arg);
|
|
|
|
_orderingMode(e.ordering);
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitInExpression(InExpression e, void arg) {
|
|
|
|
visit(e.left, arg);
|
2021-01-23 12:03:03 -08:00
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.not) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$in);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
visit(e.inside, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitInsertStatement(InsertStatement e, void arg) {
|
|
|
|
visitNullable(e.withClause, arg);
|
|
|
|
|
|
|
|
final mode = e.mode;
|
|
|
|
if (mode == InsertMode.insert) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.insert);
|
2020-08-21 07:44:17 -07:00
|
|
|
} else if (mode == InsertMode.replace) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.replace);
|
2020-08-21 07:44:17 -07:00
|
|
|
} else {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.insert);
|
|
|
|
keyword(TokenType.or);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2020-08-21 07:44:17 -07:00
|
|
|
InsertMode.insertOrReplace: TokenType.replace,
|
|
|
|
InsertMode.insertOrRollback: TokenType.rollback,
|
|
|
|
InsertMode.insertOrAbort: TokenType.abort,
|
|
|
|
InsertMode.insertOrFail: TokenType.fail,
|
|
|
|
InsertMode.insertOrIgnore: TokenType.ignore,
|
2020-12-11 01:53:17 -08:00
|
|
|
}[mode]!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.into);
|
2021-03-13 07:07:12 -08:00
|
|
|
visit(e.table, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.targetColumns.isNotEmpty) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.targetColumns, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.source, arg);
|
2021-05-06 13:35:57 -07:00
|
|
|
visitNullable(e.upsert, arg);
|
2021-03-30 14:24:28 -07:00
|
|
|
visitNullable(e.returning, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitInsertTriggerTarget(InsertTarget e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.insert);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitInvalidStatement(InvalidStatement e, void arg) {
|
|
|
|
throw UnsupportedError(
|
|
|
|
'InvalidStatement does not have a textual representation');
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitIsExpression(IsExpression e, void arg) {
|
|
|
|
visit(e.left, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$is);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2022-05-26 13:24:41 -07:00
|
|
|
// Avoid writing `DISTINCT FROM`, but be aware that it effectively negates
|
|
|
|
// the generated `IS` again.
|
|
|
|
final negated = e.negated ^ e.distinctFromSyntax;
|
|
|
|
|
|
|
|
if (negated) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
visit(e.right, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitIsNullExpression(IsNullExpression e, void arg) {
|
|
|
|
visit(e.operand, arg);
|
|
|
|
|
|
|
|
if (e.negated) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.notNull);
|
2020-08-22 03:36:36 -07:00
|
|
|
} else {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.isNull);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitJoin(Join e, void arg) {
|
2022-05-26 14:23:02 -07:00
|
|
|
visit(e.operator, null);
|
|
|
|
visit(e.query, null);
|
|
|
|
|
|
|
|
final constraint = e.constraint;
|
|
|
|
if (constraint is OnConstraint) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
2022-05-26 14:23:02 -07:00
|
|
|
visit(constraint.expression, arg);
|
|
|
|
} else if (constraint is UsingConstraint) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.using);
|
2022-05-26 14:23:02 -07:00
|
|
|
symbol('(${constraint.columnNames.join(', ')})');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitJoinOperator(JoinOperator e, void arg) {
|
|
|
|
if (e.operator == JoinOperatorKind.comma) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(',');
|
2020-08-21 07:44:17 -07:00
|
|
|
} else {
|
|
|
|
if (e.natural) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.natural);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (e.operator) {
|
2022-05-26 14:23:02 -07:00
|
|
|
case JoinOperatorKind.none:
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
2022-05-26 14:23:02 -07:00
|
|
|
case JoinOperatorKind.comma:
|
2020-08-21 07:44:17 -07:00
|
|
|
throw AssertionError("Can't happen");
|
2022-05-26 14:23:02 -07:00
|
|
|
case JoinOperatorKind.left:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.left);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
2022-05-26 14:23:02 -07:00
|
|
|
case JoinOperatorKind.right:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.right);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
2022-05-26 14:23:02 -07:00
|
|
|
case JoinOperatorKind.full:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.full);
|
2022-05-26 14:23:02 -07:00
|
|
|
break;
|
|
|
|
case JoinOperatorKind.inner:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.inner);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
2022-05-26 14:23:02 -07:00
|
|
|
case JoinOperatorKind.cross:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.cross);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-26 14:23:02 -07:00
|
|
|
if (e.outer) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.outer);
|
2022-05-26 14:23:02 -07:00
|
|
|
}
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.join);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitJoinClause(JoinClause e, void arg) {
|
|
|
|
visit(e.primary, arg);
|
|
|
|
visitList(e.joins, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitLimit(Limit e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.limit);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.count, arg);
|
|
|
|
|
|
|
|
if (e.offset != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.offset);
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(e.offset!, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitNamedVariable(ColonNamedVariable e, void arg) {
|
2020-08-22 03:36:36 -07:00
|
|
|
// Note: The name already starts with the colon
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(e.name, spaceBefore: true, spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitNullLiteral(NullLiteral e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$null);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitNumberedVariable(NumberedVariable e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('?', spaceBefore: true, spaceAfter: e.explicitIndex == null);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.explicitIndex != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(e.explicitIndex.toString(), spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitNumericLiteral(NumericLiteral e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(e.value.toString(), spaceBefore: true, spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitOrderBy(OrderBy e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.order);
|
|
|
|
keyword(TokenType.by);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.terms, ',');
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitOrderingTerm(OrderingTerm e, void arg) {
|
|
|
|
visit(e.expression, arg);
|
|
|
|
_orderingMode(e.orderingMode);
|
|
|
|
|
|
|
|
if (e.nulls != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.nulls);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2020-08-21 07:44:17 -07:00
|
|
|
OrderingBehaviorForNulls.first: TokenType.first,
|
|
|
|
OrderingBehaviorForNulls.last: TokenType.last,
|
2020-12-11 01:53:17 -08:00
|
|
|
}[e.nulls!]!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitParentheses(Parentheses e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.expression, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
@override
|
|
|
|
void visitRaiseExpression(RaiseExpression e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.raise);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2021-09-08 13:53:57 -07:00
|
|
|
RaiseKind.ignore: TokenType.ignore,
|
|
|
|
RaiseKind.rollback: TokenType.rollback,
|
|
|
|
RaiseKind.abort: TokenType.abort,
|
|
|
|
RaiseKind.fail: TokenType.fail,
|
|
|
|
}[e.raiseKind]!);
|
|
|
|
|
|
|
|
if (e.errorMessage != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(',', spaceAfter: true);
|
2021-09-08 13:53:57 -07:00
|
|
|
_stringLiteral(e.errorMessage!);
|
|
|
|
}
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitReference(Reference e, void arg) {
|
2021-07-22 12:32:53 -07:00
|
|
|
var didWriteSpaceBefore = false;
|
|
|
|
|
|
|
|
if (e.schemaName != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.schemaName!, spaceAfter: false);
|
|
|
|
symbol('.');
|
2021-07-22 12:32:53 -07:00
|
|
|
didWriteSpaceBefore = true;
|
|
|
|
}
|
2021-02-11 09:38:41 -08:00
|
|
|
if (e.entityName != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.entityName!,
|
2021-07-22 12:32:53 -07:00
|
|
|
spaceAfter: false, spaceBefore: !didWriteSpaceBefore);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('.');
|
2021-07-22 12:32:53 -07:00
|
|
|
didWriteSpaceBefore = true;
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.columnName,
|
2021-07-22 12:32:53 -07:00
|
|
|
spaceAfter: true, spaceBefore: !didWriteSpaceBefore);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2021-03-13 11:41:14 -08:00
|
|
|
@override
|
|
|
|
void visitReturning(Returning e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.returning);
|
2021-03-13 11:41:14 -08:00
|
|
|
_join(e.columns, ',');
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitSelectInsertSource(SelectInsertSource e, void arg) {
|
|
|
|
visit(e.stmt, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitSelectStatement(SelectStatement e, void arg) {
|
|
|
|
visitNullable(e.withClause, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.select);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.distinct) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.distinct);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2022-01-28 12:55:03 -08:00
|
|
|
_join(e.columns, ',');
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2021-03-13 03:02:35 -08:00
|
|
|
_from(e.from);
|
2020-08-21 07:44:17 -07:00
|
|
|
_where(e.where);
|
|
|
|
visitNullable(e.groupBy, arg);
|
|
|
|
if (e.windowDeclarations.isNotEmpty) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.window);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
var isFirst = true;
|
|
|
|
for (final declaration in e.windowDeclarations) {
|
|
|
|
if (!isFirst) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(',', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(declaration.name);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2020-08-22 03:36:36 -07:00
|
|
|
|
|
|
|
visit(declaration.definition, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
isFirst = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
visitNullable(e.orderBy, arg);
|
|
|
|
visitNullable(e.limit, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitSelectStatementAsSource(SelectStatementAsSource e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.statement, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.as != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.as!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-15 15:29:29 -07:00
|
|
|
@override
|
|
|
|
void visitSemicolonSeparatedStatements(
|
|
|
|
SemicolonSeparatedStatements e, void arg) {
|
|
|
|
for (final stmt in e.statements) {
|
|
|
|
visit(stmt, arg);
|
|
|
|
buffer.writeln(';');
|
|
|
|
needsSpace = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
2023-11-16 16:42:39 -08:00
|
|
|
void visitSingleColumnSetComponent(SingleColumnSetComponent e, void arg) {
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.column, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('=', spaceBefore: true, spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.expression, arg);
|
|
|
|
}
|
|
|
|
|
2023-11-16 16:42:39 -08:00
|
|
|
@override
|
|
|
|
void visitMultiColumnSetComponent(MultiColumnSetComponent e, void arg) {
|
|
|
|
symbol('(', spaceBefore: true);
|
|
|
|
_join(e.columns, ',');
|
|
|
|
symbol(')');
|
|
|
|
symbol('=', spaceBefore: true, spaceAfter: true);
|
|
|
|
visit(e.rowValue, arg);
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitStarFunctionParameter(StarFunctionParameter e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('*', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
@override
|
|
|
|
void visitStarResultColumn(StarResultColumn e, void arg) {
|
|
|
|
if (e.tableName != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.tableName!);
|
|
|
|
symbol('.');
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('*', spaceAfter: true, spaceBefore: e.tableName == null);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
@override
|
|
|
|
void visitStringComparison(StringComparisonExpression e, void arg) {
|
|
|
|
visit(e.left, arg);
|
|
|
|
if (e.not) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(e.operator.type);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.right, arg);
|
|
|
|
|
|
|
|
if (e.escape != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.escape);
|
2020-12-11 01:53:17 -08:00
|
|
|
visit(e.escape!, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitStringLiteral(StringLiteral e, void arg) {
|
2024-04-06 05:48:55 -07:00
|
|
|
if (e.isBinary) {
|
|
|
|
symbol('X', spaceBefore: true);
|
|
|
|
}
|
2020-08-21 07:44:17 -07:00
|
|
|
_stringLiteral(e.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitSubQuery(SubQuery e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.select, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitTableConstraint(TableConstraint e, void arg) {
|
|
|
|
if (e.name != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.constraint);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.name!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (e is KeyClause) {
|
|
|
|
if (e.isPrimaryKey) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.primary);
|
|
|
|
keyword(TokenType.key);
|
2020-08-21 07:44:17 -07:00
|
|
|
} else {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.unique);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2021-01-18 05:44:05 -08:00
|
|
|
_join(e.columns, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
_conflictClause(e.onConflict);
|
|
|
|
} else if (e is CheckTable) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.check);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.expression, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
} else if (e is ForeignKeyTableConstraint) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.foreign);
|
|
|
|
keyword(TokenType.key);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.columns, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.clause, arg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitTableReference(TableReference e, void arg) {
|
2021-07-22 12:32:53 -07:00
|
|
|
if (e.schemaName != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.schemaName!, spaceAfter: false);
|
|
|
|
symbol('.');
|
2021-07-22 12:32:53 -07:00
|
|
|
}
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.tableName, spaceBefore: e.schemaName == null);
|
2021-07-22 12:32:53 -07:00
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.as != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.as!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitTableValuedFunction(TableValuedFunction e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.name);
|
|
|
|
symbol('(');
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.parameters, arg);
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')');
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.as != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.as);
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.as!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitTimeConstantLiteral(TimeConstantLiteral e, void arg) {
|
|
|
|
switch (e.kind) {
|
|
|
|
case TimeConstantKind.currentTime:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.currentTime);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TimeConstantKind.currentDate:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.currentDate);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TimeConstantKind.currentTimestamp:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.currentTimestamp);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitTuple(Tuple e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.expressions, ',');
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitUnaryExpression(UnaryExpression e, void arg) {
|
|
|
|
switch (e.operator.type) {
|
|
|
|
case TokenType.minus:
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('-', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TokenType.plus:
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('+', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TokenType.tilde:
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('~', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
case TokenType.not:
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.not);
|
2020-08-21 07:44:17 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw AssertionError('Unknown unary operator: ${e.operator}');
|
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.inner, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitUpdateStatement(UpdateStatement e, void arg) {
|
|
|
|
visitNullable(e.withClause, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.update);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.or != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.or);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2020-08-21 07:44:17 -07:00
|
|
|
FailureMode.rollback: TokenType.rollback,
|
|
|
|
FailureMode.abort: TokenType.abort,
|
|
|
|
FailureMode.replace: TokenType.replace,
|
|
|
|
FailureMode.fail: TokenType.fail,
|
|
|
|
FailureMode.ignore: TokenType.ignore,
|
2020-12-11 01:53:17 -08:00
|
|
|
}[e.or!]!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visit(e.table, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.set);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.set, ',');
|
2021-03-13 03:02:35 -08:00
|
|
|
_from(e.from);
|
2020-08-21 07:44:17 -07:00
|
|
|
_where(e.where);
|
2021-03-30 14:24:28 -07:00
|
|
|
visitNullable(e.returning, arg);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitUpdateTriggerTarget(UpdateTarget e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.update);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.columnNames.isNotEmpty) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.of);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.columnNames, ',');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitUpsertClause(UpsertClause e, void arg) {
|
2021-03-13 07:07:12 -08:00
|
|
|
_join(e.entries, '');
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitUpsertClauseEntry(UpsertClauseEntry e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
|
|
|
keyword(TokenType.conflict);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.onColumns != null) {
|
2022-02-21 09:43:48 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-12-11 01:53:17 -08:00
|
|
|
_join(e.onColumns!, ',');
|
2022-02-21 09:43:48 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
|
|
|
|
2020-08-21 07:44:17 -07:00
|
|
|
_where(e.where);
|
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$do);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.action, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitValuesSelectStatement(ValuesSelectStatement e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$values);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.values, ',');
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitValuesSource(ValuesSource e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$values);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.values, ',');
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitWhen(WhenComponent e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.when);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.when, arg);
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.then);
|
2020-08-21 07:44:17 -07:00
|
|
|
visit(e.then, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitWindowDefinition(WindowDefinition e, void arg) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol('(', spaceBefore: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
|
|
|
|
if (e.baseWindowName != null) {
|
2021-11-11 05:40:41 -08:00
|
|
|
identifier(e.baseWindowName!);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (e.partitionBy.isNotEmpty) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.partition);
|
|
|
|
keyword(TokenType.by);
|
2020-08-21 07:44:17 -07:00
|
|
|
_join(e.partitionBy, ',');
|
|
|
|
}
|
|
|
|
|
|
|
|
visitNullable(e.orderBy, arg);
|
|
|
|
visitNullable(e.frameSpec, arg);
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(')', spaceAfter: true);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void visitWithClause(WithClause e, void arg) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$with);
|
2020-08-21 07:44:17 -07:00
|
|
|
if (e.recursive) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.recursive);
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
_join(e.ctes, ',');
|
|
|
|
}
|
2021-09-08 13:53:57 -07:00
|
|
|
|
|
|
|
void _conflictClause(ConflictClause? clause) {
|
|
|
|
if (clause != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.on);
|
|
|
|
keyword(TokenType.conflict);
|
2021-09-08 13:53:57 -07:00
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2021-09-08 13:53:57 -07:00
|
|
|
ConflictClause.rollback: TokenType.rollback,
|
|
|
|
ConflictClause.abort: TokenType.abort,
|
|
|
|
ConflictClause.fail: TokenType.fail,
|
|
|
|
ConflictClause.ignore: TokenType.ignore,
|
|
|
|
ConflictClause.replace: TokenType.replace,
|
|
|
|
}[clause]!);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _from(Queryable? from) {
|
|
|
|
if (from != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.from);
|
2021-09-08 13:53:57 -07:00
|
|
|
visit(from, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
/// Writes an identifier, escaping it if necessary.
|
|
|
|
void identifier(String identifier,
|
2021-09-08 13:53:57 -07:00
|
|
|
{bool spaceBefore = true, bool spaceAfter = true}) {
|
2023-02-05 05:28:19 -08:00
|
|
|
if (isKeyword(identifier) || _notAKeywordRegex.hasMatch(identifier)) {
|
2023-07-27 02:16:58 -07:00
|
|
|
identifier = escapeIdentifier(identifier);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(identifier, spaceBefore: spaceBefore, spaceAfter: spaceAfter);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2023-01-05 14:04:36 -08:00
|
|
|
void dartCode(String code,
|
|
|
|
{bool spaceBefore = true, bool spaceAfter = true}) {
|
|
|
|
symbol('`$code`', spaceBefore: spaceBefore, spaceAfter: spaceAfter);
|
|
|
|
}
|
|
|
|
|
2021-09-08 13:53:57 -07:00
|
|
|
void _ifNotExists(bool ifNotExists) {
|
|
|
|
if (ifNotExists) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.$if);
|
|
|
|
keyword(TokenType.not);
|
|
|
|
keyword(TokenType.exists);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _join(Iterable<AstNode> nodes, String separatingSymbol) {
|
|
|
|
var isFirst = true;
|
|
|
|
|
|
|
|
for (final node in nodes) {
|
|
|
|
if (!isFirst) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(separatingSymbol, spaceAfter: true);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
visit(node, null);
|
|
|
|
isFirst = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-06 06:10:03 -08:00
|
|
|
void keyword(TokenType type) {
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol(reverseKeywords[type]!, spaceAfter: true, spaceBefore: true);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void _orderingMode(OrderingMode? mode) {
|
|
|
|
if (mode != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(const {
|
2021-09-08 13:53:57 -07:00
|
|
|
OrderingMode.ascending: TokenType.asc,
|
|
|
|
OrderingMode.descending: TokenType.desc,
|
|
|
|
}[mode]!);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _space() => buffer.writeCharCode($space);
|
|
|
|
|
|
|
|
void _stringLiteral(String content) {
|
|
|
|
final escapedChars = content.replaceAll("'", "''");
|
2021-11-11 05:40:41 -08:00
|
|
|
symbol("'$escapedChars'", spaceBefore: true, spaceAfter: true);
|
2021-09-08 13:53:57 -07:00
|
|
|
}
|
|
|
|
|
2021-11-11 05:40:41 -08:00
|
|
|
/// Writes the [lexeme], unchanged.
|
|
|
|
void symbol(String lexeme,
|
2021-09-08 13:53:57 -07:00
|
|
|
{bool spaceBefore = false, bool spaceAfter = false}) {
|
|
|
|
if (needsSpace && spaceBefore) {
|
|
|
|
_space();
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer.write(lexeme);
|
|
|
|
needsSpace = spaceAfter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _where(Expression? where) {
|
|
|
|
if (where != null) {
|
2023-01-06 06:10:03 -08:00
|
|
|
keyword(TokenType.where);
|
2021-09-08 13:53:57 -07:00
|
|
|
visit(where, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defines the [toSql] extension method that turns ast nodes into a compatible
|
|
|
|
/// textual representation.
|
|
|
|
///
|
|
|
|
/// Parsing the output of [toSql] will result in an equal AST.
|
|
|
|
extension NodeToText on AstNode {
|
|
|
|
/// Obtains a textual representation for AST nodes.
|
|
|
|
///
|
|
|
|
/// Parsing the output of [toSql] will result in an equal AST. Since only the
|
|
|
|
/// AST is used, the output will not contain comments. It's possible for the
|
|
|
|
/// output to have more than just whitespace changes if there are multiple
|
|
|
|
/// ways to represent an equivalent node (e.g. the no-op `FOR EACH ROW` on
|
|
|
|
/// triggers).
|
|
|
|
String toSql() {
|
2021-11-11 05:40:41 -08:00
|
|
|
final builder = NodeSqlBuilder(null);
|
2021-09-08 13:53:57 -07:00
|
|
|
builder.visit(this, null);
|
|
|
|
return builder.buffer.toString();
|
|
|
|
}
|
2020-08-21 07:44:17 -07:00
|
|
|
}
|
2022-01-28 12:55:03 -08:00
|
|
|
|
2022-01-29 12:50:33 -08:00
|
|
|
// Allow 0, 1, 2, 3 in https://github.com/sqlite/sqlite/blob/665b6b6b35f10a46bb72377ade7c2e5d8ea42cb3/src/tokenize.c#L62-L80
|
|
|
|
final _notAKeywordRegex = RegExp('[^A-Za-z_0-9]');
|