Build options to enable types2 inference

This commit is contained in:
Simon Binder 2020-01-04 22:29:21 +01:00
parent 523eabaa2a
commit 70259c8f83
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
10 changed files with 98 additions and 15 deletions

View File

@ -52,6 +52,9 @@ At the moment, moor supports these options:
column constraint (e.g. `user_name VARCHAR NOT NULL JSON KEY userName`)
* `generate_connect_constructor`: Generate necessary code to support the [isolate runtime]({{< relref "isolates.md" >}}).
This is a build option because isolates are still experimental. This will be the default option eventually.
* `use_experimental_inference`: Use a new, experimental type inference algorithm when analyzing sql statements. The
algorithm is designed to yield more accurate results on nullability and complex constructs. Note that it's in a
preview state at the moment, which means that generated code might change after a minor update.
* `sqlite_modules`: This list can be used to enable sqlite extensions, like those for json or full-text search.
Modules have to be enabled explicitly because they're not supported on all platforms. See the following section for
details.

View File

@ -54,6 +54,12 @@ class MoorOptions {
@JsonKey(name: 'generate_connect_constructor', defaultValue: false)
final bool generateConnectConstructor;
/// Whether the new, experimental type inference engine should be used.
///
/// The new engine is experimental at the moment.
@JsonKey(name: 'use_experimental_inference', defaultValue: false)
final bool useExperimentalInference;
@JsonKey(name: 'sqlite_modules', defaultValue: [])
final List<SqlModule> modules;
@ -68,6 +74,7 @@ class MoorOptions {
this.useDataClassNameForCompanions = false,
this.useColumnNameAsJsonKeyWhenDefinedInMoorFile = false,
this.generateConnectConstructor = false,
this.useExperimentalInference,
this.modules = const []});
factory MoorOptions.fromJson(Map<String, dynamic> json) =>

View File

@ -16,6 +16,7 @@ MoorOptions _$MoorOptionsFromJson(Map<String, dynamic> json) {
'use_data_class_name_for_companions',
'use_column_name_as_json_key_when_defined_in_moor_file',
'generate_connect_constructor',
'use_experimental_inference',
'sqlite_modules'
]);
final val = MoorOptions(
@ -42,6 +43,9 @@ MoorOptions _$MoorOptionsFromJson(Map<String, dynamic> json) {
generateConnectConstructor: $checkedConvert(
json, 'generate_connect_constructor', (v) => v as bool) ??
false,
useExperimentalInference: $checkedConvert(
json, 'use_experimental_inference', (v) => v as bool) ??
false,
modules: $checkedConvert(
json,
'sqlite_modules',
@ -61,6 +65,7 @@ MoorOptions _$MoorOptionsFromJson(Map<String, dynamic> json) {
'useColumnNameAsJsonKeyWhenDefinedInMoorFile':
'use_column_name_as_json_key_when_defined_in_moor_file',
'generateConnectConstructor': 'generate_connect_constructor',
'useExperimentalInference': 'use_experimental_inference',
'modules': 'sqlite_modules'
});
}

View File

@ -35,11 +35,16 @@ class MoorSession {
/// Creates a properly configured [SqlEngine].
SqlEngine spawnEngine() {
return SqlEngine(
final sqlOptions = EngineOptions(
useMoorExtensions: true,
enableJson1Module: options.hasModule(SqlModule.json1),
enableFts5: options.hasModule(SqlModule.fts5),
enableJson1: options.hasModule(SqlModule.json1),
enabledExtensions: [
if (options.hasModule(SqlModule.fts5)) const Fts5Extension(),
],
enableExperimentalTypeInference: options.useExperimentalInference,
);
return SqlEngine.withOptions(sqlOptions);
}
FileType _findFileType(String path) {

View File

@ -3,7 +3,9 @@ library sqlparser;
export 'src/analysis/analysis.dart';
export 'src/ast/ast.dart';
export 'src/engine/module/fts5.dart' show Fts5Extension;
export 'src/engine/module/module.dart';
export 'src/engine/options.dart';
export 'src/engine/sql_engine.dart';
export 'src/reader/parser/parser.dart' show ParsingError;
export 'src/reader/syntactic_entity.dart';

View File

@ -7,6 +7,9 @@ import 'package:sqlparser/src/engine/options.dart';
import 'package:sqlparser/src/reader/tokenizer/token.dart';
import 'package:sqlparser/src/utils/meta.dart';
import 'types2/types.dart';
export 'types2/types.dart' show TypeInferenceResults;
part 'context.dart';
part 'error.dart';
part 'schema/column.dart';

View File

@ -25,12 +25,28 @@ class AnalysisContext {
/// [ResultSet.resolvedColumns] of a select statement.
/* late final */ TypeResolver types;
/// Experimental new type resolver with better support for nullability and
/// complex structures.
///
/// By using [TypeInferenceResults.typeOf], the type of an [Expression],
/// a [Variable] and [ResultSet.resolvedColumns] may be resolved or inferred.
///
/// This field is null when experimental type inference is disabled.
///
/// Please note that types2 is experimental at the moment. Changes to how
/// [types] resolves types are considered breaking and are handled
/// accordingly. [types2] may change results in any update.
@experimental
TypeInferenceResults types2;
/// Constructs a new analysis context from the AST and the source sql.
AnalysisContext(this.root, this.sql, EngineOptions options,
{AnalyzeStatementOptions stmtOptions, this.schemaSupport})
: stmtOptions = stmtOptions ?? const AnalyzeStatementOptions() {
if (!options.enableExperimentalTypeInference) {
types = TypeResolver(this, options);
}
}
/// Reports an analysis error.
void reportError(AnalysisError error) {

View File

@ -11,8 +11,11 @@ part 'resolving_visitor.dart';
class TypeInferenceSession {
final TypeGraph graph = TypeGraph();
final AnalysisContext context;
TypeInferenceResults results;
TypeInferenceSession(this.context);
TypeInferenceSession(this.context) {
results = TypeInferenceResults._(this);
}
void markTypeResolved(Typeable t, ResolvedType r) {
graph[t] = r;
@ -42,3 +45,16 @@ class TypeInferenceSession {
graph.performResolve();
}
}
/// Apis to view results of a type inference session.
class TypeInferenceResults {
final TypeInferenceSession session;
TypeInferenceResults._(this.session);
/// Finds the resolved type of [t], or `null` if the type of [t] could not
/// be inferred.
ResolvedType typeOf(Typeable t) {
return session.typeOf(t);
}
}

View File

@ -9,14 +9,21 @@ class EngineOptions {
/// Enables functions declared in the `json1` module for analysis
final bool enableJson1;
/// Enables the new, experimental type inference.
final bool enableExperimentalTypeInference;
/// All [Extension]s that have been enabled in this sql engine.
final List<Extension> enabledExtensions;
final List<FunctionHandler> _addedFunctionHandlers = [];
final Map<String, FunctionHandler> addedFunctions = {};
EngineOptions(
this.useMoorExtensions, this.enableJson1, this.enabledExtensions);
EngineOptions({
this.useMoorExtensions = false,
this.enableJson1 = false,
this.enabledExtensions = const [],
this.enableExperimentalTypeInference = false,
});
void addFunctionHandler(FunctionHandler handler) {
_addedFunctionHandlers.add(handler);

View File

@ -1,6 +1,7 @@
import 'dart:collection';
import 'package:sqlparser/sqlparser.dart';
import 'package:sqlparser/src/analysis/types2/types.dart' as t2;
import 'package:sqlparser/src/engine/module/fts5.dart';
import 'package:sqlparser/src/engine/options.dart';
import 'package:sqlparser/src/reader/parser/parser.dart';
@ -20,14 +21,18 @@ class SqlEngine {
SchemaFromCreateTable _schemaReader;
@Deprecated('Use SqlEngine.withOptions instead')
SqlEngine(
{bool useMoorExtensions = false,
bool enableJson1Module = false,
bool enableFts5 = false})
: options = _constructOptions(
: this.withOptions(_constructOptions(
moor: useMoorExtensions,
json1: enableJson1Module,
fts5: enableFts5) {
fts5: enableFts5,
));
SqlEngine.withOptions(this.options) {
for (final extension in options.enabledExtensions) {
extension.register(this);
}
@ -188,9 +193,19 @@ class SqlEngine {
node
..acceptWithoutArg(ColumnResolver(context))
..acceptWithoutArg(ReferenceResolver(context))
..acceptWithoutArg(TypeResolvingVisitor(context))
..acceptWithoutArg(LintingVisitor(options, context));
..acceptWithoutArg(ReferenceResolver(context));
if (options.enableExperimentalTypeInference) {
final session = t2.TypeInferenceSession(context);
final resolver = t2.TypeResolver(session);
node.acceptWithoutArg(resolver);
session.finish();
context.types2 = session.results;
} else {
node.acceptWithoutArg(TypeResolvingVisitor(context));
}
node.acceptWithoutArg(LintingVisitor(options, context));
} catch (_) {
rethrow;
}
@ -210,7 +225,11 @@ class SqlEngine {
final extensions = [
if (fts5) const Fts5Extension(),
];
return EngineOptions(moor, json1, extensions);
return EngineOptions(
useMoorExtensions: moor,
enableJson1: json1,
enabledExtensions: extensions,
);
}
}