mirror of https://github.com/AMT-Cheif/drift.git
Fix crash, support type converters in views
This commit is contained in:
parent
259e4cfdd3
commit
20e6b0d5fe
|
@ -349,6 +349,7 @@ Future<List<Route>> routesByStart(int startPointId) {
|
||||||
You can import and use [type converters]({{ "../Advanced Features/type_converters.md" | pageUrl }})
|
You can import and use [type converters]({{ "../Advanced Features/type_converters.md" | pageUrl }})
|
||||||
written in Dart in a drift file. Importing a Dart file works with a regular `import` statement.
|
written in Dart in a drift file. Importing a Dart file works with a regular `import` statement.
|
||||||
To apply a type converter on a column definition, you can use the `MAPPED BY` column constraints:
|
To apply a type converter on a column definition, you can use the `MAPPED BY` column constraints:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
@ -357,6 +358,18 @@ CREATE TABLE users (
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Queries or views that reference a table-column with a type converter will also inherit that
|
||||||
|
converter. In addition, both queries and views can specify a type converter to use for a
|
||||||
|
specific column as well:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE VIEW my_view AS SELECT 'foo' MAPPED BY `const PreferenceConverter()`
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
json_extract(preferences, '$.settings') MAPPED BY `const PreferenceConverter()`
|
||||||
|
FROM users;
|
||||||
|
```
|
||||||
|
|
||||||
More details on type converts in drift files are available
|
More details on type converts in drift files are available
|
||||||
[here]({{ "../Advanced Features/type_converters.md#using-converters-in-moor" | pageUrl }}).
|
[here]({{ "../Advanced Features/type_converters.md#using-converters-in-moor" | pageUrl }}).
|
||||||
|
@ -365,17 +378,6 @@ When using type converters, we recommend the [`apply_converters_on_variables`]({
|
||||||
build option. This will also apply the converter from Dart to SQL, for instance if used on variables: `SELECT * FROM users WHERE preferences = ?`.
|
build option. This will also apply the converter from Dart to SQL, for instance if used on variables: `SELECT * FROM users WHERE preferences = ?`.
|
||||||
With that option, the variable will be inferred to `Preferences` instead of `String`.
|
With that option, the variable will be inferred to `Preferences` instead of `String`.
|
||||||
|
|
||||||
The `MAPPED BY` syntax can also used on individual columns in a query:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
id,
|
|
||||||
json_extract(preferences, '$.settings') MAPPED BY `const PreferenceConverter`
|
|
||||||
FROM users;
|
|
||||||
```
|
|
||||||
|
|
||||||
Type converters applied to columns in a select query will be used to map that column
|
|
||||||
from SQL to Dart when the query is executed.
|
|
||||||
|
|
||||||
### Existing row classes
|
### Existing row classes
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
## 2.5.0-dev
|
## 2.5.0-dev
|
||||||
|
|
||||||
- Support `MAPPED BY` for individual columns in a select statement
|
- Support `MAPPED BY` for individual columns in queries or in views defined with SQL.
|
||||||
|
|
||||||
## 2.4.1
|
## 2.4.1
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:analyzer/dart/ast/ast.dart' as dart;
|
||||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:analyzer/dart/element/type.dart';
|
import 'package:analyzer/dart/element/type.dart';
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
import 'package:sqlparser/sqlparser.dart';
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
import 'package:sqlparser/utils/find_referenced_tables.dart';
|
import 'package:sqlparser/utils/find_referenced_tables.dart';
|
||||||
|
|
||||||
|
@ -18,6 +20,35 @@ abstract class DriftElementResolver<T extends DiscoveredElement>
|
||||||
DriftElementResolver(
|
DriftElementResolver(
|
||||||
super.file, super.discovered, super.resolver, super.state);
|
super.file, super.discovered, super.resolver, super.state);
|
||||||
|
|
||||||
|
Future<AppliedTypeConverter?> typeConverterFromMappedBy(
|
||||||
|
DriftSqlType sqlType, bool nullable, MappedBy mapper) async {
|
||||||
|
final code = mapper.mapper.dartCode;
|
||||||
|
|
||||||
|
dart.Expression expression;
|
||||||
|
try {
|
||||||
|
expression = await resolver.driver.backend.resolveExpression(
|
||||||
|
file.ownUri,
|
||||||
|
code,
|
||||||
|
file.discovery!.importDependencies
|
||||||
|
.map((e) => e.toString())
|
||||||
|
.where((e) => e.endsWith('.dart')),
|
||||||
|
);
|
||||||
|
} on CannotReadExpressionException catch (e) {
|
||||||
|
reportError(DriftAnalysisError.inDriftFile(mapper, e.msg));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final knownTypes = await resolver.driver.loadKnownTypes();
|
||||||
|
return readTypeConverter(
|
||||||
|
knownTypes.helperLibrary,
|
||||||
|
expression,
|
||||||
|
sqlType,
|
||||||
|
nullable,
|
||||||
|
(msg) => reportError(DriftAnalysisError.inDriftFile(mapper, msg)),
|
||||||
|
knownTypes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void reportLints(AnalysisContext context, Iterable<DriftElement> references) {
|
void reportLints(AnalysisContext context, Iterable<DriftElement> references) {
|
||||||
context.errors.forEach(reportLint);
|
context.errors.forEach(reportLint);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:analyzer/dart/ast/ast.dart' as dart;
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:drift/drift.dart' show DriftSqlType;
|
import 'package:drift/drift.dart' show DriftSqlType;
|
||||||
import 'package:drift_dev/src/analysis/driver/driver.dart';
|
import 'package:drift_dev/src/analysis/driver/driver.dart';
|
||||||
|
@ -8,7 +7,6 @@ import 'package:sqlparser/sqlparser.dart' as sql;
|
||||||
import 'package:sqlparser/utils/node_to_text.dart';
|
import 'package:sqlparser/utils/node_to_text.dart';
|
||||||
|
|
||||||
import '../../../utils/string_escaper.dart';
|
import '../../../utils/string_escaper.dart';
|
||||||
import '../../backend.dart';
|
|
||||||
import '../../driver/error.dart';
|
import '../../driver/error.dart';
|
||||||
import '../../driver/state.dart';
|
import '../../driver/state.dart';
|
||||||
import '../../results/results.dart';
|
import '../../results/results.dart';
|
||||||
|
@ -97,7 +95,8 @@ class DriftTableResolver extends DriftElementResolver<DiscoveredDriftTable> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
converter = await _readTypeConverter(type, nullable, constraint);
|
converter =
|
||||||
|
await typeConverterFromMappedBy(type, nullable, constraint);
|
||||||
} else if (constraint is sql.JsonKey) {
|
} else if (constraint is sql.JsonKey) {
|
||||||
writeIntoTable = false;
|
writeIntoTable = false;
|
||||||
overriddenJsonName = constraint.jsonKey;
|
overriddenJsonName = constraint.jsonKey;
|
||||||
|
@ -343,33 +342,4 @@ class DriftTableResolver extends DriftElementResolver<DiscoveredDriftTable> {
|
||||||
|
|
||||||
return driftTable;
|
return driftTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<AppliedTypeConverter?> _readTypeConverter(
|
|
||||||
DriftSqlType sqlType, bool nullable, MappedBy mapper) async {
|
|
||||||
final code = mapper.mapper.dartCode;
|
|
||||||
|
|
||||||
dart.Expression expression;
|
|
||||||
try {
|
|
||||||
expression = await resolver.driver.backend.resolveExpression(
|
|
||||||
file.ownUri,
|
|
||||||
code,
|
|
||||||
file.discovery!.importDependencies
|
|
||||||
.map((e) => e.toString())
|
|
||||||
.where((e) => e.endsWith('.dart')),
|
|
||||||
);
|
|
||||||
} on CannotReadExpressionException catch (e) {
|
|
||||||
reportError(DriftAnalysisError.inDriftFile(mapper, e.msg));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final knownTypes = await resolver.driver.loadKnownTypes();
|
|
||||||
return readTypeConverter(
|
|
||||||
knownTypes.helperLibrary,
|
|
||||||
expression,
|
|
||||||
sqlType,
|
|
||||||
nullable,
|
|
||||||
(msg) => reportError(DriftAnalysisError.inDriftFile(mapper, msg)),
|
|
||||||
knownTypes,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import 'package:recase/recase.dart';
|
import 'package:recase/recase.dart';
|
||||||
import 'package:sqlparser/sqlparser.dart';
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
import 'package:sqlparser/utils/node_to_text.dart';
|
import 'package:sqlparser/sqlparser.dart' as sql;
|
||||||
|
|
||||||
|
import '../../../writer/queries/sql_writer.dart';
|
||||||
import '../../driver/state.dart';
|
import '../../driver/state.dart';
|
||||||
import '../../results/results.dart';
|
import '../../results/results.dart';
|
||||||
import '../intermediate_state.dart';
|
import '../intermediate_state.dart';
|
||||||
|
@ -27,26 +28,48 @@ class DriftViewResolver extends DriftElementResolver<DiscoveredDriftView> {
|
||||||
|
|
||||||
final columns = <DriftColumn>[];
|
final columns = <DriftColumn>[];
|
||||||
final columnDartNames = <String>{};
|
final columnDartNames = <String>{};
|
||||||
|
|
||||||
for (final column in parserView.resolvedColumns) {
|
for (final column in parserView.resolvedColumns) {
|
||||||
final type = column.type;
|
final type = column.type;
|
||||||
|
final driftType = resolver.driver.typeMapping.sqlTypeToDrift(type);
|
||||||
|
final nullable = type?.nullable ?? true;
|
||||||
|
|
||||||
AppliedTypeConverter? converter;
|
AppliedTypeConverter? converter;
|
||||||
|
var ownsConverter = false;
|
||||||
|
|
||||||
|
// If this column has a `MAPPED BY` constraint, we can apply the converter
|
||||||
|
// through that.
|
||||||
|
final source = column.source;
|
||||||
|
if (source is ExpressionColumn) {
|
||||||
|
final mappedBy = source.mappedBy;
|
||||||
|
if (mappedBy != null) {
|
||||||
|
converter =
|
||||||
|
await typeConverterFromMappedBy(driftType, nullable, mappedBy);
|
||||||
|
ownsConverter = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (type != null && type.hint is TypeConverterHint) {
|
if (type != null && type.hint is TypeConverterHint) {
|
||||||
converter = (type.hint as TypeConverterHint).converter;
|
converter ??= (type.hint as TypeConverterHint).converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
final driftColumn = DriftColumn(
|
final driftColumn = DriftColumn(
|
||||||
sqlType: resolver.driver.typeMapping.sqlTypeToDrift(type),
|
sqlType: driftType,
|
||||||
nameInSql: column.name,
|
nameInSql: column.name,
|
||||||
nameInDart:
|
nameInDart:
|
||||||
dartNameForSqlColumn(column.name, existingNames: columnDartNames),
|
dartNameForSqlColumn(column.name, existingNames: columnDartNames),
|
||||||
declaration: DriftDeclaration.driftFile(stmt, file.ownUri),
|
declaration: DriftDeclaration.driftFile(stmt, file.ownUri),
|
||||||
nullable: type?.nullable == true,
|
nullable: nullable,
|
||||||
typeConverter: converter,
|
typeConverter: converter,
|
||||||
foreignConverter: true,
|
foreignConverter: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
columns.add(driftColumn);
|
columns.add(driftColumn);
|
||||||
columnDartNames.add(driftColumn.nameInDart);
|
columnDartNames.add(driftColumn.nameInDart);
|
||||||
|
|
||||||
|
if (ownsConverter) {
|
||||||
|
converter?.owningColumn = driftColumn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var entityInfoName = ReCase(stmt.viewName).pascalCase;
|
var entityInfoName = ReCase(stmt.viewName).pascalCase;
|
||||||
|
@ -74,7 +97,7 @@ class DriftViewResolver extends DriftElementResolver<DiscoveredDriftView> {
|
||||||
query: stmt.query,
|
query: stmt.query,
|
||||||
// Remove drift-specific syntax
|
// Remove drift-specific syntax
|
||||||
driftTableName: null,
|
driftTableName: null,
|
||||||
).toSql();
|
).toSqlWithoutDriftSpecificSyntax(resolver.driver.options);
|
||||||
|
|
||||||
return DriftView(
|
return DriftView(
|
||||||
discovered.ownId,
|
discovered.ownId,
|
||||||
|
|
|
@ -149,9 +149,10 @@ class QueryAnalyzer {
|
||||||
final expression = await driver.backend.resolveExpression(
|
final expression = await driver.backend.resolveExpression(
|
||||||
fromFile.ownUri,
|
fromFile.ownUri,
|
||||||
mappedBy.mapper.dartCode,
|
mappedBy.mapper.dartCode,
|
||||||
fromFile.discovery!.importDependencies
|
fromFile.discovery?.importDependencies
|
||||||
.map((e) => e.toString())
|
.map((e) => e.toString())
|
||||||
.where((e) => e.endsWith('.dart')),
|
.where((e) => e.endsWith('.dart')) ??
|
||||||
|
const Iterable.empty(),
|
||||||
);
|
);
|
||||||
|
|
||||||
_resolvedExpressions[mappedBy.mapper] = expression;
|
_resolvedExpressions[mappedBy.mapper] = expression;
|
||||||
|
|
|
@ -24,6 +24,13 @@ String placeholderContextName(FoundDartPlaceholder placeholder) {
|
||||||
return 'generated${placeholder.name}';
|
return 'generated${placeholder.name}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ToSqlText on AstNode {
|
||||||
|
String toSqlWithoutDriftSpecificSyntax(DriftOptions options) {
|
||||||
|
final writer = SqlWriter(options);
|
||||||
|
return writer.writeSql(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SqlWriter extends NodeSqlBuilder {
|
class SqlWriter extends NodeSqlBuilder {
|
||||||
final StringBuffer _out;
|
final StringBuffer _out;
|
||||||
final SqlQuery? query;
|
final SqlQuery? query;
|
||||||
|
|
|
@ -145,4 +145,79 @@ CREATE VIEW IF NOT EXISTS repro AS
|
||||||
'fooBarBaz', // fooBarBaz
|
'fooBarBaz', // fooBarBaz
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('copies type converter from table', () async {
|
||||||
|
final backend = TestBackend.inTest({
|
||||||
|
'a|lib/a.drift': '''
|
||||||
|
import 'converter.dart';
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
foo INTEGER NOT NULL MAPPED BY `createConverter()`
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE VIEW foos AS SELECT foo FROM users;
|
||||||
|
''',
|
||||||
|
'a|lib/converter.dart': '''
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
|
TypeConverter<Object, int> createConverter() => throw UnimplementedError();
|
||||||
|
''',
|
||||||
|
});
|
||||||
|
|
||||||
|
final state = await backend.analyze('package:a/a.drift');
|
||||||
|
backend.expectNoErrors();
|
||||||
|
|
||||||
|
final table = state.analysis[state.id('users')]!.result as DriftTable;
|
||||||
|
final tableColumn = table.columnBySqlName['foo'];
|
||||||
|
|
||||||
|
final view = state.analysis[state.id('foos')]!.result as DriftView;
|
||||||
|
final column = view.columns.single;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
column.typeConverter,
|
||||||
|
isA<AppliedTypeConverter>()
|
||||||
|
.having(
|
||||||
|
(e) => e.expression.toString(), 'expression', 'createConverter()')
|
||||||
|
.having((e) => e.owningColumn, 'owningColumn', tableColumn),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('can declare type converter on view column', () async {
|
||||||
|
final backend = TestBackend.inTest({
|
||||||
|
'a|lib/a.drift': '''
|
||||||
|
import 'converter.dart';
|
||||||
|
|
||||||
|
CREATE VIEW v AS SELECT 1 MAPPED BY `createConverter()` AS r;
|
||||||
|
''',
|
||||||
|
'a|lib/converter.dart': '''
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
|
TypeConverter<Object, int> createConverter() => throw UnimplementedError();
|
||||||
|
''',
|
||||||
|
});
|
||||||
|
|
||||||
|
final state = await backend.analyze('package:a/a.drift');
|
||||||
|
backend.expectNoErrors();
|
||||||
|
|
||||||
|
final view = state.analyzedElements.single as DriftView;
|
||||||
|
final column = view.columns.single;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
column.typeConverter,
|
||||||
|
isA<AppliedTypeConverter>()
|
||||||
|
.having(
|
||||||
|
(e) => e.expression.toString(), 'expression', 'createConverter()')
|
||||||
|
.having((e) => e.owningColumn, 'owningColumn', column),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
view.source,
|
||||||
|
isA<SqlViewSource>().having(
|
||||||
|
(e) => e.sqlCreateViewStmt,
|
||||||
|
'sqlCreateViewStmt',
|
||||||
|
'CREATE VIEW v AS SELECT 1 AS r;',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'dart:isolate';
|
||||||
import 'package:analyzer/dart/analysis/analysis_context.dart';
|
import 'package:analyzer/dart/analysis/analysis_context.dart';
|
||||||
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
|
||||||
import 'package:analyzer/dart/analysis/results.dart';
|
import 'package:analyzer/dart/analysis/results.dart';
|
||||||
import 'package:analyzer/dart/ast/ast.dart';
|
import 'package:analyzer/dart/ast/ast.dart' as dart;
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:analyzer/file_system/overlay_file_system.dart';
|
import 'package:analyzer/file_system/overlay_file_system.dart';
|
||||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||||
|
@ -34,6 +34,7 @@ class TestBackend extends DriftBackend {
|
||||||
late final DriftAnalysisDriver driver;
|
late final DriftAnalysisDriver driver;
|
||||||
|
|
||||||
AnalysisContext? _dartContext;
|
AnalysisContext? _dartContext;
|
||||||
|
OverlayResourceProvider? _resourceProvider;
|
||||||
|
|
||||||
TestBackend(
|
TestBackend(
|
||||||
Map<String, String> sourceContents, {
|
Map<String, String> sourceContents, {
|
||||||
|
@ -72,8 +73,21 @@ class TestBackend extends DriftBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _pathFor(Uri uri) {
|
||||||
|
if (uri.scheme == 'package') {
|
||||||
|
final package = uri.pathSegments.first;
|
||||||
|
final path =
|
||||||
|
p.url.joinAll(['/$package/lib', ...uri.pathSegments.skip(1)]);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.path;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _setupDartAnalyzer() async {
|
Future<void> _setupDartAnalyzer() async {
|
||||||
final provider = OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
|
final provider = _resourceProvider =
|
||||||
|
OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
|
||||||
|
|
||||||
// Analyze example sources against the drift sources from the current
|
// Analyze example sources against the drift sources from the current
|
||||||
// drift_dev test runner.
|
// drift_dev test runner.
|
||||||
|
@ -93,15 +107,8 @@ class TestBackend extends DriftBackend {
|
||||||
|
|
||||||
// Also put sources into the overlay:
|
// Also put sources into the overlay:
|
||||||
sourceContents.forEach((key, value) {
|
sourceContents.forEach((key, value) {
|
||||||
final uri = Uri.parse(key);
|
final path = _pathFor(Uri.parse(key));
|
||||||
|
provider.setOverlay(path, content: value, modificationStamp: 1);
|
||||||
if (uri.scheme == 'package') {
|
|
||||||
final package = uri.pathSegments.first;
|
|
||||||
final path =
|
|
||||||
p.url.joinAll(['/$package/lib', ...uri.pathSegments.skip(1)]);
|
|
||||||
|
|
||||||
provider.setOverlay(path, content: value, modificationStamp: 1);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (analyzerExperiments.isNotEmpty) {
|
if (analyzerExperiments.isNotEmpty) {
|
||||||
|
@ -142,9 +149,38 @@ class TestBackend extends DriftBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Never> resolveExpression(
|
Future<dart.Expression> resolveExpression(
|
||||||
Uri context, String dartExpression, Iterable<String> imports) async {
|
Uri context, String dartExpression, Iterable<String> imports) async {
|
||||||
throw UnsupportedError('Not currently supported in tests');
|
final fileContents = StringBuffer();
|
||||||
|
for (final import in imports) {
|
||||||
|
fileContents.writeln("import '$import';");
|
||||||
|
}
|
||||||
|
fileContents.writeln('var field = $dartExpression;');
|
||||||
|
final path = '${_pathFor(context)}.exp.dart';
|
||||||
|
|
||||||
|
await _setupDartAnalyzer();
|
||||||
|
final resourceProvider = _resourceProvider!;
|
||||||
|
final analysisContext = _dartContext!;
|
||||||
|
|
||||||
|
resourceProvider.setOverlay(path,
|
||||||
|
content: fileContents.toString(), modificationStamp: 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final result =
|
||||||
|
await analysisContext.currentSession.getResolvedLibrary(path);
|
||||||
|
|
||||||
|
if (result is ResolvedLibraryResult) {
|
||||||
|
final unit = result.units.single.unit;
|
||||||
|
final field =
|
||||||
|
unit.declarations.single as dart.TopLevelVariableDeclaration;
|
||||||
|
|
||||||
|
return field.variables.variables.single.initializer!;
|
||||||
|
} else {
|
||||||
|
throw CannotReadExpressionException('Could not resolve temp file');
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
resourceProvider.removeOverlay(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -157,7 +193,7 @@ class TestBackend extends DriftBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<AstNode?> loadElementDeclaration(Element element) async {
|
Future<dart.AstNode?> loadElementDeclaration(Element element) async {
|
||||||
final library = element.library;
|
final library = element.library;
|
||||||
if (library == null) return null;
|
if (library == null) return null;
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,15 @@ class ExpressionColumn extends Column {
|
||||||
/// The expression returned by this column.
|
/// The expression returned by this column.
|
||||||
final Expression expression;
|
final Expression expression;
|
||||||
|
|
||||||
ExpressionColumn({required this.name, required this.expression});
|
/// When drift extensions are enabled and this column was defined with a
|
||||||
|
/// `MAPPED BY` clause, a reference to that clause.
|
||||||
|
final MappedBy? mappedBy;
|
||||||
|
|
||||||
|
ExpressionColumn({
|
||||||
|
required this.name,
|
||||||
|
required this.expression,
|
||||||
|
this.mappedBy,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A column that is created by a reference expression. The difference to an
|
/// A column that is created by a reference expression. The difference to an
|
||||||
|
@ -219,7 +227,8 @@ class ReferenceExpressionColumn extends ExpressionColumn {
|
||||||
|
|
||||||
final String? overriddenName;
|
final String? overriddenName;
|
||||||
|
|
||||||
ReferenceExpressionColumn(Reference ref, {this.overriddenName})
|
ReferenceExpressionColumn(Reference ref,
|
||||||
|
{this.overriddenName, super.mappedBy})
|
||||||
: super(name: '_', expression: ref);
|
: super(name: '_', expression: ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -293,12 +293,18 @@ class ColumnResolver extends RecursiveVisitor<void, void> {
|
||||||
Column column;
|
Column column;
|
||||||
|
|
||||||
if (expression is Reference) {
|
if (expression is Reference) {
|
||||||
column = ReferenceExpressionColumn(expression,
|
column = ReferenceExpressionColumn(
|
||||||
overriddenName: resultColumn.as);
|
expression,
|
||||||
|
overriddenName: resultColumn.as,
|
||||||
|
mappedBy: resultColumn.mappedBy,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
final name = _nameOfResultColumn(resultColumn)!;
|
final name = _nameOfResultColumn(resultColumn)!;
|
||||||
column =
|
column = ExpressionColumn(
|
||||||
ExpressionColumn(name: name, expression: resultColumn.expression);
|
name: name,
|
||||||
|
expression: resultColumn.expression,
|
||||||
|
mappedBy: resultColumn.mappedBy,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
usedColumns.add(column);
|
usedColumns.add(column);
|
||||||
|
|
Loading…
Reference in New Issue