mirror of https://github.com/AMT-Cheif/drift.git
parent
5cbc331dda
commit
a037de6621
|
@ -1,7 +1,7 @@
|
|||
## 3.3.1
|
||||
|
||||
- Support changing `onData` handlers for query streams.
|
||||
This fixes a bug ocurring when using `queryStream.first` multiple times.
|
||||
This fixes a bug occurring when using `queryStream.first` multiple times.
|
||||
|
||||
## 3.3.0
|
||||
|
||||
|
|
|
@ -187,8 +187,10 @@ class _LintingVisitor extends RecursiveVisitor<void, void> {
|
|||
relevantNode: e.table,
|
||||
));
|
||||
} else {
|
||||
final notPresent = required.where((c) => !targeted
|
||||
.any((t) => t.name.toUpperCase() == c.name.name.toUpperCase()));
|
||||
final notPresent = required.where((c) {
|
||||
return !targeted
|
||||
.any((t) => t?.name?.toUpperCase() == c.name.name.toUpperCase());
|
||||
});
|
||||
|
||||
if (notPresent.isNotEmpty) {
|
||||
final msg = notPresent.map((c) => c.name.name).join(', ');
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import 'package:moor_generator/src/analyzer/options.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
|
||||
void main() {
|
||||
// Regression test for https://github.com/simolus3/moor/issues/754
|
||||
test('supports fts5 tables with external content', () async {
|
||||
final state = TestState.withContent({
|
||||
'foo|lib/a.moor': '''
|
||||
CREATE TABLE tbl(a INTEGER PRIMARY KEY, b TEXT, c TEXT);
|
||||
CREATE VIRTUAL TABLE fts_idx USING fts5(b, c, content='tbl', content_rowid='a');
|
||||
|
||||
-- Triggers to keep the FTS index up to date.
|
||||
CREATE TRIGGER tbl_ai AFTER INSERT ON tbl BEGIN
|
||||
INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER tbl_ad AFTER DELETE ON tbl BEGIN
|
||||
INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER tbl_au AFTER UPDATE ON tbl BEGIN
|
||||
INSERT INTO fts_idx(fts_idx, rowid, b, c) VALUES('delete', old.a, old.b, old.c);
|
||||
INSERT INTO fts_idx(rowid, b, c) VALUES (new.a, new.b, new.c);
|
||||
END;
|
||||
''',
|
||||
}, options: const MoorOptions(modules: [SqlModule.fts5]));
|
||||
|
||||
final result = await state.analyze('package:foo/a.moor');
|
||||
|
||||
// The generator used to crash while analyzing, so consider the test passed
|
||||
// if it can analyze the file and sees that there aren't any errors.
|
||||
expect(result.errors.errors, isEmpty);
|
||||
});
|
||||
}
|
|
@ -8,11 +8,21 @@ class SchemaFromCreateTable {
|
|||
|
||||
const SchemaFromCreateTable({this.moorExtensions = false});
|
||||
|
||||
/// Reads a [Table] schema from the [stmt] inducing a table (either a
|
||||
/// [CreateTableStatement] or a [CreateVirtualTableStatement]).
|
||||
///
|
||||
/// This method might throw an exception if the table could not be read.
|
||||
Table read(TableInducingStatement stmt) {
|
||||
if (stmt is CreateTableStatement) {
|
||||
return _readCreateTable(stmt);
|
||||
} else if (stmt is CreateVirtualTableStatement) {
|
||||
final module = stmt.scope.resolve<Module>(stmt.moduleName);
|
||||
|
||||
if (module == null) {
|
||||
throw CantReadSchemaException('Unknown module "${stmt.moduleName}", '
|
||||
'did you register it?');
|
||||
}
|
||||
|
||||
return module.parseTable(stmt);
|
||||
}
|
||||
|
||||
|
@ -122,3 +132,15 @@ class SchemaFromCreateTable {
|
|||
@visibleForTesting
|
||||
BasicType columnAffinity(String typeName) => resolveColumnType(typeName).type;
|
||||
}
|
||||
|
||||
/// Thrown when a table schema could not be read.
|
||||
class CantReadSchemaException implements Exception {
|
||||
final String message;
|
||||
|
||||
CantReadSchemaException(this.message);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Could not read table schema: $message';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,16 +84,17 @@ class ReferenceResolver extends RecursiveVisitor<void, void> {
|
|||
|
||||
Column _resolveRowIdAlias(Reference e) {
|
||||
// to resolve those aliases when they're not bound to a table, the
|
||||
// surrounding select statement may only read from one table
|
||||
final select = e.parents.firstWhere((node) => node is SelectStatement,
|
||||
orElse: () => null) as SelectStatement;
|
||||
// surrounding statement may only read from one table
|
||||
final stmt = e.enclosingOfType<HasPrimarySource>();
|
||||
|
||||
if (select == null) return null;
|
||||
if (select.from is! TableReference) {
|
||||
if (stmt == null) return null;
|
||||
|
||||
final from = stmt.table;
|
||||
if (from is! TableReference) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final table = (select.from as TableReference).resolved as Table;
|
||||
final table = (from as TableReference).resolved as Table;
|
||||
if (table == null) return null;
|
||||
|
||||
// table.findColumn contains logic to resolve row id aliases
|
||||
|
|
|
@ -113,6 +113,19 @@ abstract class AstNode with HasMetaMixin implements SyntacticEntity {
|
|||
yield* allDescendants;
|
||||
}
|
||||
|
||||
/// Finds the first element in [selfAndParents] of the type [T].
|
||||
///
|
||||
/// Returns `null` if there's no node of type [T] surrounding this ast node.
|
||||
T /*?*/ enclosingOfType<T extends AstNode>() {
|
||||
for (final element in selfAndParents) {
|
||||
if (element is T) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// The [ReferenceScope], which contains available tables, column references
|
||||
/// and functions for this node.
|
||||
ReferenceScope get scope {
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
part of '../ast.dart';
|
||||
|
||||
class DeleteStatement extends CrudStatement implements StatementWithWhere {
|
||||
class DeleteStatement extends CrudStatement
|
||||
implements StatementWithWhere, HasPrimarySource {
|
||||
TableReference from;
|
||||
@override
|
||||
Expression where;
|
||||
|
||||
@override
|
||||
TableReference get table => from;
|
||||
|
||||
DeleteStatement({WithClause withClause, @required this.from, this.where})
|
||||
: super._(withClause);
|
||||
|
||||
|
|
|
@ -10,8 +10,9 @@ enum InsertMode {
|
|||
insertOrIgnore
|
||||
}
|
||||
|
||||
class InsertStatement extends CrudStatement {
|
||||
class InsertStatement extends CrudStatement implements HasPrimarySource {
|
||||
final InsertMode mode;
|
||||
@override
|
||||
TableReference table;
|
||||
final List<Reference> targetColumns;
|
||||
InsertSource source;
|
||||
|
|
|
@ -14,7 +14,7 @@ abstract class BaseSelectStatement extends CrudStatement with ResultSet {
|
|||
abstract class SelectStatementNoCompound implements BaseSelectStatement {}
|
||||
|
||||
class SelectStatement extends BaseSelectStatement
|
||||
implements StatementWithWhere, SelectStatementNoCompound {
|
||||
implements StatementWithWhere, SelectStatementNoCompound, HasPrimarySource {
|
||||
final bool distinct;
|
||||
final List<ResultColumn> columns;
|
||||
Queryable /*?*/ from;
|
||||
|
@ -27,6 +27,9 @@ class SelectStatement extends BaseSelectStatement
|
|||
OrderByBase orderBy;
|
||||
LimitBase limit;
|
||||
|
||||
@override
|
||||
Queryable get table => from;
|
||||
|
||||
SelectStatement(
|
||||
{WithClause withClause,
|
||||
this.distinct = false,
|
||||
|
|
|
@ -12,6 +12,18 @@ abstract class CrudStatement extends Statement {
|
|||
CrudStatement._(this.withClause);
|
||||
}
|
||||
|
||||
/// Interfaces for statements that have a primary source table on which they
|
||||
/// operate.
|
||||
/// This includes delete, update and insert statements. It also includes the
|
||||
/// common [SelectStatement], but not compound select statements or `VALUES`
|
||||
/// statements.
|
||||
abstract class HasPrimarySource extends Statement {
|
||||
/// The primary table this statement operates on. This is the part after the
|
||||
/// `FROM` for select and delete statements, the part after the `INTO` for
|
||||
/// inserts and the name after the `UPDATE` for updates.
|
||||
Queryable get table;
|
||||
}
|
||||
|
||||
/// Interface for statements that have a primary where clause (select, update,
|
||||
/// delete).
|
||||
abstract class StatementWithWhere extends Statement implements HasWhereClause {}
|
||||
|
|
|
@ -16,8 +16,10 @@ const Map<TokenType, FailureMode> _tokensToMode = {
|
|||
TokenType.ignore: FailureMode.ignore,
|
||||
};
|
||||
|
||||
class UpdateStatement extends CrudStatement implements StatementWithWhere {
|
||||
class UpdateStatement extends CrudStatement
|
||||
implements StatementWithWhere, HasPrimarySource {
|
||||
final FailureMode or;
|
||||
@override
|
||||
TableReference table;
|
||||
final List<SetComponent> set;
|
||||
@override
|
||||
|
|
Loading…
Reference in New Issue