Fix generating variables with custom types

This commit is contained in:
Simon Binder 2023-12-10 14:23:19 +01:00
parent 5115bc1525
commit 417d1f59d9
11 changed files with 101 additions and 118 deletions

View File

@ -167,7 +167,7 @@ class WithDefault extends DataClass implements Insertable<WithDefault> {
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{}; final map = <String, Expression>{};
if (!nullToAbsent || a != null) { if (!nullToAbsent || a != null) {
map['a'] = Variable<String>(a); map['a'] = Variable<String>(a, const CustomTextType());
} }
if (!nullToAbsent || b != null) { if (!nullToAbsent || b != null) {
map['b'] = Variable<int>(b); map['b'] = Variable<int>(b);
@ -645,13 +645,12 @@ class Config extends DataClass implements Insertable<Config> {
map['config_value'] = Variable<DriftAny>(configValue); map['config_value'] = Variable<DriftAny>(configValue);
} }
if (!nullToAbsent || syncState != null) { if (!nullToAbsent || syncState != null) {
final converter = ConfigTable.$convertersyncStaten; map['sync_state'] =
map['sync_state'] = Variable<int>(converter.toSql(syncState)); Variable<int>(ConfigTable.$convertersyncStaten.toSql(syncState));
} }
if (!nullToAbsent || syncStateImplicit != null) { if (!nullToAbsent || syncStateImplicit != null) {
final converter = ConfigTable.$convertersyncStateImplicitn; map['sync_state_implicit'] = Variable<int>(
map['sync_state_implicit'] = ConfigTable.$convertersyncStateImplicitn.toSql(syncStateImplicit));
Variable<int>(converter.toSql(syncStateImplicit));
} }
return map; return map;
} }
@ -796,15 +795,13 @@ class ConfigCompanion extends UpdateCompanion<Config> {
map['config_value'] = Variable<DriftAny>(configValue.value); map['config_value'] = Variable<DriftAny>(configValue.value);
} }
if (syncState.present) { if (syncState.present) {
final converter = ConfigTable.$convertersyncStaten; map['sync_state'] = Variable<int>(
ConfigTable.$convertersyncStaten.toSql(syncState.value));
map['sync_state'] = Variable<int>(converter.toSql(syncState.value));
} }
if (syncStateImplicit.present) { if (syncStateImplicit.present) {
final converter = ConfigTable.$convertersyncStateImplicitn; map['sync_state_implicit'] = Variable<int>(ConfigTable
.$convertersyncStateImplicitn
map['sync_state_implicit'] = .toSql(syncStateImplicit.value));
Variable<int>(converter.toSql(syncStateImplicit.value));
} }
if (rowid.present) { if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value); map['rowid'] = Variable<int>(rowid.value);
@ -1747,12 +1744,10 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
return customSelect( return customSelect(
'SELECT config_key FROM config WHERE ${generatedpred.sql} AND(sync_state = ?1 OR sync_state_implicit IN ($expandedvar2))', 'SELECT config_key FROM config WHERE ${generatedpred.sql} AND(sync_state = ?1 OR sync_state_implicit IN ($expandedvar2))',
variables: [ variables: [
Variable<int>(NullAwareTypeConverter.wrapToSql( Variable<int>(ConfigTable.$convertersyncStaten.toSql(var1)),
ConfigTable.$convertersyncState, var1)),
...generatedpred.introducedVariables, ...generatedpred.introducedVariables,
for (var $ in var2) for (var $ in var2)
Variable<int>(NullAwareTypeConverter.wrapToSql( Variable<int>(ConfigTable.$convertersyncStateImplicitn.toSql($))
ConfigTable.$convertersyncStateImplicit, $))
], ],
readsFrom: { readsFrom: {
config, config,
@ -1893,7 +1888,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
return customSelect( return customSelect(
'SELECT"defaults"."a" AS "nested_0.a", "defaults"."b" AS "nested_0.b", defaults.b AS "\$n_0" FROM with_defaults AS defaults WHERE a = ?1', 'SELECT"defaults"."a" AS "nested_0.a", "defaults"."b" AS "nested_0.b", defaults.b AS "\$n_0" FROM with_defaults AS defaults WHERE a = ?1',
variables: [ variables: [
Variable<String>(var1) Variable<String>(var1, const CustomTextType())
], ],
readsFrom: { readsFrom: {
withConstraints, withConstraints,

View File

@ -119,8 +119,8 @@ class Category extends DataClass implements Insertable<Category> {
map['id'] = Variable<int>(id); map['id'] = Variable<int>(id);
map['desc'] = Variable<String>(description); map['desc'] = Variable<String>(description);
{ {
final converter = $CategoriesTable.$converterpriority; map['priority'] =
map['priority'] = Variable<int>(converter.toSql(priority)); Variable<int>($CategoriesTable.$converterpriority.toSql(priority));
} }
return map; return map;
} }
@ -246,9 +246,8 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
map['desc'] = Variable<String>(description.value); map['desc'] = Variable<String>(description.value);
} }
if (priority.present) { if (priority.present) {
final converter = $CategoriesTable.$converterpriority; map['priority'] = Variable<int>(
$CategoriesTable.$converterpriority.toSql(priority.value));
map['priority'] = Variable<int>(converter.toSql(priority.value));
} }
return map; return map;
} }
@ -423,8 +422,8 @@ class TodoEntry extends DataClass implements Insertable<TodoEntry> {
map['category'] = Variable<int>(category); map['category'] = Variable<int>(category);
} }
if (!nullToAbsent || status != null) { if (!nullToAbsent || status != null) {
final converter = $TodosTableTable.$converterstatusn; map['status'] =
map['status'] = Variable<String>(converter.toSql(status)); Variable<String>($TodosTableTable.$converterstatusn.toSql(status));
} }
return map; return map;
} }
@ -598,9 +597,8 @@ class TodosTableCompanion extends UpdateCompanion<TodoEntry> {
map['category'] = Variable<int>(category.value); map['category'] = Variable<int>(category.value);
} }
if (status.present) { if (status.present) {
final converter = $TodosTableTable.$converterstatusn; map['status'] = Variable<String>(
$TodosTableTable.$converterstatusn.toSql(status.value));
map['status'] = Variable<String>(converter.toSql(status.value));
} }
return map; return map;
} }
@ -1270,9 +1268,8 @@ class TableWithoutPKCompanion extends UpdateCompanion<CustomRowClass> {
map['web_safe_int'] = Variable<BigInt>(webSafeInt.value); map['web_safe_int'] = Variable<BigInt>(webSafeInt.value);
} }
if (custom.present) { if (custom.present) {
final converter = $TableWithoutPKTable.$convertercustom; map['custom'] = Variable<String>(
$TableWithoutPKTable.$convertercustom.toSql(custom.value));
map['custom'] = Variable<String>(converter.toSql(custom.value));
} }
if (rowid.present) { if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value); map['rowid'] = Variable<int>(rowid.value);
@ -1371,8 +1368,8 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{}; final map = <String, Expression>{};
if (!nullToAbsent || txt != null) { if (!nullToAbsent || txt != null) {
final converter = $PureDefaultsTable.$convertertxtn; map['insert'] =
map['insert'] = Variable<String>(converter.toSql(txt)); Variable<String>($PureDefaultsTable.$convertertxtn.toSql(txt));
} }
return map; return map;
} }
@ -1457,9 +1454,8 @@ class PureDefaultsCompanion extends UpdateCompanion<PureDefault> {
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{}; final map = <String, Expression>{};
if (txt.present) { if (txt.present) {
final converter = $PureDefaultsTable.$convertertxtn; map['insert'] =
Variable<String>($PureDefaultsTable.$convertertxtn.toSql(txt.value));
map['insert'] = Variable<String>(converter.toSql(txt.value));
} }
if (rowid.present) { if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value); map['rowid'] = Variable<int>(rowid.value);
@ -1532,7 +1528,7 @@ class WithCustomTypeData extends DataClass
@override @override
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{}; final map = <String, Expression>{};
map['id'] = Variable<UuidValue>(id); map['id'] = Variable<UuidValue>(id, const UuidType());
return map; return map;
} }

View File

@ -1,3 +1,8 @@
## 2.14.1
- Fix inconsistencies when generating `Variable` instances for columns with
custom types.
## 2.14.0 ## 2.14.0
- __Breaking change__: The name of the generated row class derived from the name - __Breaking change__: The name of the generated row class derived from the name

View File

@ -25,6 +25,8 @@ class AnnotatedDartCode {
AnnotatedDartCode(this.elements) AnnotatedDartCode(this.elements)
: assert(elements.every((e) => e is String || e is DartTopLevelSymbol)); : assert(elements.every((e) => e is String || e is DartTopLevelSymbol));
AnnotatedDartCode.text(String e) : elements = [e];
factory AnnotatedDartCode.ast(AstNode node) { factory AnnotatedDartCode.ast(AstNode node) {
return AnnotatedDartCode.build(((builder) => builder.addAstNode(node))); return AnnotatedDartCode.build(((builder) => builder.addAstNode(node)));
} }

View File

@ -843,37 +843,22 @@ class _ExpandedVariableWriter {
// Variables without type converters are written as: // Variables without type converters are written as:
// `Variable<int>(x)`. When there's a type converter, we instead use // `Variable<int>(x)`. When there's a type converter, we instead use
// `Variable<int>(typeConverter.toSql(x))`. // `Variable<int>(typeConverter.toSql(x))`.
// Finally, if we're dealing with a list, we use a collection for to // Finally, if we're dealing with a list, we use a collection for to write
// write all the variables sequentially. // all the variables sequentially.
String constructVar(String dartExpr) { String constructVar(String dartExpr) {
// No longer an array here, we apply a for loop if necessary
final type = _emitter
.dartCode(_emitter.innerColumnType(element.sqlType, nullable: false));
final varType = _emitter.drift('Variable');
final buffer = StringBuffer('$varType<$type>(');
final capture = element.forCaptured; final capture = element.forCaptured;
if (capture != null) {
final converter = element.typeConverter; dartExpr = ('row.read(${asDartLiteral(capture.helperColumn)})');
if (converter != null) {
// Apply the converter.
if (element.nullable && converter.canBeSkippedForNulls) {
final nullAware = _emitter.drift('NullAwareTypeConverter');
buffer.write('$nullAware.wrapToSql('
'${readConverter(_emitter, element.typeConverter!)}, $dartExpr)');
} else {
buffer.write(
'${readConverter(_emitter, element.typeConverter!)}.toSql($dartExpr)');
}
} else if (capture != null) {
buffer.write('row.read(${asDartLiteral(capture.helperColumn)})');
} else {
buffer.write(dartExpr);
} }
buffer.write(')'); final code = _emitter.wrapInVariable(
return buffer.toString(); element,
AnnotatedDartCode.text(dartExpr),
// No longer an array here, we apply a for loop below and run this on
// individual values only.
ignoreArray: true,
);
return _emitter.dartCode(code);
} }
final name = element.dartParameterName; final name = element.dartParameterName;

View File

@ -387,7 +387,6 @@ class RowMappingWriter {
extension WriteToColumns on TextEmitter { extension WriteToColumns on TextEmitter {
void writeToColumnsOverride(Iterable<DriftColumn> columns) { void writeToColumnsOverride(Iterable<DriftColumn> columns) {
final expression = drift('Expression'); final expression = drift('Expression');
final variable = drift('Variable');
this this
..write('@override\nMap<String, $expression> toColumns' ..write('@override\nMap<String, $expression> toColumns'
@ -409,28 +408,10 @@ extension WriteToColumns on TextEmitter {
} }
if (needsScope) write('{'); if (needsScope) write('{');
final typeName = dartCode(variableTypeCode(column, nullable: false)); write('map[${asDartLiteral(column.nameInSql)}] = ');
final mapSetter = 'map[${asDartLiteral(column.nameInSql)}] = ' writeDart(
'$variable<$typeName>'; wrapInVariable(column, AnnotatedDartCode.text(column.nameInDart)));
writeln(';');
if (column.typeConverter != null) {
// apply type converter before writing the variable
final converter = column.typeConverter!;
this
..write('final converter = ')
..writeDart(readConverter(converter, forNullable: column.nullable))
..writeln(';')
..write(mapSetter)
..write('(converter.toSql(${column.nameInDart}));');
} else {
// no type converter. Write variable directly
this
..write(mapSetter)
..write('(')
..write(column.nameInDart)
..write(');');
}
// This one closes the optional if from before. // This one closes the optional if from before.
if (needsScope) write('}'); if (needsScope) write('}');

View File

@ -192,34 +192,13 @@ class UpdateCompanionWriter {
final getterName = thisIfNeeded(column.nameInDart, locals); final getterName = thisIfNeeded(column.nameInDart, locals);
_buffer.writeln('if ($getterName.present) {'); _buffer.writeln('if ($getterName.present) {');
final typeName = _buffer.write('map[${asDartLiteral(column.nameInSql)}] = ');
_emitter.dartCode(_emitter.variableTypeCode(column, nullable: false));
final mapSetter = 'map[${asDartLiteral(column.nameInSql)}] = '
'${_emitter.drift('Variable')}<$typeName>';
var value = '$getterName.value'; var value = '$getterName.value';
final converter = column.typeConverter; _emitter.writeDart(
if (converter != null) { _emitter.wrapInVariable(column, AnnotatedDartCode.text(value)));
// apply type converter before writing the variable
final fieldName = _emitter.dartCode(
_emitter.readConverter(converter, forNullable: column.nullable));
_buffer.writeln('final converter = $fieldName;\n');
value = 'converter.toSql($value)';
}
_buffer _buffer.writeln(';}');
..write(mapSetter)
..write('($value');
if (column.sqlType.isCustom) {
// Also specify the custom type since it can't be inferred from the
// value passed to the variable.
_buffer
..write(', ')
..write(_emitter.dartCode(column.sqlType.custom!.expression));
}
_buffer.writeln(');}');
} }
_buffer.write('return map; \n}\n'); _buffer.write('return map; \n}\n');

View File

@ -181,9 +181,10 @@ abstract class _NodeOrWriter {
/// The Dart type that matches the type of this column, ignoring type /// The Dart type that matches the type of this column, ignoring type
/// converters. /// converters.
/// ///
/// This is the same as [dartType] but without custom types. /// This is the same as [dartType] but without type converters.
AnnotatedDartCode variableTypeCode(HasType type, {bool? nullable}) { AnnotatedDartCode variableTypeCode(HasType type,
if (type.isArray) { {bool? nullable, bool ignoreArray = false}) {
if (type.isArray && !ignoreArray) {
final inner = final inner =
innerColumnType(type.sqlType, nullable: nullable ?? type.nullable); innerColumnType(type.sqlType, nullable: nullable ?? type.nullable);
return AnnotatedDartCode([ return AnnotatedDartCode([
@ -217,6 +218,40 @@ abstract class _NodeOrWriter {
}); });
} }
AnnotatedDartCode wrapInVariable(HasType column, AnnotatedDartCode expression,
{bool ignoreArray = false}) {
return AnnotatedDartCode.build((b) {
b
..addTopLevel(DartTopLevelSymbol.drift('Variable'))
..addText('<')
..addCode(
variableTypeCode(column, nullable: false, ignoreArray: ignoreArray))
..addText('>(');
final converter = column.typeConverter;
if (converter != null) {
// apply type converter before writing the variable
b
..addCode(readConverter(converter, forNullable: column.nullable))
..addText('.toSql(')
..addCode(expression)
..addText(')');
} else {
b.addCode(expression);
}
if (column.sqlType.isCustom) {
// Also specify the custom type since it can't be inferred from the
// value passed to the variable.
b
..addText(', ')
..addCode(column.sqlType.custom!.expression);
}
b.addText(')');
});
}
String refUri(Uri definition, String element) { String refUri(Uri definition, String element) {
final prefix = final prefix =
writer.generationOptions.imports.prefixFor(definition, element); writer.generationOptions.imports.prefixFor(definition, element);

View File

@ -1,6 +1,6 @@
name: drift_dev name: drift_dev
description: Dev-dependency for users of drift. Contains the generator and development tools. description: Dev-dependency for users of drift. Contains the generator and development tools.
version: 2.14.0 version: 2.14.1
repository: https://github.com/simolus3/drift repository: https://github.com/simolus3/drift
homepage: https://drift.simonbinder.eu/ homepage: https://drift.simonbinder.eu/
issue_tracker: https://github.com/simolus3/drift/issues issue_tracker: https://github.com/simolus3/drift/issues

View File

@ -8,6 +8,9 @@ part 'main.g.dart';
class Users extends Table { class Users extends Table {
UuidColumn get id => customType(PgTypes.uuid).withDefault(genRandomUuid())(); UuidColumn get id => customType(PgTypes.uuid).withDefault(genRandomUuid())();
TextColumn get name => text()(); TextColumn get name => text()();
@override
Set<Column<Object>>? get primaryKey => {id};
} }
@DriftDatabase(tables: [Users]) @DriftDatabase(tables: [Users])
@ -38,5 +41,7 @@ void main() async {
UsersCompanion.insert(name: 'Simon', id: Value(Uuid().v4obj()))); UsersCompanion.insert(name: 'Simon', id: Value(Uuid().v4obj())));
print(user); print(user);
await database.users.deleteOne(user);
await database.close(); await database.close();
} }

View File

@ -45,7 +45,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
} }
@override @override
Set<GeneratedColumn> get $primaryKey => const {}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
User map(Map<String, dynamic> data, {String? tablePrefix}) { User map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
@ -70,7 +70,7 @@ class User extends DataClass implements Insertable<User> {
@override @override
Map<String, Expression> toColumns(bool nullToAbsent) { Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{}; final map = <String, Expression>{};
map['id'] = Variable<UuidValue>(id); map['id'] = Variable<UuidValue>(id, PgTypes.uuid);
map['name'] = Variable<String>(name); map['name'] = Variable<String>(name);
return map; return map;
} }