mirror of https://github.com/AMT-Cheif/drift.git
Relax constraints on element order in drift files
This commit is contained in:
parent
1a51dbf4d6
commit
387a21c580
|
@ -62,11 +62,10 @@ class DatabaseWriter {
|
||||||
..write('class $className extends ')
|
..write('class $className extends ')
|
||||||
..writeDriftRef('GeneratedDatabase')
|
..writeDriftRef('GeneratedDatabase')
|
||||||
..writeln('{')
|
..writeln('{')
|
||||||
..writeln(
|
..writeln('$className(${firstLeaf.drift('QueryExecutor e')}): super(e);');
|
||||||
'$className(${firstLeaf.refDrift('QueryExecutor e')}): super(e);');
|
|
||||||
|
|
||||||
if (dbScope.options.generateConnectConstructor) {
|
if (dbScope.options.generateConnectConstructor) {
|
||||||
final conn = firstLeaf.refDrift('DatabaseConnection');
|
final conn = firstLeaf.drift('DatabaseConnection');
|
||||||
firstLeaf.write('$className.connect($conn c): super.connect(c); \n');
|
firstLeaf.write('$className.connect($conn c): super.connect(c); \n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,7 +219,7 @@ class DatabaseWriter {
|
||||||
|
|
||||||
if (scope.options.storeDateTimeValuesAsText) {
|
if (scope.options.storeDateTimeValuesAsText) {
|
||||||
// Override database options to reflect that DateTimes are stored as text.
|
// Override database options to reflect that DateTimes are stored as text.
|
||||||
final options = schemaScope.refDrift('DriftDatabaseOptions');
|
final options = schemaScope.drift('DriftDatabaseOptions');
|
||||||
|
|
||||||
schemaScope
|
schemaScope
|
||||||
..writeln('@override')
|
..writeln('@override')
|
||||||
|
|
|
@ -664,14 +664,18 @@ class _ExpandedVariableWriter {
|
||||||
String constructVar(String dartExpr) {
|
String constructVar(String dartExpr) {
|
||||||
// No longer an array here, we apply a for loop if necessary
|
// No longer an array here, we apply a for loop if necessary
|
||||||
final type = element.innerColumnType(nullable: false);
|
final type = element.innerColumnType(nullable: false);
|
||||||
final buffer = StringBuffer('Variable<$type>(');
|
|
||||||
|
final varType = _emitter.drift('Variable');
|
||||||
|
final buffer = StringBuffer('$varType<$type>(');
|
||||||
final capture = element.forCaptured;
|
final capture = element.forCaptured;
|
||||||
|
|
||||||
final converter = element.typeConverter;
|
final converter = element.typeConverter;
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
// Apply the converter.
|
// Apply the converter.
|
||||||
if (element.nullable && converter.canBeSkippedForNulls) {
|
if (element.nullable && converter.canBeSkippedForNulls) {
|
||||||
buffer.write('NullAwareTypeConverter.wrapToSql('
|
final nullAware = _emitter.drift('NullAwareTypeConverter');
|
||||||
|
|
||||||
|
buffer.write('$nullAware.wrapToSql('
|
||||||
'${_converter(_emitter, element.typeConverter!)}, $dartExpr)');
|
'${_converter(_emitter, element.typeConverter!)}, $dartExpr)');
|
||||||
} else {
|
} else {
|
||||||
buffer.write(
|
buffer.write(
|
||||||
|
|
|
@ -7,8 +7,6 @@ import '../analysis/options.dart';
|
||||||
import 'import_manager.dart';
|
import 'import_manager.dart';
|
||||||
import 'queries/sql_writer.dart';
|
import 'queries/sql_writer.dart';
|
||||||
|
|
||||||
Uri _driftImport = Uri.parse('package:drift/drift.dart');
|
|
||||||
|
|
||||||
/// Manages a tree structure which we use to generate code.
|
/// Manages a tree structure which we use to generate code.
|
||||||
///
|
///
|
||||||
/// Each leaf in the tree is a [StringBuffer] that contains some code. A
|
/// Each leaf in the tree is a [StringBuffer] that contains some code. A
|
||||||
|
@ -287,9 +285,7 @@ class TextEmitter extends _Node {
|
||||||
return write(refUri(definition, element));
|
return write(refUri(definition, element));
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeDriftRef(String element) => write(refDrift(element));
|
void writeDriftRef(String element) => write(drift(element));
|
||||||
|
|
||||||
String refDrift(String element) => refUri(_driftImport, element);
|
|
||||||
|
|
||||||
void writeDart(AnnotatedDartCode code) => write(dartCode(code));
|
void writeDart(AnnotatedDartCode code) => write(dartCode(code));
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ CREATE VIRTUAL TABLE search_in_posts USING fts5 (
|
||||||
content_rowid=id
|
content_rowid=id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
search: WITH relevant_ports AS (SELECT rowid FROM search_in_posts WHERE search_in_posts MATCH ?)
|
||||||
|
SELECT posts.* FROM relevant_ports results
|
||||||
|
INNER JOIN posts ON id = results.rowid;
|
||||||
|
|
||||||
-- Keep fts5 table and posts synchronized
|
-- Keep fts5 table and posts synchronized
|
||||||
|
|
||||||
CREATE TRIGGER posts_insert AFTER INSERT ON posts BEGIN
|
CREATE TRIGGER posts_insert AFTER INSERT ON posts BEGIN
|
||||||
|
|
|
@ -205,5 +205,20 @@ i0.Trigger get postsDelete => i0.Trigger(
|
||||||
|
|
||||||
class SearchDrift extends i2.ModularAccessor {
|
class SearchDrift extends i2.ModularAccessor {
|
||||||
SearchDrift(i0.GeneratedDatabase db) : super(db);
|
SearchDrift(i0.GeneratedDatabase db) : super(db);
|
||||||
|
i0.Selectable<i3.Post> search(String var1) {
|
||||||
|
return customSelect(
|
||||||
|
'WITH relevant_ports AS (SELECT "rowid" FROM search_in_posts WHERE search_in_posts MATCH ?1) SELECT posts.* FROM relevant_ports AS results INNER JOIN posts ON id = results."rowid"',
|
||||||
|
variables: [
|
||||||
|
i0.Variable<String>(var1)
|
||||||
|
],
|
||||||
|
readsFrom: {
|
||||||
|
searchInPosts,
|
||||||
|
posts,
|
||||||
|
}).asyncMap(posts.mapFromRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
i1.SearchInPosts get searchInPosts =>
|
||||||
|
this.resultSet<i1.SearchInPosts>('search_in_posts');
|
||||||
|
i3.Posts get posts => this.resultSet<i3.Posts>('posts');
|
||||||
i3.PostsDrift get postsDrift => this.accessor(i3.PostsDrift.new);
|
i3.PostsDrift get postsDrift => this.accessor(i3.PostsDrift.new);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,6 @@ class Parser {
|
||||||
final List<ParsingError> errors = [];
|
final List<ParsingError> errors = [];
|
||||||
final AutoCompleteEngine? autoComplete;
|
final AutoCompleteEngine? autoComplete;
|
||||||
|
|
||||||
// todo remove this and don't be that lazy in driftFile()
|
|
||||||
var _lastStmtHadParsingError = false;
|
|
||||||
|
|
||||||
/// Whether to enable the extensions drift makes to the sql grammar.
|
/// Whether to enable the extensions drift makes to the sql grammar.
|
||||||
final bool enableDriftExtensions;
|
final bool enableDriftExtensions;
|
||||||
|
|
||||||
|
@ -242,31 +239,8 @@ class Parser {
|
||||||
final first = _peek;
|
final first = _peek;
|
||||||
final foundComponents = <PartOfDriftFile?>[];
|
final foundComponents = <PartOfDriftFile?>[];
|
||||||
|
|
||||||
// (we try again if the last statement had a parsing error)
|
while (!_isAtEnd) {
|
||||||
|
foundComponents.add(_parseAsStatement(_partOfDriftFile));
|
||||||
// first, parse import statements
|
|
||||||
for (var stmt = _parseAsStatement(_import);
|
|
||||||
stmt != null || _lastStmtHadParsingError;
|
|
||||||
stmt = _parseAsStatement(_import)) {
|
|
||||||
foundComponents.add(stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// next, table declarations
|
|
||||||
for (var stmt = _parseAsStatement(_create);
|
|
||||||
stmt != null || _lastStmtHadParsingError;
|
|
||||||
stmt = _parseAsStatement(_create)) {
|
|
||||||
foundComponents.add(stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally, declared statements
|
|
||||||
for (var stmt = _parseAsStatement(_declaredStatement);
|
|
||||||
stmt != null || _lastStmtHadParsingError;
|
|
||||||
stmt = _parseAsStatement(_declaredStatement)) {
|
|
||||||
foundComponents.add(stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_isAtEnd) {
|
|
||||||
_error('Expected the file to end here.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foundComponents.removeWhere((c) => c == null);
|
foundComponents.removeWhere((c) => c == null);
|
||||||
|
@ -275,11 +249,26 @@ class Parser {
|
||||||
if (foundComponents.isNotEmpty) {
|
if (foundComponents.isNotEmpty) {
|
||||||
file.setSpan(first, _previous);
|
file.setSpan(first, _previous);
|
||||||
} else {
|
} else {
|
||||||
|
_suggestHintForTokens([TokenType.create, TokenType.import]);
|
||||||
|
|
||||||
|
if (_reportAutoComplete) {}
|
||||||
|
|
||||||
file.setSpan(first, first); // empty file
|
file.setSpan(first, first); // empty file
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PartOfDriftFile _partOfDriftFile() {
|
||||||
|
final found = _import() ?? _create() ?? _declaredStatement();
|
||||||
|
|
||||||
|
if (found != null) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
_error('Expected `IMPORT`, `CREATE`, or an identifier starting a compiled '
|
||||||
|
'query.');
|
||||||
|
}
|
||||||
|
|
||||||
ImportStatement? _import() {
|
ImportStatement? _import() {
|
||||||
if (_matchOne(TokenType.import)) {
|
if (_matchOne(TokenType.import)) {
|
||||||
final importToken = _previous;
|
final importToken = _previous;
|
||||||
|
@ -393,7 +382,6 @@ class Parser {
|
||||||
/// semicolon if one exists.
|
/// semicolon if one exists.
|
||||||
T? _parseAsStatement<T extends Statement>(T? Function() parser,
|
T? _parseAsStatement<T extends Statement>(T? Function() parser,
|
||||||
{bool requireSemicolon = true}) {
|
{bool requireSemicolon = true}) {
|
||||||
_lastStmtHadParsingError = false;
|
|
||||||
final first = _peek;
|
final first = _peek;
|
||||||
T? result;
|
T? result;
|
||||||
try {
|
try {
|
||||||
|
@ -405,7 +393,6 @@ class Parser {
|
||||||
result.setSpan(first, _previous);
|
result.setSpan(first, _previous);
|
||||||
}
|
}
|
||||||
} on ParsingError {
|
} on ParsingError {
|
||||||
_lastStmtHadParsingError = true;
|
|
||||||
// the error is added to the list errors, so ignore. We skip after the
|
// the error is added to the list errors, so ignore. We skip after the
|
||||||
// next semicolon to parse the next statement.
|
// next semicolon to parse the next statement.
|
||||||
_synchronize(TokenType.semicolon, skipTarget: true);
|
_synchronize(TokenType.semicolon, skipTarget: true);
|
||||||
|
@ -422,13 +409,15 @@ class Parser {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CrudStatement> _crudStatements() {
|
List<CrudStatement> _crudStatements(bool Function() reachedEnd) {
|
||||||
final stmts = <CrudStatement>[];
|
final stmts = <CrudStatement>[];
|
||||||
|
|
||||||
for (var stmt = _parseAsStatement(_crud);
|
while (!reachedEnd()) {
|
||||||
stmt != null || _lastStmtHadParsingError;
|
final stmt = _parseAsStatement(_crud);
|
||||||
stmt = _parseAsStatement(_crud)) {
|
|
||||||
if (stmt != null) stmts.add(stmt);
|
if (stmt != null) {
|
||||||
|
stmts.add(stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stmts;
|
return stmts;
|
||||||
|
@ -437,7 +426,7 @@ class Parser {
|
||||||
/// Parses a block, which consists of statements between `BEGIN` and `END`.
|
/// Parses a block, which consists of statements between `BEGIN` and `END`.
|
||||||
Block _consumeBlock() {
|
Block _consumeBlock() {
|
||||||
final begin = _consume(TokenType.begin, 'Expected BEGIN');
|
final begin = _consume(TokenType.begin, 'Expected BEGIN');
|
||||||
final stmts = _crudStatements();
|
final stmts = _crudStatements(() => _check(TokenType.end));
|
||||||
final end = _consume(TokenType.end, 'Expected END');
|
final end = _consume(TokenType.end, 'Expected END');
|
||||||
|
|
||||||
return Block(stmts)
|
return Block(stmts)
|
||||||
|
@ -449,7 +438,8 @@ class Parser {
|
||||||
TransactionBlock _transactionBlock() {
|
TransactionBlock _transactionBlock() {
|
||||||
final first = _peek;
|
final first = _peek;
|
||||||
final begin = _beginStatement();
|
final begin = _beginStatement();
|
||||||
final stmts = _crudStatements();
|
final stmts = _crudStatements(
|
||||||
|
() => _checkAny(const [TokenType.commit, TokenType.end]));
|
||||||
final end = _commit();
|
final end = _commit();
|
||||||
|
|
||||||
return TransactionBlock(begin: begin, innerStatements: stmts, commit: end)
|
return TransactionBlock(begin: begin, innerStatements: stmts, commit: end)
|
||||||
|
|
|
@ -219,4 +219,21 @@ SELECT DISTINCT A.* FROM works A, works B ON A.id =
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('allows statements to appear in any order', () {
|
||||||
|
final result =
|
||||||
|
SqlEngine(EngineOptions(useDriftExtensions: true)).parseDriftFile('''
|
||||||
|
CREATE TABLE foo (
|
||||||
|
a INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
import 'b.dart';
|
||||||
|
|
||||||
|
a: SELECT * FROM foo;
|
||||||
|
|
||||||
|
CREATE INDEX x ON foo (a);
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(result.errors, isEmpty);
|
||||||
|
});
|
||||||
}
|
}
|
Loading…
Reference in New Issue