mirror of https://github.com/AMT-Cheif/drift.git
Merge branch 'develop' into modular-generation
This commit is contained in:
commit
b16b5ad2c2
|
@ -10,7 +10,6 @@ extension Expressions on MyDatabase {
|
||||||
return (select(categories)..where((row) => hasNoTodo)).get();
|
return (select(categories)..where((row) => hasNoTodo)).get();
|
||||||
}
|
}
|
||||||
// #enddocregion emptyCategories
|
// #enddocregion emptyCategories
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #docregion bitwise
|
// #docregion bitwise
|
||||||
|
|
|
@ -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
|
You can also override the `toJson` and `fromJson` methods to customize serialization as long as the types
|
||||||
stay the compatible.
|
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
|
If the JSON type you want to serialize to is different to the SQL type you're
|
||||||
want to map to a string in JSON), you'll have to write a custom [`ValueSerializer`](https://drift.simonbinder.eu/api/drift/valueserializer-class)
|
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<String, Object?>`. Here, simply
|
||||||
|
add the `JsonTypeConverter2<MyObject, String, Map<String, Object?>>` 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.
|
and pass it to the serialization methods.
|
||||||
|
|
|
@ -167,7 +167,7 @@ void main() {
|
||||||
|
|
||||||
final db = WebDatabase.withStorage(DriftWebStorage.indexedDb('worker',
|
final db = WebDatabase.withStorage(DriftWebStorage.indexedDb('worker',
|
||||||
migrateFromLocalStorage: false, inWebWorker: true));
|
migrateFromLocalStorage: false, inWebWorker: true));
|
||||||
final server = DriftServer(DatabaseConnection.fromExecutor(db));
|
final server = DriftServer(DatabaseConnection(db));
|
||||||
|
|
||||||
self.onConnect.listen((event) {
|
self.onConnect.listen((event) {
|
||||||
final msg = event as MessageEvent;
|
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.
|
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).
|
If you're running into any issues with the new backend, please post them [here](https://github.com/simolus3/sqlite3.dart/issues).
|
||||||
|
|
|
@ -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
|
## 2.2.0
|
||||||
|
|
||||||
- Always escape column names, avoiding the costs of using a regular expression
|
- Always escape column names, avoiding the costs of using a regular expression
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// This field is analyzed by drift_dev to easily obtain common types.
|
// 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 'runtime/query_builder/query_builder.dart' show TableInfo;
|
||||||
|
|
||||||
export 'dsl/dsl.dart' show Table, View, DriftDatabase, DriftAccessor;
|
export 'dsl/dsl.dart' show Table, View, DriftDatabase, DriftAccessor;
|
||||||
|
|
|
@ -29,22 +29,21 @@ abstract class TypeConverter<D, S> {
|
||||||
/// A mixin for [TypeConverter]s that should also apply to drift's builtin
|
/// A mixin for [TypeConverter]s that should also apply to drift's builtin
|
||||||
/// JSON serialization of data classes.
|
/// JSON serialization of data classes.
|
||||||
///
|
///
|
||||||
/// By default, a [TypeConverter] only applies to the serialization from Dart
|
/// Unlike the old [JsonTypeConverter] mixin, this more general mixin allows
|
||||||
/// to SQL (and vice-versa).
|
/// using a different type when serializing to JSON ([J]) than the type used in
|
||||||
/// When a [BuildGeneralColumn.map] column (or a `MAPPED BY` constraint in
|
/// SQL ([S]).
|
||||||
/// `.drift` files) refers to a type converter that inherits from
|
/// For the cases where the JSON serialization and the mapping to SQL use the
|
||||||
/// [JsonTypeConverter], it will also be used for the conversion from and to
|
/// same types, it may be more convenient to mix-in [JsonTypeConverter] instead.
|
||||||
/// JSON.
|
mixin JsonTypeConverter2<D, S, J> on TypeConverter<D, S> {
|
||||||
mixin JsonTypeConverter<D, S> on TypeConverter<D, S> {
|
|
||||||
/// Map a value from the Data class to json.
|
/// Map a value from the Data class to json.
|
||||||
///
|
///
|
||||||
/// Defaults to doing the same conversion as for Dart -> SQL, [toSql].
|
/// 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.
|
/// Map a value from json to something understood by the data class.
|
||||||
///
|
///
|
||||||
/// Defaults to doing the same conversion as for SQL -> Dart, [toSql].
|
/// 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
|
/// Wraps an [inner] type converter that only considers non-nullable values
|
||||||
/// as a type converter that handles null values too.
|
/// as a type converter that handles null values too.
|
||||||
|
@ -52,12 +51,35 @@ mixin JsonTypeConverter<D, S> on TypeConverter<D, S> {
|
||||||
/// The returned type converter will use the [inner] type converter for non-
|
/// The returned type converter will use the [inner] type converter for non-
|
||||||
/// null values. Further, `null` is mapped to `null` in both directions (from
|
/// null values. Further, `null` is mapped to `null` in both directions (from
|
||||||
/// Dart to SQL and vice-versa).
|
/// Dart to SQL and vice-versa).
|
||||||
static JsonTypeConverter<D?, S?> asNullable<D, S extends Object>(
|
static JsonTypeConverter2<D?, S?, J?>
|
||||||
TypeConverter<D, S> inner) {
|
asNullable<D, S extends Object, J extends Object>(
|
||||||
|
JsonTypeConverter2<D, S, J> inner) {
|
||||||
return _NullWrappingTypeConverterWithJson(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<D, S> implements JsonTypeConverter2<D, S, S> {
|
||||||
|
@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
|
/// Implementation for an enum to int converter that uses the index of the enum
|
||||||
/// as the value stored in the database.
|
/// as the value stored in the database.
|
||||||
class EnumIndexConverter<T extends Enum> extends TypeConverter<T, int> {
|
class EnumIndexConverter<T extends Enum> extends TypeConverter<T, int> {
|
||||||
|
@ -150,9 +172,10 @@ class _NullWrappingTypeConverter<D, S extends Object>
|
||||||
S requireToSql(D value) => _inner.toSql(value);
|
S requireToSql(D value) => _inner.toSql(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NullWrappingTypeConverterWithJson<D, S extends Object>
|
class _NullWrappingTypeConverterWithJson<D, S extends Object, J extends Object>
|
||||||
extends NullAwareTypeConverter<D, S> with JsonTypeConverter<D?, S?> {
|
extends NullAwareTypeConverter<D, S>
|
||||||
final TypeConverter<D, S> _inner;
|
implements JsonTypeConverter2<D?, S?, J?> {
|
||||||
|
final JsonTypeConverter2<D, S, J> _inner;
|
||||||
|
|
||||||
const _NullWrappingTypeConverterWithJson(this._inner);
|
const _NullWrappingTypeConverterWithJson(this._inner);
|
||||||
|
|
||||||
|
@ -161,4 +184,18 @@ class _NullWrappingTypeConverterWithJson<D, S extends Object>
|
||||||
|
|
||||||
@override
|
@override
|
||||||
S requireToSql(D value) => _inner.toSql(value);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: drift
|
name: drift
|
||||||
description: Drift is a reactive library to store relational data in Dart and Flutter applications.
|
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
|
repository: https://github.com/simolus3/drift
|
||||||
homepage: https://drift.simonbinder.eu/
|
homepage: https://drift.simonbinder.eu/
|
||||||
issue_tracker: https://github.com/simolus3/drift/issues
|
issue_tracker: https://github.com/simolus3/drift/issues
|
||||||
|
|
|
@ -5,6 +5,15 @@ part of 'custom_tables.dart';
|
||||||
abstract class _$CustomTablesDb extends GeneratedDatabase {
|
abstract class _$CustomTablesDb extends GeneratedDatabase {
|
||||||
_$CustomTablesDb(QueryExecutor e) : super(e);
|
_$CustomTablesDb(QueryExecutor e) : super(e);
|
||||||
_$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c);
|
_$CustomTablesDb.connect(DatabaseConnection c) : super.connect(c);
|
||||||
|
Future<int> writeConfig({required String key, required String value}) {
|
||||||
|
return customInsert(
|
||||||
|
'REPLACE INTO config (config_key, config_value) VALUES (?1, ?2)',
|
||||||
|
variables: [Variable<String>(key), Variable<String>(value)],
|
||||||
|
updates: {},
|
||||||
|
updateKind: UpdateKind.delete,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DriftDatabaseOptions get options =>
|
DriftDatabaseOptions get options =>
|
||||||
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
||||||
|
|
|
@ -135,8 +135,18 @@ class CustomConverter extends TypeConverter<MyCustomObject, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomJsonConverter extends CustomConverter
|
class CustomJsonConverter extends CustomConverter
|
||||||
with JsonTypeConverter<MyCustomObject, String> {
|
with JsonTypeConverter2<MyCustomObject, String, Map> {
|
||||||
const CustomJsonConverter();
|
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 {
|
abstract class CategoryTodoCountView extends View {
|
||||||
|
|
|
@ -470,11 +470,11 @@ return PureDefaultsCompanion(txt: txt == null && nullToAbsent ? const Value.abse
|
||||||
}
|
}
|
||||||
factory PureDefault.fromJson(Map<String, dynamic> json, {ValueSerializer? serializer}) {
|
factory PureDefault.fromJson(Map<String, dynamic> json, {ValueSerializer? serializer}) {
|
||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return PureDefault(txt: $PureDefaultsTable.$convertertxt.fromJson(serializer.fromJson<String?>(json['txt'])),);}
|
return PureDefault(txt: $PureDefaultsTable.$convertertxt.fromJson(serializer.fromJson<Map<dynamic, dynamic>>(json['txt'])),);}
|
||||||
factory PureDefault.fromJsonString(String encodedJson, {ValueSerializer? serializer}) => PureDefault.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>, serializer: serializer);@override Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
factory PureDefault.fromJsonString(String encodedJson, {ValueSerializer? serializer}) => PureDefault.fromJson(DataClass.parseJson(encodedJson) as Map<String, dynamic>, serializer: serializer);@override Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return <String, dynamic>{
|
return <String, dynamic>{
|
||||||
'txt': serializer.toJson<String?>($PureDefaultsTable.$convertertxt.toJson(txt)),};}PureDefault copyWith({Value<MyCustomObject?> txt = const Value.absent()}) => PureDefault(txt: txt.present ? txt.value : this.txt,);@override
|
'txt': serializer.toJson<Map<dynamic, dynamic>?>($PureDefaultsTable.$convertertxt.toJson(txt)),};}PureDefault copyWith({Value<MyCustomObject?> txt = const Value.absent()}) => PureDefault(txt: txt.present ? txt.value : this.txt,);@override
|
||||||
String toString() {return (StringBuffer('PureDefault(')..write('txt: $txt')..write(')')).toString();}
|
String toString() {return (StringBuffer('PureDefault(')..write('txt: $txt')..write(')')).toString();}
|
||||||
@override
|
@override
|
||||||
int get hashCode => txt.hashCode;@override
|
int get hashCode => txt.hashCode;@override
|
||||||
|
@ -523,7 +523,7 @@ final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';return PureDe
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
$PureDefaultsTable createAlias(String alias) {
|
$PureDefaultsTable createAlias(String alias) {
|
||||||
return $PureDefaultsTable(attachedDatabase, alias);}static JsonTypeConverter<MyCustomObject,String> $convertertxt = const CustomJsonConverter();static JsonTypeConverter<MyCustomObject?,String> $convertertxtn = JsonTypeConverter.asNullable($convertertxt);}class CategoryTodoCountViewData extends DataClass {
|
return $PureDefaultsTable(attachedDatabase, alias);}static JsonTypeConverter<MyCustomObject,String> $convertertxt = const CustomJsonConverter();static JsonTypeConverter<MyCustomObject?,String> $convertertxtn = JsonTypeConverter2.asNullable($convertertxt);}class CategoryTodoCountViewData extends DataClass {
|
||||||
final String? description;
|
final String? description;
|
||||||
final int? itemCount;
|
final int? itemCount;
|
||||||
const CategoryTodoCountViewData({this.description, this.itemCount});factory CategoryTodoCountViewData.fromJson(Map<String, dynamic> json, {ValueSerializer? serializer}) {
|
const CategoryTodoCountViewData({this.description, this.itemCount});factory CategoryTodoCountViewData.fromJson(Map<String, dynamic> json, {ValueSerializer? serializer}) {
|
||||||
|
|
|
@ -82,8 +82,12 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('applies json type converter', () {
|
test('applies json type converter', () {
|
||||||
expect(PureDefault(txt: MyCustomObject('foo')).toJson(), {'txt': 'foo'});
|
const serialized = {
|
||||||
expect(PureDefault.fromJson({'txt': 'foo'}),
|
'txt': {'data': 'foo'}
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(PureDefault(txt: MyCustomObject('foo')).toJson(), serialized);
|
||||||
|
expect(PureDefault.fromJson(serialized),
|
||||||
PureDefault(txt: MyCustomObject('foo')));
|
PureDefault(txt: MyCustomObject('foo')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class KnownDriftTypes {
|
||||||
(exportNamespace.get('View') as InterfaceElement).thisType,
|
(exportNamespace.get('View') as InterfaceElement).thisType,
|
||||||
(exportNamespace.get('TableInfo') as InterfaceElement).thisType,
|
(exportNamespace.get('TableInfo') as InterfaceElement).thisType,
|
||||||
exportNamespace.get('TypeConverter') as InterfaceElement,
|
exportNamespace.get('TypeConverter') as InterfaceElement,
|
||||||
exportNamespace.get('JsonTypeConverter') as InterfaceElement,
|
exportNamespace.get('JsonTypeConverter2') as InterfaceElement,
|
||||||
dbElement.defaultInstantiation,
|
dbElement.defaultInstantiation,
|
||||||
daoElement.defaultInstantiation,
|
daoElement.defaultInstantiation,
|
||||||
);
|
);
|
||||||
|
@ -59,17 +59,14 @@ class KnownDriftTypes {
|
||||||
return type.asInstanceOf(typeConverter);
|
return type.asInstanceOf(typeConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) {
|
/// Converts the given Dart [type] into an instantiation of the
|
||||||
final jsonConverterType = jsonTypeConverter.instantiate(
|
/// `JsonTypeConverter` class from drift.
|
||||||
typeArguments: [
|
///
|
||||||
context.typeProvider.dynamicType,
|
/// Returns `null` if [type] is not a subtype of `TypeConverter`.
|
||||||
context.typeProvider.dynamicType
|
InterfaceType? asJsonTypeConverter(DartType? type) {
|
||||||
],
|
final converter = helperLibrary.exportNamespace.get('JsonTypeConverter2')
|
||||||
nullabilitySuffix: NullabilitySuffix.none,
|
as InterfaceElement;
|
||||||
);
|
return type?.asInstanceOf(converter);
|
||||||
|
|
||||||
return type != null &&
|
|
||||||
context.typeSystem.isSubtypeOf(type, jsonConverterType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<KnownDriftTypes> resolve(DriftAnalysisDriver driver) async {
|
static Future<KnownDriftTypes> resolve(DriftAnalysisDriver driver) async {
|
||||||
|
|
|
@ -184,7 +184,8 @@ AppliedTypeConverter? readTypeConverter(
|
||||||
final dartTypeNullable = typeSystem.isNullable(dartType);
|
final dartTypeNullable = typeSystem.isNullable(dartType);
|
||||||
final sqlTypeNullable = typeSystem.isNullable(sqlType);
|
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
|
// Make the type converter support nulls by just mapping null to null if this
|
||||||
// converter is otherwise non-nullable in both directions.
|
// converter is otherwise non-nullable in both directions.
|
||||||
|
@ -213,10 +214,10 @@ AppliedTypeConverter? readTypeConverter(
|
||||||
return AppliedTypeConverter(
|
return AppliedTypeConverter(
|
||||||
expression: AnnotatedDartCode.ast(dartExpression),
|
expression: AnnotatedDartCode.ast(dartExpression),
|
||||||
dartType: dartType,
|
dartType: dartType,
|
||||||
|
jsonType: appliesToJsonToo ? asJsonConverter.typeArguments[2] : null,
|
||||||
sqlType: columnType,
|
sqlType: columnType,
|
||||||
dartTypeIsNullable: dartTypeNullable,
|
dartTypeIsNullable: dartTypeNullable,
|
||||||
sqlTypeIsNullable: sqlTypeNullable,
|
sqlTypeIsNullable: sqlTypeNullable,
|
||||||
alsoAppliesToJsonConversion: appliesToJsonToo,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,6 +249,7 @@ AppliedTypeConverter readEnumConverter(
|
||||||
return AppliedTypeConverter(
|
return AppliedTypeConverter(
|
||||||
expression: expression,
|
expression: expression,
|
||||||
dartType: enumType,
|
dartType: enumType,
|
||||||
|
jsonType: null,
|
||||||
sqlType: DriftSqlType.int,
|
sqlType: DriftSqlType.int,
|
||||||
dartTypeIsNullable: false,
|
dartTypeIsNullable: false,
|
||||||
sqlTypeIsNullable: false,
|
sqlTypeIsNullable: false,
|
||||||
|
|
|
@ -118,6 +118,10 @@ class AppliedTypeConverter {
|
||||||
final AnnotatedDartCode expression;
|
final AnnotatedDartCode expression;
|
||||||
|
|
||||||
final DartType dartType;
|
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;
|
final DriftSqlType sqlType;
|
||||||
|
|
||||||
late DriftColumn owningColumn;
|
late DriftColumn owningColumn;
|
||||||
|
@ -134,7 +138,7 @@ class AppliedTypeConverter {
|
||||||
|
|
||||||
/// Whether this type converter should also be used in the generated JSON
|
/// Whether this type converter should also be used in the generated JSON
|
||||||
/// serialization.
|
/// serialization.
|
||||||
final bool alsoAppliesToJsonConversion;
|
bool get alsoAppliesToJsonConversion => jsonType != null;
|
||||||
|
|
||||||
/// Whether this type converter can be skipped for `null` values.
|
/// Whether this type converter can be skipped for `null` values.
|
||||||
///
|
///
|
||||||
|
@ -170,7 +174,7 @@ class AppliedTypeConverter {
|
||||||
required this.sqlType,
|
required this.sqlType,
|
||||||
required this.dartTypeIsNullable,
|
required this.dartTypeIsNullable,
|
||||||
required this.sqlTypeIsNullable,
|
required this.sqlTypeIsNullable,
|
||||||
this.alsoAppliesToJsonConversion = false,
|
required this.jsonType,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,10 +229,10 @@ class ElementSerializer {
|
||||||
return {
|
return {
|
||||||
'expression': converter.expression.toJson(),
|
'expression': converter.expression.toJson(),
|
||||||
'dart_type': converter.dartType.accept(const _DartTypeSerializer()),
|
'dart_type': converter.dartType.accept(const _DartTypeSerializer()),
|
||||||
|
'json_type': converter.jsonType?.accept(const _DartTypeSerializer()),
|
||||||
'sql_type': converter.sqlType.name,
|
'sql_type': converter.sqlType.name,
|
||||||
'dart_type_is_nullable': converter.dartTypeIsNullable,
|
'dart_type_is_nullable': converter.dartTypeIsNullable,
|
||||||
'sql_type_is_nullable': converter.sqlTypeIsNullable,
|
'sql_type_is_nullable': converter.sqlTypeIsNullable,
|
||||||
'also_applies_to_json_conversion': converter.alsoAppliesToJsonConversion,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,11 +618,12 @@ class ElementDeserializer {
|
||||||
return AppliedTypeConverter(
|
return AppliedTypeConverter(
|
||||||
expression: AnnotatedDartCode.fromJson(json['expression'] as Map),
|
expression: AnnotatedDartCode.fromJson(json['expression'] as Map),
|
||||||
dartType: await _readDartType(json['dart_type'] 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),
|
sqlType: DriftSqlType.values.byName(json['sql_type'] as String),
|
||||||
dartTypeIsNullable: json['dart_type_is_nullable'] as bool,
|
dartTypeIsNullable: json['dart_type_is_nullable'] as bool,
|
||||||
sqlTypeIsNullable: json['sql_type_is_nullable'] as bool,
|
sqlTypeIsNullable: json['sql_type_is_nullable'] as bool,
|
||||||
alsoAppliesToJsonConversion:
|
|
||||||
json['also_applies_to_json_conversion'] as bool,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,8 @@ UsedTypeConverter? readTypeConverter(
|
||||||
final staticType = dartExpression.staticType;
|
final staticType = dartExpression.staticType;
|
||||||
final asTypeConverter =
|
final asTypeConverter =
|
||||||
staticType != null ? helper.asTypeConverter(staticType) : null;
|
staticType != null ? helper.asTypeConverter(staticType) : null;
|
||||||
|
final asJsonTypeConverter =
|
||||||
|
staticType != null ? helper.asJsonTypeConverter(staticType) : null;
|
||||||
|
|
||||||
if (asTypeConverter == null) {
|
if (asTypeConverter == null) {
|
||||||
reportError('Not a type converter');
|
reportError('Not a type converter');
|
||||||
|
@ -160,6 +162,7 @@ UsedTypeConverter? readTypeConverter(
|
||||||
|
|
||||||
final dartType = asTypeConverter.typeArguments[0];
|
final dartType = asTypeConverter.typeArguments[0];
|
||||||
final sqlType = asTypeConverter.typeArguments[1];
|
final sqlType = asTypeConverter.typeArguments[1];
|
||||||
|
final jsonType = asJsonTypeConverter?.typeArguments[2] ?? sqlType;
|
||||||
|
|
||||||
final typeSystem = library.typeSystem;
|
final typeSystem = library.typeSystem;
|
||||||
final dartTypeNullable = typeSystem.isNullable(dartType);
|
final dartTypeNullable = typeSystem.isNullable(dartType);
|
||||||
|
@ -178,7 +181,7 @@ UsedTypeConverter? readTypeConverter(
|
||||||
"potentially map to `null` which can't be stored in the database.");
|
"potentially map to `null` which can't be stored in the database.");
|
||||||
} else if (!canBeSkippedForNulls) {
|
} else if (!canBeSkippedForNulls) {
|
||||||
final alternative = appliesToJsonToo
|
final alternative = appliesToJsonToo
|
||||||
? 'JsonTypeConverter.asNullable'
|
? 'JsonTypeConverter2.asNullable'
|
||||||
: 'NullAwareTypeConverter.wrap';
|
: 'NullAwareTypeConverter.wrap';
|
||||||
|
|
||||||
reportError('This column is nullable, but the type converter has a non-'
|
reportError('This column is nullable, but the type converter has a non-'
|
||||||
|
@ -195,6 +198,7 @@ UsedTypeConverter? readTypeConverter(
|
||||||
expression: dartExpression.toSource(),
|
expression: dartExpression.toSource(),
|
||||||
dartType: resolvedDartType ?? DriftDartType.of(dartType),
|
dartType: resolvedDartType ?? DriftDartType.of(dartType),
|
||||||
sqlType: sqlType,
|
sqlType: sqlType,
|
||||||
|
jsonType: jsonType,
|
||||||
dartTypeIsNullable: dartTypeNullable,
|
dartTypeIsNullable: dartTypeNullable,
|
||||||
sqlTypeIsNullable: sqlTypeNullable,
|
sqlTypeIsNullable: sqlTypeNullable,
|
||||||
alsoAppliesToJsonConversion: appliesToJsonToo,
|
alsoAppliesToJsonConversion: appliesToJsonToo,
|
||||||
|
|
|
@ -26,13 +26,24 @@ class HelperLibrary {
|
||||||
return type.asInstanceOf(converter);
|
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) {
|
bool isJsonAwareTypeConverter(DartType? type, LibraryElement context) {
|
||||||
final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter')
|
final jsonMixin = helperLibrary.exportNamespace.get('JsonTypeConverter2')
|
||||||
as InterfaceElement;
|
as InterfaceElement;
|
||||||
final jsonConverterType = jsonMixin.instantiate(
|
final jsonConverterType = jsonMixin.instantiate(
|
||||||
typeArguments: [
|
typeArguments: [
|
||||||
context.typeProvider.dynamicType,
|
context.typeProvider.dynamicType,
|
||||||
context.typeProvider.dynamicType
|
context.typeProvider.dynamicType,
|
||||||
|
context.typeProvider.dynamicType,
|
||||||
],
|
],
|
||||||
nullabilitySuffix: NullabilitySuffix.none,
|
nullabilitySuffix: NullabilitySuffix.none,
|
||||||
);
|
);
|
||||||
|
|
|
@ -136,6 +136,19 @@ extension OperationOnTypes on HasType {
|
||||||
|
|
||||||
return variableTypeCode();
|
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<DriftSqlType, String> dartTypeNames = {
|
const Map<DriftSqlType, String> dartTypeNames = {
|
||||||
|
|
|
@ -31,6 +31,10 @@ class UsedTypeConverter {
|
||||||
/// mapped values in the database.
|
/// mapped values in the database.
|
||||||
final DartType sqlType;
|
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.
|
/// Whether the Dart-value output of this type converter is nullable.
|
||||||
///
|
///
|
||||||
/// In other words, [dartType] is potentially nullable.
|
/// In other words, [dartType] is potentially nullable.
|
||||||
|
@ -80,6 +84,7 @@ class UsedTypeConverter {
|
||||||
required this.expression,
|
required this.expression,
|
||||||
required this.dartType,
|
required this.dartType,
|
||||||
required this.sqlType,
|
required this.sqlType,
|
||||||
|
required this.jsonType,
|
||||||
required this.dartTypeIsNullable,
|
required this.dartTypeIsNullable,
|
||||||
required this.sqlTypeIsNullable,
|
required this.sqlTypeIsNullable,
|
||||||
this.alsoAppliesToJsonConversion = false,
|
this.alsoAppliesToJsonConversion = false,
|
||||||
|
@ -115,6 +120,7 @@ class UsedTypeConverter {
|
||||||
sqlTypeIsNullable: false,
|
sqlTypeIsNullable: false,
|
||||||
dartTypeIsNullable: false,
|
dartTypeIsNullable: false,
|
||||||
sqlType: typeProvider.intType,
|
sqlType: typeProvider.intType,
|
||||||
|
jsonType: typeProvider.intType,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,11 +139,13 @@ class UsedTypeConverter {
|
||||||
String converterNameInCode({bool makeNullable = false}) {
|
String converterNameInCode({bool makeNullable = false}) {
|
||||||
var sqlDartType = sqlType.getDisplayString(withNullability: true);
|
var sqlDartType = sqlType.getDisplayString(withNullability: true);
|
||||||
if (makeNullable) sqlDartType += '?';
|
if (makeNullable) sqlDartType += '?';
|
||||||
|
var jsonDartType = jsonType.getDisplayString(withNullability: true);
|
||||||
|
if (makeNullable) jsonDartType += '?';
|
||||||
|
|
||||||
final className =
|
if (alsoAppliesToJsonConversion) {
|
||||||
alsoAppliesToJsonConversion ? 'JsonTypeConverter' : 'TypeConverter';
|
return 'JsonTypeConverter2<${dartTypeCode(makeNullable)}, $sqlDartType, $jsonDartType>';
|
||||||
|
}
|
||||||
return '$className<${dartTypeCode(makeNullable)}, $sqlDartType>';
|
return 'TypeConverter<${dartTypeCode(makeNullable)}, $sqlDartType>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,22 @@ class DataClassWriter {
|
||||||
String get serializerType => 'ValueSerializer?';
|
String get serializerType => 'ValueSerializer?';
|
||||||
|
|
||||||
String _columnType(DriftColumn column) {
|
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) {
|
String _converter(DriftColumn column) {
|
||||||
|
@ -116,7 +131,7 @@ class DataClassWriter {
|
||||||
|
|
||||||
final typeConverter = column.typeConverter;
|
final typeConverter = column.typeConverter;
|
||||||
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
||||||
final type = column.innerColumnType(nullable: column.nullable);
|
final type = typeConverter.jsonType;
|
||||||
final fromConverter = "serializer.fromJson<$type>(json['$jsonKey'])";
|
final fromConverter = "serializer.fromJson<$type>(json['$jsonKey'])";
|
||||||
final converterField = _converter(column);
|
final converterField = _converter(column);
|
||||||
deserialized = '$converterField.fromJson($fromConverter)';
|
deserialized = '$converterField.fromJson($fromConverter)';
|
||||||
|
@ -158,7 +173,7 @@ class DataClassWriter {
|
||||||
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
if (typeConverter != null && typeConverter.alsoAppliesToJsonConversion) {
|
||||||
final converterField = _converter(column);
|
final converterField = _converter(column);
|
||||||
value = '$converterField.toJson($value)';
|
value = '$converterField.toJson($value)';
|
||||||
dartType = column.innerColumnType(nullable: true);
|
dartType = _jsonType(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer.write("'$name': serializer.toJson<$dartType>($value),");
|
_buffer.write("'$name': serializer.toJson<$dartType>($value),");
|
||||||
|
|
|
@ -326,7 +326,7 @@ class TableWriter extends TableOrViewWriter {
|
||||||
emitter.writer.converterType(converter, makeNullable: true));
|
emitter.writer.converterType(converter, makeNullable: true));
|
||||||
|
|
||||||
final wrap = converter.alsoAppliesToJsonConversion
|
final wrap = converter.alsoAppliesToJsonConversion
|
||||||
? 'JsonTypeConverter.asNullable'
|
? 'JsonTypeConverter2.asNullable'
|
||||||
: 'NullAwareTypeConverter.wrap';
|
: 'NullAwareTypeConverter.wrap';
|
||||||
|
|
||||||
final code = '$wrap(${converter.fieldName})';
|
final code = '$wrap(${converter.fieldName})';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: drift_dev
|
name: drift_dev
|
||||||
description: Dev-dependency for users of drift. Contains a the generator and development tools.
|
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
|
repository: https://github.com/simolus3/drift
|
||||||
homepage: https://drift.simonbinder.eu/
|
homepage: https://drift.simonbinder.eu/
|
||||||
issue_tracker: https://github.com/simolus3/drift/issues
|
issue_tracker: https://github.com/simolus3/drift/issues
|
||||||
|
@ -25,7 +25,7 @@ dependencies:
|
||||||
io: ^1.0.3
|
io: ^1.0.3
|
||||||
|
|
||||||
# Drift-specific analysis and apis
|
# 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'
|
sqlite3: '>=0.1.6 <2.0.0'
|
||||||
sqlparser: ^0.23.3
|
sqlparser: ^0.23.3
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue