mirror of https://github.com/AMT-Cheif/drift.git
Support queries declared in .moor files
This commit is contained in:
parent
6a0716daaf
commit
156ef1ceb5
|
@ -6,12 +6,15 @@ import 'package:moor_generator/src/model/specified_table.dart';
|
|||
import 'package:moor_generator/src/model/sql_query.dart';
|
||||
import 'package:sqlparser/sqlparser.dart';
|
||||
|
||||
abstract class FileResult {}
|
||||
abstract class FileResult {
|
||||
final List<SpecifiedTable> declaredTables;
|
||||
|
||||
FileResult(this.declaredTables);
|
||||
}
|
||||
|
||||
class ParsedDartFile extends FileResult {
|
||||
final LibraryElement library;
|
||||
|
||||
final List<SpecifiedTable> declaredTables;
|
||||
final List<SpecifiedDao> declaredDaos;
|
||||
final List<SpecifiedDatabase> declaredDatabases;
|
||||
|
||||
|
@ -20,9 +23,10 @@ class ParsedDartFile extends FileResult {
|
|||
|
||||
ParsedDartFile(
|
||||
{@required this.library,
|
||||
this.declaredTables = const [],
|
||||
List<SpecifiedTable> declaredTables = const [],
|
||||
this.declaredDaos = const [],
|
||||
this.declaredDatabases = const []});
|
||||
this.declaredDatabases = const []})
|
||||
: super(declaredTables);
|
||||
}
|
||||
|
||||
class ParsedMoorFile extends FileResult {
|
||||
|
@ -30,14 +34,14 @@ class ParsedMoorFile extends FileResult {
|
|||
MoorFile get parsedFile => parseResult.rootNode as MoorFile;
|
||||
|
||||
final List<ImportStatement> imports;
|
||||
final List<SpecifiedTable> declaredTables;
|
||||
final List<DeclaredQuery> queries;
|
||||
|
||||
List<SqlQuery> resolvedQueries;
|
||||
Map<ImportStatement, FoundFile> resolvedImports;
|
||||
|
||||
ParsedMoorFile(this.parseResult,
|
||||
{this.declaredTables = const [],
|
||||
{List<SpecifiedTable> declaredTables = const [],
|
||||
this.queries = const [],
|
||||
this.imports = const []});
|
||||
this.imports = const []})
|
||||
: super(declaredTables);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:moor_generator/src/model/sql_query.dart';
|
|||
import 'package:source_gen/source_gen.dart';
|
||||
|
||||
part 'steps/analyze_dart.dart';
|
||||
part 'steps/analyze_moor.dart';
|
||||
part 'steps/parse_dart.dart';
|
||||
part 'steps/parse_moor.dart';
|
||||
|
||||
|
@ -35,3 +36,19 @@ abstract class Step {
|
|||
void reportError(MoorError error) =>
|
||||
errors.report(error..wasDuringParsing = isParsing);
|
||||
}
|
||||
|
||||
abstract class AnalyzingStep extends Step {
|
||||
AnalyzingStep(Task task, FoundFile file) : super(task, file);
|
||||
|
||||
@override
|
||||
final bool isParsing = false;
|
||||
|
||||
List<FoundFile> _transitiveImports(Iterable<FoundFile> directImports) {
|
||||
return task.crawlImports(directImports).toList();
|
||||
}
|
||||
|
||||
Iterable<SpecifiedTable> _availableTables(List<FoundFile> imports) {
|
||||
return imports.expand<SpecifiedTable>(
|
||||
(file) => file.currentResult?.declaredTables ?? const Iterable.empty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
part of '../steps.dart';
|
||||
|
||||
/// Analyzes the compiled queries found in a Dart file.
|
||||
class AnalyzeDartStep extends Step {
|
||||
class AnalyzeDartStep extends AnalyzingStep {
|
||||
AnalyzeDartStep(Task task, FoundFile file) : super(task, file);
|
||||
|
||||
@override
|
||||
final bool isParsing = false;
|
||||
|
||||
void analyze() {
|
||||
final parseResult = file.currentResult as ParsedDartFile;
|
||||
|
||||
for (var accessor in parseResult.dbAccessors) {
|
||||
final transitivelyAvailable = accessor.resolvedImports
|
||||
.where((file) => file.type == FileType.moor)
|
||||
.map((file) => file.currentResult as ParsedMoorFile)
|
||||
.expand((file) => file.declaredTables);
|
||||
final availableTables =
|
||||
accessor.tables.followedBy(transitivelyAvailable).toList();
|
||||
accessor.allTables = availableTables;
|
||||
final transitiveImports = _transitiveImports(accessor.resolvedImports);
|
||||
|
||||
final availableTables = _availableTables(transitiveImports)
|
||||
.followedBy(accessor.tables)
|
||||
.toList();
|
||||
|
||||
final availableQueries = transitiveImports
|
||||
.map((f) => f.currentResult)
|
||||
.whereType<ParsedMoorFile>()
|
||||
.expand((f) => f.resolvedQueries);
|
||||
|
||||
final parser = SqlParser(this, availableTables, accessor.queries);
|
||||
parser.parse();
|
||||
|
||||
accessor.resolvedQueries = parser.foundQueries;
|
||||
accessor.allTables = availableTables;
|
||||
|
||||
accessor.resolvedQueries =
|
||||
availableQueries.followedBy(parser.foundQueries).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
part of '../steps.dart';
|
||||
|
||||
class AnalyzeMoorStep extends AnalyzingStep {
|
||||
AnalyzeMoorStep(Task task, FoundFile file) : super(task, file);
|
||||
|
||||
void analyze() {
|
||||
final parseResult = file.currentResult as ParsedMoorFile;
|
||||
|
||||
final transitiveImports =
|
||||
task.crawlImports(parseResult.resolvedImports.values).toList();
|
||||
|
||||
final availableTables = _availableTables(transitiveImports)
|
||||
.followedBy(parseResult.declaredTables)
|
||||
.toList();
|
||||
|
||||
final parser = SqlParser(this, availableTables, parseResult.queries);
|
||||
parseResult.resolvedQueries = parser.foundQueries;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:moor_generator/src/analyzer/errors.dart';
|
||||
import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
|
||||
import 'package:moor_generator/src/analyzer/runner/results.dart';
|
||||
import 'package:moor_generator/src/analyzer/runner/steps.dart';
|
||||
import 'package:moor_generator/src/analyzer/session.dart';
|
||||
import 'package:moor_generator/src/backends/backend.dart';
|
||||
|
@ -47,8 +48,14 @@ class Task {
|
|||
_analyzedFiles.add(file);
|
||||
}
|
||||
|
||||
// step 2: resolve queries in the input
|
||||
for (var file in _analyzedFiles) {
|
||||
// step 2: resolve queries in the input.
|
||||
// todo we force that moor files are analyzed first because they contain
|
||||
// resolved queries which are copied into database accessors. Can we find
|
||||
// a way to remove this special-handling?
|
||||
final moorFiles = _analyzedFiles.where((f) => f.type == FileType.moor);
|
||||
final otherFiles = _analyzedFiles.where((f) => f.type != FileType.moor);
|
||||
|
||||
for (var file in moorFiles.followedBy(otherFiles)) {
|
||||
file.errors.clearNonParsingErrors();
|
||||
await _analyze(file);
|
||||
}
|
||||
|
@ -130,6 +137,36 @@ class Task {
|
|||
return createdStep;
|
||||
}
|
||||
|
||||
/// Crawls through all (transitive) imports of the provided [roots]. Each
|
||||
/// [FoundFile] in the iterable provides queries and tables that are available
|
||||
/// to the entity that imports them.
|
||||
///
|
||||
/// This is different to [FileGraph.crawl] because imports are not accurate on
|
||||
/// Dart files: Two accessors in a single Dart file could reference different
|
||||
/// imports, but the [FileGraph] would only know about the union.
|
||||
Iterable<FoundFile> crawlImports(Iterable<FoundFile> roots) sync* {
|
||||
final found = <FoundFile>{};
|
||||
final unhandled = roots.toList();
|
||||
|
||||
while (unhandled.isNotEmpty) {
|
||||
final available = unhandled.removeLast();
|
||||
found.add(available);
|
||||
yield available;
|
||||
|
||||
var importsFromHere = const Iterable<FoundFile>.empty();
|
||||
if (available.type == FileType.moor) {
|
||||
importsFromHere =
|
||||
(available.currentResult as ParsedMoorFile).resolvedImports.values;
|
||||
}
|
||||
|
||||
for (var next in importsFromHere) {
|
||||
if (!found.contains(next) && !unhandled.contains(next)) {
|
||||
unhandled.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _analyze(FoundFile file) async {
|
||||
// skip if already analyzed.
|
||||
if (file.state == FileState.analyzed) return;
|
||||
|
@ -140,6 +177,9 @@ class Task {
|
|||
case FileType.dart:
|
||||
step = AnalyzeDartStep(this, file)..analyze();
|
||||
break;
|
||||
case FileType.moor:
|
||||
step = AnalyzeMoorStep(this, file)..analyze();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import 'package:sqlparser/sqlparser.dart' hide ResultColumn;
|
|||
|
||||
class SqlParser {
|
||||
final List<SpecifiedTable> tables;
|
||||
final AnalyzeDartStep step;
|
||||
final Step step;
|
||||
final List<DeclaredQuery> definedQueries;
|
||||
|
||||
final TypeMapper _mapper = TypeMapper();
|
||||
|
|
|
@ -12,6 +12,9 @@ class SpecifiedDbAccessor {
|
|||
final List<DeclaredQuery> queries;
|
||||
|
||||
List<FoundFile> resolvedImports = [];
|
||||
|
||||
/// Resolved queries. This includes queries that weren't declared on this
|
||||
/// class but imported via an `includes` directive.
|
||||
List<SqlQuery> resolvedQueries = const [];
|
||||
|
||||
/// All tables available to this class. This includes the [tables] and all
|
||||
|
|
Loading…
Reference in New Issue