Add integration test for existing types in drift

This commit is contained in:
Simon Binder 2022-12-27 20:58:15 +01:00
parent a463ee14cb
commit a3fea1af04
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
7 changed files with 104 additions and 5 deletions

View File

@ -1853,6 +1853,33 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
});
}
Selectable<MyCustomResultClass> customResult() {
return customSelect(
'SELECT with_constraints.b, config.sync_state,"config"."config_key" AS "nested_0.config_key", "config"."config_value" AS "nested_0.config_value", "config"."sync_state" AS "nested_0.sync_state", "config"."sync_state_implicit" AS "nested_0.sync_state_implicit","no_ids"."payload" AS "nested_1.payload" FROM with_constraints INNER JOIN config ON config_key = with_constraints.a CROSS JOIN no_ids',
variables: [],
readsFrom: {
withConstraints,
config,
noIds,
}).asyncMap((QueryRow row) async => MyCustomResultClass(
row.read<int>('b'),
syncState: NullAwareTypeConverter.wrapFromSql(
ConfigTable.$convertersyncState,
row.readNullable<int>('sync_state')),
config: await config.mapFromRow(row, tablePrefix: 'nested_0'),
noIds: await noIds.mapFromRow(row, tablePrefix: 'nested_1'),
nested: await customSelect('SELECT * FROM no_ids',
variables: [],
readsFrom: {
noIds,
})
.map((QueryRow row) => Buffer(
row.read<Uint8List>('payload'),
))
.get(),
));
}
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();

View File

@ -1,5 +1,41 @@
import 'dart:typed_data';
import 'converter.dart';
import 'custom_tables.dart';
class NoIdRow {
final List<int> payload;
NoIdRow(this.payload);
}
class Buffer {
Buffer(TypedData payload);
}
/// The existing result class for the `customResult` query in `tables.drift`
class MyCustomResultClass {
// with_constraints.b
final int b;
// config.sync_state
final SyncType? syncState;
// config.** (drift-generated table row class)
final Config config;
// no_ids.** (custom table row class)
final NoIdRow noIds;
// LIST(SELECT * FROM no_ids). Note that we're replacing the custom table
// row class with a custom structure class just for this query.
final List<Buffer> nested;
MyCustomResultClass(
this.b, {
required this.syncState,
required this.config,
required this.noIds,
required this.nested,
});
}

View File

@ -98,3 +98,14 @@ addConfig: INSERT INTO config $value RETURNING *;
nested: SELECT defaults.**, LIST(SELECT * FROM with_constraints c WHERE c.b = defaults.b)
FROM with_defaults defaults
WHERE a = ?;
customResult WITH MyCustomResultClass:
SELECT
with_constraints.b,
config.sync_state,
config.**,
no_ids.**,
LIST(SELECT * FROM no_ids) AS nested
FROM with_constraints
INNER JOIN config ON config_key = with_constraints.a
CROSS JOIN no_ids;

View File

@ -172,4 +172,13 @@ void main() {
);
});
}, skip: ifOlderThanSqlite335(sqlite3Version));
test('can run query with custom result set', () async {
await db.withConstraints
.insertOne(WithConstraintsCompanion.insert(b: 1, a: Value('key')));
await db.noIds.insertOne(NoIdsCompanion.insert(payload: Uint8List(512)));
final result = await db.customResult().get();
print('result');
});
}

View File

@ -100,7 +100,8 @@ class FileAnalyzer {
references: element.references,
requiredVariables: options.variables);
result.resolvedQueries[element.id] = analyzer.analyze(element)
result.resolvedQueries[element.id] = analyzer.analyze(element,
sourceForCustomName: stmt.as)
..declaredInDriftFile = true;
for (final error in analyzer.lints) {

View File

@ -25,6 +25,8 @@ class _QueryHandlerContext {
final String? requestedResultClass;
final DartType? requestedResultType;
final DriftTableName? sourceForFixedName;
_QueryHandlerContext({
required List<FoundElement> foundElements,
required this.root,
@ -32,6 +34,7 @@ class _QueryHandlerContext {
required this.nestedScope,
this.requestedResultClass,
this.requestedResultType,
this.sourceForFixedName,
}) : foundElements = List.unmodifiable(foundElements);
}
@ -72,7 +75,18 @@ class QueryAnalyzer {
return referencesByName[name.toLowerCase()] as E;
}
SqlQuery analyze(DriftQueryDeclaration declaration) {
/// Analyzes the query from its [declaration].
///
/// This runs drfit-specific query analysis and lints on the query. It will
/// also detect read or written tables and a suitable result set for this
/// query in Dart.
///
/// The [sourceForCustomName] can be set to the syntactic source responsible
/// for a [DefinedSqlQuery.existingDartType] or[DefinedSqlQuery.resultClassName],
/// respectively. It will improve the highlighted source span in error
/// messages.
SqlQuery analyze(DriftQueryDeclaration declaration,
{DriftTableName? sourceForCustomName}) {
final nestedAnalyzer = NestedQueryAnalyzer();
NestedQueriesContainer? nestedScope;
@ -102,6 +116,7 @@ class QueryAnalyzer {
requestedResultType: requestedResultType,
root: context.root,
nestedScope: nestedScope,
sourceForFixedName: sourceForCustomName,
));
final linter = DriftSqlLinter(
@ -349,7 +364,7 @@ class QueryAnalyzer {
lints.add(AnalysisError(
type: AnalysisErrorType.other,
message: message,
relevantNode: queryContext.root,
relevantNode: queryContext.sourceForFixedName ?? queryContext.root,
));
});

View File

@ -424,7 +424,7 @@ bool checkType(
if (typeConverter != null) {
expectedDartType = typeConverter.dartType;
if (typeConverter.canBeSkippedForNulls && columnIsNullable) {
typeToCheck = typeSystem.promoteToNonNull(typeToCheck);
expectedDartType = typeProvider.makeNullable(expectedDartType);
}
} else {
expectedDartType = typeProvider.typeFor(columnType, knownTypes);
@ -503,7 +503,7 @@ extension CreateRecordType on TypeProvider {
if (type is InterfaceType) {
return type.element.instantiate(
typeArguments: type.typeArguments,
nullabilitySuffix: NullabilitySuffix.none,
nullabilitySuffix: NullabilitySuffix.question,
);
} else if (type is NeverType) {
return nullType;