mirror of https://github.com/AMT-Cheif/drift.git
add LIST parsing to the sqlparser
This commit is contained in:
parent
0e331933af
commit
ca8482be71
|
@ -320,6 +320,8 @@ class ColumnResolver extends RecursiveVisitor<void, void> {
|
|||
});
|
||||
|
||||
if (target != null) resultColumn.resultSet = target.resultSet.resultSet;
|
||||
} else if (resultColumn is NestedQueryColumn) {
|
||||
_resolveSelect(resultColumn.select);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ export 'moor/declared_statement.dart';
|
|||
export 'moor/import_statement.dart';
|
||||
export 'moor/inline_dart.dart';
|
||||
export 'moor/moor_file.dart';
|
||||
export 'moor/nested_query_column.dart';
|
||||
export 'moor/nested_star_result_column.dart';
|
||||
export 'node.dart';
|
||||
export 'statements/block.dart';
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import '../../../sqlparser.dart';
|
||||
import '../ast.dart' show ResultColumn, Renamable;
|
||||
import '../node.dart';
|
||||
import '../visitor.dart';
|
||||
import 'moor_file.dart';
|
||||
|
||||
/// A nested query column, denoted by `LIST(...)` in user queries.
|
||||
///
|
||||
/// Nested query columns take a select query and execute it for every result
|
||||
/// returned from the main query. Nested query columns can only be added to a
|
||||
/// top level select query, because the result of them can only be computed
|
||||
/// in dart.
|
||||
class NestedQueryColumn extends ResultColumn
|
||||
implements MoorSpecificNode, Renamable, Referencable {
|
||||
@override
|
||||
final String? as;
|
||||
|
||||
SelectStatement select;
|
||||
|
||||
NestedQueryColumn({required this.select, this.as});
|
||||
|
||||
@override
|
||||
Iterable<AstNode> get childNodes => [select];
|
||||
|
||||
@override
|
||||
void transformChildren<A>(Transformer<A> transformer, A arg) {
|
||||
select = transformer.transformChild(select, this, arg);
|
||||
}
|
||||
|
||||
@override
|
||||
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
|
||||
return visitor.visitMoorSpecificNode(this, arg);
|
||||
}
|
||||
|
||||
// idk is this required?
|
||||
@override
|
||||
bool get visibleToChildren => false;
|
||||
}
|
|
@ -1933,6 +1933,34 @@ class Parser {
|
|||
_current = positionBefore;
|
||||
}
|
||||
|
||||
// parsing for the nested query column
|
||||
if (enableMoorExtensions && _matchOne(TokenType.list)) {
|
||||
final list = _previous;
|
||||
|
||||
_consume(
|
||||
TokenType.leftParen,
|
||||
'Expected opening parenthesis after LIST',
|
||||
);
|
||||
|
||||
// or _fullSelect but I don't think with support is required here because
|
||||
// with statements can be added to the main select statement
|
||||
final statement = select();
|
||||
if (statement == null || statement is! SelectStatement) {
|
||||
_error(
|
||||
'Expected a select statement but found ${statement?.toString()}',
|
||||
);
|
||||
}
|
||||
|
||||
_consume(
|
||||
TokenType.rightParen,
|
||||
'Expected closing parenthesis to finish LIST expression',
|
||||
);
|
||||
|
||||
final as = _as();
|
||||
return NestedQueryColumn(select: statement, as: as?.identifier)
|
||||
..setSpan(list, _previous);
|
||||
}
|
||||
|
||||
final tokenBefore = _peek;
|
||||
|
||||
final expr = expression();
|
||||
|
|
|
@ -218,6 +218,7 @@ enum TokenType {
|
|||
import,
|
||||
json,
|
||||
required,
|
||||
list,
|
||||
|
||||
/// A `**` token. This is only scanned when scanning for moor tokens.
|
||||
doubleStar,
|
||||
|
@ -413,6 +414,7 @@ const Map<String, TokenType> moorKeywords = {
|
|||
'JSON': TokenType.json,
|
||||
'MAPPED': TokenType.mapped,
|
||||
'REQUIRED': TokenType.required,
|
||||
'LIST': TokenType.list,
|
||||
};
|
||||
|
||||
/// A set of [TokenType]s that can be parsed as an identifier.
|
||||
|
|
|
@ -443,6 +443,12 @@ class EqualityEnforcingVisitor implements AstVisitor<void, void> {
|
|||
_checkChildren(e);
|
||||
}
|
||||
|
||||
void visitMoorNestedQueryColumn(NestedQueryColumn e, void arg) {
|
||||
final current = _currentAs<NestedQueryColumn>(e);
|
||||
_assert(current.as == e.as, e);
|
||||
_checkChildren(e);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitMoorSpecificNode(MoorSpecificNode e, void arg) {
|
||||
if (e is DartPlaceholder) {
|
||||
|
@ -459,6 +465,8 @@ class EqualityEnforcingVisitor implements AstVisitor<void, void> {
|
|||
return visitMoorStatementParameter(e, arg);
|
||||
} else if (e is MoorTableName) {
|
||||
return visitMoorTableName(e, arg);
|
||||
} else if (e is NestedQueryColumn) {
|
||||
return visitMoorNestedQueryColumn(e, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import 'package:sqlparser/sqlparser.dart';
|
||||
import 'package:sqlparser/src/utils/ast_equality.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
|
||||
void main() {
|
||||
test('parses nested query statements', () {
|
||||
final stmt = SqlEngine(EngineOptions(useMoorExtensions: true))
|
||||
.parse('SELECT LIST(SELECT * FROM test) FROM test')
|
||||
.rootNode as SelectStatement;
|
||||
|
||||
enforceHasSpan(stmt);
|
||||
return enforceEqual(
|
||||
stmt.columns[0],
|
||||
NestedQueryColumn(
|
||||
select: SelectStatement(
|
||||
columns: [StarResultColumn(null)],
|
||||
from: TableReference('test'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('parses nested query statements with as', () {
|
||||
final stmt = SqlEngine(EngineOptions(useMoorExtensions: true))
|
||||
.parse('SELECT LIST(SELECT * FROM test) AS newname FROM test')
|
||||
.rootNode as SelectStatement;
|
||||
|
||||
enforceHasSpan(stmt);
|
||||
return enforceEqual(
|
||||
stmt.columns[0],
|
||||
NestedQueryColumn(
|
||||
as: 'newname',
|
||||
select: SelectStatement(
|
||||
columns: [StarResultColumn(null)],
|
||||
from: TableReference('test'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue