diff --git a/hive/lib/src/adapters/ignored_type_adapter.dart b/hive/lib/src/adapters/ignored_type_adapter.dart index c4cabfaf6..c71a26883 100644 --- a/hive/lib/src/adapters/ignored_type_adapter.dart +++ b/hive/lib/src/adapters/ignored_type_adapter.dart @@ -7,6 +7,11 @@ class IgnoredTypeAdapter implements TypeAdapter { @override final int typeId; + @override + dynamic defaultKey(obj) { + return null; + } + @override T? read(BinaryReader reader) => null; diff --git a/hive/lib/src/annotations/hive_field.dart b/hive/lib/src/annotations/hive_field.dart index 9eba2119c..c86c065d3 100644 --- a/hive/lib/src/annotations/hive_field.dart +++ b/hive/lib/src/annotations/hive_field.dart @@ -22,5 +22,8 @@ class HiveField { /// ``` final dynamic defaultValue; - const HiveField(this.index, {this.defaultValue}); + /// Whether use this field as the default key of this type + final bool isKey; + + const HiveField(this.index, {this.defaultValue, this.isKey = false}); } diff --git a/hive/lib/src/box/box_base_impl.dart b/hive/lib/src/box/box_base_impl.dart index 368ab6584..87e5a3b5c 100644 --- a/hive/lib/src/box/box_base_impl.dart +++ b/hive/lib/src/box/box_base_impl.dart @@ -108,7 +108,7 @@ abstract class BoxBaseImpl implements BoxBase { @override Future add(E value) async { - var key = keystore.autoIncrement(); + var key = _getDefaultKey(value); await put(key, value); return key; } @@ -117,7 +117,7 @@ abstract class BoxBaseImpl implements BoxBase { Future> addAll(Iterable values) async { var entries = {}; for (var value in values) { - entries[keystore.autoIncrement()] = value; + entries[_getDefaultKey(value)] = value; } await putAll(entries); return entries.keys; @@ -183,6 +183,20 @@ abstract class BoxBaseImpl implements BoxBase { await backend.deleteFromDisk(); } + + dynamic _getDefaultKey(E value) { + var resolved = hive.findAdapterForValue(value); + if (resolved == null) { + return keystore.autoIncrement(); + } + var adapter = resolved.adapter; + var key = adapter.defaultKey(value); + if (key == null) { + return keystore.autoIncrement(); + } else { + return key; + } + } } class _NullBoxBase implements BoxBase { diff --git a/hive/lib/src/registry/type_adapter.dart b/hive/lib/src/registry/type_adapter.dart index 0af4416d7..ee753eaf0 100644 --- a/hive/lib/src/registry/type_adapter.dart +++ b/hive/lib/src/registry/type_adapter.dart @@ -6,6 +6,11 @@ abstract class TypeAdapter { /// Called for type registration int get typeId; + // Is called when the value is adding to box without a specific key. + dynamic defaultKey(T obj) { + return null; + } + /// Is called when a value has to be decoded. T read(BinaryReader reader); diff --git a/hive_generator/lib/src/builder.dart b/hive_generator/lib/src/builder.dart index c523cb389..ee9e870b7 100644 --- a/hive_generator/lib/src/builder.dart +++ b/hive_generator/lib/src/builder.dart @@ -7,8 +7,9 @@ class AdapterField { final String name; final DartType type; final DartObject? defaultValue; + final bool isKey; - AdapterField(this.index, this.name, this.type, this.defaultValue); + AdapterField(this.index, this.name, this.type, this.defaultValue, this.isKey); } abstract class Builder { diff --git a/hive_generator/lib/src/helper.dart b/hive_generator/lib/src/helper.dart index 0b26021e6..7a05b2d9c 100644 --- a/hive_generator/lib/src/helper.dart +++ b/hive_generator/lib/src/helper.dart @@ -6,10 +6,11 @@ import 'package:source_gen/source_gen.dart'; final _hiveFieldChecker = const TypeChecker.fromRuntime(HiveField); class HiveFieldInfo { - HiveFieldInfo(this.index, this.defaultValue); + HiveFieldInfo(this.index, this.defaultValue, this.isKey); final int index; final DartObject? defaultValue; + final bool isKey; } HiveFieldInfo? getHiveFieldAnn(Element element) { @@ -19,6 +20,7 @@ HiveFieldInfo? getHiveFieldAnn(Element element) { return HiveFieldInfo( obj.getField('index')!.toIntValue()!, obj.getField('defaultValue'), + obj.getField('isKey')!.toBoolValue()!, ); } diff --git a/hive_generator/lib/src/type_adapter_generator.dart b/hive_generator/lib/src/type_adapter_generator.dart index 704128ad8..68207225a 100644 --- a/hive_generator/lib/src/type_adapter_generator.dart +++ b/hive_generator/lib/src/type_adapter_generator.dart @@ -40,11 +40,17 @@ class TypeAdapterGenerator extends GeneratorForAnnotation { ? EnumBuilder(cls, getters) : ClassBuilder(cls, getters, setters); + var defaultKey = getDefaultKey(getters); + return ''' class $adapterName extends TypeAdapter<${cls.name}> { @override final int typeId = $typeId; + @override + dynamic defaultKey(${cls.name} obj) => + ${defaultKey}; + @override ${cls.name} read(BinaryReader reader) { ${builder.buildRead()} @@ -111,6 +117,7 @@ class TypeAdapterGenerator extends GeneratorForAnnotation { field.name, field.type, getterAnn.defaultValue, + getterAnn.isKey, )); } } @@ -126,6 +133,7 @@ class TypeAdapterGenerator extends GeneratorForAnnotation { field.name, field.type, setterAnn.defaultValue, + false, )); } } @@ -151,6 +159,22 @@ class TypeAdapterGenerator extends GeneratorForAnnotation { } } + String getDefaultKey(List fields) { + String defaultKey = "null"; + int keysCount = 0; + for (var field in fields) { + if (field.isKey) { + keysCount++; + defaultKey = "obj." + field.name; + } + } + check( + keysCount <= 1, + 'At most one field can have isKey=true', + ); + return defaultKey; + } + String getAdapterName(String typeName, ConstantReader annotation) { var annAdapterName = annotation.read('adapterName'); if (annAdapterName.isNull) {