mirror of https://github.com/AMT-Cheif/drift.git
Merge branch 'develop' into fix-tests
This commit is contained in:
commit
1b06fcfc77
|
@ -114,6 +114,24 @@ abstract class NullAwareTypeConverter<D, S extends Object>
|
|||
/// Map a non-null value from an object in Dart into something that will be
|
||||
/// understood by the database.
|
||||
S requireToSql(D value);
|
||||
|
||||
/// Invokes a non-nullable [inner] type converter for a single conversion from
|
||||
/// SQL to Dart.
|
||||
///
|
||||
/// Returns `null` if [sqlValue] is `null`, [TypeConverter.fromSql] otherwise.
|
||||
/// This method is mostly intended to be used for code generated by drift-dev.
|
||||
static D? wrapFromSql<D, S>(TypeConverter<D, S> inner, S? sqlValue) {
|
||||
return sqlValue == null ? null : inner.fromSql(sqlValue);
|
||||
}
|
||||
|
||||
/// Invokes a non-nullable [inner] type converter for a single conversion from
|
||||
/// Dart to SQL.
|
||||
///
|
||||
/// Returns `null` if [dartValue] is `null`, [TypeConverter.toSql] otherwise.
|
||||
/// This method is mostly intended to be used for code generated by drift-dev.
|
||||
static S? wrapToSql<D, S>(TypeConverter<D, S> inner, D? dartValue) {
|
||||
return dartValue == null ? null : inner.toSql(dartValue);
|
||||
}
|
||||
}
|
||||
|
||||
class _NullWrappingTypeConverter<D, S extends Object>
|
||||
|
|
|
@ -24,7 +24,7 @@ class Config extends DataClass implements Insertable<Config> {
|
|||
.mapFromDatabaseResponse(data['${effectivePrefix}config_key'])!,
|
||||
configValue: const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}config_value']),
|
||||
syncState: ConfigTable.$converter0.fromSql(const IntType()
|
||||
syncState: ConfigTable.$converter0n.fromSql(const IntType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}sync_state'])),
|
||||
syncStateImplicit: ConfigTable.$converter1.fromSql(const IntType()
|
||||
.mapFromDatabaseResponse(
|
||||
|
@ -39,7 +39,7 @@ class Config extends DataClass implements Insertable<Config> {
|
|||
map['config_value'] = Variable<String?>(configValue);
|
||||
}
|
||||
if (!nullToAbsent || syncState != null) {
|
||||
final converter = ConfigTable.$converter0;
|
||||
final converter = ConfigTable.$converter0n;
|
||||
map['sync_state'] = Variable<int?>(converter.toSql(syncState));
|
||||
}
|
||||
if (!nullToAbsent || syncStateImplicit != null) {
|
||||
|
@ -182,7 +182,7 @@ class ConfigCompanion extends UpdateCompanion<Config> {
|
|||
map['config_value'] = Variable<String?>(configValue.value);
|
||||
}
|
||||
if (syncState.present) {
|
||||
final converter = ConfigTable.$converter0;
|
||||
final converter = ConfigTable.$converter0n;
|
||||
map['sync_state'] = Variable<int?>(converter.toSql(syncState.value));
|
||||
}
|
||||
if (syncStateImplicit.present) {
|
||||
|
@ -229,7 +229,7 @@ class ConfigTable extends Table with TableInfo<ConfigTable, Config> {
|
|||
type: const IntType(),
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: '')
|
||||
.withConverter<SyncType?>(ConfigTable.$converter0);
|
||||
.withConverter<SyncType?>(ConfigTable.$converter0n);
|
||||
final VerificationMeta _syncStateImplicitMeta =
|
||||
const VerificationMeta('syncStateImplicit');
|
||||
late final GeneratedColumnWithTypeConverter<SyncType?, int?>
|
||||
|
@ -281,11 +281,12 @@ class ConfigTable extends Table with TableInfo<ConfigTable, Config> {
|
|||
return ConfigTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static TypeConverter<SyncType?, int?> $converter0 =
|
||||
NullAwareTypeConverter.wrap(const SyncTypeConverter());
|
||||
static TypeConverter<SyncType, int> $converter0 = const SyncTypeConverter();
|
||||
static TypeConverter<SyncType?, int?> $converter1 =
|
||||
const NullAwareTypeConverter.wrap(
|
||||
EnumIndexConverter<SyncType>(SyncType.values));
|
||||
static TypeConverter<SyncType?, int?> $converter0n =
|
||||
NullAwareTypeConverter.wrap($converter0);
|
||||
@override
|
||||
bool get isStrict => true;
|
||||
@override
|
||||
|
@ -1476,7 +1477,7 @@ class MyViewData extends DataClass {
|
|||
.mapFromDatabaseResponse(data['${effectivePrefix}config_key'])!,
|
||||
configValue: const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}config_value']),
|
||||
syncState: ConfigTable.$converter0.fromSql(const IntType()
|
||||
syncState: ConfigTable.$converter0n.fromSql(const IntType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}sync_state'])),
|
||||
syncStateImplicit: ConfigTable.$converter1.fromSql(const IntType()
|
||||
.mapFromDatabaseResponse(
|
||||
|
@ -1579,7 +1580,7 @@ class MyView extends ViewInfo<MyView, MyViewData> implements HasResultSet {
|
|||
late final GeneratedColumnWithTypeConverter<SyncType?, int?> syncState =
|
||||
GeneratedColumn<int?>('sync_state', aliasedName, true,
|
||||
type: const IntType())
|
||||
.withConverter<SyncType?>(ConfigTable.$converter0);
|
||||
.withConverter<SyncType?>(ConfigTable.$converter0n);
|
||||
late final GeneratedColumnWithTypeConverter<SyncType?, int?>
|
||||
syncStateImplicit = GeneratedColumn<int?>(
|
||||
'sync_state_implicit', aliasedName, true,
|
||||
|
@ -1677,7 +1678,8 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
return customSelect(
|
||||
'SELECT config_key FROM config WHERE ${generatedpred.sql} AND(sync_state = ?1 OR sync_state_implicit IN ($expandedvar2))',
|
||||
variables: [
|
||||
Variable<int?>(ConfigTable.$converter0.toSql(var1)),
|
||||
Variable<int?>(
|
||||
NullAwareTypeConverter.wrapToSql(ConfigTable.$converter0, var1)),
|
||||
...generatedpred.introducedVariables,
|
||||
for (var $ in var2) Variable<int?>(ConfigTable.$converter1.toSql($))
|
||||
],
|
||||
|
@ -1775,8 +1777,8 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
rowid: row.read<int>('rowid'),
|
||||
configKey: row.read<String>('config_key'),
|
||||
configValue: row.read<String?>('config_value'),
|
||||
syncState:
|
||||
ConfigTable.$converter0.fromSql(row.read<int?>('sync_state')),
|
||||
syncState: NullAwareTypeConverter.wrapFromSql(
|
||||
ConfigTable.$converter0, row.read<int?>('sync_state')),
|
||||
syncStateImplicit: ConfigTable.$converter1
|
||||
.fromSql(row.read<int?>('sync_state_implicit')),
|
||||
);
|
||||
|
|
|
@ -1246,7 +1246,7 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
|
|||
factory PureDefault.fromData(Map<String, dynamic> data, {String? prefix}) {
|
||||
final effectivePrefix = prefix ?? '';
|
||||
return PureDefault(
|
||||
txt: $PureDefaultsTable.$converter0.fromSql(const StringType()
|
||||
txt: $PureDefaultsTable.$converter0n.fromSql(const StringType()
|
||||
.mapFromDatabaseResponse(data['${effectivePrefix}insert'])),
|
||||
);
|
||||
}
|
||||
|
@ -1254,7 +1254,7 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
|
|||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (!nullToAbsent || txt != null) {
|
||||
final converter = $PureDefaultsTable.$converter0;
|
||||
final converter = $PureDefaultsTable.$converter0n;
|
||||
map['insert'] = Variable<String?>(converter.toSql(txt));
|
||||
}
|
||||
return map;
|
||||
|
@ -1270,7 +1270,7 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
|
|||
{ValueSerializer? serializer}) {
|
||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return PureDefault(
|
||||
txt: $PureDefaultsTable.$converter0
|
||||
txt: $PureDefaultsTable.$converter0n
|
||||
.fromJson(serializer.fromJson<String?>(json['txt'])),
|
||||
);
|
||||
}
|
||||
|
@ -1284,7 +1284,7 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
|
|||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'txt': serializer
|
||||
.toJson<String?>($PureDefaultsTable.$converter0.toJson(txt)),
|
||||
.toJson<String?>($PureDefaultsTable.$converter0n.toJson(txt)),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1333,7 +1333,7 @@ class PureDefaultsCompanion extends UpdateCompanion<PureDefault> {
|
|||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, Expression>{};
|
||||
if (txt.present) {
|
||||
final converter = $PureDefaultsTable.$converter0;
|
||||
final converter = $PureDefaultsTable.$converter0n;
|
||||
map['insert'] = Variable<String?>(converter.toSql(txt.value));
|
||||
}
|
||||
return map;
|
||||
|
@ -1359,7 +1359,7 @@ class $PureDefaultsTable extends PureDefaults
|
|||
late final GeneratedColumnWithTypeConverter<MyCustomObject?, String?> txt =
|
||||
GeneratedColumn<String?>('insert', aliasedName, true,
|
||||
type: const StringType(), requiredDuringInsert: false)
|
||||
.withConverter<MyCustomObject?>($PureDefaultsTable.$converter0);
|
||||
.withConverter<MyCustomObject?>($PureDefaultsTable.$converter0n);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [txt];
|
||||
@override
|
||||
|
@ -1388,8 +1388,10 @@ class $PureDefaultsTable extends PureDefaults
|
|||
return $PureDefaultsTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static JsonTypeConverter<MyCustomObject?, String?> $converter0 =
|
||||
JsonTypeConverter.asNullable(const CustomJsonConverter());
|
||||
static JsonTypeConverter<MyCustomObject, String> $converter0 =
|
||||
const CustomJsonConverter();
|
||||
static JsonTypeConverter<MyCustomObject?, String?> $converter0n =
|
||||
JsonTypeConverter.asNullable($converter0);
|
||||
}
|
||||
|
||||
class CategoryTodoCountViewData extends DataClass {
|
||||
|
|
|
@ -135,16 +135,15 @@ UsedTypeConverter? readTypeConverter(
|
|||
final appliesToJsonToo = helper.isJsonAwareTypeConverter(staticType, library);
|
||||
|
||||
// Make the type converter support nulls by just mapping null to null if this
|
||||
// converter is otherwise non-nullable in both directions but applied on a
|
||||
// nullable column
|
||||
final skipForNull = !dartTypeNullable && !sqlTypeNullable && columnIsNullable;
|
||||
// converter is otherwise non-nullable in both directions.
|
||||
final canBeSkippedForNulls = !dartTypeNullable && !sqlTypeNullable;
|
||||
|
||||
if (sqlTypeNullable != columnIsNullable) {
|
||||
if (!columnIsNullable) {
|
||||
reportError('This column is non-nullable in the database, but has a '
|
||||
'type converter with a nullable SQL type, meaning that it may '
|
||||
"potentially map to `null` which can't be stored in the database.");
|
||||
} else if (!skipForNull) {
|
||||
} else if (!canBeSkippedForNulls) {
|
||||
final alternative = appliesToJsonToo
|
||||
? 'JsonTypeConverter.asNullable'
|
||||
: 'NullAwareTypeConverter.wrap';
|
||||
|
@ -156,7 +155,7 @@ UsedTypeConverter? readTypeConverter(
|
|||
}
|
||||
}
|
||||
|
||||
_checkType(columnType, null, sqlType, library.typeProvider,
|
||||
_checkType(columnType, columnIsNullable, null, sqlType, library.typeProvider,
|
||||
library.typeSystem, reportError);
|
||||
|
||||
return UsedTypeConverter(
|
||||
|
@ -166,7 +165,7 @@ UsedTypeConverter? readTypeConverter(
|
|||
dartTypeIsNullable: dartTypeNullable,
|
||||
sqlTypeIsNullable: sqlTypeNullable,
|
||||
alsoAppliesToJsonConversion: appliesToJsonToo,
|
||||
skipForNulls: skipForNull,
|
||||
canBeSkippedForNulls: canBeSkippedForNulls,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -184,7 +183,7 @@ void _checkParameterType(
|
|||
}
|
||||
|
||||
final nullableDartType = column.typeConverter != null
|
||||
? column.typeConverter!.mapsToNullableDart
|
||||
? column.typeConverter!.mapsToNullableDart(column.nullable)
|
||||
: column.nullableInDart;
|
||||
|
||||
if (library.isNonNullableByDefault &&
|
||||
|
@ -197,6 +196,7 @@ void _checkParameterType(
|
|||
|
||||
_checkType(
|
||||
column.type,
|
||||
column.nullable,
|
||||
column.typeConverter,
|
||||
element.type,
|
||||
library.typeProvider,
|
||||
|
@ -207,6 +207,7 @@ void _checkParameterType(
|
|||
|
||||
void _checkType(
|
||||
ColumnType columnType,
|
||||
bool columnIsNullable,
|
||||
UsedTypeConverter? typeConverter,
|
||||
DartType typeToCheck,
|
||||
TypeProvider typeProvider,
|
||||
|
@ -216,7 +217,7 @@ void _checkType(
|
|||
DriftDartType expectedDartType;
|
||||
if (typeConverter != null) {
|
||||
expectedDartType = typeConverter.dartType;
|
||||
if (typeConverter.skipForNulls) {
|
||||
if (typeConverter.canBeSkippedForNulls && columnIsNullable) {
|
||||
typeToCheck = typeSystem.promoteToNonNull(typeToCheck);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -75,7 +75,8 @@ class DriftDartType {
|
|||
extension OperationOnTypes on HasType {
|
||||
/// Whether this type is nullable in Dart
|
||||
bool get nullableInDart {
|
||||
return (nullable && !isArray) || typeConverter?.mapsToNullableDart == true;
|
||||
return (nullable && !isArray) ||
|
||||
typeConverter?.mapsToNullableDart(nullable) == true;
|
||||
}
|
||||
|
||||
/// the Dart type of this column that can be handled by moors type mapping.
|
||||
|
@ -111,7 +112,7 @@ extension OperationOnTypes on HasType {
|
|||
final converter = typeConverter;
|
||||
if (converter != null) {
|
||||
var inner = converter.dartType.codeString(options);
|
||||
if (converter.skipForNulls) inner += '?';
|
||||
if (converter.canBeSkippedForNulls && nullable) inner += '?';
|
||||
return isArray ? 'List<$inner>' : inner;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,22 +46,36 @@ class UsedTypeConverter {
|
|||
/// serialization.
|
||||
final bool alsoAppliesToJsonConversion;
|
||||
|
||||
/// Whether this type converter should be skipped for `null` values.
|
||||
/// Whether this type converter can be skipped for `null` values.
|
||||
///
|
||||
/// This applies to type converters with a non-nullable Dart and SQL type if
|
||||
/// the column is nullable. For those converters, drift maps `null` to `null`
|
||||
/// without calling the type converter at all.
|
||||
///
|
||||
/// This is implemented by wrapping it in a `NullAwareTypeConverter` in the
|
||||
/// generated code.
|
||||
final bool skipForNulls;
|
||||
/// For nullable columns, this is implemented by wrapping it in a
|
||||
/// `NullAwareTypeConverter` in the generated code for table classes. For
|
||||
/// nullable references to non-nullable columns (e.g. from outer joins), this
|
||||
/// is done with static helper methods on `NullAwareTypeConverter`.
|
||||
final bool canBeSkippedForNulls;
|
||||
|
||||
/// Type converters are stored as static fields in the table that created
|
||||
/// them. This will be the field name for this converter.
|
||||
String get fieldName => '\$converter$index';
|
||||
|
||||
/// If this converter [canBeSkippedForNulls] and is applied to a nullable
|
||||
/// column, drift generates a new wrapped type converter which will deal with
|
||||
/// `null` values.
|
||||
/// That converter is stored in this field.
|
||||
String get nullableFieldName => '${fieldName}n';
|
||||
|
||||
/// A Dart expression resolving to this converter.
|
||||
String get tableAndField => '${table!.entityInfoName}.$fieldName';
|
||||
String tableAndField({bool forNullableColumn = false}) {
|
||||
final field = canBeSkippedForNulls && forNullableColumn
|
||||
? nullableFieldName
|
||||
: fieldName;
|
||||
|
||||
return '${table!.entityInfoName}.$field';
|
||||
}
|
||||
|
||||
UsedTypeConverter({
|
||||
required this.expression,
|
||||
|
@ -70,7 +84,7 @@ class UsedTypeConverter {
|
|||
required this.dartTypeIsNullable,
|
||||
required this.sqlTypeIsNullable,
|
||||
this.alsoAppliesToJsonConversion = false,
|
||||
this.skipForNulls = false,
|
||||
this.canBeSkippedForNulls = false,
|
||||
});
|
||||
|
||||
factory UsedTypeConverter.forEnumColumn(
|
||||
|
@ -114,24 +128,27 @@ class UsedTypeConverter {
|
|||
);
|
||||
}
|
||||
|
||||
bool get mapsToNullableDart => dartTypeIsNullable || skipForNulls;
|
||||
bool mapsToNullableDart(bool nullableInSql) {
|
||||
return dartTypeIsNullable || (canBeSkippedForNulls && nullableInSql);
|
||||
}
|
||||
|
||||
String dartTypeCode(GenerationOptions options) {
|
||||
String dartTypeCode(GenerationOptions options, bool nullableInSql) {
|
||||
var type = dartType.codeString(options);
|
||||
if (options.nnbd && skipForNulls) type += '?';
|
||||
if (options.nnbd && (canBeSkippedForNulls && nullableInSql)) type += '?';
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/// A suitable typename to store an instance of the type converter used here.
|
||||
String converterNameInCode(GenerationOptions options) {
|
||||
String converterNameInCode(GenerationOptions options,
|
||||
{bool makeNullable = false}) {
|
||||
var sqlDartType = sqlType.getDisplayString(withNullability: options.nnbd);
|
||||
if (options.nnbd && skipForNulls) sqlDartType += '?';
|
||||
if (makeNullable) sqlDartType += '?';
|
||||
|
||||
final className =
|
||||
alsoAppliesToJsonConversion ? 'JsonTypeConverter' : 'TypeConverter';
|
||||
|
||||
return '$className<${dartTypeCode(options)}, $sqlDartType>';
|
||||
return '$className<${dartTypeCode(options, makeNullable)}, $sqlDartType>';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -182,9 +182,18 @@ class QueryWriter {
|
|||
final dartLiteral = asDartLiteral(specialName ?? column.name);
|
||||
var code = 'row.read<$rawDartType>($dartLiteral)';
|
||||
|
||||
if (column.typeConverter != null) {
|
||||
final converter = column.typeConverter;
|
||||
code = '${_converter(converter!)}.fromSql($code)';
|
||||
final converter = column.typeConverter;
|
||||
if (converter != null) {
|
||||
if (converter.canBeSkippedForNulls && column.nullable) {
|
||||
// The type converter maps non-nullable types, but the column may be
|
||||
// nullable in SQL => just map null to null and only invoke the type
|
||||
// converter for non-null values.
|
||||
code = 'NullAwareTypeConverter.wrapFromSql(${_converter(converter)}, '
|
||||
'$code)';
|
||||
} else {
|
||||
// Just apply the type converter directly.
|
||||
code = '${_converter(converter)}.fromSql($code)';
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
@ -861,9 +870,16 @@ class _ExpandedVariableWriter {
|
|||
final buffer = StringBuffer('Variable<$type>(');
|
||||
final capture = element.forCaptured;
|
||||
|
||||
if (element.typeConverter != null) {
|
||||
// Apply the converter
|
||||
buffer.write('${_converter(element.typeConverter!)}.toSql($dartExpr)');
|
||||
final converter = element.typeConverter;
|
||||
if (converter != null) {
|
||||
// Apply the converter.
|
||||
if (element.nullable && converter.canBeSkippedForNulls) {
|
||||
buffer.write('NullAwareTypeConverter.wrapToSql('
|
||||
'${_converter(element.typeConverter!)}, $dartExpr)');
|
||||
} else {
|
||||
buffer
|
||||
.write('${_converter(element.typeConverter!)}.toSql($dartExpr)');
|
||||
}
|
||||
|
||||
final needsNullAssertion =
|
||||
!element.nullable && scope.generationOptions.nnbd;
|
||||
|
|
|
@ -59,7 +59,7 @@ class DataClassWriter {
|
|||
..write('({')
|
||||
..write(columns.map((column) {
|
||||
final nullableDartType = column.typeConverter != null
|
||||
? column.typeConverter!.mapsToNullableDart
|
||||
? column.typeConverter!.mapsToNullableDart(column.nullable)
|
||||
: column.nullable;
|
||||
|
||||
if (nullableDartType) {
|
||||
|
@ -143,10 +143,11 @@ class DataClassWriter {
|
|||
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
||||
final type = column.innerColumnType(scope.generationOptions);
|
||||
final fromConverter = "serializer.fromJson<$type>(json['$jsonKey'])";
|
||||
final converterField =
|
||||
typeConverter.tableAndField(forNullableColumn: column.nullable);
|
||||
final notNull =
|
||||
!column.nullable && scope.generationOptions.nnbd ? '!' : '';
|
||||
deserialized =
|
||||
'${typeConverter.tableAndField}.fromJson($fromConverter)$notNull';
|
||||
deserialized = '$converterField.fromJson($fromConverter)$notNull';
|
||||
} else {
|
||||
final type = column.dartTypeCode(scope.generationOptions);
|
||||
|
||||
|
@ -183,7 +184,9 @@ class DataClassWriter {
|
|||
|
||||
final typeConverter = column.typeConverter;
|
||||
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
||||
value = '${typeConverter.tableAndField}.toJson($value)';
|
||||
final converterField =
|
||||
typeConverter.tableAndField(forNullableColumn: column.nullable);
|
||||
value = '$converterField.toJson($value)';
|
||||
dartType = '${column.innerColumnType(scope.generationOptions)}';
|
||||
}
|
||||
|
||||
|
@ -268,15 +271,13 @@ class DataClassWriter {
|
|||
if (column.typeConverter != null) {
|
||||
// apply type converter before writing the variable
|
||||
final converter = column.typeConverter;
|
||||
final fieldName = converter!.tableAndField;
|
||||
final assertNotNull = !column.nullable &&
|
||||
converter.sqlTypeIsNullable &&
|
||||
scope.generationOptions.nnbd;
|
||||
final fieldName =
|
||||
converter!.tableAndField(forNullableColumn: column.nullable);
|
||||
|
||||
_buffer
|
||||
..write('final converter = $fieldName;\n')
|
||||
..write(mapSetter)
|
||||
..write('(converter.toSql(${column.dartGetterName})');
|
||||
if (assertNotNull) _buffer.write('!');
|
||||
_buffer.write(');');
|
||||
} else {
|
||||
// no type converter. Write variable directly
|
||||
|
@ -376,9 +377,8 @@ class RowMappingWriter {
|
|||
// result.
|
||||
if (column.typeConverter != null) {
|
||||
// stored as a static field
|
||||
final converter = column.typeConverter!;
|
||||
final loaded =
|
||||
'${converter.table!.entityInfoName}.${converter.fieldName}';
|
||||
final loaded = column.typeConverter!
|
||||
.tableAndField(forNullableColumn: column.nullable);
|
||||
loadType = '$loaded.fromSql($loadType)';
|
||||
}
|
||||
|
||||
|
|
|
@ -100,14 +100,17 @@ abstract class TableOrViewWriter {
|
|||
if (converter != null) {
|
||||
// Generate a GeneratedColumnWithTypeConverter instance, as it has
|
||||
// additional methods to check for equality against a mapped value.
|
||||
final mappedType = converter.dartTypeCode(options);
|
||||
final mappedType = converter.dartTypeCode(options, column.nullable);
|
||||
|
||||
final converterCode =
|
||||
converter.tableAndField(forNullableColumn: column.nullable);
|
||||
|
||||
type = 'GeneratedColumnWithTypeConverter<$mappedType, $innerType>';
|
||||
expressionBuffer
|
||||
..write('.withConverter<')
|
||||
..write(mappedType)
|
||||
..write('>(')
|
||||
..write(converter.tableAndField)
|
||||
..write(converterCode)
|
||||
..write(')');
|
||||
}
|
||||
|
||||
|
@ -311,18 +314,32 @@ class TableWriter extends TableOrViewWriter {
|
|||
void _writeConvertersAsStaticFields() {
|
||||
for (final converter in table.converters) {
|
||||
final typeName = converter.converterNameInCode(scope.generationOptions);
|
||||
var code = converter.expression;
|
||||
|
||||
if (converter.skipForNulls) {
|
||||
if (converter.alsoAppliesToJsonConversion) {
|
||||
code = 'JsonTypeConverter.asNullable($code)';
|
||||
} else {
|
||||
code = 'NullAwareTypeConverter.wrap($code)';
|
||||
}
|
||||
}
|
||||
final code = converter.expression;
|
||||
|
||||
buffer.write('static $typeName ${converter.fieldName} = $code;');
|
||||
}
|
||||
|
||||
// Generate wrappers for non-nullable type converters that are applied to
|
||||
// nullable converters.
|
||||
for (final column in table.columns) {
|
||||
final converter = column.typeConverter;
|
||||
if (converter != null &&
|
||||
converter.canBeSkippedForNulls &&
|
||||
column.nullable) {
|
||||
final nullableTypeName = converter
|
||||
.converterNameInCode(scope.generationOptions, makeNullable: true);
|
||||
|
||||
final wrap = converter.alsoAppliesToJsonConversion
|
||||
? 'JsonTypeConverter.asNullable'
|
||||
: 'NullAwareTypeConverter.wrap';
|
||||
|
||||
final code = '$wrap(${converter.fieldName})';
|
||||
|
||||
buffer
|
||||
.write('static $nullableTypeName ${converter.nullableFieldName} = '
|
||||
'$code;');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _writeColumnVerificationMeta(MoorColumn column) {
|
||||
|
|
|
@ -188,18 +188,13 @@ class UpdateCompanionWriter {
|
|||
final converter = column.typeConverter;
|
||||
if (converter != null) {
|
||||
// apply type converter before writing the variable
|
||||
final fieldName = '${table.entityInfoName}.${converter.fieldName}';
|
||||
final fieldName =
|
||||
converter.tableAndField(forNullableColumn: column.nullable);
|
||||
_buffer
|
||||
..write('final converter = $fieldName;\n')
|
||||
..write(mapSetter)
|
||||
..write('(converter.toSql($getterName.value)');
|
||||
|
||||
if (!column.nullable &&
|
||||
converter.sqlTypeIsNullable &&
|
||||
scope.generationOptions.nnbd) {
|
||||
_buffer.write('!');
|
||||
}
|
||||
_buffer.write(');');
|
||||
..write('(converter.toSql($getterName.value)')
|
||||
..write(');');
|
||||
} else {
|
||||
// no type converter. Write variable directly
|
||||
_buffer
|
||||
|
|
|
@ -94,7 +94,7 @@ CREATE TABLE users (
|
|||
);
|
||||
|
||||
final implicitlyNullAware = table.columns[3];
|
||||
expect(implicitlyNullAware.typeConverter?.skipForNulls, isTrue);
|
||||
expect(implicitlyNullAware.typeConverter?.canBeSkippedForNulls, isTrue);
|
||||
});
|
||||
|
||||
test('json converters in drift files', () {
|
||||
|
|
|
@ -10,8 +10,8 @@ part of 'database.dart';
|
|||
class Category extends DataClass implements Insertable<Category> {
|
||||
final int id;
|
||||
final String name;
|
||||
final Color? color;
|
||||
Category({required this.id, required this.name, this.color});
|
||||
final Color color;
|
||||
Category({required this.id, required this.name, required this.color});
|
||||
factory Category.fromData(Map<String, dynamic> data, {String? prefix}) {
|
||||
final effectivePrefix = prefix ?? '';
|
||||
return Category(
|
||||
|
@ -30,7 +30,7 @@ class Category extends DataClass implements Insertable<Category> {
|
|||
map['name'] = Variable<String>(name);
|
||||
{
|
||||
final converter = $CategoriesTable.$converter0;
|
||||
map['color'] = Variable<int>(converter.toSql(color)!);
|
||||
map['color'] = Variable<int>(converter.toSql(color));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ class Category extends DataClass implements Insertable<Category> {
|
|||
return Category(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
name: serializer.fromJson<String>(json['name']),
|
||||
color: serializer.fromJson<Color?>(json['color']),
|
||||
color: serializer.fromJson<Color>(json['color']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
|
@ -58,18 +58,14 @@ class Category extends DataClass implements Insertable<Category> {
|
|||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'name': serializer.toJson<String>(name),
|
||||
'color': serializer.toJson<Color?>(color),
|
||||
'color': serializer.toJson<Color>(color),
|
||||
};
|
||||
}
|
||||
|
||||
Category copyWith(
|
||||
{int? id,
|
||||
String? name,
|
||||
Value<Color?> color = const Value.absent()}) =>
|
||||
Category(
|
||||
Category copyWith({int? id, String? name, Color? color}) => Category(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
color: color.present ? color.value : this.color,
|
||||
color: color ?? this.color,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
|
@ -95,7 +91,7 @@ class Category extends DataClass implements Insertable<Category> {
|
|||
class CategoriesCompanion extends UpdateCompanion<Category> {
|
||||
final Value<int> id;
|
||||
final Value<String> name;
|
||||
final Value<Color?> color;
|
||||
final Value<Color> color;
|
||||
const CategoriesCompanion({
|
||||
this.id = const Value.absent(),
|
||||
this.name = const Value.absent(),
|
||||
|
@ -104,13 +100,13 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
|
|||
CategoriesCompanion.insert({
|
||||
this.id = const Value.absent(),
|
||||
required String name,
|
||||
required Color? color,
|
||||
required Color color,
|
||||
}) : name = Value(name),
|
||||
color = Value(color);
|
||||
static Insertable<Category> custom({
|
||||
Expression<int>? id,
|
||||
Expression<String>? name,
|
||||
Expression<Color?>? color,
|
||||
Expression<Color>? color,
|
||||
}) {
|
||||
return RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
|
@ -120,7 +116,7 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
|
|||
}
|
||||
|
||||
CategoriesCompanion copyWith(
|
||||
{Value<int>? id, Value<String>? name, Value<Color?>? color}) {
|
||||
{Value<int>? id, Value<String>? name, Value<Color>? color}) {
|
||||
return CategoriesCompanion(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
|
@ -139,7 +135,7 @@ class CategoriesCompanion extends UpdateCompanion<Category> {
|
|||
}
|
||||
if (color.present) {
|
||||
final converter = $CategoriesTable.$converter0;
|
||||
map['color'] = Variable<int>(converter.toSql(color.value)!);
|
||||
map['color'] = Variable<int>(converter.toSql(color.value));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -175,10 +171,10 @@ class $CategoriesTable extends Categories
|
|||
type: const StringType(), requiredDuringInsert: true);
|
||||
final VerificationMeta _colorMeta = const VerificationMeta('color');
|
||||
@override
|
||||
late final GeneratedColumnWithTypeConverter<Color?, int?> color =
|
||||
late final GeneratedColumnWithTypeConverter<Color, int?> color =
|
||||
GeneratedColumn<int?>('color', aliasedName, false,
|
||||
type: const IntType(), requiredDuringInsert: true)
|
||||
.withConverter<Color?>($CategoriesTable.$converter0);
|
||||
.withConverter<Color>($CategoriesTable.$converter0);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, color];
|
||||
@override
|
||||
|
@ -216,7 +212,7 @@ class $CategoriesTable extends Categories
|
|||
return $CategoriesTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static TypeConverter<Color?, int?> $converter0 = const ColorConverter();
|
||||
static TypeConverter<Color, int> $converter0 = const ColorConverter();
|
||||
}
|
||||
|
||||
class TodoEntry extends DataClass implements Insertable<TodoEntry> {
|
||||
|
@ -650,7 +646,8 @@ abstract class _$AppDatabase extends GeneratedDatabase {
|
|||
return CategoriesWithCountResult(
|
||||
id: row.read<int?>('id'),
|
||||
name: row.read<String?>('name'),
|
||||
color: $CategoriesTable.$converter0.fromSql(row.read<int?>('color')),
|
||||
color: NullAwareTypeConverter.wrapFromSql(
|
||||
$CategoriesTable.$converter0, row.read<int?>('color')),
|
||||
amount: row.read<int>('amount'),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -35,12 +35,12 @@ mixin AutoIncrementingPrimaryKey on Table {
|
|||
IntColumn get id => integer().autoIncrement()();
|
||||
}
|
||||
|
||||
class ColorConverter extends NullAwareTypeConverter<Color, int> {
|
||||
class ColorConverter extends TypeConverter<Color, int> {
|
||||
const ColorConverter();
|
||||
|
||||
@override
|
||||
Color requireFromSql(int fromDb) => Color(fromDb);
|
||||
Color fromSql(int fromDb) => Color(fromDb);
|
||||
|
||||
@override
|
||||
int requireToSql(Color value) => value.value;
|
||||
int toSql(Color value) => value.value;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,32 @@
|
|||
targets:
|
||||
# This setup exists so that the main entrypoint (web/main.dart) gets compiled
|
||||
# with dartdevc for debug builds while the worker is compiled with dart2js
|
||||
# (since workers don't support the JS moduled emitted by dartdevc).
|
||||
# In release builds (`--release` on the CLI), both entrypoints are compiled
|
||||
# with dart2js.
|
||||
#
|
||||
# If you're ok with compiling everything with dart2js, just use
|
||||
# `compiler: dartj2s` on the options of the default target and ignore the two
|
||||
# additional targets here.
|
||||
dart2js_archives:
|
||||
auto_apply_builders: false
|
||||
dependencies: [":$default", ":worker"]
|
||||
builders:
|
||||
build_web_compilers:dart2js_archive_extractor:
|
||||
enabled: true
|
||||
worker:
|
||||
auto_apply_builders: false
|
||||
dependencies: [":$default"]
|
||||
builders:
|
||||
build_web_compilers:entrypoint:
|
||||
enabled: true
|
||||
generate_for:
|
||||
- web/worker.dart
|
||||
options:
|
||||
compiler: dart2js
|
||||
build_web_compilers:dart2js_archive_extractor:
|
||||
enabled: false
|
||||
|
||||
$default:
|
||||
builders:
|
||||
drift_dev:
|
||||
|
@ -9,9 +37,11 @@ targets:
|
|||
generate_values_in_copy_with: true
|
||||
named_parameters: true
|
||||
new_sql_code_generation: true
|
||||
build_web_compilers|entrypoint:
|
||||
enabled: true
|
||||
build_web_compilers:entrypoint:
|
||||
generate_for:
|
||||
- web/worker.dart
|
||||
options:
|
||||
compiler: dart2js
|
||||
# This one is compiled in the other target
|
||||
exclude:
|
||||
- "web/worker.dart"
|
||||
# We have a designated target for this step.
|
||||
build_web_compilers:dart2js_archive_extractor:
|
||||
enabled: false
|
||||
|
|
|
@ -4,13 +4,12 @@ set -e
|
|||
function generate() {
|
||||
echo "------------- Generate: $1 -------------"
|
||||
pushd $1 > /dev/null
|
||||
rm -rf .dart_tool
|
||||
dart pub get
|
||||
dart pub upgrade
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
cd ..
|
||||
cd "$(dirname "$0")/.."
|
||||
generate 'drift'
|
||||
generate 'drift_dev'
|
||||
generate 'docs'
|
||||
|
|
|
@ -4,8 +4,7 @@ set -e
|
|||
function run_test() {
|
||||
echo "------------- Running test: $1 -------------"
|
||||
pushd $1 > /dev/null
|
||||
rm -rf .dart_tool
|
||||
dart pub get
|
||||
dart pub upgrade
|
||||
dart format -o none --set-exit-if-changed .
|
||||
dart analyze --fatal-infos --fatal-warnings
|
||||
if [[ "$2" == 'vm+web' ]]; then
|
||||
|
@ -22,8 +21,7 @@ function run_test() {
|
|||
function run_test_flutter() {
|
||||
echo "------------- Running flutter test: $1 -------------"
|
||||
pushd $1 > /dev/null
|
||||
rm -rf .dart_tool
|
||||
flutter pub get
|
||||
flutter pub upgrade
|
||||
flutter clean
|
||||
dart format -o none --set-exit-if-changed .
|
||||
flutter analyze --fatal-infos --fatal-warnings
|
||||
|
|
Loading…
Reference in New Issue