From aa75cbaa198e5e19f2e54dbcc0033aab47ba634a Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Thu, 22 Jul 2021 21:32:53 +0200 Subject: [PATCH] Prepare parser for schema support --- sqlparser/lib/src/ast/common/queryables.dart | 3 +- .../lib/src/ast/expressions/reference.dart | 25 +++- sqlparser/lib/src/reader/parser.dart | 121 +++++++++++------- sqlparser/lib/src/utils/ast_equality.dart | 9 +- sqlparser/lib/utils/node_to_text.dart | 25 +++- sqlparser/test/parser/create_table_test.dart | 4 +- sqlparser/test/parser/delete_test.dart | 4 +- sqlparser/test/parser/expression_test.dart | 11 +- sqlparser/test/parser/inline_dart_test.dart | 8 +- sqlparser/test/parser/insert_test.dart | 8 +- sqlparser/test/parser/moor_file_test.dart | 8 +- .../test/parser/multiple_statements.dart | 8 +- .../test/parser/regression_891_test.dart | 4 +- .../test/parser/select/compound_test.dart | 2 +- sqlparser/test/parser/select/from_test.dart | 26 ++-- .../test/parser/select/generic_test.dart | 6 +- sqlparser/test/parser/update_test.dart | 2 +- sqlparser/test/utils/node_to_text_test.dart | 11 ++ 18 files changed, 188 insertions(+), 97 deletions(-) diff --git a/sqlparser/lib/src/ast/common/queryables.dart b/sqlparser/lib/src/ast/common/queryables.dart index ec52508d..b625f91d 100644 --- a/sqlparser/lib/src/ast/common/queryables.dart +++ b/sqlparser/lib/src/ast/common/queryables.dart @@ -42,13 +42,14 @@ abstract class TableOrSubquery extends Queryable { class TableReference extends TableOrSubquery with ReferenceOwner implements Renamable, ResolvesToResultSet { + final String? schemaName; final String tableName; Token? tableNameToken; @override final String? as; - TableReference(this.tableName, [this.as]); + TableReference(this.tableName, {this.as, this.schemaName}); @override Iterable get childNodes => const []; diff --git a/sqlparser/lib/src/ast/expressions/reference.dart b/sqlparser/lib/src/ast/expressions/reference.dart index f3e8cb52..01b6e074 100644 --- a/sqlparser/lib/src/ast/expressions/reference.dart +++ b/sqlparser/lib/src/ast/expressions/reference.dart @@ -8,6 +8,11 @@ part of '../ast.dart'; /// 2 * c AS d FROM table", the "c" after the "2 *" is a reference that refers /// to the expression "COUNT(*)". class Reference extends Expression with ReferenceOwner { + /// An optional schema name. + /// + /// When this is non-null, [entityName] will not be null either. + final String? schemaName; + /// Entity can be either a table or a view. final String? entityName; final String columnName; @@ -17,7 +22,11 @@ class Reference extends Expression with ReferenceOwner { Column? get resolvedColumn => resolved as Column?; - Reference({this.entityName, required this.columnName}); + Reference({this.entityName, this.schemaName, required this.columnName}) + : assert( + entityName != null || schemaName == null, + 'When setting a schemaName, entityName must not be null either.', + ); @override R accept(AstVisitor visitor, A arg) { @@ -32,10 +41,16 @@ class Reference extends Expression with ReferenceOwner { @override String toString() { - if (entityName != null) { - return 'Reference to the column $entityName.$columnName'; - } else { - return 'Reference to the column $columnName'; + final result = StringBuffer(); + + if (schemaName != null) { + result..write(schemaName)..write('.'); } + if (entityName != null) { + result..write(entityName)..write('.'); + } + result.write(columnName); + + return result.toString(); } } diff --git a/sqlparser/lib/src/reader/parser.dart b/sqlparser/lib/src/reader/parser.dart index 257f679a..7b20cad8 100644 --- a/sqlparser/lib/src/reader/parser.dart +++ b/sqlparser/lib/src/reader/parser.dart @@ -751,32 +751,7 @@ class Parser { return CastExpression(operand, typeName)..setSpan(first, _previous); } else if (_checkIdentifier()) { - final first = _consumeIdentifier( - 'This error message should never be displayed. Please report.'); - - // could be table.column, function(...) or just column - if (_matchOne(TokenType.dot)) { - final second = - _consumeIdentifier('Expected a column name here', lenient: true); - return Reference( - entityName: first.identifier, columnName: second.identifier) - ..setSpan(first, second); - } else if (_matchOne(TokenType.leftParen)) { - // regular function invocation - final parameters = _functionParameters(); - final rightParen = _consume(TokenType.rightParen, - 'Expected closing bracket after argument list'); - - if (_peek.type == TokenType.filter || _peek.type == TokenType.over) { - return _aggregate(first, parameters); - } - - return FunctionExpression( - name: first.identifier, parameters: parameters) - ..setSpan(first, rightParen); - } else { - return Reference(columnName: first.identifier)..setSpan(first, first); - } + return _referenceOrFunctionCall(); } if (_peek is KeywordToken) { @@ -787,6 +762,55 @@ class Parser { } } + Expression _referenceOrFunctionCall() { + final first = _consumeIdentifier( + 'This error message should never be displayed. Please report.'); + + // An expression starting with an identifier could be three things: + // - a simple reference: "foo" + // - a reference with a table: "foo.bar" + // - a reference with a table and a schema: "foo.bar.baz" + // - a function call: "foo()" + + if (_matchOne(TokenType.dot)) { + // Ok, we're down to two here. it's either a table or a schema ref + final second = _consumeIdentifier('Expected a column or table name here', + lenient: true); + + if (_matchOne(TokenType.dot)) { + // Three identifiers, that's a schema reference + final third = + _consumeIdentifier('Expected a column name here', lenient: true); + return Reference( + schemaName: first.identifier, + entityName: second.identifier, + columnName: third.identifier, + )..setSpan(first, third); + } else { + // Two identifiers only, so we have a table-based reference + return Reference( + entityName: first.identifier, + columnName: second.identifier, + )..setSpan(first, second); + } + } else if (_matchOne(TokenType.leftParen)) { + // We have something like "foo(" -> that's a function! + final parameters = _functionParameters(); + final rightParen = _consume( + TokenType.rightParen, 'Expected closing bracket after argument list'); + + if (_peek.type == TokenType.filter || _peek.type == TokenType.over) { + return _aggregate(first, parameters); + } + + return FunctionExpression(name: first.identifier, parameters: parameters) + ..setSpan(first, rightParen); + } else { + // Ok, just a regular reference then + return Reference(columnName: first.identifier)..setSpan(first, first); + } + } + Variable? _variableOrNull() { if (_matchOne(TokenType.questionMarkVariable)) { return NumberedVariable(_previous as QuestionMarkVariableToken) @@ -1171,19 +1195,6 @@ class Parser { return null; } - TableReference _tableReference() { - _suggestHint(const TableNameDescription()); - // ignore the schema name, it's not supported. Besides that, we're on the - // first branch in the diagram here https://www.sqlite.org/syntax/table-or-subquery.html - final firstToken = _consumeIdentifier('Expected a table reference'); - - final tableName = firstToken.identifier; - final alias = _as(); - return TableReference(tableName, alias?.identifier) - ..setSpan(firstToken, _previous) - ..tableNameToken = firstToken; - } - JoinClause? _joinClause(TableOrSubquery start) { var operator = _parseJoinOperator(); if (operator == null) { @@ -2424,15 +2435,37 @@ class Parser { return null; } + TableReference _tableReference({bool allowAlias = true}) { + _suggestHint(const TableNameDescription()); + + final first = _consumeIdentifier('Expected table or schema name here'); + IdentifierToken? second; + IdentifierToken? as; + if (_matchOne(TokenType.dot)) { + second = _consumeIdentifier('Expected a table name here'); + } + + if (allowAlias) { + as = _as(); + } + + final tableNameToken = second ?? first; + + return TableReference( + tableNameToken.identifier, + as: as?.identifier, + schemaName: second == null ? null : first.identifier, + ) + ..setSpan(first, _previous) + ..tableNameToken = tableNameToken; + } + ForeignKeyClause _foreignKeyClause() { // https://www.sqlite.org/syntax/foreign-key-clause.html _consume(TokenType.references, 'Expected REFERENCES'); final firstToken = _previous; - final foreignTable = _consumeIdentifier('Expected a table name'); - final foreignTableName = TableReference(foreignTable.identifier, null) - ..setSpan(foreignTable, foreignTable); - + final foreignTable = _tableReference(allowAlias: false); final columnNames = _listColumnsInParentheses(allowEmpty: true); ReferenceAction? onDelete, onUpdate; @@ -2472,7 +2505,7 @@ class Parser { } return ForeignKeyClause( - foreignTable: foreignTableName, + foreignTable: foreignTable, columnNames: columnNames, onUpdate: onUpdate, onDelete: onDelete, diff --git a/sqlparser/lib/src/utils/ast_equality.dart b/sqlparser/lib/src/utils/ast_equality.dart index 6179da12..079e5468 100644 --- a/sqlparser/lib/src/utils/ast_equality.dart +++ b/sqlparser/lib/src/utils/ast_equality.dart @@ -547,7 +547,8 @@ class EqualityEnforcingVisitor implements AstVisitor { void visitReference(Reference e, void arg) { final current = _currentAs(e); _assert( - current.entityName == e.entityName && + current.schemaName == e.schemaName && + current.entityName == e.entityName && current.columnName == e.columnName, e); _checkChildren(e); @@ -628,7 +629,11 @@ class EqualityEnforcingVisitor implements AstVisitor { @override void visitTableReference(TableReference e, void arg) { final current = _currentAs(e); - _assert(current.tableName == e.tableName && current.as == e.as, e); + _assert( + current.schemaName == e.schemaName && + current.tableName == e.tableName && + current.as == e.as, + e); _checkChildren(e); } diff --git a/sqlparser/lib/utils/node_to_text.dart b/sqlparser/lib/utils/node_to_text.dart index d5d0baa8..d6106eb2 100644 --- a/sqlparser/lib/utils/node_to_text.dart +++ b/sqlparser/lib/utils/node_to_text.dart @@ -964,14 +964,22 @@ class NodeSqlBuilder extends AstVisitor { @override void visitReference(Reference e, void arg) { - var hasTable = false; - if (e.entityName != null) { - hasTable = true; - _identifier(e.entityName!, spaceAfter: false); + var didWriteSpaceBefore = false; + + if (e.schemaName != null) { + _identifier(e.schemaName!, spaceAfter: false); _symbol('.'); + didWriteSpaceBefore = true; + } + if (e.entityName != null) { + _identifier(e.entityName!, + spaceAfter: false, spaceBefore: !didWriteSpaceBefore); + _symbol('.'); + didWriteSpaceBefore = true; } - _identifier(e.columnName, spaceAfter: true, spaceBefore: !hasTable); + _identifier(e.columnName, + spaceAfter: true, spaceBefore: !didWriteSpaceBefore); } @override @@ -1131,7 +1139,12 @@ class NodeSqlBuilder extends AstVisitor { @override void visitTableReference(TableReference e, void arg) { - _identifier(e.tableName); + if (e.schemaName != null) { + _identifier(e.schemaName!, spaceAfter: false); + _symbol('.'); + } + _identifier(e.tableName, spaceBefore: e.schemaName == null); + if (e.as != null) { _keyword(TokenType.as); _identifier(e.as!); diff --git a/sqlparser/test/parser/create_table_test.dart b/sqlparser/test/parser/create_table_test.dart index 8ff6370c..f79499a4 100644 --- a/sqlparser/test/parser/create_table_test.dart +++ b/sqlparser/test/parser/create_table_test.dart @@ -77,7 +77,7 @@ void main() { ForeignKeyColumnConstraint( null, ForeignKeyClause( - foreignTable: TableReference('some', null), + foreignTable: TableReference('some'), columnNames: [Reference(columnName: 'thing')], onUpdate: ReferenceAction.cascade, onDelete: ReferenceAction.setNull, @@ -107,7 +107,7 @@ void main() { Reference(columnName: 'email'), ], clause: ForeignKeyClause( - foreignTable: TableReference('another', null), + foreignTable: TableReference('another'), columnNames: [ Reference(columnName: 'a'), Reference(columnName: 'b'), diff --git a/sqlparser/test/parser/delete_test.dart b/sqlparser/test/parser/delete_test.dart index c9af4e86..59c7f6ee 100644 --- a/sqlparser/test/parser/delete_test.dart +++ b/sqlparser/test/parser/delete_test.dart @@ -9,7 +9,7 @@ void main() { testStatement( 'DELETE FROM tbl WHERE id = 5', DeleteStatement( - from: TableReference('tbl', null), + from: TableReference('tbl'), where: BinaryExpression( Reference(columnName: 'id'), token(TokenType.equal), @@ -26,7 +26,7 @@ void main() { testStatement( 'DELETE FROM tbl RETURNING *;', DeleteStatement( - from: TableReference('tbl', null), + from: TableReference('tbl'), returning: Returning([StarResultColumn()]), ), ); diff --git a/sqlparser/test/parser/expression_test.dart b/sqlparser/test/parser/expression_test.dart index 0cd9045f..62a3ffef 100644 --- a/sqlparser/test/parser/expression_test.dart +++ b/sqlparser/test/parser/expression_test.dart @@ -106,7 +106,7 @@ final Map _testCases = { ExistsExpression( select: SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('demo', null), + from: TableReference('demo'), ), ), ), @@ -141,7 +141,7 @@ final Map _testCases = { expression: Reference(columnName: 'col'), ) ], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), ), ), @@ -192,6 +192,13 @@ final Map _testCases = { 'RAISE(IGNORE)': RaiseExpression(RaiseKind.ignore), "RAISE(ROLLBACK, 'Not allowed')": RaiseExpression(RaiseKind.rollback, 'Not allowed'), + 'foo': Reference(columnName: 'foo'), + 'foo.bar': Reference(entityName: 'foo', columnName: 'bar'), + 'foo.bar.baz': Reference( + schemaName: 'foo', + entityName: 'bar', + columnName: 'baz', + ), }; void main() { diff --git a/sqlparser/test/parser/inline_dart_test.dart b/sqlparser/test/parser/inline_dart_test.dart index 793fcde3..98e7a95b 100644 --- a/sqlparser/test/parser/inline_dart_test.dart +++ b/sqlparser/test/parser/inline_dart_test.dart @@ -9,7 +9,7 @@ void main() { r'SELECT * FROM tbl LIMIT $limit', SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), limit: DartLimitPlaceholder(name: 'limit'), ), moorMode: true, @@ -21,7 +21,7 @@ void main() { r'SELECT * FROM tbl LIMIT $amount OFFSET 3', SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), limit: Limit( count: DartExpressionPlaceholder(name: 'amount'), offsetSeparator: token(TokenType.offset), @@ -37,7 +37,7 @@ void main() { r'SELECT * FROM tbl ORDER BY $term, $expr DESC', SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), orderBy: OrderBy( terms: [ DartOrderingTermPlaceholder(name: 'term'), @@ -57,7 +57,7 @@ void main() { r'SELECT * FROM tbl ORDER BY $order', SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), orderBy: DartOrderByPlaceholder(name: 'order'), ), moorMode: true, diff --git a/sqlparser/test/parser/insert_test.dart b/sqlparser/test/parser/insert_test.dart index 4b4f4aab..344802b3 100644 --- a/sqlparser/test/parser/insert_test.dart +++ b/sqlparser/test/parser/insert_test.dart @@ -9,7 +9,7 @@ void main() { 'INSERT OR REPLACE INTO tbl (a, b, c) VALUES (d, e, f)', InsertStatement( mode: InsertMode.insertOrReplace, - table: TableReference('tbl', null), + table: TableReference('tbl'), targetColumns: [ Reference(columnName: 'a'), Reference(columnName: 'b'), @@ -31,7 +31,7 @@ void main() { 'INSERT INTO tbl DEFAULT VALUES', InsertStatement( mode: InsertMode.insert, - table: TableReference('tbl', null), + table: TableReference('tbl'), targetColumns: const [], source: DefaultValues(), ), @@ -43,12 +43,12 @@ void main() { 'REPLACE INTO tbl SELECT * FROM tbl', InsertStatement( mode: InsertMode.replace, - table: TableReference('tbl', null), + table: TableReference('tbl'), targetColumns: const [], source: SelectInsertSource( SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), ), ), diff --git a/sqlparser/test/parser/moor_file_test.dart b/sqlparser/test/parser/moor_file_test.dart index e962c0e9..28577d4b 100644 --- a/sqlparser/test/parser/moor_file_test.dart +++ b/sqlparser/test/parser/moor_file_test.dart @@ -46,7 +46,7 @@ void main() { ForeignKeyColumnConstraint( null, ForeignKeyClause( - foreignTable: TableReference('other', null), + foreignTable: TableReference('other'), columnNames: [ Reference(columnName: 'location'), ], @@ -62,7 +62,7 @@ void main() { SimpleName('all'), SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), where: DartExpressionPlaceholder(name: 'predicate'), ), ), @@ -70,7 +70,7 @@ void main() { SpecialStatementIdentifier('special'), SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), ), DeclaredStatement( @@ -104,7 +104,7 @@ void main() { SimpleName('nested'), SelectStatement( columns: [NestedStarResultColumn('foo')], - from: TableReference('tbl', 'foo'), + from: TableReference('tbl', as: 'foo'), ), as: 'MyResultSet', ), diff --git a/sqlparser/test/parser/multiple_statements.dart b/sqlparser/test/parser/multiple_statements.dart index 825d4731..3862dedd 100644 --- a/sqlparser/test/parser/multiple_statements.dart +++ b/sqlparser/test/parser/multiple_statements.dart @@ -16,7 +16,7 @@ void main() { DeclaredStatement( SimpleName('a'), UpdateStatement( - table: TableReference('tbl', null), + table: TableReference('tbl'), set: [ SetComponent( column: Reference(columnName: 'a'), @@ -29,7 +29,7 @@ void main() { SimpleName('b'), SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), ), ]), @@ -48,7 +48,7 @@ void main() { SimpleName('b'), SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), ), ); @@ -78,7 +78,7 @@ void main() { SimpleName('query'), SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), ), ); diff --git a/sqlparser/test/parser/regression_891_test.dart b/sqlparser/test/parser/regression_891_test.dart index f17acbc9..3841f283 100644 --- a/sqlparser/test/parser/regression_891_test.dart +++ b/sqlparser/test/parser/regression_891_test.dart @@ -47,7 +47,7 @@ void main() { and n.folderId = :selectedFolderId; ''', SelectStatement( - from: TableReference('notes', 'n'), + from: TableReference('notes', as: 'n'), columns: [StarResultColumn()], where: BinaryExpression( caseExpr, @@ -69,7 +69,7 @@ void main() { END; ''', SelectStatement( - from: TableReference('notes', 'n'), + from: TableReference('notes', as: 'n'), columns: [StarResultColumn()], where: BinaryExpression( folderExpr, diff --git a/sqlparser/test/parser/select/compound_test.dart b/sqlparser/test/parser/select/compound_test.dart index 800a7c98..4123f590 100644 --- a/sqlparser/test/parser/select/compound_test.dart +++ b/sqlparser/test/parser/select/compound_test.dart @@ -10,7 +10,7 @@ void main() { CompoundSelectStatement( base: SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), additional: [ CompoundSelectPart( diff --git a/sqlparser/test/parser/select/from_test.dart b/sqlparser/test/parser/select/from_test.dart index 0a96138a..404e2ff2 100644 --- a/sqlparser/test/parser/select/from_test.dart +++ b/sqlparser/test/parser/select/from_test.dart @@ -16,7 +16,13 @@ void main() { final stmt = SqlEngine().parse('SELECT * FROM tbl').rootNode as SelectStatement; - enforceEqual(stmt.from!, TableReference('tbl', null)); + _enforceFrom(stmt, TableReference('tbl')); + }); + + test('schema name and alias', () { + final stmt = SqlEngine().parse('SELECT * FROM main.tbl foo').rootNode + as SelectStatement; + _enforceFrom(stmt, TableReference('tbl', schemaName: 'main', as: 'foo')); }); test('from more than one table', () { @@ -27,11 +33,11 @@ void main() { _enforceFrom( stmt, JoinClause( - primary: TableReference('tbl', 'test'), + primary: TableReference('tbl', as: 'test'), joins: [ Join( operator: JoinOperator.comma, - query: TableReference('table2', null), + query: TableReference('table2'), ), ], ), @@ -46,11 +52,11 @@ void main() { _enforceFrom( stmt, JoinClause( - primary: TableReference('tbl', 'test'), + primary: TableReference('tbl', as: 'test'), joins: [ Join( operator: JoinOperator.comma, - query: TableReference('table2', null), + query: TableReference('table2'), constraint: OnConstraint( expression: BooleanLiteral.withTrue(token(TokenType.$true)), ), @@ -69,14 +75,14 @@ void main() { _enforceFrom( stmt, JoinClause( - primary: TableReference('table1', null), + primary: TableReference('table1'), joins: [ Join( operator: JoinOperator.comma, query: SelectStatementAsSource( statement: SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('table2', null), + from: TableReference('table2'), where: Reference(columnName: 'a'), ), as: 'inner', @@ -132,16 +138,16 @@ void main() { _enforceFrom( stmt, JoinClause( - primary: TableReference('table1', null), + primary: TableReference('table1'), joins: [ Join( operator: JoinOperator.inner, - query: TableReference('table2', null), + query: TableReference('table2'), constraint: UsingConstraint(columnNames: ['test']), ), Join( operator: JoinOperator.leftOuter, - query: TableReference('table3', null), + query: TableReference('table3'), constraint: OnConstraint( expression: BooleanLiteral.withTrue(token(TokenType.$true)), ), diff --git a/sqlparser/test/parser/select/generic_test.dart b/sqlparser/test/parser/select/generic_test.dart index a6b58cdf..14886f70 100644 --- a/sqlparser/test/parser/select/generic_test.dart +++ b/sqlparser/test/parser/select/generic_test.dart @@ -32,16 +32,16 @@ final Map testCases = { expression: SubQuery( select: SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('table2', null), + from: TableReference('table2'), ), ), ), ], - from: TableReference('tbl', null), + from: TableReference('tbl'), ), 'SELECT * FROM tbl WHERE id IN ()': SelectStatement( columns: [StarResultColumn(null)], - from: TableReference('tbl', null), + from: TableReference('tbl'), where: InExpression( left: Reference(columnName: 'id'), inside: Tuple(expressions: []), diff --git a/sqlparser/test/parser/update_test.dart b/sqlparser/test/parser/update_test.dart index 4ad0956d..a79ca512 100644 --- a/sqlparser/test/parser/update_test.dart +++ b/sqlparser/test/parser/update_test.dart @@ -6,7 +6,7 @@ import 'utils.dart'; final Map testCases = { 'UPDATE OR ROLLBACK tbl SET a = NULL, b = c WHERE d': UpdateStatement( or: FailureMode.rollback, - table: TableReference('tbl', null), + table: TableReference('tbl'), set: [ SetComponent( column: Reference(columnName: 'a'), diff --git a/sqlparser/test/utils/node_to_text_test.dart b/sqlparser/test/utils/node_to_text_test.dart index 4a142326..2dde5e0d 100644 --- a/sqlparser/test/utils/node_to_text_test.dart +++ b/sqlparser/test/utils/node_to_text_test.dart @@ -221,6 +221,11 @@ CREATE UNIQUE INDEX my_idx ON t1 (c1, c2, c3) WHERE c1 < c3; '''); }); + test('table references', () { + testFormat('SELECT * FROM foo'); + testFormat('SELECT * FROM main.foo'); + }); + test('limit', () { testFormat('SELECT * FROM foo LIMIT 3, 4'); testFormat('SELECT * FROM foo LIMIT 4 OFFSET 3'); @@ -379,6 +384,12 @@ CREATE UNIQUE INDEX my_idx ON t1 (c1, c2, c3) WHERE c1 < c3; test('unary expression', () { testFormat('SELECT -(+(~3));'); }); + + test('references', () { + testFormat('SELECT foo'); + testFormat('SELECT foo.bar'); + testFormat('SELECT foo.bar.baz'); + }); }); group('moor', () {