Support virtual tables in the analyzer plugin

This commit is contained in:
Simon Binder 2020-01-09 22:45:25 +01:00
parent 643ef5640c
commit 6434f7a7d5
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
13 changed files with 86 additions and 16 deletions

View File

@ -0,0 +1,8 @@
targets:
$default:
builders:
moor_generator:
options:
sqlite_modules:
- json1
- fts5

View File

@ -7,6 +7,8 @@ CREATE TABLE playground (
name VARCHAR NOT NULL
);
CREATE VIRTUAL TABLE email USING fts5(name);
unknownColumn: SELECT * FROM playground WHERE bar = 'foo';
syntaxError: SELECT 3 + FROM playground;
lints: INSERT INTO playground DEFAULT VALUES;

View File

@ -1,4 +1,5 @@
import 'package:moor_generator/moor_generator.dart';
import 'package:moor_generator/src/analyzer/errors.dart';
import 'package:moor_generator/src/analyzer/runner/steps.dart';
import 'package:moor_generator/src/analyzer/sql_queries/type_mapping.dart';
import 'package:moor_generator/src/model/declarations/declaration.dart';
@ -16,7 +17,15 @@ class CreateTableReader {
CreateTableReader(this.stmt, this.step);
MoorTable extractTable(TypeMapper mapper) {
final table = SchemaFromCreateTable(moorExtensions: true).read(stmt);
Table table;
try {
table = SchemaFromCreateTable(moorExtensions: true).read(stmt);
} catch (e) {
step.reportError(ErrorInMoorFile(
span: stmt.tableNameToken.span,
message: 'Could not extract schema information for this table: $e',
));
}
final foundColumns = <String, MoorColumn>{};
final primaryKey = <MoorColumn>{};

View File

@ -17,7 +17,7 @@ const _fileEndings = {
class MoorSession {
final FileGraph fileGraph = FileGraph();
final Backend backend;
final MoorOptions options;
MoorOptions options;
final _completedTasks = StreamController<Task>.broadcast();
final _changedFiles = StreamController<List<FoundFile>>.broadcast();

View File

@ -66,7 +66,7 @@ abstract class BaseMoorPlugin extends ServerPlugin {
final tracker = FileTracker();
final driver = MoorDriver(tracker, analysisDriverScheduler, dartDriver,
fileContentOverlay, resourceProvider, options);
fileContentOverlay, resourceProvider, options, contextRoot.root);
didCreateDriver(driver);
return driver;

View File

@ -11,6 +11,7 @@ import 'package:moor_generator/src/analyzer/options.dart';
import 'package:moor_generator/src/analyzer/runner/file_graph.dart';
import 'package:moor_generator/src/analyzer/session.dart';
import 'package:moor_generator/src/services/ide/moor_ide.dart';
import 'package:moor_generator/src/utils/options_reader.dart' as options;
import 'backend.dart';
import 'file_tracker.dart';
@ -26,6 +27,7 @@ class MoorDriver implements AnalysisDriverGeneric {
/// unsaved files.
final FileContentOverlay contentOverlay;
final ResourceProvider _resourceProvider;
final String contextRoot;
/* late final */ MoorSession session;
StreamSubscription _fileChangeSubscription;
@ -33,7 +35,7 @@ class MoorDriver implements AnalysisDriverGeneric {
MoorDriver(this._tracker, this._scheduler, this.dartDriver,
this.contentOverlay, this._resourceProvider,
[MoorOptions options]) {
[MoorOptions options, this.contextRoot]) {
_scheduler.add(this);
final backend = CommonBackend(this);
@ -110,6 +112,20 @@ class MoorDriver implements AnalysisDriverGeneric {
}
}
/// Attempt to load the appropriate [MoorOptions] by reading the `build.yaml`
/// located in the context root.
///
/// When something fails, the default options will be used an an error message
/// will be logged.
Future<void> tryToLoadOptions() async {
try {
final result = await options.fromRootDir(contextRoot);
session.options = result;
} catch (e, s) {
Logger.root.info('Could not load options, using defaults', e, s);
}
}
String readFile(String path) {
final overlay = contentOverlay[path];
if (overlay != null) {

View File

@ -45,6 +45,7 @@ class MoorPlugin extends BaseMoorPlugin
@override
void didCreateDriver(MoorDriver driver) {
driver.tryToLoadOptions();
driver.session
.completedFiles()
.where((file) => file.isParsed)

View File

@ -46,6 +46,25 @@ class _OutlineVisitor extends RecursiveVisitor<void, void> {
collector.endElement();
}
@override
void visitCreateVirtualTableStatement(
CreateVirtualTableStatement e, void arg) {
_startElement(ElementKind.CLASS, e.tableName, e);
// if the file is analyzed, we can report analyzed columns
final resolved = request.parsedMoor.declaredTables
?.singleWhere((t) => t.sqlName == e.tableName, orElse: () => null);
if (resolved != null) {
for (final column in resolved.columns) {
_startElement(ElementKind.FIELD, column.name.name, e);
collector.endElement();
}
}
collector.endElement();
}
@override
void visitColumnDefinition(ColumnDefinition e, void arg) {
// we use parameters instead of returnType because VS Code doesn't show

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:build_config/build_config.dart';
import 'package:moor_generator/src/analyzer/options.dart';
import 'package:moor_generator/src/utils/options_reader.dart';
import 'package:path/path.dart' as p;
import 'package:stream_transform/stream_transform.dart';
@ -15,7 +16,7 @@ class MoorProject {
final Directory directory;
MoorProject(this.buildConfig, this.directory)
: moorOptions = _readOptions(buildConfig);
: moorOptions = readOptionsFromConfig(buildConfig);
Stream<File> get sourceFiles {
const topLevelDirs = {'lib', 'test', 'bin', 'example'};
@ -33,16 +34,6 @@ class MoorProject {
}).whereType();
}
static MoorOptions _readOptions(BuildConfig config) {
final options = config.buildTargets.values
.map((t) => t.builders['moor_generator:moor_generator']?.options)
.where((t) => t != null)
.map((json) => MoorOptions.fromJson(json));
final iterator = options.iterator;
return iterator.moveNext() ? iterator.current : const MoorOptions();
}
static Future<MoorProject> readFromDir(Directory directory) async {
final config = await BuildConfig.fromPackageDir(directory.path);

View File

@ -89,6 +89,11 @@ class _HighlightingVisitor extends RecursiveVisitor<void, void> {
_contribute(e.tableNameToken, HighlightRegionType.CLASS);
}
if (e is CreateVirtualTableStatement && e.moduleNameToken != null) {
_contribute(
e.moduleNameToken, HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE);
}
visitChildren(e, arg);
}

View File

@ -0,0 +1,17 @@
import 'package:build_config/build_config.dart';
import 'package:moor_generator/src/analyzer/options.dart';
Future<MoorOptions> fromRootDir(String path) async {
final options = await BuildConfig.fromPackageDir(path);
return readOptionsFromConfig(options);
}
MoorOptions readOptionsFromConfig(BuildConfig config) {
final options = config.buildTargets.values
.map((t) => t.builders['moor_generator:moor_generator']?.options)
.where((t) => t != null)
.map((json) => MoorOptions.fromJson(json));
final iterator = options.iterator;
return iterator.moveNext() ? iterator.current : const MoorOptions();
}

View File

@ -58,6 +58,7 @@ class CreateTableStatement extends TableInducingStatement {
class CreateVirtualTableStatement extends TableInducingStatement {
/// The module that will be invoked when creating the virtual table.
final String moduleName;
Token moduleNameToken;
/// Arguments passed to the module. Since the specific module is responsible
/// for parsing them, the general parser only exposes them as strings with a

View File

@ -149,7 +149,8 @@ mixin SchemaParser on ParserBase {
overriddenDataClassName: moorDataClassName,
)
..setSpan(first, _previous)
..tableNameToken = nameToken;
..tableNameToken = nameToken
..moduleNameToken = moduleName;
}
String _overriddenDataClassName() {