Thanks, I'll take a look. It will be hard to achieve this with the changes planned for Hive 2.0 but I'll try to figure it out.
That would be great! I remember some time ago trying to tag my models as @immutable but got warnings as HiveObjects are mutable
@frank06 exactly that!
I suppose that instead of "working with Freezed", it's more of a "working with immutable models".
Freezed doesn't do anything fancy.
I'd also really love this to work. I'll try to find some time to look into the issues that occur when using hive with freezed. It would make our data classes so much shorter!
EDIT: I just started looking into it, but because the hive_generator repo got archived, I decided it's not worth the effort.
Hand-written immutable Hive data classes
@HiveType(typeId: TypeId.user)
class User implements Entity<User> {
const User({
@required this.id,
@required this.firstName,
@required this.lastName,
@required this.email,
@required this.schoolId,
String displayName,
@required this.avatarInitials,
@required this.avatarBackgroundColor,
@required this.permissions,
@required this.roleIds,
}) : assert(id != null),
assert(firstName != null),
assert(lastName != null),
assert(email != null),
assert(schoolId != null),
displayName = displayName ?? '$firstName $lastName',
assert(avatarInitials != null),
assert(avatarBackgroundColor != null),
assert(permissions != null),
assert(roleIds != null);
User.fromJson(Map<String, dynamic> data)
: this(
id: Id<User>(data['_id']),
firstName: data['firstName'],
lastName: data['lastName'],
email: data['email'],
schoolId: data['schoolId'],
displayName: data['displayName'],
avatarInitials: data['avatarInitials'],
avatarBackgroundColor:
(data['avatarBackgroundColor'] as String).hexToColor,
permissions: (data['permissions'] as List<dynamic>).cast<String>(),
roleIds: parseIds(data['roles']),
);
static Future<User> fetch(Id<User> id) async =>
User.fromJson(await services.api.get('users/$id').json);
@override
@HiveField(0)
final Id<User> id;
@HiveField(1)
final String firstName;
@HiveField(2)
final String lastName;
String get shortName => '${firstName.chars.first}. $lastName';
@HiveField(3)
final String email;
@HiveField(4)
final String schoolId;
@HiveField(5)
final String displayName;
@HiveField(7)
final String avatarInitials;
@HiveField(8)
final Color avatarBackgroundColor;
@HiveField(6)
final List<String> permissions;
bool hasPermission(String permission) => permissions.contains(permission);
@HiveField(9)
final List<Id<Role>> roleIds;
bool get isTeacher => hasRole(Role.teacherName);
bool hasRole(String name) {
// TODO(marcelgarus): Remove the hard-coded mapping and use runtime lookup when upgrading flutter_cached and flattening is supported.
final id = {
Role.teacherName: '0000d186816abba584714c98',
}[name];
return id != null && roleIds.contains(Id<Role>(id));
}
@override
bool operator ==(Object other) =>
other is User &&
id == other.id &&
firstName == other.firstName &&
lastName == other.lastName &&
email == other.email &&
schoolId == other.schoolId &&
displayName == other.displayName &&
avatarInitials == other.avatarInitials &&
avatarBackgroundColor == other.avatarBackgroundColor &&
permissions.deeplyEquals(other.permissions, unordered: true) &&
roleIds.deeplyEquals(other.roleIds, unordered: true);
@override
int get hashCode => hashList([
id,
firstName,
lastName,
email,
schoolId,
displayName,
avatarInitials,
avatarBackgroundColor,
permissions,
roleIds
]);
}
Using freezed with Hive (doesn't work yet)
@freezed
@HiveType(typeId: TypeId.user)
abstract class User implements Entity<User>, _$User {
const User._();
const factory User({
@HiveField(0) @required Id<User> id,
@HiveField(1) @required String firstName,
@HiveField(2) @required String lastName,
@HiveField(3) @required String email,
@HiveField(4) @required String schoolId,
@HiveField(5) String displayName,
@HiveField(7) @required String avatarInitials,
@HiveField(8) @required Color avatarBackgroundColor,
@HiveField(6) @required List<String> permissions,
@HiveField(9) @required List<Id<Role>> roleIds,
}) = _User;
// displayName = displayName ?? '$firstName $lastName',
static User fromJson(Map<String, dynamic> data) => User(
id: Id<User>(data['_id']),
firstName: data['firstName'],
lastName: data['lastName'],
email: data['email'],
schoolId: data['schoolId'],
displayName: data['displayName'],
avatarInitials: data['avatarInitials'],
avatarBackgroundColor:
(data['avatarBackgroundColor'] as String).hexToColor,
permissions: (data['permissions'] as List<dynamic>).cast<String>(),
roleIds: parseIds(data['roles']),
);
static Future<User> fetch(Id<User> id) async =>
User.fromJson(await services.api.get('users/$id').json);
String get shortName => '${firstName.chars.first}. $lastName';
bool hasPermission(String permission) => permissions.contains(permission);
bool get isTeacher => hasRole(Role.teacherName);
bool hasRole(String name) {
// TODO(marcelgarus): Remove the hard-coded mapping and use runtime lookup when upgrading flutter_cached and flattening is supported.
final id = {
Role.teacherName: '0000d186816abba584714c98',
}[name];
return id != null; // && roleIds.contains(Id<Role>(id));
}
}
I'd also really love this to work. I'll try to find some time to look into the issues that occur when using hive with freezed. It would make our data classes so much shorter!
EDIT: I just started looking into it, but because the hive_generator repo got archived, I decided it's not worth the effort.
Hand-written immutable Hive data classes
Using freezed with Hive (doesn't work yet)
Any update about this feature?
Sure. I have a kind of love-hate relationship with the Hive serializer. I think it got a lot of things right, but I also strongly disagree with some of the design decisions (like the format not being self-descriptive, like JSON, or the adapters having the responsibility to define their own ids, causing IDs to be scattered all over your project instead of being defined in one central place). I also wanted to use the serializer on its own separate from Hive, so in #152 I did some brainstorming with @leisim about how the serializer could be improved – and several great ideas came up. I wanted to play around with some of them, so I started writing a serializer with a slightly different approach, which ended up in tape. I also focused on great tooling, but it's not production-ready by a long shot. For the Hive replacement – isar – @leisim wrote a completely new serializer with some different design philosophies which also looks promising.
Tape does work with freezed, and I think the part of being able to use freezed could also be applied to Hive – I'm currently quite busy with studying and work stuff as well as other projects, so it's probably gonna take some time before I find time to look at it though. If anyone has spare time and feels like it, don't hesitate to code something up and file a PR. Tape already works with freezed, so in the repo you should find some guidance on how that could work. I'm also available for concrete questions, if you have any.
Any updates?
What do you mean by "working with @immutable class"? I haven't used freezed package, so I don't know what's exact issue.
"@immutable class" is not about freezed - you could read thread history for more details
freezed just example
it is just Hive blocker issue that force many users to use Sembast instead
"@immutable class" is not about
freezed- you could read thread history for more details
freezedjust example
it is justHiveblocker issue that force many users to useSembastinstead
I have tried adding @immutable to my hive models. But did not get any warnings or errors.
Does the issue is related to model adapters generated by hive_generator or caused when extending models with HiveObject?

@immutable to my hive models
"@immutable classes" usually constructed using with or implements
so it will compile and run but it will store empty objects in the Hive DB.
I like Hive so hope it will be fixed once.
for example with freezed immutable class looks like:
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
part 'immutable_class.freezed.dart';
part 'immutable_class.g.dart';
@freezed
abstract class ImmutableClass with _$ImmutableClass {
@HiveType(typeId: 5)
const factory ImmutableClass({
@JsonKey(name: 'id', required: true, disallowNullValue: true) @HiveField(0) int id,
@HiveField(1) int someField1,
@HiveField(2) String someField2,
}) = _ImmutableClass;
factory ImmutableClass.fromJson(Map<String, dynamic> json) => _$ImmutableClassFromJson(json);
}
I'm not planning to implement this feature. The implementation will be package specific (freezed in your example). Instead you can write your own hive adapter. Or at least human readable model classes (which hive generator currently supports). Fyi: hive_generator generates code for fields annotated with HiveField inside classes mentioned with HiveType. It doesn't checks for constructor arguments or something else.
Dart have no @immutable classes other then packages specific built_value freezed and etc (@immutable attribute only will not class immutable)
So user have to choose reliable code with specific packages or non-reliable code with Hive - therefore many forced to use Sembast instead of Hive
moreover
hive_generator generates code for fields annotated with
HiveFieldinside classes mentioned withHiveType.
-- freezed generate fields annotated with HiveField inside classes mentioned with HiveType (as base class or mixin)
-- and Hive still do not save objects correctly
the only way I found to workarround it some-how, but it looks quite ugly with adapter name string, hope Hive will be improved to fix it:
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hive/hive.dart';
part 'immutable_class.freezed.dart';
part 'immutable_class.g.dart';
@freezed
abstract class ImmutableClass with _$ImmutableClass {
@HiveType(typeId: 5, adapterName: 'ImmutableClassAdapter')
const factory ImmutableClass({
@JsonKey(name: 'id', required: true, disallowNullValue: true) @HiveField(0) int id,
@HiveField(1) int someField1,
@HiveField(2) String someField2,
}) = _ImmutableClass;
factory ImmutableClass.fromJson(Map<String, dynamic> json) => _$ImmutableClassFromJson(json);
}
What do you think about that, @leisim ?
the only way I found to workarround it some-how, but it looks quite ugly with adapter name string, hope Hive will be improved to fix it:
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hive/hive.dart'; part 'immutable_class.freezed.dart'; part 'immutable_class.g.dart'; @freezed abstract class ImmutableClass with _$ImmutableClass { @HiveType(typeId: 5, adapterName: 'ImmutableClassAdapter') const factory ImmutableClass({ @JsonKey(name: 'id', required: true, disallowNullValue: true) @HiveField(0) int id, @HiveField(1) int someField1, @HiveField(2) String someField2, }) = _ImmutableClass; factory ImmutableClass.fromJson(Map<String, dynamic> json) => _$ImmutableClassFromJson(json); }
@TheMisir I have been using this solution since last 3-4 months. And I didn't get any issues.
The problem with using Hive with Freezed is, Freezed creates Private classes (_$*), so for example, our class Product will have adapter called _$ProductAdapter, which we won't be able to access anywhere.
The solution is to manually provide adapterName just as this solution and it would work PERFECTLY.
So, to conclude, neither of the libraries are at fault.
It's ugly to use String as name
What about trim start '_' and '$' symbols from adapter name by default? As adapter should not be private
So the problem is adapter names. I can trim _$ part from adapter names.
I can trim _$ part from adapter names.
It could be awesome, thanks a lot
Published to pub.dev. You will need to set min version to 0.7.2+1:
dev_dependencies:
hive_generator: ^0.7.2+1
@TheMisir
Adapter still have '_' sign:
class _SomeClassAdapter extends TypeAdapter<_$_SomeClass> {
Thanks for the fast update, hope you will fix it as adapter name started with '_' sign could not be really used
Thanks in advance
@TheMisir
Adapterstill have '_' sign:class _SomeClassAdapter extends TypeAdapter<_$_SomeClass> {Thanks for the fast update, hope you will fix it as adapter name started with '_' sign could not be really used
Thanks in advance
Oops 😅 Now fixing.
Fixed and published!
Wow, Adapters are generated correctly, awesome, thanks a lot for the fast fix!
any update to the docs, regarding these changes?
is it possible to have sth like this for union classes ?
HIVE
@HiveType(typeId: 2)
enum AudioOrderDao {
@HiveField(0)
order,
@HiveField(2)
repeatAll,
@HiveField(1)
repeatOne,
@HiveField(3)
shuffle
}
FREEZED
@freezed
abstract class AudioOrder with _$AudioOrder {
const factory AudioOrder.order() = _Order;
const factory AudioOrder.repeatAll() = _RepeatAll;
const factory AudioOrder.repeatOne() = _RepeatOne;
const factory AudioOrder.shuffle() = _Shuffle;
}
thanks
is it possible to have sth like this for union classes ?
HIVE
@HiveType(typeId: 2) enum AudioOrderDao { @HiveField(0) order, @HiveField(2) repeatAll, @HiveField(1) repeatOne, @HiveField(3) shuffle }FREEZED
@freezed abstract class AudioOrder with _$AudioOrder { const factory AudioOrder.order() = _Order; const factory AudioOrder.repeatAll() = _RepeatAll; const factory AudioOrder.repeatOne() = _RepeatOne; const factory AudioOrder.shuffle() = _Shuffle; }thanks
The first is enum and second one is class. They are not same thing. Anyways you can create custom type adapter for that.
Most helpful comment
Thanks, I'll take a look. It will be hard to achieve this with the changes planned for Hive 2.0 but I'll try to figure it out.