diff --git a/drift/lib/src/drift_dev_helper.dart b/drift/lib/src/drift_dev_helper.dart index cd21be52..85e31942 100644 --- a/drift/lib/src/drift_dev_helper.dart +++ b/drift/lib/src/drift_dev_helper.dart @@ -1,2 +1,3 @@ // This field is analyzed by drift_dev to easily obtain common types. -export 'runtime/types/converters.dart' show TypeConverter, JsonTypeConverter; +export 'runtime/types/converters.dart' + show TypeConverter, JsonTypeConverter, JsonTypeConverterWithDifferentTypes; diff --git a/drift/lib/src/runtime/types/converters.dart b/drift/lib/src/runtime/types/converters.dart index 4a362bb1..0c140df6 100644 --- a/drift/lib/src/runtime/types/converters.dart +++ b/drift/lib/src/runtime/types/converters.dart @@ -33,13 +33,9 @@ abstract class TypeConverter { /// to SQL (and vice-versa). /// When a [BuildGeneralColumn.map] column (or a `MAPPED BY` constraint in /// `.drift` files) refers to a type converter that inherits from -/// [JsonTypeConverter], it will also be used for the conversion from and to +/// [JsonTypeConverterWithDifferentTypes], it will also be used for the conversion from and to /// JSON. -abstract class JsonTypeConverter extends TypeConverter { - /// Empty constant constructor so that subclasses can have a constant - /// constructor. - const JsonTypeConverter(); - +mixin JsonTypeConverterWithDifferentTypes on TypeConverter { /// Map a value from the Data class to json. /// /// Defaults to doing the same conversion as for Dart -> SQL, [toSql]. @@ -56,9 +52,39 @@ abstract class JsonTypeConverter extends TypeConverter { /// 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 + static JsonTypeConverterWithDifferentTypes asNullable( - JsonTypeConverter inner) { + JsonTypeConverterWithDifferentTypes inner) { + return _NullWrappingTypeConverterWithJson(inner); + } +} + +/// A mixin for [TypeConverter]s that should also apply to drift's builtin +/// JSON serialization of data classes. +/// +/// By default, a [TypeConverter] only applies to the serialization from Dart +/// to SQL (and vice-versa). +/// When a [BuildGeneralColumn.map] column (or a `MAPPED BY` constraint in +/// `.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 + implements JsonTypeConverterWithDifferentTypes { + @override + S toJson(D value) => toSql(value); + + @override + D fromJson(S json) => fromSql(json); + + /// Wraps an [inner] type converter that only considers non-nullable values + /// as a type converter that handles null values too. + /// + /// 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 JsonTypeConverterWithDifferentTypes + asNullable( + JsonTypeConverterWithDifferentTypes inner) { return _NullWrappingTypeConverterWithJson(inner); } } @@ -157,8 +183,8 @@ class _NullWrappingTypeConverter class _NullWrappingTypeConverterWithJson extends NullAwareTypeConverter - implements JsonTypeConverter { - final JsonTypeConverter _inner; + implements JsonTypeConverterWithDifferentTypes { + final JsonTypeConverterWithDifferentTypes _inner; const _NullWrappingTypeConverterWithJson(this._inner); diff --git a/drift/test/generated/todos.dart b/drift/test/generated/todos.dart index dd5fdff5..0168dbf6 100644 --- a/drift/test/generated/todos.dart +++ b/drift/test/generated/todos.dart @@ -135,14 +135,8 @@ class CustomConverter extends TypeConverter { } class CustomJsonConverter extends CustomConverter - implements JsonTypeConverter { + with JsonTypeConverter { const CustomJsonConverter(); - - @override - MyCustomObject fromJson(String json) => fromSql(json); - - @override - String toJson(MyCustomObject value) => toSql(value); } abstract class CategoryTodoCountView extends View { diff --git a/drift/test/generated/todos.g.dart b/drift/test/generated/todos.g.dart index a58388c1..b3c0ee71 100644 --- a/drift/test/generated/todos.g.dart +++ b/drift/test/generated/todos.g.dart @@ -1373,10 +1373,11 @@ class $PureDefaultsTable extends PureDefaults return $PureDefaultsTable(attachedDatabase, alias); } - static JsonTypeConverter $converter0 = - const CustomJsonConverter(); - static JsonTypeConverter $converter0n = - JsonTypeConverter.asNullable($converter0); + static JsonTypeConverterWithDifferentTypes + $converter0 = const CustomJsonConverter(); + static JsonTypeConverterWithDifferentTypes + $converter0n = + JsonTypeConverterWithDifferentTypes.asNullable($converter0); } class CategoryTodoCountViewData extends DataClass { diff --git a/drift_dev/lib/src/analyzer/dart_types.dart b/drift_dev/lib/src/analyzer/dart_types.dart index 1d33cba8..24a0df30 100644 --- a/drift_dev/lib/src/analyzer/dart_types.dart +++ b/drift_dev/lib/src/analyzer/dart_types.dart @@ -181,7 +181,7 @@ UsedTypeConverter? readTypeConverter( "potentially map to `null` which can't be stored in the database."); } else if (!canBeSkippedForNulls) { final alternative = appliesToJsonToo - ? 'JsonTypeConverter.asNullable' + ? 'JsonTypeConverterWithDifferentTypes.asNullable' : 'NullAwareTypeConverter.wrap'; reportError('This column is nullable, but the type converter has a non-' diff --git a/drift_dev/lib/src/analyzer/helper.dart b/drift_dev/lib/src/analyzer/helper.dart index 8a5e343e..f6053153 100644 --- a/drift_dev/lib/src/analyzer/helper.dart +++ b/drift_dev/lib/src/analyzer/helper.dart @@ -27,18 +27,18 @@ class HelperLibrary { } /// Converts the given Dart [type] into an instantiation of the - /// `TypeConverter` class from drift. + /// `JsonTypeConverter` 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; + final converter = helperLibrary.exportNamespace + .get('JsonTypeConverterWithDifferentTypes') as InterfaceElement; return type.asInstanceOf(converter); } bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) { - final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter') - as InterfaceElement; + final jsonMixin = helperLibrary.exportNamespace + .get('JsonTypeConverterWithDifferentTypes') as InterfaceElement; final jsonConverterType = jsonMixin.instantiate( typeArguments: [ context.typeProvider.dynamicType, diff --git a/drift_dev/lib/src/model/used_type_converter.dart b/drift_dev/lib/src/model/used_type_converter.dart index f5525dbb..e4846181 100644 --- a/drift_dev/lib/src/model/used_type_converter.dart +++ b/drift_dev/lib/src/model/used_type_converter.dart @@ -143,7 +143,7 @@ class UsedTypeConverter { if (makeNullable) jsonDartType += '?'; if (alsoAppliesToJsonConversion) { - return 'JsonTypeConverter<${dartTypeCode(makeNullable)}, $sqlDartType, $jsonDartType>'; + return 'JsonTypeConverterWithDifferentTypes<${dartTypeCode(makeNullable)}, $sqlDartType, $jsonDartType>'; } return 'TypeConverter<${dartTypeCode(makeNullable)}, $sqlDartType>'; } diff --git a/drift_dev/lib/src/writer/tables/table_writer.dart b/drift_dev/lib/src/writer/tables/table_writer.dart index db5550f6..fbaf6993 100644 --- a/drift_dev/lib/src/writer/tables/table_writer.dart +++ b/drift_dev/lib/src/writer/tables/table_writer.dart @@ -336,7 +336,7 @@ class TableWriter extends TableOrViewWriter { converter.converterNameInCode(makeNullable: true); final wrap = converter.alsoAppliesToJsonConversion - ? 'JsonTypeConverter.asNullable' + ? 'JsonTypeConverterWithDifferentTypes.asNullable' : 'NullAwareTypeConverter.wrap'; final code = '$wrap(${converter.fieldName})'; diff --git a/drift_dev/test/analyzer/dart/type_converter_test.dart b/drift_dev/test/analyzer/dart/type_converter_test.dart index 62fa5e7c..297568c5 100644 --- a/drift_dev/test/analyzer/dart/type_converter_test.dart +++ b/drift_dev/test/analyzer/dart/type_converter_test.dart @@ -15,7 +15,7 @@ void main() { import 'package:drift/drift.dart'; TypeConverter withoutJson() => throw 'stub'; -JsonTypeConverter withJson() => throw 'stub'; +JsonTypeConverter withJson() => throw 'stub'; class Users extends Table { TextColumn get foo => text().map(withoutJson())();