Support explicit type arguments in moor_generator

This commit is contained in:
Simon Binder 2019-12-25 21:07:08 +01:00
parent 868dde358f
commit d2b70e69dc
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
10 changed files with 85 additions and 13 deletions

View File

@ -1,3 +1,9 @@
## unreleased
- Support explicit type arguments for queries in moor files. In
`foo(:bar AS TEXT, :baz AS INT): SELECT :bar, :baz;`, the column type can now be inferred.
Previously, the query would fail because of an unknown type.
## 2.2.0
- Experimental new CLI tool (`pub run moor_generator`). Not useful at the moment

View File

@ -40,8 +40,11 @@ class SqlParser {
final sql = query.sql;
context = _engine.analyze(sql);
} else if (query is DeclaredMoorQuery) {
context =
_engine.analyzeNode(query.query, query.file.parseResult.sql);
context = _engine.analyzeNode(
query.query,
query.file.parseResult.sql,
stmtOptions: _createOptions(query.astNode),
);
declaredInMoor = true;
}
} catch (e, s) {
@ -89,4 +92,26 @@ class SqlParser {
));
}
}
AnalyzeStatementOptions _createOptions(DeclaredStatement stmt) {
final reader = _engine.schemaReader;
final indexedHints = <int, ResolvedType>{};
final namedHints = <String, ResolvedType>{};
for (final hint in stmt.parameters.whereType<VariableTypeHint>()) {
final variable = hint.variable;
final type = reader.resolveColumnType(hint.typeName);
if (variable is ColonNamedVariable) {
namedHints[variable.name] = type;
} else if (variable is NumberedVariable) {
indexedHints[variable.resolvedIndex] = type;
}
}
return AnalyzeStatementOptions(
indexedVariableTypes: indexedHints,
namedVariableTypes: namedHints,
);
}
}

View File

@ -35,16 +35,16 @@ class DeclaredDartQuery extends DeclaredQuery {
/// A [DeclaredQuery] read from a `.moor` file, where the AST is already
/// available.
class DeclaredMoorQuery extends DeclaredQuery {
final AstNode query;
final DeclaredStatement astNode;
CrudStatement get query => astNode.statement;
ParsedMoorFile file;
DeclaredMoorQuery(String name, this.query) : super(name);
DeclaredMoorQuery(String name, this.astNode) : super(name);
factory DeclaredMoorQuery.fromStatement(DeclaredStatement stmt) {
assert(stmt.identifier is SimpleName);
final name = (stmt.identifier as SimpleName).name;
final query = stmt.statement;
return DeclaredMoorQuery(name, query);
return DeclaredMoorQuery(name, stmt);
}
}

View File

@ -2,7 +2,7 @@
import 'package:moor_generator/src/analyzer/runner/results.dart';
import 'package:test/test.dart';
import 'utils.dart';
import '../utils.dart';
void main() {
test('supports inheritance for daos', () async {

View File

@ -5,7 +5,7 @@ import 'package:moor_generator/src/analyzer/runner/results.dart';
import 'package:moor_generator/src/model/sql_query.dart';
import 'package:test/test.dart';
import 'utils.dart';
import '../utils.dart';
void main() {
TestState state;

View File

@ -0,0 +1,30 @@
import 'package:moor_generator/moor_generator.dart';
import 'package:moor_generator/src/analyzer/runner/results.dart';
import 'package:test/test.dart';
import '../utils.dart';
void main() {
test('respects explicit type arguments', () async {
final state = TestState.withContent({
'foo|lib/main.moor': '''
bar(?1 AS TEXT, :foo AS BOOLEAN): SELECT ?, :foo;
''',
});
await state.runTask('package:foo/main.moor');
final file = state.file('package:foo/main.moor');
expect(file.errors.errors, isEmpty);
final content = file.currentResult as ParsedMoorFile;
final query = content.resolvedQueries.single;
expect(query, const TypeMatcher<SqlSelectQuery>());
final resultSet = (query as SqlSelectQuery).resultSet;
expect(resultSet.matchingTable, isNull);
expect(resultSet.columns.map((c) => c.name), ['?', ':foo']);
expect(resultSet.columns.map((c) => c.type),
[ColumnType.text, ColumnType.boolean]);
});
}

View File

@ -3,7 +3,7 @@ import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
import 'package:moor_generator/src/analyzer/runner/task.dart';
import 'package:moor_generator/src/analyzer/session.dart';
import '../../utils/test_backend.dart';
import '../utils/test_backend.dart';
class TestState {
TestBackend backend;

View File

@ -1,8 +1,7 @@
part of '../ast.dart';
abstract class TableInducingStatement extends Statement
with SchemaStatement
implements PartOfMoorFile {
implements PartOfMoorFile, SchemaStatement {
final bool ifNotExists;
final String tableName;

View File

@ -18,5 +18,5 @@ abstract class HasWhereClause extends Statement {
Expression get where;
}
/// Marker mixin for statements that change the table structure.
mixin SchemaStatement on Statement {}
/// Marker interface for statements that change the table structure.
abstract class SchemaStatement extends Statement {}

View File

@ -18,6 +18,8 @@ class SqlEngine {
/// Internal options for this sql engine.
final EngineOptions options;
SchemaFromCreateTable _schemaReader;
SqlEngine(
{bool useMoorExtensions = false,
bool enableJson1Module = false,
@ -34,6 +36,16 @@ class SqlEngine {
registerTable(sqliteSequence);
}
/// Obtain a [SchemaFromCreateTable] instance compatible with the
/// configuration of this engine.
///
/// The returned reader can be used to read the table structure from a
/// [TableInducingStatement] by using [SchemaFromCreateTable.read].
SchemaFromCreateTable get schemaReader {
return _schemaReader ??=
SchemaFromCreateTable(moorExtensions: options.useMoorExtensions);
}
/// Registers the [table], which means that it can later be used in sql
/// statements.
void registerTable(Table table) {