mirror of https://github.com/AMT-Cheif/drift.git
Decouple JsonTypeConverter from TypeConverter
This commit is contained in:
parent
3253cd7ead
commit
ba28b51125
|
@ -10,7 +10,6 @@ extension Expressions on MyDatabase {
|
|||
return (select(categories)..where((row) => hasNoTodo)).get();
|
||||
}
|
||||
// #enddocregion emptyCategories
|
||||
|
||||
}
|
||||
|
||||
// #docregion bitwise
|
||||
|
|
|
@ -35,16 +35,20 @@ abstract class TypeConverter<D, S> {
|
|||
/// `.drift` files) refers to a type converter that inherits from
|
||||
/// [JsonTypeConverter], it will also be used for the conversion from and to
|
||||
/// JSON.
|
||||
mixin JsonTypeConverter<D, S> on TypeConverter<D, S> {
|
||||
abstract class JsonTypeConverter<D, S, J> extends TypeConverter<D, S> {
|
||||
/// Empty constant constructor so that subclasses can have a constant
|
||||
/// constructor.
|
||||
const JsonTypeConverter();
|
||||
|
||||
/// Map a value from the Data class to json.
|
||||
///
|
||||
/// Defaults to doing the same conversion as for Dart -> SQL, [toSql].
|
||||
S toJson(D value) => toSql(value);
|
||||
J toJson(D value);
|
||||
|
||||
/// Map a value from json to something understood by the data class.
|
||||
///
|
||||
/// Defaults to doing the same conversion as for SQL -> Dart, [toSql].
|
||||
D fromJson(S json) => fromSql(json);
|
||||
D fromJson(J json);
|
||||
|
||||
/// Wraps an [inner] type converter that only considers non-nullable values
|
||||
/// as a type converter that handles null values too.
|
||||
|
@ -52,8 +56,9 @@ mixin JsonTypeConverter<D, S> on TypeConverter<D, S> {
|
|||
/// The returned type converter will use the [inner] type converter for non-
|
||||
/// null values. Further, `null` is mapped to `null` in both directions (from
|
||||
/// Dart to SQL and vice-versa).
|
||||
static JsonTypeConverter<D?, S?> asNullable<D, S extends Object>(
|
||||
TypeConverter<D, S> inner) {
|
||||
static JsonTypeConverter<D?, S?, J?>
|
||||
asNullable<D, S extends Object, J extends Object>(
|
||||
JsonTypeConverter<D, S, J> inner) {
|
||||
return _NullWrappingTypeConverterWithJson(inner);
|
||||
}
|
||||
}
|
||||
|
@ -150,9 +155,10 @@ class _NullWrappingTypeConverter<D, S extends Object>
|
|||
S requireToSql(D value) => _inner.toSql(value);
|
||||
}
|
||||
|
||||
class _NullWrappingTypeConverterWithJson<D, S extends Object>
|
||||
extends NullAwareTypeConverter<D, S> with JsonTypeConverter<D?, S?> {
|
||||
final TypeConverter<D, S> _inner;
|
||||
class _NullWrappingTypeConverterWithJson<D, S extends Object, J extends Object>
|
||||
extends NullAwareTypeConverter<D, S>
|
||||
implements JsonTypeConverter<D?, S?, J?> {
|
||||
final JsonTypeConverter<D, S, J> _inner;
|
||||
|
||||
const _NullWrappingTypeConverterWithJson(this._inner);
|
||||
|
||||
|
@ -161,4 +167,18 @@ class _NullWrappingTypeConverterWithJson<D, S extends Object>
|
|||
|
||||
@override
|
||||
S requireToSql(D value) => _inner.toSql(value);
|
||||
|
||||
D requireFromJson(J json) => _inner.fromJson(json);
|
||||
|
||||
@override
|
||||
D? fromJson(J? json) {
|
||||
return json == null ? null : requireFromJson(json);
|
||||
}
|
||||
|
||||
J? requireToJson(D? value) => _inner.toJson(value as D);
|
||||
|
||||
@override
|
||||
J? toJson(D? value) {
|
||||
return value == null ? null : requireToJson(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,8 +135,14 @@ class CustomConverter extends TypeConverter<MyCustomObject, String> {
|
|||
}
|
||||
|
||||
class CustomJsonConverter extends CustomConverter
|
||||
with JsonTypeConverter<MyCustomObject, String> {
|
||||
implements JsonTypeConverter<MyCustomObject, String, String> {
|
||||
const CustomJsonConverter();
|
||||
|
||||
@override
|
||||
MyCustomObject fromJson(String json) => fromSql(json);
|
||||
|
||||
@override
|
||||
String toJson(MyCustomObject value) => toSql(value);
|
||||
}
|
||||
|
||||
abstract class CategoryTodoCountView extends View {
|
||||
|
|
|
@ -1252,7 +1252,7 @@ class PureDefault extends DataClass implements Insertable<PureDefault> {
|
|||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||
return PureDefault(
|
||||
txt: $PureDefaultsTable.$converter0n
|
||||
.fromJson(serializer.fromJson<String?>(json['txt'])),
|
||||
.fromJson(serializer.fromJson<String>(json['txt'])),
|
||||
);
|
||||
}
|
||||
factory PureDefault.fromJsonString(String encodedJson,
|
||||
|
@ -1373,9 +1373,9 @@ class $PureDefaultsTable extends PureDefaults
|
|||
return $PureDefaultsTable(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
static JsonTypeConverter<MyCustomObject, String> $converter0 =
|
||||
static JsonTypeConverter<MyCustomObject, String, String> $converter0 =
|
||||
const CustomJsonConverter();
|
||||
static JsonTypeConverter<MyCustomObject?, String?> $converter0n =
|
||||
static JsonTypeConverter<MyCustomObject?, String?, String?> $converter0n =
|
||||
JsonTypeConverter.asNullable($converter0);
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,8 @@ UsedTypeConverter? readTypeConverter(
|
|||
final staticType = dartExpression.staticType;
|
||||
final asTypeConverter =
|
||||
staticType != null ? helper.asTypeConverter(staticType) : null;
|
||||
final asJsonTypeConverter =
|
||||
staticType != null ? helper.asJsonTypeConverter(staticType) : null;
|
||||
|
||||
if (asTypeConverter == null) {
|
||||
reportError('Not a type converter');
|
||||
|
@ -160,6 +162,7 @@ UsedTypeConverter? readTypeConverter(
|
|||
|
||||
final dartType = asTypeConverter.typeArguments[0];
|
||||
final sqlType = asTypeConverter.typeArguments[1];
|
||||
final jsonType = asJsonTypeConverter?.typeArguments[2] ?? sqlType;
|
||||
|
||||
final typeSystem = library.typeSystem;
|
||||
final dartTypeNullable = typeSystem.isNullable(dartType);
|
||||
|
@ -195,6 +198,7 @@ UsedTypeConverter? readTypeConverter(
|
|||
expression: dartExpression.toSource(),
|
||||
dartType: resolvedDartType ?? DriftDartType.of(dartType),
|
||||
sqlType: sqlType,
|
||||
jsonType: jsonType,
|
||||
dartTypeIsNullable: dartTypeNullable,
|
||||
sqlTypeIsNullable: sqlTypeNullable,
|
||||
alsoAppliesToJsonConversion: appliesToJsonToo,
|
||||
|
|
|
@ -26,13 +26,24 @@ class HelperLibrary {
|
|||
return type.asInstanceOf(converter);
|
||||
}
|
||||
|
||||
/// Converts the given Dart [type] into an instantiation of the
|
||||
/// `TypeConverter` class from drift.
|
||||
///
|
||||
/// Returns `null` if [type] is not a subtype of `TypeConverter`.
|
||||
InterfaceType? asJsonTypeConverter(DartType type) {
|
||||
final converter = helperLibrary.exportNamespace.get('JsonTypeConverter')
|
||||
as InterfaceElement;
|
||||
return type.asInstanceOf(converter);
|
||||
}
|
||||
|
||||
bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) {
|
||||
final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter')
|
||||
as InterfaceElement;
|
||||
final jsonConverterType = jsonMixin.instantiate(
|
||||
typeArguments: [
|
||||
context.typeProvider.dynamicType,
|
||||
context.typeProvider.dynamicType
|
||||
context.typeProvider.dynamicType,
|
||||
context.typeProvider.dynamicType,
|
||||
],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
|
|
|
@ -136,6 +136,20 @@ extension OperationOnTypes on HasType {
|
|||
|
||||
return variableTypeCode();
|
||||
}
|
||||
|
||||
/// The dart type that matches the values of this column. For instance, if a
|
||||
/// table has declared an `IntColumn`, the matching dart type name would be
|
||||
/// [int].
|
||||
String jsonTypeCode() {
|
||||
final converter = typeConverter;
|
||||
if (converter != null) {
|
||||
var inner = converter.jsonType.codeString();
|
||||
if (converter.canBeSkippedForNulls && nullable) inner += '?';
|
||||
return isArray ? 'List<$inner>' : inner;
|
||||
}
|
||||
|
||||
return variableTypeCode();
|
||||
}
|
||||
}
|
||||
|
||||
const Map<DriftSqlType, String> dartTypeNames = {
|
||||
|
|
|
@ -31,6 +31,10 @@ class UsedTypeConverter {
|
|||
/// mapped values in the database.
|
||||
final DartType sqlType;
|
||||
|
||||
/// The "JSON" type of this type converter. This is the type used to represent
|
||||
/// mapped values in the database.
|
||||
final DartType jsonType;
|
||||
|
||||
/// Whether the Dart-value output of this type converter is nullable.
|
||||
///
|
||||
/// In other words, [dartType] is potentially nullable.
|
||||
|
@ -80,6 +84,7 @@ class UsedTypeConverter {
|
|||
required this.expression,
|
||||
required this.dartType,
|
||||
required this.sqlType,
|
||||
required this.jsonType,
|
||||
required this.dartTypeIsNullable,
|
||||
required this.sqlTypeIsNullable,
|
||||
this.alsoAppliesToJsonConversion = false,
|
||||
|
@ -115,6 +120,7 @@ class UsedTypeConverter {
|
|||
sqlTypeIsNullable: false,
|
||||
dartTypeIsNullable: false,
|
||||
sqlType: typeProvider.intType,
|
||||
jsonType: typeProvider.intType,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -133,11 +139,13 @@ class UsedTypeConverter {
|
|||
String converterNameInCode({bool makeNullable = false}) {
|
||||
var sqlDartType = sqlType.getDisplayString(withNullability: true);
|
||||
if (makeNullable) sqlDartType += '?';
|
||||
var jsonDartType = jsonType.getDisplayString(withNullability: true);
|
||||
if (makeNullable) jsonDartType += '?';
|
||||
|
||||
final className =
|
||||
alsoAppliesToJsonConversion ? 'JsonTypeConverter' : 'TypeConverter';
|
||||
|
||||
return '$className<${dartTypeCode(makeNullable)}, $sqlDartType>';
|
||||
if (alsoAppliesToJsonConversion) {
|
||||
return 'JsonTypeConverter<${dartTypeCode(makeNullable)}, $sqlDartType, $jsonDartType>';
|
||||
}
|
||||
return 'TypeConverter<${dartTypeCode(makeNullable)}, $sqlDartType>';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ class DataClassWriter {
|
|||
|
||||
final typeConverter = column.typeConverter;
|
||||
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
||||
final type = column.innerColumnType(nullable: column.nullable);
|
||||
final type = typeConverter.jsonType;
|
||||
final fromConverter = "serializer.fromJson<$type>(json['$jsonKey'])";
|
||||
final converterField =
|
||||
typeConverter.tableAndField(forNullableColumn: column.nullable);
|
||||
|
@ -151,7 +151,7 @@ class DataClassWriter {
|
|||
final converterField =
|
||||
typeConverter.tableAndField(forNullableColumn: column.nullable);
|
||||
value = '$converterField.toJson($value)';
|
||||
dartType = column.innerColumnType(nullable: true);
|
||||
dartType = column.jsonTypeCode();
|
||||
}
|
||||
|
||||
_buffer.write("'$name': serializer.toJson<$dartType>($value),");
|
||||
|
|
|
@ -15,7 +15,7 @@ void main() {
|
|||
import 'package:drift/drift.dart';
|
||||
|
||||
TypeConverter<String, String> withoutJson() => throw 'stub';
|
||||
JsonTypeConverter<String, String> withJson() => throw 'stub';
|
||||
JsonTypeConverter<String, String, String> withJson() => throw 'stub';
|
||||
|
||||
class Users extends Table {
|
||||
TextColumn get foo => text().map(withoutJson())();
|
||||
|
|
Loading…
Reference in New Issue