mirror of https://github.com/AMT-Cheif/drift.git
assumeCorrectReference resovels #2715
assumeCorrectReference option added assume the correct reference of the dart code in views, when resolver fails.
This commit is contained in:
parent
39018d381c
commit
7c2c17d5e4
|
@ -102,6 +102,9 @@ class DriftOptions {
|
|||
@JsonKey(name: 'write_to_columns_mixins', defaultValue: false)
|
||||
final bool writeToColumnsMixins;
|
||||
|
||||
@JsonKey(name: 'assume_correct_reference', defaultValue: false)
|
||||
final bool assumeCorrectReference;
|
||||
|
||||
@JsonKey(name: 'has_separate_analyzer', defaultValue: false)
|
||||
final bool hasDriftAnalyzer;
|
||||
|
||||
|
@ -135,6 +138,7 @@ class DriftOptions {
|
|||
this.writeToColumnsMixins = false,
|
||||
this.fatalWarnings = false,
|
||||
this.hasDriftAnalyzer = false,
|
||||
this.assumeCorrectReference = false,
|
||||
});
|
||||
|
||||
DriftOptions({
|
||||
|
@ -160,6 +164,7 @@ class DriftOptions {
|
|||
required this.fatalWarnings,
|
||||
required this.preamble,
|
||||
required this.hasDriftAnalyzer,
|
||||
required this.assumeCorrectReference,
|
||||
this.dialect,
|
||||
}) {
|
||||
// ignore: deprecated_member_use_from_same_package
|
||||
|
|
|
@ -34,6 +34,7 @@ class DartViewResolver extends LocalElementResolver<DiscoveredDartView> {
|
|||
structure.dartQuerySource,
|
||||
structure.primarySource,
|
||||
staticReferences,
|
||||
structure.staticSource
|
||||
),
|
||||
references: [
|
||||
for (final reference in staticReferences) reference.table,
|
||||
|
@ -178,7 +179,7 @@ class DartViewResolver extends LocalElementResolver<DiscoveredDartView> {
|
|||
final from = target.argumentList.arguments[0].toSource();
|
||||
final resolvedFrom =
|
||||
references.firstWhereOrNull((element) => element.name == from);
|
||||
if (resolvedFrom == null) {
|
||||
if (resolvedFrom == null && !resolver.driver.options.assumeCorrectReference) {
|
||||
reportError(
|
||||
DriftAnalysisError.inDartAst(
|
||||
as,
|
||||
|
@ -188,11 +189,28 @@ class DartViewResolver extends LocalElementResolver<DiscoveredDartView> {
|
|||
),
|
||||
);
|
||||
}
|
||||
AnnotatedDartCode query;
|
||||
if (resolvedFrom == null &&
|
||||
resolver.driver.options.assumeCorrectReference) {
|
||||
query = AnnotatedDartCode.build(
|
||||
(builder) => builder.addText(body.expression.toSource().replaceAll(target!.toSource(), '')));
|
||||
} else {
|
||||
query = AnnotatedDartCode.build(
|
||||
(builder) => builder.addAstNode(body.expression, exclude: {target!}));
|
||||
}
|
||||
|
||||
final query = AnnotatedDartCode.build(
|
||||
(builder) => builder.addAstNode(body.expression, exclude: {target!}));
|
||||
// if(resolver.driver.options.assumeCorrectReference){
|
||||
// bool separate = false;
|
||||
// for (int i = 0; i < query.elements.length; i++) {
|
||||
// if (separate && query.elements[i] is String && i != query.elements.length-1) {
|
||||
// query.elements[i]+=',';
|
||||
// separate = false;
|
||||
// }
|
||||
// separate = query.elements[i] is DartTopLevelSymbol;
|
||||
// }
|
||||
// }
|
||||
return _ParsedDartViewSelect(
|
||||
resolvedFrom, innerJoins, outerJoins, columnExpressions, query);
|
||||
resolvedFrom, innerJoins, outerJoins, columnExpressions, query, from);
|
||||
}
|
||||
|
||||
Future<List<DriftColumn>> _parseColumns(
|
||||
|
@ -209,7 +227,7 @@ class DartViewResolver extends LocalElementResolver<DiscoveredDartView> {
|
|||
if (parts.length > 1) {
|
||||
final reference =
|
||||
references.firstWhereOrNull((ref) => ref.name == parts[0]);
|
||||
if (reference == null) {
|
||||
if (reference == null || reference.table == null) {
|
||||
reportError(DriftAnalysisError.inDartAst(
|
||||
discovered.dartElement,
|
||||
columnReference,
|
||||
|
@ -280,7 +298,11 @@ class DartViewResolver extends LocalElementResolver<DiscoveredDartView> {
|
|||
nameInSql: ReCase(getter.name).snakeCase,
|
||||
nullable: true,
|
||||
constraints: [
|
||||
ColumnGeneratedAs(AnnotatedDartCode.ast(expression), false)
|
||||
resolver.driver.options.assumeCorrectReference
|
||||
? ColumnGeneratedAs(AnnotatedDartCode.build((builder) {
|
||||
builder.addText(expression.toSource());
|
||||
}), false)
|
||||
: ColumnGeneratedAs(AnnotatedDartCode.ast(expression), false),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
@ -310,8 +332,9 @@ class _ParsedDartViewSelect {
|
|||
final List<Expression> selectedColumns;
|
||||
final AnnotatedDartCode dartQuerySource;
|
||||
|
||||
final String? staticSource;
|
||||
_ParsedDartViewSelect(this.primarySource, this.innerJoins, this.outerJoins,
|
||||
this.selectedColumns, this.dartQuerySource);
|
||||
this.selectedColumns, this.dartQuerySource, [this.staticSource]);
|
||||
|
||||
bool referenceIsNullable(TableReferenceInDartView ref) {
|
||||
return ref != primarySource && !innerJoins.contains(ref);
|
||||
|
|
|
@ -96,6 +96,6 @@ class DartViewSource extends DriftViewSource {
|
|||
final AnnotatedDartCode dartQuerySource;
|
||||
final TableReferenceInDartView? primaryFrom;
|
||||
final List<TableReferenceInDartView> staticReferences;
|
||||
|
||||
DartViewSource(this.dartQuerySource, this.primaryFrom, this.staticReferences);
|
||||
final String? staticSource;
|
||||
DartViewSource(this.dartQuerySource, this.primaryFrom, this.staticReferences, [this.staticSource]);
|
||||
}
|
||||
|
|
|
@ -129,7 +129,8 @@ class ElementSerializer {
|
|||
'staticReferences': [
|
||||
for (final reference in source.staticReferences)
|
||||
_serializeTableReferenceInDartView(reference),
|
||||
]
|
||||
],
|
||||
'staticSource':source.staticSource
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -657,6 +658,9 @@ class ElementDeserializer {
|
|||
for (final element in serializedSource.list('staticReferences'))
|
||||
readReference(element as Map)
|
||||
],
|
||||
serializedSource['staticSource'] != null
|
||||
? serializedSource['staticSource'] as String
|
||||
: null,
|
||||
);
|
||||
} else {
|
||||
throw UnsupportedError('Unknown view source $serializedSource');
|
||||
|
|
|
@ -33,6 +33,7 @@ DriftOptions _$DriftOptionsFromJson(Map json) => $checkedCreate(
|
|||
'store_date_time_values_as_text',
|
||||
'case_from_dart_to_sql',
|
||||
'write_to_columns_mixins',
|
||||
'assume_correct_reference',
|
||||
'has_separate_analyzer',
|
||||
'preamble',
|
||||
'fatal_warnings'
|
||||
|
@ -94,6 +95,8 @@ DriftOptions _$DriftOptionsFromJson(Map json) => $checkedCreate(
|
|||
preamble: $checkedConvert('preamble', (v) => v as String?),
|
||||
hasDriftAnalyzer: $checkedConvert(
|
||||
'has_separate_analyzer', (v) => v as bool? ?? false),
|
||||
assumeCorrectReference: $checkedConvert(
|
||||
'assume_correct_reference', (v) => v as bool? ?? false),
|
||||
dialect: $checkedConvert('sql',
|
||||
(v) => v == null ? null : DialectOptions.fromJson(v as Map)),
|
||||
);
|
||||
|
@ -124,6 +127,7 @@ DriftOptions _$DriftOptionsFromJson(Map json) => $checkedCreate(
|
|||
'writeToColumnsMixins': 'write_to_columns_mixins',
|
||||
'fatalWarnings': 'fatal_warnings',
|
||||
'hasDriftAnalyzer': 'has_separate_analyzer',
|
||||
'assumeCorrectReference': 'assume_correct_reference',
|
||||
'dialect': 'sql'
|
||||
},
|
||||
);
|
||||
|
@ -157,6 +161,7 @@ Map<String, dynamic> _$DriftOptionsToJson(DriftOptions instance) =>
|
|||
'case_from_dart_to_sql':
|
||||
_$CaseFromDartToSqlEnumMap[instance.caseFromDartToSql]!,
|
||||
'write_to_columns_mixins': instance.writeToColumnsMixins,
|
||||
'assume_correct_reference': instance.assumeCorrectReference,
|
||||
'has_separate_analyzer': instance.hasDriftAnalyzer,
|
||||
'preamble': instance.preamble,
|
||||
'fatal_warnings': instance.fatalWarnings,
|
||||
|
|
|
@ -138,7 +138,7 @@ class ViewWriter extends TableOrViewWriter {
|
|||
final source = view.source;
|
||||
if (source is DartViewSource) {
|
||||
emitter
|
||||
..write('(attachedDatabase.selectOnly(${source.primaryFrom?.name})'
|
||||
..write('(attachedDatabase.selectOnly(${scope.options.assumeCorrectReference? source.primaryFrom?.name ?? source.staticSource:source.primaryFrom?.name})'
|
||||
'..addColumns(\$columns))')
|
||||
..writeDart(source.dartQuerySource)
|
||||
..writeln(';');
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:build/build.dart';
|
||||
import 'package:build_test/build_test.dart';
|
||||
import 'package:drift_dev/src/backends/build/analyzer.dart';
|
||||
|
@ -614,6 +616,153 @@ class MyDatabase {
|
|||
expect(readAssets, isEmpty);
|
||||
});
|
||||
|
||||
test('generates views from drift tables', () async {
|
||||
final debugLogger = Logger('driftBuild');
|
||||
debugLogger.onRecord.listen((e) => print(e.message));
|
||||
|
||||
final result = await emulateDriftBuild(
|
||||
inputs: {
|
||||
'a|lib/drift/datastore_db.dart': '''
|
||||
import 'package:drift/drift.dart';
|
||||
part 'datastore_db.g.dart';
|
||||
mixin AutoIncrement on Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
}
|
||||
@DataClassName('TodoEntry')
|
||||
class TodosTable extends Table with AutoIncrement {
|
||||
@override
|
||||
String get tableName => 'todos';
|
||||
TextColumn get title => text().withLength(min: 4, max: 16).nullable()();
|
||||
TextColumn get content => text()();
|
||||
@JsonKey('target_date')
|
||||
DateTimeColumn get targetDate => dateTime().nullable().unique()();
|
||||
IntColumn get category => integer().references(Categories, #id).nullable()();
|
||||
TextColumn get status => textEnum<TodoStatus>().nullable()();
|
||||
|
||||
@override
|
||||
List<Set<Column>>? get uniqueKeys => [
|
||||
{title, category},
|
||||
{title, targetDate},
|
||||
];
|
||||
}
|
||||
|
||||
enum TodoStatus { open, workInProgress, done }
|
||||
|
||||
class Users extends Table with AutoIncrement {
|
||||
TextColumn get name => text().withLength(min: 6, max: 32).unique()();
|
||||
BoolColumn get isAwesome => boolean().withDefault(const Constant(true))();
|
||||
|
||||
BlobColumn get profilePicture => blob()();
|
||||
DateTimeColumn get creationTime => dateTime()
|
||||
// ignore: recursive_getters
|
||||
.check(creationTime.isBiggerThan(Constant(DateTime.utc(1950))))
|
||||
.withDefault(currentDateAndTime)();
|
||||
}
|
||||
|
||||
@DataClassName('Category')
|
||||
class Categories extends Table with AutoIncrement {
|
||||
TextColumn get description =>
|
||||
text().named('desc').customConstraint('NOT NULL UNIQUE')();
|
||||
IntColumn get priority =>
|
||||
intEnum<CategoryPriority>().withDefault(const Constant(0))();
|
||||
|
||||
TextColumn get descriptionInUpperCase =>
|
||||
text().generatedAs(description.upper())();
|
||||
}
|
||||
|
||||
enum CategoryPriority { low, medium, high }
|
||||
abstract class CategoryTodoCountView extends View {
|
||||
TodosTable get todos;
|
||||
Categories get categories;
|
||||
|
||||
Expression<int> get categoryId => categories.id;
|
||||
Expression<String> get description =>
|
||||
categories.description + const Variable('!');
|
||||
Expression<int> get itemCount => todos.id.count();
|
||||
|
||||
@override
|
||||
Query as() => select([categoryId, description, itemCount])
|
||||
.from(categories)
|
||||
.join([innerJoin(todos, todos.category.equalsExp(categories.id))])
|
||||
..groupBy([categories.id]);
|
||||
}
|
||||
abstract class ComboGroupView extends View {
|
||||
late final DatastoreDb attachedDatabase;
|
||||
IntColumn get comboGroupID => attachedDatabase.comboGroup.comboGroupID;
|
||||
IntColumn get objectNumber => attachedDatabase.comboGroup.objectNumber;
|
||||
TextColumn get stringText => attachedDatabase.stringTable.stringText;
|
||||
// ComboGroup get comboGroup => attachedDatabase.comboGroup;
|
||||
// late final ComboGroup comboGroup;
|
||||
@override
|
||||
Query as() => select([
|
||||
comboGroupID,
|
||||
objectNumber,
|
||||
stringText,
|
||||
]).from(attachedDatabase.comboGroup).join([
|
||||
innerJoin(
|
||||
attachedDatabase.stringTable,
|
||||
attachedDatabase.stringTable.stringNumberID
|
||||
.equalsExp(attachedDatabase.comboGroup.nameID)),
|
||||
]);
|
||||
}
|
||||
|
||||
@DriftDatabase(
|
||||
tables: [TodosTable, Categories],
|
||||
include: {'combo_group.drift','string_table.drift'},
|
||||
views: [CategoryTodoCountView,ComboGroupView],
|
||||
)
|
||||
class DatastoreDb extends _\$DatastoreDb {
|
||||
DatastoreDb(super.e);
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
||||
''',
|
||||
'a|lib/drift/combo_group.drift': '''
|
||||
CREATE TABLE [COMBO_GROUP](
|
||||
[ComboGroupID] [int] NOT NULL PRIMARY KEY,
|
||||
[HierStrucID] [bigint] NULL,
|
||||
[ObjectNumber] [int] NULL,
|
||||
[NameID] [bigint] NULL,
|
||||
[OptionBits] [nvarchar](8) NULL,
|
||||
[SluIndex] [int] NULL,
|
||||
[HhtSluIndex] [int] NULL);
|
||||
''',
|
||||
'a|lib/drift/string_table.drift': '''
|
||||
CREATE TABLE [STRING_TABLE](
|
||||
[StringID] [bigint] NOT NULL PRIMARY KEY,
|
||||
[StringNumberID] [bigint] NULL,
|
||||
[LangID] [int] NULL,
|
||||
[IsVisible] [bit] NOT NULL DEFAULT ((1)),
|
||||
[IsDeleted] [bit] NOT NULL DEFAULT ((0)),
|
||||
[HierStrucID] [bigint] NULL,
|
||||
[PosRef] [bigint] NULL,
|
||||
[StringText] [nvarchar](128) NULL
|
||||
);
|
||||
''',
|
||||
},
|
||||
modularBuild: true,
|
||||
options: BuilderOptions({'assume_correct_reference': true}),
|
||||
logger: debugLogger
|
||||
);
|
||||
|
||||
// var actual = utf8.decode(result.writer.assets[(result.writer.assets.keys
|
||||
// .firstWhere((key) => key.path == ('lib/drift/datastore_db.drift.dart')))]!);
|
||||
|
||||
checkOutputs(
|
||||
{
|
||||
'a|lib/drift/datastore_db.drift.dart': decodedMatches(
|
||||
allOf(
|
||||
contains(r'attachedDatabase.selectOnly(attachedDatabase.comboGroup)'),
|
||||
),
|
||||
),
|
||||
'a|lib/drift/combo_group.drift.dart' : anything,
|
||||
'a|lib/drift/string_table.drift.dart' : anything,
|
||||
},
|
||||
result.dartOutputs,
|
||||
result.writer,
|
||||
);
|
||||
});
|
||||
|
||||
group('reports issues', () {
|
||||
for (final fatalWarnings in [false, true]) {
|
||||
group('fatalWarnings: $fatalWarnings', () {
|
||||
|
|
Loading…
Reference in New Issue