mirror of https://github.com/AMT-Cheif/drift.git
Use enforceHasSpan on all parse results in tests
This commit is contained in:
parent
591e1b2bff
commit
a304d13927
|
@ -52,6 +52,10 @@ abstract class AstNode with HasMetaMixin {
|
||||||
/// all nodes.
|
/// all nodes.
|
||||||
Token last;
|
Token last;
|
||||||
|
|
||||||
|
/// Whether this ast node is synthetic, meaning that it doesn't appear in the
|
||||||
|
/// actual source.
|
||||||
|
bool synthetic;
|
||||||
|
|
||||||
/// The first index in the source that belongs to this node. Not set for all
|
/// The first index in the source that belongs to this node. Not set for all
|
||||||
/// nodes.
|
/// nodes.
|
||||||
int get firstPosition => first.span.start.offset;
|
int get firstPosition => first.span.start.offset;
|
||||||
|
|
|
@ -674,7 +674,7 @@ mixin CrudParser on ParserBase {
|
||||||
baseWindowName: baseWindowName,
|
baseWindowName: baseWindowName,
|
||||||
partitionBy: partitionBy,
|
partitionBy: partitionBy,
|
||||||
orderBy: orderBy,
|
orderBy: orderBy,
|
||||||
frameSpec: spec ?? FrameSpec(),
|
frameSpec: spec ?? (FrameSpec()..synthetic = true),
|
||||||
)..setSpan(leftParen, _previous);
|
)..setSpan(leftParen, _previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -266,9 +266,8 @@ mixin ExpressionParser on ParserBase {
|
||||||
|
|
||||||
final selectStmt = _fullSelect(); // returns null if there's no select
|
final selectStmt = _fullSelect(); // returns null if there's no select
|
||||||
if (selectStmt != null) {
|
if (selectStmt != null) {
|
||||||
final stmt = select(noCompound: true) as SelectStatement;
|
|
||||||
_consume(TokenType.rightParen, 'Expected a closing bracket');
|
_consume(TokenType.rightParen, 'Expected a closing bracket');
|
||||||
return SubQuery(select: stmt)..setSpan(left, _previous);
|
return SubQuery(select: selectStmt)..setSpan(left, _previous);
|
||||||
} else {
|
} else {
|
||||||
final expr = expression();
|
final expr = expression();
|
||||||
_consume(TokenType.rightParen, 'Expected a closing bracket');
|
_consume(TokenType.rightParen, 'Expected a closing bracket');
|
||||||
|
@ -382,7 +381,8 @@ mixin ExpressionParser on ParserBase {
|
||||||
_consume(TokenType.leftParen, 'Expected opening parenthesis for tuple');
|
_consume(TokenType.leftParen, 'Expected opening parenthesis for tuple');
|
||||||
final expressions = <Expression>[];
|
final expressions = <Expression>[];
|
||||||
|
|
||||||
final subQuery = _fullSelect();
|
// if desired, attempt to parse select statement
|
||||||
|
final subQuery = orSubQuery ? _fullSelect() : null;
|
||||||
if (subQuery == null) {
|
if (subQuery == null) {
|
||||||
// no sub query found. read expressions that form the tuple.
|
// no sub query found. read expressions that form the tuple.
|
||||||
// tuples can be empty `()`, so only start parsing values when it's not
|
// tuples can be empty `()`, so only start parsing values when it's not
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:sqlparser/sqlparser.dart';
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
import 'package:sqlparser/src/ast/ast.dart';
|
import 'package:sqlparser/src/ast/ast.dart';
|
||||||
import 'package:sqlparser/src/utils/ast_equality.dart';
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
import '../common_data.dart';
|
import '../common_data.dart';
|
||||||
|
@ -118,11 +117,8 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('parses MAPPED BY constraints when in moor mode', () {
|
test('parses MAPPED BY constraints when in moor mode', () {
|
||||||
const stmt = 'CREATE TABLE a (b NOT NULL MAPPED BY `Mapper()` PRIMARY KEY)';
|
testStatement(
|
||||||
final parsed = SqlEngine(useMoorExtensions: true).parse(stmt).rootNode;
|
'CREATE TABLE a (b NOT NULL MAPPED BY `Mapper()` PRIMARY KEY)',
|
||||||
|
|
||||||
enforceEqual(
|
|
||||||
parsed,
|
|
||||||
CreateTableStatement(tableName: 'a', columns: [
|
CreateTableStatement(tableName: 'a', columns: [
|
||||||
ColumnDefinition(
|
ColumnDefinition(
|
||||||
columnName: 'b',
|
columnName: 'b',
|
||||||
|
@ -134,15 +130,13 @@ void main() {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
moorMode: true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('parses JSON KEY constraints in moor mode', () {
|
test('parses JSON KEY constraints in moor mode', () {
|
||||||
const stmt = 'CREATE TABLE a (b INTEGER JSON KEY "my_json_key")';
|
testStatement(
|
||||||
final parsed = SqlEngine(useMoorExtensions: true).parse(stmt).rootNode;
|
'CREATE TABLE a (b INTEGER JSON KEY "my_json_key")',
|
||||||
|
|
||||||
enforceEqual(
|
|
||||||
parsed,
|
|
||||||
CreateTableStatement(
|
CreateTableStatement(
|
||||||
tableName: 'a',
|
tableName: 'a',
|
||||||
columns: [
|
columns: [
|
||||||
|
@ -158,6 +152,7 @@ void main() {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
moorMode: true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,8 +146,8 @@ void main() {
|
||||||
final tokens = scanner.scanTokens();
|
final tokens = scanner.scanTokens();
|
||||||
final parser = Parser(tokens);
|
final parser = Parser(tokens);
|
||||||
final expression = parser.expression();
|
final expression = parser.expression();
|
||||||
enforceHasSpan(expression);
|
|
||||||
|
|
||||||
|
enforceHasSpan(expression);
|
||||||
enforceEqual(expression, expected);
|
enforceEqual(expression, expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:sqlparser/sqlparser.dart';
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
import 'package:sqlparser/src/utils/ast_equality.dart';
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
import 'utils.dart';
|
import 'utils.dart';
|
||||||
|
@ -19,12 +18,8 @@ all: SELECT /* COUNT(*), */ * FROM tbl WHERE $predicate;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('parses moor files', () {
|
test('parses moor files', () {
|
||||||
final parsed = SqlEngine(useMoorExtensions: true).parseMoorFile(content);
|
testMoorFile(
|
||||||
final file = parsed.rootNode;
|
content,
|
||||||
enforceHasSpan(file);
|
|
||||||
|
|
||||||
enforceEqual(
|
|
||||||
file,
|
|
||||||
MoorFile([
|
MoorFile([
|
||||||
ImportStatement('other.dart'),
|
ImportStatement('other.dart'),
|
||||||
ImportStatement('another.moor'),
|
ImportStatement('another.moor'),
|
||||||
|
|
|
@ -4,38 +4,35 @@ import 'package:sqlparser/src/reader/tokenizer/scanner.dart';
|
||||||
import 'package:sqlparser/src/utils/ast_equality.dart';
|
import 'package:sqlparser/src/utils/ast_equality.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'utils.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('can parse multiple statements', () {
|
test('can parse multiple statements', () {
|
||||||
final sql = 'a: UPDATE tbl SET a = b; b: SELECT * FROM tbl;';
|
final sql = 'a: UPDATE tbl SET a = b; b: SELECT * FROM tbl;';
|
||||||
final tokens = Scanner(sql).scanTokens();
|
|
||||||
final moorFile = Parser(tokens).moorFile();
|
|
||||||
|
|
||||||
final statements = moorFile.statements;
|
testMoorFile(
|
||||||
|
sql,
|
||||||
enforceEqual(
|
MoorFile([
|
||||||
statements[0],
|
DeclaredStatement(
|
||||||
DeclaredStatement(
|
'a',
|
||||||
'a',
|
UpdateStatement(
|
||||||
UpdateStatement(
|
table: TableReference('tbl', null),
|
||||||
table: TableReference('tbl', null),
|
set: [
|
||||||
set: [
|
SetComponent(
|
||||||
SetComponent(
|
column: Reference(columnName: 'a'),
|
||||||
column: Reference(columnName: 'a'),
|
expression: Reference(columnName: 'b'),
|
||||||
expression: Reference(columnName: 'b'),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
DeclaredStatement(
|
||||||
);
|
'b',
|
||||||
enforceEqual(
|
SelectStatement(
|
||||||
statements[1],
|
columns: [StarResultColumn(null)],
|
||||||
DeclaredStatement(
|
from: [TableReference('tbl', null)],
|
||||||
'b',
|
),
|
||||||
SelectStatement(
|
|
||||||
columns: [StarResultColumn(null)],
|
|
||||||
from: [TableReference('tbl', null)],
|
|
||||||
),
|
),
|
||||||
),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ void main() {
|
||||||
final tokens = scanner.scanTokens();
|
final tokens = scanner.scanTokens();
|
||||||
final parser = Parser(tokens);
|
final parser = Parser(tokens);
|
||||||
final expression = parser.expression();
|
final expression = parser.expression();
|
||||||
|
|
||||||
|
enforceHasSpan(expression);
|
||||||
enforceEqual(expression, expected);
|
enforceEqual(expression, expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:sqlparser/src/utils/ast_equality.dart';
|
||||||
import '../utils.dart';
|
import '../utils.dart';
|
||||||
|
|
||||||
void _enforceFrom(SelectStatement stmt, List<Queryable> expected) {
|
void _enforceFrom(SelectStatement stmt, List<Queryable> expected) {
|
||||||
|
enforceHasSpan(stmt);
|
||||||
expect(stmt.from.length, expected.length);
|
expect(stmt.from.length, expected.length);
|
||||||
|
|
||||||
for (var i = 0; i < stmt.from.length; i++) {
|
for (var i = 0; i < stmt.from.length; i++) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ void main() {
|
||||||
.parse("SELECT * FROM test GROUP BY country HAVING country LIKE '%G%'")
|
.parse("SELECT * FROM test GROUP BY country HAVING country LIKE '%G%'")
|
||||||
.rootNode as SelectStatement;
|
.rootNode as SelectStatement;
|
||||||
|
|
||||||
|
enforceHasSpan(stmt);
|
||||||
return enforceEqual(
|
return enforceEqual(
|
||||||
stmt.groupBy,
|
stmt.groupBy,
|
||||||
GroupBy(
|
GroupBy(
|
||||||
|
|
|
@ -12,6 +12,7 @@ void main() {
|
||||||
.parse('SELECT * FROM test LIMIT 5 * 3')
|
.parse('SELECT * FROM test LIMIT 5 * 3')
|
||||||
.rootNode as SelectStatement;
|
.rootNode as SelectStatement;
|
||||||
|
|
||||||
|
enforceHasSpan(select);
|
||||||
enforceEqual(
|
enforceEqual(
|
||||||
select.limit,
|
select.limit,
|
||||||
Limit(
|
Limit(
|
||||||
|
@ -29,6 +30,7 @@ void main() {
|
||||||
.parse('SELECT * FROM test LIMIT 10 OFFSET 2')
|
.parse('SELECT * FROM test LIMIT 10 OFFSET 2')
|
||||||
.rootNode as SelectStatement;
|
.rootNode as SelectStatement;
|
||||||
|
|
||||||
|
enforceHasSpan(select);
|
||||||
enforceEqual(
|
enforceEqual(
|
||||||
select.limit,
|
select.limit,
|
||||||
Limit(
|
Limit(
|
||||||
|
@ -46,6 +48,7 @@ void main() {
|
||||||
.parse('SELECT * FROM test LIMIT 10, 2')
|
.parse('SELECT * FROM test LIMIT 10, 2')
|
||||||
.rootNode as SelectStatement;
|
.rootNode as SelectStatement;
|
||||||
|
|
||||||
|
enforceHasSpan(select);
|
||||||
enforceEqual(
|
enforceEqual(
|
||||||
select.limit,
|
select.limit,
|
||||||
Limit(
|
Limit(
|
||||||
|
|
|
@ -11,6 +11,7 @@ void main() {
|
||||||
.parse('SELECT * FROM tbl ORDER BY -a, b DESC')
|
.parse('SELECT * FROM tbl ORDER BY -a, b DESC')
|
||||||
.rootNode as SelectStatement;
|
.rootNode as SelectStatement;
|
||||||
|
|
||||||
|
enforceHasSpan(parsed);
|
||||||
enforceEqual(
|
enforceEqual(
|
||||||
parsed.orderBy,
|
parsed.orderBy,
|
||||||
OrderBy(
|
OrderBy(
|
||||||
|
|
|
@ -18,6 +18,14 @@ IdentifierToken identifier(String content) {
|
||||||
return IdentifierToken(false, fakeSpan(content));
|
return IdentifierToken(false, fakeSpan(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testMoorFile(String moorFile, MoorFile expected) {
|
||||||
|
final parsed =
|
||||||
|
SqlEngine(useMoorExtensions: true).parseMoorFile(moorFile).rootNode;
|
||||||
|
|
||||||
|
enforceHasSpan(parsed);
|
||||||
|
enforceEqual(parsed, expected);
|
||||||
|
}
|
||||||
|
|
||||||
void testStatement(String sql, AstNode expected, {bool moorMode = false}) {
|
void testStatement(String sql, AstNode expected, {bool moorMode = false}) {
|
||||||
final parsed = SqlEngine(useMoorExtensions: moorMode).parse(sql).rootNode;
|
final parsed = SqlEngine(useMoorExtensions: moorMode).parse(sql).rootNode;
|
||||||
enforceHasSpan(parsed);
|
enforceHasSpan(parsed);
|
||||||
|
@ -38,9 +46,9 @@ void testAll(Map<String, AstNode> testCases) {
|
||||||
|
|
||||||
/// The parser should make sure [AstNode.hasSpan] is true on relevant nodes.
|
/// The parser should make sure [AstNode.hasSpan] is true on relevant nodes.
|
||||||
void enforceHasSpan(AstNode node) {
|
void enforceHasSpan(AstNode node) {
|
||||||
final problematic = [node]
|
final problematic = [node].followedBy(node.allDescendants).firstWhere(
|
||||||
.followedBy(node.allDescendants)
|
(node) => !node.hasSpan && !node.synthetic,
|
||||||
.firstWhere((node) => !node.hasSpan, orElse: () => null);
|
orElse: () => null);
|
||||||
|
|
||||||
if (problematic != null) {
|
if (problematic != null) {
|
||||||
throw ArgumentError('Node $problematic did not have a span');
|
throw ArgumentError('Node $problematic did not have a span');
|
||||||
|
|
Loading…
Reference in New Issue