mirror of https://github.com/AMT-Cheif/drift.git
Document json type converters
This commit is contained in:
parent
5f6beb76ca
commit
e607ffe183
|
@ -0,0 +1,55 @@
|
|||
// #docregion start
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:json_annotation/json_annotation.dart' as j;
|
||||
|
||||
part 'converters.g.dart';
|
||||
|
||||
@j.JsonSerializable()
|
||||
class Preferences {
|
||||
bool receiveEmails;
|
||||
String selectedTheme;
|
||||
|
||||
Preferences(this.receiveEmails, this.selectedTheme);
|
||||
|
||||
factory Preferences.fromJson(Map<String, dynamic> json) =>
|
||||
_$PreferencesFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$PreferencesToJson(this);
|
||||
}
|
||||
// #enddocregion start
|
||||
|
||||
// #docregion converter
|
||||
// stores preferences as strings
|
||||
class PreferenceConverter extends TypeConverter<Preferences, String>
|
||||
with JsonTypeConverter<Preferences, String> {
|
||||
const PreferenceConverter();
|
||||
@override
|
||||
Preferences? mapToDart(String? fromDb) {
|
||||
if (fromDb == null) {
|
||||
return null;
|
||||
}
|
||||
return Preferences.fromJson(json.decode(fromDb) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
@override
|
||||
String? mapToSql(Preferences? value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return json.encode(value.toJson());
|
||||
}
|
||||
}
|
||||
// #enddocregion converter
|
||||
|
||||
// #docregion table
|
||||
class Users extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text()();
|
||||
|
||||
TextColumn get preferences =>
|
||||
text().map(const PreferenceConverter()).nullable()();
|
||||
}
|
||||
// #enddocregion table
|
|
@ -8,70 +8,25 @@ template: layouts/docs/single
|
|||
---
|
||||
|
||||
Drift supports a variety of types out of the box, but sometimes you need to store more complex data.
|
||||
You can achieve this by using `TypeConverters`. In this example, we'll use the the
|
||||
You can achieve this by using `TypeConverters`. In this example, we'll use the the
|
||||
[json_serializable](https://pub.dev/packages/json_annotation) package to store a custom object in a
|
||||
text column. Drift supports any Dart type for which you provide a `TypeConverter`, we're using that
|
||||
package here to make the example simpler.
|
||||
|
||||
{% assign dart = 'package:moor_documentation/snippets/type_converters/converters.dart.excerpt.json' | readString | json_decode %}
|
||||
|
||||
## Using converters in Dart
|
||||
|
||||
```dart
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart' as j;
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
|
||||
@j.JsonSerializable()
|
||||
class Preferences {
|
||||
bool receiveEmails;
|
||||
String selectedTheme;
|
||||
|
||||
Preferences(this.receiveEmails, this.selectedTheme);
|
||||
|
||||
factory Preferences.fromJson(Map<String, dynamic> json) =>
|
||||
_$PreferencesFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$PreferencesToJson(this);
|
||||
}
|
||||
```
|
||||
{% include "blocks/snippet" snippets = dart name = 'start' %}
|
||||
|
||||
Next, we have to tell drift how to store a `Preferences` object in the database. We write
|
||||
a `TypeConverter` for that:
|
||||
```dart
|
||||
// stores preferences as strings
|
||||
class PreferenceConverter extends TypeConverter<Preferences, String> {
|
||||
const PreferenceConverter();
|
||||
@override
|
||||
Preferences? mapToDart(String? fromDb) {
|
||||
if (fromDb == null) {
|
||||
return null;
|
||||
}
|
||||
return Preferences.fromJson(json.decode(fromDb) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
@override
|
||||
String? mapToSql(Preferences? value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return json.encode(value.toJson());
|
||||
}
|
||||
}
|
||||
```
|
||||
{% include "blocks/snippet" snippets = dart name = 'converter' %}
|
||||
|
||||
Finally, we can use that converter in a table declaration:
|
||||
```dart
|
||||
class Users extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get name => text()();
|
||||
|
||||
TextColumn get preferences =>
|
||||
text().map(const PreferenceConverter()).nullable()();
|
||||
}
|
||||
```
|
||||
{% include "blocks/snippet" snippets = dart name = 'table' %}
|
||||
|
||||
The generated `User` class will then have a `preferences` column of type
|
||||
`Preferences`. Drift will automatically take care of storing and loading
|
||||
|
@ -158,3 +113,16 @@ CREATE TABLE tasks (
|
|||
```
|
||||
|
||||
Of course, the warning about automatic enum converters also applies to drift files.
|
||||
|
||||
## Type converters and json serialization
|
||||
|
||||
By default, type converters only apply to the conversion from Dart to the database. They don't impact how
|
||||
values are serialized to and from JSON.
|
||||
If you want to apply the same conversion to JSON as well, make your type converter mix-in the
|
||||
`JsonTypeConverter` class.
|
||||
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 `<MyObject, int>` 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)
|
||||
and pass it to the serialization methods.
|
||||
|
|
|
@ -18,6 +18,8 @@ dev_dependencies:
|
|||
hosted: https://simonbinder.eu
|
||||
version: ^0.2.5
|
||||
linkcheck: ^2.0.19
|
||||
json_annotation: ^4.4.0
|
||||
json_serializable: ^6.1.6
|
||||
shelf: ^1.2.0
|
||||
shelf_static: ^1.1.0
|
||||
code_snippets:
|
||||
|
|
|
@ -6,6 +6,10 @@ part of 'sql_types.dart';
|
|||
/// Dart currently supports [DateTime], [double], [int], [Uint8List], [bool]
|
||||
/// and [String] for [S].
|
||||
///
|
||||
/// Using a type converter does impact the way drift serializes data classes to
|
||||
/// JSON by default. To control that, use a [JsonTypeConverter] or a custom
|
||||
/// [ValueSerializer].
|
||||
///
|
||||
/// Also see [BuildGeneralColumn.map] for details.
|
||||
abstract class TypeConverter<D, S> {
|
||||
/// Empty constant constructor so that subclasses can have a constant
|
||||
|
@ -22,6 +26,12 @@ abstract class TypeConverter<D, S> {
|
|||
|
||||
/// 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 to conversion from and to json.
|
||||
mixin JsonTypeConverter<D, S> on TypeConverter<D, S> {
|
||||
/// Map a value from the Data class to json.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue