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

View File

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

View File

@ -161,17 +161,6 @@ abstract class SqlQuery {
placeholders = elements.whereType<FoundDartPlaceholder>().toList(); 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 { bool get _useResultClassName {
final resultSet = this.resultSet!; final resultSet = this.resultSet!;
@ -245,9 +234,6 @@ class SqlSelectQuery extends SqlQuery {
bool get hasNestedQuery => bool get hasNestedQuery =>
resultSet.nestedResults.any((e) => e is NestedResultQuery); resultSet.nestedResults.any((e) => e is NestedResultQuery);
@override
bool get needsAsyncMapping => hasNestedQuery || super.needsAsyncMapping;
SqlSelectQuery( SqlSelectQuery(
String name, String name,
this.fromContext, this.fromContext,
@ -547,7 +533,7 @@ class InferredResultSet {
singleValue: null, singleValue: null,
positionalArguments: const [], positionalArguments: const [],
namedArguments: { namedArguments: {
if (options.rawResultSetData) 'raw': RawQueryRow(), if (options.rawResultSetData) 'row': RawQueryRow(),
for (final column in columns) for (final column in columns)
dartNameFor(column): _columnAsArgument(column, options), dartNameFor(column): _columnAsArgument(column, options),
}, },
@ -597,6 +583,19 @@ class QueryRowType implements ArgumentForQueryRowType {
this.isRecord = false, 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 @override
String toString() { String toString() {
return 'ExistingQueryRowType(type: $rowType, singleValue: $singleValue, ' 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. /// An argument that just maps the raw query row.
/// ///
/// This is used for generated query classes which can optionally hold a /// This is used for generated query classes which can optionally hold a
/// reference to the raw result set. /// reference to the raw result set.
class RawQueryRow extends ArgumentForQueryRowType {} class RawQueryRow extends ArgumentForQueryRowType {
@override
bool get requiresAsynchronousContext => false;
}
class StructuredFromNestedColumn extends ArgumentForQueryRowType { class StructuredFromNestedColumn extends ArgumentForQueryRowType {
final NestedResultTable table; final NestedResultTable table;
@ -619,6 +625,10 @@ class StructuredFromNestedColumn extends ArgumentForQueryRowType {
bool get nullable => table.isNullable; bool get nullable => table.isNullable;
StructuredFromNestedColumn(this.table, this.nestedType); StructuredFromNestedColumn(this.table, this.nestedType);
@override
bool get requiresAsynchronousContext =>
nestedType.requiresAsynchronousContext;
} }
class MappedNestedListQuery extends ArgumentForQueryRowType { class MappedNestedListQuery extends ArgumentForQueryRowType {
@ -626,6 +636,10 @@ class MappedNestedListQuery extends ArgumentForQueryRowType {
final QueryRowType nestedType; final QueryRowType nestedType;
MappedNestedListQuery(this.column, this.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 /// 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); 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. /// Whether the column alias can be ignored.
/// ///
/// This is the case if each result column name maps to a drift column with /// 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 @override
bool get isArray => false; bool get isArray => false;
@override
bool get requiresAsynchronousContext => false;
@override @override
String dartGetterName(Iterable<String> existingNames) { String dartGetterName(Iterable<String> existingNames) {
return dartNameForSqlColumn(name, existingNames: 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 /// Writes the function literal that turns a "QueryRow" into the desired
/// custom return type of a query. /// custom return type of a query.
void _writeMappingLambda(SqlQuery query) { void _writeMappingLambda(InferredResultSet resultSet, QueryRowType rowClass) {
final resultSet = query.resultSet!;
final rowClass = query.queryRowType(options);
final queryRow = _emitter.drift('QueryRow'); 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 // We can write every available mapping as a Dart expression via
// _writeArgumentExpression. This can be turned into a lambda by appending // _writeArgumentExpression. This can be turned into a lambda by appending
// it with `(QueryRow row) => $expression`. That's also what we're doing, // 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 // but if we'll just call mapFromRow in there, we can just tear that method
// off instead. This is just an optimization. // off instead. This is just an optimization.
final matchingTable = resultSet.matchingTable; final singleValue = rowClass.singleValue;
if (matchingTable != null && matchingTable.effectivelyNoAlias) { if (singleValue is MatchingDriftTable && singleValue.effectivelyNoAlias) {
// Tear-off mapFromRow method on table // Tear-off mapFromRow method on table
_emitter.write('${matchingTable.table.dbGetterName}.mapFromRow'); _emitter.write('${singleValue.table.dbGetterName}.mapFromRow');
} else { } else {
// In all other cases, we're off to write the expression. // In all other cases, we're off to write the expression.
_emitter.write('($queryRow row) $asyncModifier => '); _emitter.write('($queryRow row) $asyncModifier => ');
@ -132,7 +129,7 @@ class QueryWriter {
case MappedNestedListQuery(): case MappedNestedListQuery():
_buffer.write('await '); _buffer.write('await ');
final query = argument.column.query; final query = argument.column.query;
_writeCustomSelectStatement(query); _writeCustomSelectStatement(query, argument.nestedType);
_buffer.write('.get()'); _buffer.write('.get()');
case QueryRowType(): case QueryRowType():
final singleValue = argument.singleValue; final singleValue = argument.singleValue;
@ -297,19 +294,23 @@ class QueryWriter {
_buffer.write(';\n}\n'); _buffer.write(';\n}\n');
} }
void _writeCustomSelectStatement(SqlSelectQuery select) { void _writeCustomSelectStatement(SqlSelectQuery select,
[QueryRowType? resultType]) {
_buffer.write(' customSelect(${_queryCode(select)}, '); _buffer.write(' customSelect(${_queryCode(select)}, ');
_writeVariables(select); _writeVariables(select);
_buffer.write(', '); _buffer.write(', ');
_writeReadsFrom(select); _writeReadsFrom(select);
if (select.needsAsyncMapping) { final resultSet = select.resultSet;
resultType ??= select.queryRowType(options);
if (resultType.requiresAsynchronousContext) {
_buffer.write(').asyncMap('); _buffer.write(').asyncMap(');
} else { } else {
_buffer.write(').map('); _buffer.write(').map(');
} }
_writeMappingLambda(select); _writeMappingLambda(resultSet, resultType);
_buffer.write(')'); _buffer.write(')');
} }
@ -335,13 +336,17 @@ class QueryWriter {
_writeCommonUpdateParameters(update); _writeCommonUpdateParameters(update);
_buffer.write(').then((rows) => '); _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('); _buffer.write('Future.wait(rows.map(');
_writeMappingLambda(update); _writeMappingLambda(resultSet, rowType);
_buffer.write('))'); _buffer.write('))');
} else { } else {
_buffer.write('rows.map('); _buffer.write('rows.map(');
_writeMappingLambda(update); _writeMappingLambda(resultSet, rowType);
_buffer.write(').toList()'); _buffer.write(').toList()');
} }
_buffer.write(');\n}'); _buffer.write(');\n}');