-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Hive working with @immutable class #225
Comments
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 |
@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));
}
} |
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 |
"@immutable class" is not about |
I have tried adding Does the issue is related to model adapters generated by hive_generator or caused when extending models with |
I like Hive so hope it will be fixed once. for example with 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 ( |
Dart have no |
moreover
-- |
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 ? |
@themisir I have been using this solution since last 3-4 months. And I didn't get any issues. The solution is to manually provide So, to conclude, neither of the libraries are at fault. |
It's ugly to use String as name |
So the problem is 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 |
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, |
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 |
The first is enum and second one is class. They are not same thing. Anyways you can create custom type adapter for that. |
how to register this adapter? |
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter<Employee>(EmployeeType());
Hive.registerAdapter<Role>(RoleType());
await Hive.openBox<List<Employee>>('employees_box');
runApp(const ProviderScope(child: MyApp()));
} |
Can't find my adapter and therefore can't register it Here is some of the code part 'profile.freezed.dart';
part 'profile.g.dart';
@freezed
class Profile with _$Profile{
@HiveType(typeId: 5, adapterName: "ProfileAdapter")
const factory Profile({
@HiveField(1)
required String name,
@HiveField(2)
required List<String> ideas,
@HiveField(3)
@Default(false) bool isAllowSomething
}) = _Profile; The generated profile.g.dart file does have class ProfileAdapter extends TypeAdapter<_$ProfileImpl> { But I can't seem to be able to access it to register it as an adapter |
UPDATE And for an older For some reason the code snippets above didn't work for me - than I've set the part 'profile.freezed.dart';
part 'profile.g.dart';
@freezed
@HiveType(typeId: 5, adapterName: "ProfileAdapter")
class Profile with _$Profile{
const factory Profile({
@HiveField(1)
required String name,
@HiveField(2)
required List<String> ideas,
@HiveField(3)
@Default(false) bool isAllowSomething
}) = _Profile;
This is what being created class ProfileAdapter extends TypeAdapter<Profile> { which can be used when registering the adapter. the issue is probably around those lines: class ProfileAdapter extends TypeAdapter<_$_Profile> {
@override
final int typeId = 5;
@override
_$_Profile read(BinaryReader reader) { the read method returns a |
@leisim Hi there!
It will be awesome to get this awesome plugin Freezed working with immutable models, so we can have immutable model that can be generated and stored directly in Hive database.
cc: @rrousselGit
The text was updated successfully, but these errors were encountered: