diff --git a/docs/lib/snippets/expressions.dart b/docs/lib/snippets/expressions.dart index 43927164..6c979900 100644 --- a/docs/lib/snippets/expressions.dart +++ b/docs/lib/snippets/expressions.dart @@ -10,7 +10,6 @@ extension Expressions on MyDatabase { return (select(categories)..where((row) => hasNoTodo)).get(); } // #enddocregion emptyCategories - } // #docregion bitwise diff --git a/docs/pages/docs/Advanced Features/type_converters.md b/docs/pages/docs/Advanced Features/type_converters.md index 08eca372..ba71d93f 100644 --- a/docs/pages/docs/Advanced Features/type_converters.md +++ b/docs/pages/docs/Advanced Features/type_converters.md @@ -123,6 +123,13 @@ If you want to apply the same conversion to JSON as well, make your type convert You can also override the `toJson` and `fromJson` methods to customize serialization as long as the types stay the compatible. -If you want to serialize to a different JSON type (e.g. you have a type converter `` in SQL but -want to map to a string in JSON), you'll have to write a custom [`ValueSerializer`](https://drift.simonbinder.eu/api/drift/valueserializer-class) +If the JSON type you want to serialize to is different to the SQL type you're +mapping to, you can mix-in `JsonTypeConverter2` instead. +For instance, say you have a type converter mapping to a complex Dart type +`MyObject`. In SQL, you might want to store this as an `String`. But when +serializing to JSON, you may want to use a `Map`. Here, simply +add the `JsonTypeConverter2>` mixin to +your type converter. + +As an alternative to using JSON type converters, you can use a custom [`ValueSerializer`](https://drift.simonbinder.eu/api/drift/valueserializer-class) and pass it to the serialization methods. diff --git a/docs/pages/docs/Other engines/web.md b/docs/pages/docs/Other engines/web.md index 34bf1d77..7842e96c 100644 --- a/docs/pages/docs/Other engines/web.md +++ b/docs/pages/docs/Other engines/web.md @@ -167,7 +167,7 @@ void main() { final db = WebDatabase.withStorage(DriftWebStorage.indexedDb('worker', migrateFromLocalStorage: false, inWebWorker: true)); - final server = DriftServer(DatabaseConnection.fromExecutor(db)); + final server = DriftServer(DatabaseConnection(db)); self.onConnect.listen((event) { final msg = event as MessageEvent; @@ -294,4 +294,4 @@ With this setup, sqlite3 can be used on the web without an external library: This snippet also works in a service worker. -If you're running into any issues with the new backend, please post them [here](https://github.com/simolus3/sqlite3.dart/issues). \ No newline at end of file +If you're running into any issues with the new backend, please post them [here](https://github.com/simolus3/sqlite3.dart/issues). diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index 60d68b5d..66591d38 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.3.0-dev + +- Add the `JsonTypeConverter2` mixin. It behaves similar to the existing json + type converters, but can use a different SQL and JSON type. + ## 2.2.0 - Always escape column names, avoiding the costs of using a regular expression diff --git a/drift/lib/src/drift_dev_helper.dart b/drift/lib/src/drift_dev_helper.dart index 6cb71f0c..5b1429a1 100644 --- a/drift/lib/src/drift_dev_helper.dart +++ b/drift/lib/src/drift_dev_helper.dart @@ -1,5 +1,5 @@ // 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, JsonTypeConverter2; export 'runtime/query_builder/query_builder.dart' show TableInfo; export 'dsl/dsl.dart' show Table, View, DriftDatabase, DriftAccessor; diff --git a/drift/lib/src/runtime/types/converters.dart b/drift/lib/src/runtime/types/converters.dart index 8171458b..a6b3011b 100644 --- a/drift/lib/src/runtime/types/converters.dart +++ b/drift/lib/src/runtime/types/converters.dart @@ -29,22 +29,21 @@ abstract class TypeConverter { /// 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 on TypeConverter { +/// Unlike the old [JsonTypeConverter] mixin, this more general mixin allows +/// using a different type when serializing to JSON ([J]) than the type used in +/// SQL ([S]). +/// For the cases where the JSON serialization and the mapping to SQL use the +/// same types, it may be more convenient to mix-in [JsonTypeConverter] instead. +mixin JsonTypeConverter2 on TypeConverter { /// 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,12 +51,35 @@ mixin JsonTypeConverter on 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 asNullable( - TypeConverter inner) { + static JsonTypeConverter2 + asNullable( + JsonTypeConverter2 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. +/// +/// If the serialized JSON has a different type than the type in SQL ([S]), use +/// a [JsonTypeConverter2]. For instance, this could be useful if your type +/// converter between Dart and SQL maps to a string in SQL, but to a `Map` in +/// JSON. +mixin JsonTypeConverter implements JsonTypeConverter2 { + @override + S toJson(D value) => toSql(value); + + @override + D fromJson(S json) => fromSql(json); +} + /// Implementation for an enum to int converter that uses the index of the enum /// as the value stored in the database. class EnumIndexConverter extends TypeConverter { @@ -150,9 +172,10 @@ class _NullWrappingTypeConverter S requireToSql(D value) => _inner.toSql(value); } -class _NullWrappingTypeConverterWithJson - extends NullAwareTypeConverter with JsonTypeConverter { - final TypeConverter _inner; +class _NullWrappingTypeConverterWithJson + extends NullAwareTypeConverter + implements JsonTypeConverter2 { + final JsonTypeConverter2 _inner; const _NullWrappingTypeConverterWithJson(this._inner); @@ -161,4 +184,18 @@ class _NullWrappingTypeConverterWithJson @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); + } } diff --git a/drift/pubspec.yaml b/drift/pubspec.yaml index 4f2df168..a96cc96f 100644 --- a/drift/pubspec.yaml +++ b/drift/pubspec.yaml @@ -1,6 +1,6 @@ name: drift description: Drift is a reactive library to store relational data in Dart and Flutter applications. -version: 2.2.0 +version: 2.3.0-dev repository: https://github.com/simolus3/drift homepage: https://drift.simonbinder.eu/ issue_tracker: https://github.com/simolus3/drift/issues diff --git a/drift/test/generated/custom_tables.g.dart b/drift/test/generated/custom_tables.g.dart index 0c9abdf0..ffce932f 100644 --- a/drift/test/generated/custom_tables.g.dart +++ b/drift/test/generated/custom_tables.g.dart @@ -5,6 +5,15 @@ part of 'custom_tables.dart'; abstract class _$CustomTablesDb extends GeneratedDatabase { _$CustomTablesDb(QueryExecutor e) : super(e); _$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c); + Future writeConfig({required String key, required String value}) { + return customInsert( + 'REPLACE INTO config (config_key, config_value) VALUES (?1, ?2)', + variables: [Variable(key), Variable(value)], + updates: {}, + updateKind: UpdateKind.delete, + ); + } + @override DriftDatabaseOptions get options => const DriftDatabaseOptions(storeDateTimeAsText: true); diff --git a/drift/test/generated/todos.dart b/drift/test/generated/todos.dart index 0168dbf6..02d46fc7 100644 --- a/drift/test/generated/todos.dart +++ b/drift/test/generated/todos.dart @@ -135,8 +135,18 @@ class CustomConverter extends TypeConverter { } class CustomJsonConverter extends CustomConverter - with JsonTypeConverter { + with JsonTypeConverter2 { const CustomJsonConverter(); + + @override + MyCustomObject fromJson(Map json) { + return MyCustomObject(json['data'] as String); + } + + @override + Map toJson(MyCustomObject value) { + return {'data': value.data}; + } } abstract class CategoryTodoCountView extends View { diff --git a/drift/test/generated/todos.g.dart b/drift/test/generated/todos.g.dart index 19da24a5..e01a60a6 100644 --- a/drift/test/generated/todos.g.dart +++ b/drift/test/generated/todos.g.dart @@ -470,11 +470,11 @@ return PureDefaultsCompanion(txt: txt == null && nullToAbsent ? const Value.abse } factory PureDefault.fromJson(Map json, {ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; -return PureDefault(txt: $PureDefaultsTable.$convertertxt.fromJson(serializer.fromJson(json['txt'])),);} +return PureDefault(txt: $PureDefaultsTable.$convertertxt.fromJson(serializer.fromJson>(json['txt'])),);} factory PureDefault.fromJsonString(String encodedJson, {ValueSerializer? serializer}) => PureDefault.fromJson(DataClass.parseJson(encodedJson) as Map, serializer: serializer);@override Map toJson({ValueSerializer? serializer}) { serializer ??= driftRuntimeOptions.defaultSerializer; return { -'txt': serializer.toJson($PureDefaultsTable.$convertertxt.toJson(txt)),};}PureDefault copyWith({Value txt = const Value.absent()}) => PureDefault(txt: txt.present ? txt.value : this.txt,);@override +'txt': serializer.toJson?>($PureDefaultsTable.$convertertxt.toJson(txt)),};}PureDefault copyWith({Value txt = const Value.absent()}) => PureDefault(txt: txt.present ? txt.value : this.txt,);@override String toString() {return (StringBuffer('PureDefault(')..write('txt: $txt')..write(')')).toString();} @override int get hashCode => txt.hashCode;@override @@ -523,7 +523,7 @@ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';return PureDe } @override $PureDefaultsTable createAlias(String alias) { -return $PureDefaultsTable(attachedDatabase, alias);}static JsonTypeConverter $convertertxt = const CustomJsonConverter();static JsonTypeConverter $convertertxtn = JsonTypeConverter.asNullable($convertertxt);}class CategoryTodoCountViewData extends DataClass { +return $PureDefaultsTable(attachedDatabase, alias);}static JsonTypeConverter $convertertxt = const CustomJsonConverter();static JsonTypeConverter $convertertxtn = JsonTypeConverter2.asNullable($convertertxt);}class CategoryTodoCountViewData extends DataClass { final String? description; final int? itemCount; const CategoryTodoCountViewData({this.description, this.itemCount});factory CategoryTodoCountViewData.fromJson(Map json, {ValueSerializer? serializer}) { diff --git a/drift/test/serialization_test.dart b/drift/test/serialization_test.dart index c04b00b9..f3b8f18d 100644 --- a/drift/test/serialization_test.dart +++ b/drift/test/serialization_test.dart @@ -82,8 +82,12 @@ void main() { }); test('applies json type converter', () { - expect(PureDefault(txt: MyCustomObject('foo')).toJson(), {'txt': 'foo'}); - expect(PureDefault.fromJson({'txt': 'foo'}), + const serialized = { + 'txt': {'data': 'foo'} + }; + + expect(PureDefault(txt: MyCustomObject('foo')).toJson(), serialized); + expect(PureDefault.fromJson(serialized), PureDefault(txt: MyCustomObject('foo'))); }); diff --git a/drift_dev/lib/src/analysis/resolver/dart/helper.dart b/drift_dev/lib/src/analysis/resolver/dart/helper.dart index 335e0593..b40dcec2 100644 --- a/drift_dev/lib/src/analysis/resolver/dart/helper.dart +++ b/drift_dev/lib/src/analysis/resolver/dart/helper.dart @@ -45,7 +45,7 @@ class KnownDriftTypes { (exportNamespace.get('View') as InterfaceElement).thisType, (exportNamespace.get('TableInfo') as InterfaceElement).thisType, exportNamespace.get('TypeConverter') as InterfaceElement, - exportNamespace.get('JsonTypeConverter') as InterfaceElement, + exportNamespace.get('JsonTypeConverter2') as InterfaceElement, dbElement.defaultInstantiation, daoElement.defaultInstantiation, ); @@ -59,17 +59,14 @@ class KnownDriftTypes { return type.asInstanceOf(typeConverter); } - bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) { - final jsonConverterType = jsonTypeConverter.instantiate( - typeArguments: [ - context.typeProvider.dynamicType, - context.typeProvider.dynamicType - ], - nullabilitySuffix: NullabilitySuffix.none, - ); - - return type != null && - context.typeSystem.isSubtypeOf(type, jsonConverterType); + /// Converts the given Dart [type] into an instantiation of the + /// `JsonTypeConverter` class from drift. + /// + /// Returns `null` if [type] is not a subtype of `TypeConverter`. + InterfaceType? asJsonTypeConverter(DartType? type) { + final converter = helperLibrary.exportNamespace.get('JsonTypeConverter2') + as InterfaceElement; + return type?.asInstanceOf(converter); } static Future resolve(DriftAnalysisDriver driver) async { diff --git a/drift_dev/lib/src/analysis/resolver/shared/dart_types.dart b/drift_dev/lib/src/analysis/resolver/shared/dart_types.dart index 39aa2402..805aff6f 100644 --- a/drift_dev/lib/src/analysis/resolver/shared/dart_types.dart +++ b/drift_dev/lib/src/analysis/resolver/shared/dart_types.dart @@ -184,7 +184,8 @@ AppliedTypeConverter? readTypeConverter( final dartTypeNullable = typeSystem.isNullable(dartType); final sqlTypeNullable = typeSystem.isNullable(sqlType); - final appliesToJsonToo = helper.isJsonAwareTypeConverter(staticType, library); + final asJsonConverter = helper.asJsonTypeConverter(staticType); + final appliesToJsonToo = asJsonConverter != null; // Make the type converter support nulls by just mapping null to null if this // converter is otherwise non-nullable in both directions. @@ -213,10 +214,10 @@ AppliedTypeConverter? readTypeConverter( return AppliedTypeConverter( expression: AnnotatedDartCode.ast(dartExpression), dartType: dartType, + jsonType: appliesToJsonToo ? asJsonConverter.typeArguments[2] : null, sqlType: columnType, dartTypeIsNullable: dartTypeNullable, sqlTypeIsNullable: sqlTypeNullable, - alsoAppliesToJsonConversion: appliesToJsonToo, ); } @@ -248,6 +249,7 @@ AppliedTypeConverter readEnumConverter( return AppliedTypeConverter( expression: expression, dartType: enumType, + jsonType: null, sqlType: DriftSqlType.int, dartTypeIsNullable: false, sqlTypeIsNullable: false, diff --git a/drift_dev/lib/src/analysis/results/column.dart b/drift_dev/lib/src/analysis/results/column.dart index 41e8195a..2a35e5b0 100644 --- a/drift_dev/lib/src/analysis/results/column.dart +++ b/drift_dev/lib/src/analysis/results/column.dart @@ -118,6 +118,10 @@ class AppliedTypeConverter { final AnnotatedDartCode expression; final DartType dartType; + + /// The JSON type representation of this column, if this type converter + /// applies to the JSON serialization as well. + final DartType? jsonType; final DriftSqlType sqlType; late DriftColumn owningColumn; @@ -134,7 +138,7 @@ class AppliedTypeConverter { /// Whether this type converter should also be used in the generated JSON /// serialization. - final bool alsoAppliesToJsonConversion; + bool get alsoAppliesToJsonConversion => jsonType != null; /// Whether this type converter can be skipped for `null` values. /// @@ -170,7 +174,7 @@ class AppliedTypeConverter { required this.sqlType, required this.dartTypeIsNullable, required this.sqlTypeIsNullable, - this.alsoAppliesToJsonConversion = false, + required this.jsonType, }); } diff --git a/drift_dev/lib/src/analysis/serializer.dart b/drift_dev/lib/src/analysis/serializer.dart index abffac17..6362db23 100644 --- a/drift_dev/lib/src/analysis/serializer.dart +++ b/drift_dev/lib/src/analysis/serializer.dart @@ -229,10 +229,10 @@ class ElementSerializer { return { 'expression': converter.expression.toJson(), 'dart_type': converter.dartType.accept(const _DartTypeSerializer()), + 'json_type': converter.jsonType?.accept(const _DartTypeSerializer()), 'sql_type': converter.sqlType.name, 'dart_type_is_nullable': converter.dartTypeIsNullable, 'sql_type_is_nullable': converter.sqlTypeIsNullable, - 'also_applies_to_json_conversion': converter.alsoAppliesToJsonConversion, }; } @@ -618,11 +618,12 @@ class ElementDeserializer { return AppliedTypeConverter( expression: AnnotatedDartCode.fromJson(json['expression'] as Map), dartType: await _readDartType(json['dart_type'] as Map), + jsonType: json['json_type'] != null + ? await _readDartType(json['json_type'] as Map) + : null, sqlType: DriftSqlType.values.byName(json['sql_type'] as String), dartTypeIsNullable: json['dart_type_is_nullable'] as bool, sqlTypeIsNullable: json['sql_type_is_nullable'] as bool, - alsoAppliesToJsonConversion: - json['also_applies_to_json_conversion'] as bool, ); } diff --git a/drift_dev/lib/src/analyzer/dart_types.dart b/drift_dev/lib/src/analyzer/dart_types.dart index f3647dfb..bff4315d 100644 --- a/drift_dev/lib/src/analyzer/dart_types.dart +++ b/drift_dev/lib/src/analyzer/dart_types.dart @@ -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); @@ -178,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' + ? 'JsonTypeConverter2.asNullable' : 'NullAwareTypeConverter.wrap'; reportError('This column is nullable, but the type converter has a non-' @@ -195,6 +198,7 @@ UsedTypeConverter? readTypeConverter( expression: dartExpression.toSource(), dartType: resolvedDartType ?? DriftDartType.of(dartType), sqlType: sqlType, + jsonType: jsonType, dartTypeIsNullable: dartTypeNullable, sqlTypeIsNullable: sqlTypeNullable, alsoAppliesToJsonConversion: appliesToJsonToo, diff --git a/drift_dev/lib/src/analyzer/helper.dart b/drift_dev/lib/src/analyzer/helper.dart index 5b563dd7..fc956746 100644 --- a/drift_dev/lib/src/analyzer/helper.dart +++ b/drift_dev/lib/src/analyzer/helper.dart @@ -26,13 +26,24 @@ class HelperLibrary { return type.asInstanceOf(converter); } + /// Converts the given Dart [type] into an instantiation of the + /// `JsonTypeConverter` class from drift. + /// + /// Returns `null` if [type] is not a subtype of `TypeConverter`. + InterfaceType? asJsonTypeConverter(DartType type) { + final converter = helperLibrary.exportNamespace.get('JsonTypeConverter2') + as InterfaceElement; + return type.asInstanceOf(converter); + } + bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) { - final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter') + final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter2') as InterfaceElement; final jsonConverterType = jsonMixin.instantiate( typeArguments: [ context.typeProvider.dynamicType, - context.typeProvider.dynamicType + context.typeProvider.dynamicType, + context.typeProvider.dynamicType, ], nullabilitySuffix: NullabilitySuffix.none, ); diff --git a/drift_dev/lib/src/model/types.dart b/drift_dev/lib/src/model/types.dart index b9672154..097ed43d 100644 --- a/drift_dev/lib/src/model/types.dart +++ b/drift_dev/lib/src/model/types.dart @@ -136,6 +136,19 @@ extension OperationOnTypes on HasType { return variableTypeCode(); } + + /// The Dart type that matches the values of this column when serialized to + /// JSON. + 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 dartTypeNames = { diff --git a/drift_dev/lib/src/model/used_type_converter.dart b/drift_dev/lib/src/model/used_type_converter.dart index ea91a24a..6c1573fb 100644 --- a/drift_dev/lib/src/model/used_type_converter.dart +++ b/drift_dev/lib/src/model/used_type_converter.dart @@ -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 'JsonTypeConverter2<${dartTypeCode(makeNullable)}, $sqlDartType, $jsonDartType>'; + } + return 'TypeConverter<${dartTypeCode(makeNullable)}, $sqlDartType>'; } } diff --git a/drift_dev/lib/src/writer/tables/data_class_writer.dart b/drift_dev/lib/src/writer/tables/data_class_writer.dart index 859409a9..afd59bfb 100644 --- a/drift_dev/lib/src/writer/tables/data_class_writer.dart +++ b/drift_dev/lib/src/writer/tables/data_class_writer.dart @@ -20,7 +20,22 @@ class DataClassWriter { String get serializerType => 'ValueSerializer?'; String _columnType(DriftColumn column) { - return _emitter.dartCode(_emitter.writer.dartType(column)); + return _emitter.dartCode(_emitter.dartType(column)); + } + + String _jsonType(DriftColumn column) { + final converter = column.typeConverter; + if (converter != null && converter.alsoAppliesToJsonConversion) { + final nullable = converter.canBeSkippedForNulls && column.nullable; + final code = AnnotatedDartCode([ + ...AnnotatedDartCode.type(converter.jsonType!).elements, + if (nullable) '?', + ]); + + return _emitter.dartCode(code); + } else { + return _columnType(column); + } } String _converter(DriftColumn column) { @@ -116,7 +131,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 = _converter(column); deserialized = '$converterField.fromJson($fromConverter)'; @@ -158,7 +173,7 @@ class DataClassWriter { if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) { final converterField = _converter(column); value = '$converterField.toJson($value)'; - dartType = column.innerColumnType(nullable: true); + dartType = _jsonType(column); } _buffer.write("'$name': serializer.toJson<$dartType>($value),"); diff --git a/drift_dev/lib/src/writer/tables/table_writer.dart b/drift_dev/lib/src/writer/tables/table_writer.dart index 187e0e27..d1d12143 100644 --- a/drift_dev/lib/src/writer/tables/table_writer.dart +++ b/drift_dev/lib/src/writer/tables/table_writer.dart @@ -326,7 +326,7 @@ class TableWriter extends TableOrViewWriter { emitter.writer.converterType(converter, makeNullable: true)); final wrap = converter.alsoAppliesToJsonConversion - ? 'JsonTypeConverter.asNullable' + ? 'JsonTypeConverter2.asNullable' : 'NullAwareTypeConverter.wrap'; final code = '$wrap(${converter.fieldName})'; diff --git a/drift_dev/pubspec.yaml b/drift_dev/pubspec.yaml index 719344cd..27334a70 100644 --- a/drift_dev/pubspec.yaml +++ b/drift_dev/pubspec.yaml @@ -1,6 +1,6 @@ name: drift_dev description: Dev-dependency for users of drift. Contains a the generator and development tools. -version: 2.2.0+1 +version: 2.3.0-dev repository: https://github.com/simolus3/drift homepage: https://drift.simonbinder.eu/ issue_tracker: https://github.com/simolus3/drift/issues @@ -25,7 +25,7 @@ dependencies: io: ^1.0.3 # Drift-specific analysis and apis - drift: '>=2.0.0 <2.3.0' + drift: '>=2.3.0 <2.4.0' sqlite3: '>=0.1.6 <2.0.0' sqlparser: ^0.23.3