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 ')
|
||||
..writeDriftRef('GeneratedDatabase')
|
||||
..writeln('{')
|
||||
..writeln(
|
||||
'$className(${firstLeaf.refDrift('QueryExecutor e')}): super(e);');
|
||||
..writeln('$className(${firstLeaf.drift('QueryExecutor e')}): super(e);');
|
||||
|
||||
if (dbScope.options.generateConnectConstructor) {
|
||||
final conn = firstLeaf.refDrift('DatabaseConnection');
|
||||
final conn = firstLeaf.drift('DatabaseConnection');
|
||||
firstLeaf.write('$className.connect($conn c): super.connect(c); \n');
|
||||
}
|
||||
|
||||
|
@ -220,7 +219,7 @@ class DatabaseWriter {
|
|||
|
||||
if (scope.options.storeDateTimeValuesAsText) {
|
||||
// Override database options to reflect that DateTimes are stored as text.
|
||||
final options = schemaScope.refDrift('DriftDatabaseOptions');
|
||||
final options = schemaScope.drift('DriftDatabaseOptions');
|
||||
|
||||
schemaScope
|
||||
..writeln('@override')
|
||||
|
|
|
@ -664,14 +664,18 @@ class _ExpandedVariableWriter {
|
|||
String constructVar(String dartExpr) {
|
||||
// No longer an array here, we apply a for loop if necessary
|
||||
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 converter = element.typeConverter;
|
||||
if (converter != null) {
|
||||
// Apply the converter.
|
||||
if (element.nullable && converter.canBeSkippedForNulls) {
|
||||
buffer.write('NullAwareTypeConverter.wrapToSql('
|
||||
final nullAware = _emitter.drift('NullAwareTypeConverter');
|
||||
|
||||
buffer.write('$nullAware.wrapToSql('
|
||||
'${_converter(_emitter, element.typeConverter!)}, $dartExpr)');
|
||||
} else {
|
||||
buffer.write(
|
||||
|
|
|
@ -7,8 +7,6 @@ import '../analysis/options.dart';
|
|||
import 'import_manager.dart';
|
||||
import 'queries/sql_writer.dart';
|
||||
|
||||
Uri _driftImport = Uri.parse('package:drift/drift.dart');
|
||||
|
||||
/// Manages a tree structure which we use to generate code.
|
||||
///
|
||||
/// 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));
|
||||
}
|
||||
|
||||
void writeDriftRef(String element) => write(refDrift(element));
|
||||
|
||||
String refDrift(String element) => refUri(_driftImport, element);
|
||||
void writeDriftRef(String element) => write(drift(element));
|
||||
|
||||
void writeDart(AnnotatedDartCode code) => write(dartCode(code));
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@ CREATE VIRTUAL TABLE search_in_posts USING fts5 (
|
|||
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
|
||||
|
||||
CREATE TRIGGER posts_insert AFTER INSERT ON posts BEGIN
|
||||
|
|
|
@ -205,5 +205,20 @@ i0.Trigger get postsDelete => i0.Trigger(
|
|||
|
||||
class SearchDrift extends i2.ModularAccessor {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -33,9 +33,6 @@ class Parser {
|
|||
final List<ParsingError> errors = [];
|
||||
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.
|
||||
final bool enableDriftExtensions;
|
||||
|
||||
|
@ -242,31 +239,8 @@ class Parser {
|
|||
final first = _peek;
|
||||
final foundComponents = <PartOfDriftFile?>[];
|
||||
|
||||
// (we try again if the last statement had a parsing error)
|
||||
|
||||
// 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.');
|
||||
while (!_isAtEnd) {
|
||||
foundComponents.add(_parseAsStatement(_partOfDriftFile));
|
||||
}
|
||||
|
||||
foundComponents.removeWhere((c) => c == null);
|
||||
|
@ -275,11 +249,26 @@ class Parser {
|
|||
if (foundComponents.isNotEmpty) {
|
||||
file.setSpan(first, _previous);
|
||||
} else {
|
||||
_suggestHintForTokens([TokenType.create, TokenType.import]);
|
||||
|
||||
if (_reportAutoComplete) {}
|
||||
|
||||
file.setSpan(first, first); // empty 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() {
|
||||
if (_matchOne(TokenType.import)) {
|
||||
final importToken = _previous;
|
||||
|
@ -393,7 +382,6 @@ class Parser {
|
|||
/// semicolon if one exists.
|
||||
T? _parseAsStatement<T extends Statement>(T? Function() parser,
|
||||
{bool requireSemicolon = true}) {
|
||||
_lastStmtHadParsingError = false;
|
||||
final first = _peek;
|
||||
T? result;
|
||||
try {
|
||||
|
@ -405,7 +393,6 @@ class Parser {
|
|||
result.setSpan(first, _previous);
|
||||
}
|
||||
} on ParsingError {
|
||||
_lastStmtHadParsingError = true;
|
||||
// the error is added to the list errors, so ignore. We skip after the
|
||||
// next semicolon to parse the next statement.
|
||||
_synchronize(TokenType.semicolon, skipTarget: true);
|
||||
|
@ -422,13 +409,15 @@ class Parser {
|
|||
return result;
|
||||
}
|
||||
|
||||
List<CrudStatement> _crudStatements() {
|
||||
List<CrudStatement> _crudStatements(bool Function() reachedEnd) {
|
||||
final stmts = <CrudStatement>[];
|
||||
|
||||
for (var stmt = _parseAsStatement(_crud);
|
||||
stmt != null || _lastStmtHadParsingError;
|
||||
stmt = _parseAsStatement(_crud)) {
|
||||
if (stmt != null) stmts.add(stmt);
|
||||
while (!reachedEnd()) {
|
||||
final stmt = _parseAsStatement(_crud);
|
||||
|
||||
if (stmt != null) {
|
||||
stmts.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
return stmts;
|
||||
|
@ -437,7 +426,7 @@ class Parser {
|
|||
/// Parses a block, which consists of statements between `BEGIN` and `END`.
|
||||
Block _consumeBlock() {
|
||||
final begin = _consume(TokenType.begin, 'Expected BEGIN');
|
||||
final stmts = _crudStatements();
|
||||
final stmts = _crudStatements(() => _check(TokenType.end));
|
||||
final end = _consume(TokenType.end, 'Expected END');
|
||||
|
||||
return Block(stmts)
|
||||
|
@ -449,7 +438,8 @@ class Parser {
|
|||
TransactionBlock _transactionBlock() {
|
||||
final first = _peek;
|
||||
final begin = _beginStatement();
|
||||
final stmts = _crudStatements();
|
||||
final stmts = _crudStatements(
|
||||
() => _checkAny(const [TokenType.commit, TokenType.end]));
|
||||
final end = _commit();
|
||||
|
||||
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