Hive: Support for pointers

Created on 24 Jan 2020  Â·  7Comments  Â·  Source: hivedb/hive

In apps, entities often have references to other entities. For example, a User might have a "friends" collection of other Users and a "supervisor" User. This concept is known as _foreign keys_ in databases or _pointers_ in low-level software.

Strangely, Hive only supports saving collections of pointers in the form of a HiveList, not saving a single pointer.
I'd really like a HivePointer<T> type of some sort which points to another entity, possibly in another box. Maybe, the HivePointer could have a .resolve() method which resolves the reference.

enhancement

Most helpful comment

Another thing I thought about: We could add a @HiveLink() annotation which could be added to any field of type HiveObject or List<HiveObject>.

@HiveType
class _Person {
  String name;

  @HiveLink(boxName: 'persons')
  List<Person> friends;

  @HiveLink(boxName: 'pets')
  Pet dog;
}

The hive_generator would generate a class Person extends _Person which handles all the linking stuff without the user noticing. This generated class could also support optional auto-saving the object when a property is changed.

This is a major breaking change and would be Hive 2.0

All 7 comments

Because it is so easy to implement such a class, I chose not to add it to Hive:

class HivePointer<T extends HiveObject> {
  final Box foreignBox;

  String _key;

  HivePointer(this.foreignBox);

  T get value => _key != null  ? foreignBox.get(_key) : null;

  set value(T obj) => _key = obj.key;
}

Now that I think about it, the adapter for the class above needs to be supported by the hive_generator to cast it automatically. This would be an argument for adding the HivePointer and its adapter.

Another thing I thought about: We could add a @HiveLink() annotation which could be added to any field of type HiveObject or List<HiveObject>.

@HiveType
class _Person {
  String name;

  @HiveLink(boxName: 'persons')
  List<Person> friends;

  @HiveLink(boxName: 'pets')
  Pet dog;
}

The hive_generator would generate a class Person extends _Person which handles all the linking stuff without the user noticing. This generated class could also support optional auto-saving the object when a property is changed.

This is a major breaking change and would be Hive 2.0

Cool, looking forward to it 😊

I was looking for exactly that feature. Why is that a major breaking change?

Why is that a major breaking change?

Adding the HivePointer class is not a breaking change but I probably won't do that. Instead, I will require users to make their model classes private and let the hive_generator create a public subclass that handles the HivePointer and HiveList stuff. This will be a breaking change because every model class needs to be made private.

I'm not entirely sure I like that. I did go in the same direction with my data_classes package, where you create mutable classes and it generates an immutable one with copyWith methods, fancy constructor and the sorts – but in reality, I never used it for one simple reason: loss of control.

You want to add a different constructor for convenience? Not possible.
You want to use other packages, like json_serializable to generate methods for you? Nope, that doesn't work unless you're willing to litter your fetching and business logic with code like MutableUser.fromJson(…).toImmutable() or want to tinker with meta-annotations like e.g. @Annotation(JsonSerializable()), which I'm still not entirely convinced are possible at all.
Want to use multiple packages that use these "data class generation" functionalities? Not possible. People that use built_value for example, are equally cut off.

Generating the data classes I use just makes me as a developer feel like I lose a lot of control over classes that "should be mine". Implementing them as a requirement for Hive classes would be a deal-breaker for me. Let's just hope data classes become a language-level Dart feature sometime.

You want to add a different constructor for convenience? Not possible.

Why not? The generated class just needs to call your constructor with the same parameters.

You want to use other packages, like json_serializable to generate methods for you? Nope, that doesn't work

I also don't see why json_serializable would be a big problem...
Instead of

@HiveType()
@JsonSerializable()
class Person {
  Person fromJson(Map<String, dynamic> json) {
    return _$PersonFromJson(json);
  }
}

You would need to write:

@HiveType()
@JsonSerializable()
class _Person {
  Person fromJson(Map<String, dynamic> json) {
    return Person._fromPerson(_$_PersonFromJson(json));
  }
}

People that use built_value for example, are equally cut off.

I'm almost sure that build_value already does not work with Hive today. Personally I really dislike this package and I don't understand why people would use it. When Dart gets data classes, it will be obsolete anyway.

Generating the data classes I use just makes me as a developer feel like I lose a lot of control over classes that "should be mine"

I understand but the classes are managed by Hive and I don't really see any other way. The biggest reason why I want to make this change is that HiveLists need to be disposed before the object is garbage collected. Dart will probably get weak references in a few years (they are currently a stage 3 TC39 proposal in javascript) but until then, HiveLists need to be disposed manually. After this change, Hive could do the disposing automatically.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

juandiago picture juandiago  Â·  4Comments

kthecoder picture kthecoder  Â·  3Comments

jamesdixon picture jamesdixon  Â·  3Comments

abacaj picture abacaj  Â·  3Comments

rupamking1 picture rupamking1  Â·  3Comments