Don't generate async mapping if not needed

This commit is contained in:
Simon Binder 2023-07-24 20:50:43 +02:00
parent 941409381b
commit 6a36957a85
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 71 additions and 43 deletions

View File

@ -1756,7 +1756,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
readsFrom: {
config,
}).map((QueryRow row) => JsonResult(
raw: row,
row: row,
key: row.read<String>('key'),
value: row.readNullable<String>('value'),
));
@ -1765,7 +1765,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
Selectable<JsonResult> another() {
return customSelect('SELECT \'one\' AS "key", NULLIF(\'two\', \'another\') AS value', variables: [], readsFrom: {})
.map((QueryRow row) => JsonResult(
raw: row,
row: row,
key: row.read<String>('key'),
value: row.readNullable<String>('value'),
));
@ -1789,10 +1789,11 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
withConstraints,
...generatedpredicate.watchedTables,
}).asyncMap((QueryRow row) async => MultipleResult(
raw: row,
row: row,
a: row.readNullable<String>('a'),
b: row.readNullable<int>('b'),
c: withConstraints.mapFromRow(row),
c: await withConstraints.mapFromRowOrNull(row,
tablePrefix: 'nested_0'),
));
}
@ -1821,7 +1822,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
config,
...generatedexpr.watchedTables,
}).map((QueryRow row) => ReadRowIdResult(
raw: row,
row: row,
rowid: row.read<int>('rowid'),
configKey: row.read<String>('config_key'),
configValue: row.readNullable<DriftAny>('config_value'),
@ -1887,8 +1888,8 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
withConstraints,
withDefaults,
}).asyncMap((QueryRow row) async => NestedResult(
raw: row,
defaults: withDefaults.mapFromRow(row),
row: row,
defaults: await withDefaults.mapFromRow(row, tablePrefix: 'nested_0'),
nestedQuery1: await customSelect(
'SELECT * FROM with_constraints AS c WHERE c.b = ?1',
variables: [
@ -1897,7 +1898,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
readsFrom: {
withConstraints,
withDefaults,
}).map((QueryRow row) => withConstraints.mapFromRow(row)).get(),
}).asyncMap(withConstraints.mapFromRow).get(),
));
}
@ -1914,8 +1915,8 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
syncState: NullAwareTypeConverter.wrapFromSql(
ConfigTable.$convertersyncState,
row.readNullable<int>('sync_state')),
config: config.mapFromRow(row, tablePrefix: 'nested_0'),
noIds: noIds.mapFromRow(row, tablePrefix: 'nested_1'),
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: {

View File

@ -1715,7 +1715,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
categories,
todosTable,
}).map((QueryRow row) => AllTodosWithCategoryResult(
raw: row,
row: row,
id: row.read<int>('id'),
title: row.readNullable<String>('title'),
content: row.read<String>('content'),

View File

@ -161,17 +161,6 @@ abstract class SqlQuery {
placeholders = elements.whereType<FoundDartPlaceholder>().toList();
}
bool get needsAsyncMapping {
final result = resultSet;
if (result != null) {
// Mapping to tables is asynchronous
if (result.matchingTable != null) return true;
if (result.nestedResults.any((e) => e is NestedResultTable)) return true;
}
return false;
}
bool get _useResultClassName {
final resultSet = this.resultSet!;
@ -245,9 +234,6 @@ class SqlSelectQuery extends SqlQuery {
bool get hasNestedQuery =>
resultSet.nestedResults.any((e) => e is NestedResultQuery);
@override
bool get needsAsyncMapping => hasNestedQuery || super.needsAsyncMapping;
SqlSelectQuery(
String name,
this.fromContext,
@ -547,7 +533,7 @@ class InferredResultSet {
singleValue: null,
positionalArguments: const [],
namedArguments: {
if (options.rawResultSetData) 'raw': RawQueryRow(),
if (options.rawResultSetData) 'row': RawQueryRow(),
for (final column in columns)
dartNameFor(column): _columnAsArgument(column, options),
},
@ -597,6 +583,19 @@ class QueryRowType implements ArgumentForQueryRowType {
this.isRecord = false,
});
Iterable<ArgumentForQueryRowType> get allArguments sync* {
if (singleValue != null) {
yield singleValue!;
} else {
yield* positionalArguments;
yield* namedArguments.values;
}
}
@override
bool get requiresAsynchronousContext =>
allArguments.any((arg) => arg.requiresAsynchronousContext);
@override
String toString() {
return 'ExistingQueryRowType(type: $rowType, singleValue: $singleValue, '
@ -604,13 +603,20 @@ class QueryRowType implements ArgumentForQueryRowType {
}
}
sealed class ArgumentForQueryRowType {}
sealed class ArgumentForQueryRowType {
/// Whether the code constructing this argument may need to be in an async
/// context.
bool get requiresAsynchronousContext;
}
/// An argument that just maps the raw query row.
///
/// This is used for generated query classes which can optionally hold a
/// reference to the raw result set.
class RawQueryRow extends ArgumentForQueryRowType {}
class RawQueryRow extends ArgumentForQueryRowType {
@override
bool get requiresAsynchronousContext => false;
}
class StructuredFromNestedColumn extends ArgumentForQueryRowType {
final NestedResultTable table;
@ -619,6 +625,10 @@ class StructuredFromNestedColumn extends ArgumentForQueryRowType {
bool get nullable => table.isNullable;
StructuredFromNestedColumn(this.table, this.nestedType);
@override
bool get requiresAsynchronousContext =>
nestedType.requiresAsynchronousContext;
}
class MappedNestedListQuery extends ArgumentForQueryRowType {
@ -626,6 +636,10 @@ class MappedNestedListQuery extends ArgumentForQueryRowType {
final QueryRowType nestedType;
MappedNestedListQuery(this.column, this.nestedType);
// List queries run another statement and always need an asynchronous mapping.
@override
bool get requiresAsynchronousContext => true;
}
/// Information about a matching table. A table matches a query if a query
@ -638,6 +652,11 @@ class MatchingDriftTable implements ArgumentForQueryRowType {
MatchingDriftTable(this.table, this.aliasToColumn);
@override
// Mapping from tables is currently asynchronous because the existing data
// class could be an asynchronous factory.
bool get requiresAsynchronousContext => true;
/// Whether the column alias can be ignored.
///
/// This is the case if each result column name maps to a drift column with
@ -680,6 +699,9 @@ final class ScalarResultColumn extends ResultColumn
@override
bool get isArray => false;
@override
bool get requiresAsynchronousContext => false;
@override
String dartGetterName(Iterable<String> existingNames) {
return dartNameForSqlColumn(name, existingNames: existingNames);

View File

@ -84,22 +84,19 @@ class QueryWriter {
/// Writes the function literal that turns a "QueryRow" into the desired
/// custom return type of a query.
void _writeMappingLambda(SqlQuery query) {
final resultSet = query.resultSet!;
final rowClass = query.queryRowType(options);
void _writeMappingLambda(InferredResultSet resultSet, QueryRowType rowClass) {
final queryRow = _emitter.drift('QueryRow');
final asyncModifier = query.needsAsyncMapping ? 'async' : '';
final asyncModifier = rowClass.requiresAsynchronousContext ? 'async' : '';
// We can write every available mapping as a Dart expression via
// _writeArgumentExpression. This can be turned into a lambda by appending
// it with `(QueryRow row) => $expression`. That's also what we're doing,
// but if we'll just call mapFromRow in there, we can just tear that method
// off instead. This is just an optimization.
final matchingTable = resultSet.matchingTable;
if (matchingTable != null && matchingTable.effectivelyNoAlias) {
final singleValue = rowClass.singleValue;
if (singleValue is MatchingDriftTable && singleValue.effectivelyNoAlias) {
// Tear-off mapFromRow method on table
_emitter.write('${matchingTable.table.dbGetterName}.mapFromRow');
_emitter.write('${singleValue.table.dbGetterName}.mapFromRow');
} else {
// In all other cases, we're off to write the expression.
_emitter.write('($queryRow row) $asyncModifier => ');
@ -132,7 +129,7 @@ class QueryWriter {
case MappedNestedListQuery():
_buffer.write('await ');
final query = argument.column.query;
_writeCustomSelectStatement(query);
_writeCustomSelectStatement(query, argument.nestedType);
_buffer.write('.get()');
case QueryRowType():
final singleValue = argument.singleValue;
@ -297,19 +294,23 @@ class QueryWriter {
_buffer.write(';\n}\n');
}
void _writeCustomSelectStatement(SqlSelectQuery select) {
void _writeCustomSelectStatement(SqlSelectQuery select,
[QueryRowType? resultType]) {
_buffer.write(' customSelect(${_queryCode(select)}, ');
_writeVariables(select);
_buffer.write(', ');
_writeReadsFrom(select);
if (select.needsAsyncMapping) {
final resultSet = select.resultSet;
resultType ??= select.queryRowType(options);
if (resultType.requiresAsynchronousContext) {
_buffer.write(').asyncMap(');
} else {
_buffer.write(').map(');
}
_writeMappingLambda(select);
_writeMappingLambda(resultSet, resultType);
_buffer.write(')');
}
@ -335,13 +336,17 @@ class QueryWriter {
_writeCommonUpdateParameters(update);
_buffer.write(').then((rows) => ');
if (update.needsAsyncMapping) {
final resultSet = update.resultSet!;
final rowType = update.queryRowType(options);
if (rowType.requiresAsynchronousContext) {
_buffer.write('Future.wait(rows.map(');
_writeMappingLambda(update);
_writeMappingLambda(resultSet, rowType);
_buffer.write('))');
} else {
_buffer.write('rows.map(');
_writeMappingLambda(update);
_writeMappingLambda(resultSet, rowType);
_buffer.write(').toList()');
}
_buffer.write(');\n}');