diff --git a/hive/CHANGELOG.md b/hive/CHANGELOG.md index 19b36dec..624f123b 100644 --- a/hive/CHANGELOG.md +++ b/hive/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.5.0+1 + +- Documentation updates for `HiveField` in support of `hive_ce_generator` changes + ## 2.5.0 - Adds `Target` annotations to `HiveField` and `HiveType` to prevent invalid usage diff --git a/hive/lib/src/annotations/hive_field.dart b/hive/lib/src/annotations/hive_field.dart index ba42f505..a01f1226 100644 --- a/hive/lib/src/annotations/hive_field.dart +++ b/hive/lib/src/annotations/hive_field.dart @@ -13,6 +13,8 @@ class HiveField { /// The default value of this field for class hive types. /// + /// This value takes precedence over constructor parameter default values. + /// /// In enum hive types set `true` to use this enum value as default value /// instead of null in null-safety. /// diff --git a/hive/pubspec.yaml b/hive/pubspec.yaml index 5e188028..7ce5311a 100644 --- a/hive/pubspec.yaml +++ b/hive/pubspec.yaml @@ -1,6 +1,6 @@ name: hive_ce description: Hive Community Edition - A spiritual continuation of Hive v2 -version: 2.5.0 +version: 2.5.0+1 homepage: https://github.com/IO-Design-Team/hive_ce/tree/main/hive documentation: https://docs.hivedb.dev/ diff --git a/hive_generator/CHANGELOG.md b/hive_generator/CHANGELOG.md index a3584386..a5c24646 100644 --- a/hive_generator/CHANGELOG.md +++ b/hive_generator/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.5.0 + +- Supports constructor parameter default values +- No longer generates the `HiveRegistrar` if there are no adapters +- Removes unnecessary print statement in `HiveRegistrar` generator +- Bumps `analyzer` to `^6.5.0` to deal with deprecations + ## 1.4.0 - Adds a generator to create a `HiveRegistrar` extension that allows registration of all generated `TypeAdapters` in one call diff --git a/hive_generator/example/lib/hive_registrar.g.dart b/hive_generator/example/lib/hive_registrar.g.dart index 8726bdf7..29472572 100644 --- a/hive_generator/example/lib/hive_registrar.g.dart +++ b/hive_generator/example/lib/hive_registrar.g.dart @@ -7,6 +7,8 @@ extension HiveRegistrar on HiveInterface { registerAdapter(Class2Adapter()); registerAdapter(EmptyClassAdapter()); registerAdapter(IterableClassAdapter()); + registerAdapter(ConstructorDefaultsAdapter()); + registerAdapter(NullableTypesAdapter()); registerAdapter(Enum1Adapter()); } } diff --git a/hive_generator/example/lib/types.dart b/hive_generator/example/lib/types.dart index 72eb8742..a1c65b65 100644 --- a/hive_generator/example/lib/types.dart +++ b/hive_generator/example/lib/types.dart @@ -78,3 +78,39 @@ class IterableClass { @HiveField(3) final Set> nestedSet; } + +@HiveType(typeId: 6) +class ConstructorDefaults { + ConstructorDefaults({ + this.a = 42, + this.b = '42', + this.c = true, + DateTime? d, + }) : d = d ?? DateTime.now(); + + @HiveField(0) + final int a; + + @HiveField(1, defaultValue: '6 * 7') + final String b; + + @HiveField(2) + final bool c; + + @HiveField(3) + final DateTime d; +} + +@HiveType(typeId: 7) +class NullableTypes { + NullableTypes({this.a, this.b, this.c}); + + @HiveField(0) + final int? a; + + @HiveField(1) + final String? b; + + @HiveField(2) + final bool? c; +} diff --git a/hive_generator/example/lib/types.g.dart b/hive_generator/example/lib/types.g.dart index fb559bc3..2d4bf6cc 100644 --- a/hive_generator/example/lib/types.g.dart +++ b/hive_generator/example/lib/types.g.dart @@ -165,6 +165,89 @@ class IterableClassAdapter extends TypeAdapter { typeId == other.typeId; } +class ConstructorDefaultsAdapter extends TypeAdapter { + @override + final int typeId = 6; + + @override + ConstructorDefaults read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return ConstructorDefaults( + a: fields[0] == null ? 42 : (fields[0] as num).toInt(), + b: fields[1] == null ? '6 * 7' : fields[1] as String, + c: fields[2] == null ? true : fields[2] as bool, + d: fields[3] as DateTime?, + ); + } + + @override + void write(BinaryWriter writer, ConstructorDefaults obj) { + writer + ..writeByte(4) + ..writeByte(0) + ..write(obj.a) + ..writeByte(1) + ..write(obj.b) + ..writeByte(2) + ..write(obj.c) + ..writeByte(3) + ..write(obj.d); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ConstructorDefaultsAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class NullableTypesAdapter extends TypeAdapter { + @override + final int typeId = 7; + + @override + NullableTypes read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return NullableTypes( + a: (fields[0] as num?)?.toInt(), + b: fields[1] as String?, + c: fields[2] as bool?, + ); + } + + @override + void write(BinaryWriter writer, NullableTypes obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.a) + ..writeByte(1) + ..write(obj.b) + ..writeByte(2) + ..write(obj.c); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is NullableTypesAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + class Enum1Adapter extends TypeAdapter { @override final int typeId = 3; diff --git a/hive_generator/lib/src/builder.dart b/hive_generator/lib/src/builder.dart index 01070180..9786c2d3 100644 --- a/hive_generator/lib/src/builder.dart +++ b/hive_generator/lib/src/builder.dart @@ -2,22 +2,33 @@ import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; -/// TODO: Document this! +/// Metadata about a field in a class adapter class AdapterField { - /// TODO: Document this! + /// The index of the field + /// + /// Determines the order fields are read and written final int index; - /// TODO: Document this! + /// The name of the field final String name; - /// TODO: Document this! + /// The type of the field final DartType type; - /// TODO: Document this! - final DartObject? defaultValue; + /// A default value provided by the field annotation + final DartObject? annotationDefault; - /// TODO: Document this! - AdapterField(this.index, this.name, this.type, this.defaultValue); + /// A default value provided by the constructor + final String? constructorDefault; + + /// Constructor + AdapterField( + this.index, + this.name, + this.type, + this.annotationDefault, + this.constructorDefault, + ); } /// TODO: Document this! diff --git a/hive_generator/lib/src/class_builder.dart b/hive_generator/lib/src/class_builder.dart index 70f7048b..7c3d082c 100644 --- a/hive_generator/lib/src/class_builder.dart +++ b/hive_generator/lib/src/class_builder.dart @@ -1,6 +1,5 @@ import 'dart:typed_data'; -import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:hive_ce/hive.dart'; @@ -68,13 +67,7 @@ class ClassBuilder extends Builder { if (param.isNamed) { code.write('${param.name}: '); } - code.write( - _value( - param.type, - 'fields[${field.index}]', - field.defaultValue, - ), - ); + code.write(_value(param.type, field)); code.writeln(','); fields.remove(field); } @@ -86,13 +79,7 @@ class ClassBuilder extends Builder { // as initializing formals. We do so using cascades. for (final field in fields) { code.write('..${field.name} = '); - code.writeln( - _value( - field.type, - 'fields[${field.index}]', - field.defaultValue, - ), - ); + code.writeln(_value(field.type, field)); } code.writeln(';'); @@ -100,10 +87,25 @@ class ClassBuilder extends Builder { return code.toString(); } - String _value(DartType type, String variable, DartObject? defaultValue) { + String _value(DartType type, AdapterField field) { + final variable = 'fields[${field.index}]'; final value = _cast(type, variable); - if (defaultValue?.isNull != false) return value; - return '$variable == null ? ${constantToString(defaultValue!)} : $value'; + + final annotationDefaultIsNull = field.annotationDefault?.isNull ?? true; + final constructorDefaultIsNull = field.constructorDefault == null; + + final String? defaultValue; + if (!annotationDefaultIsNull) { + defaultValue = constantToString(field.annotationDefault); + } else if (!constructorDefaultIsNull) { + defaultValue = field.constructorDefault; + } else { + defaultValue = null; + } + + if (defaultValue == null) return value; + + return '$variable == null ? $defaultValue : $value'; } String _cast(DartType type, String variable) { @@ -121,7 +123,7 @@ class ClassBuilder extends Builder { } else if (type.isDartCoreDouble) { return '($variable as num$suffix)$suffix.toDouble()'; } else { - return '$variable as ${_displayString(type)}'; + return '$variable as ${type.getDisplayString()}'; } } @@ -152,7 +154,7 @@ class ClassBuilder extends Builder { return '$suffix.map((e) => ${_cast(arg, 'e')})$cast'; } else { - return '$suffix.cast<${_displayString(arg)}>()'; + return '$suffix.cast<${arg.getDisplayString()}>()'; } } @@ -165,8 +167,8 @@ class ClassBuilder extends Builder { return '$suffix.map((dynamic k, dynamic v)=>' 'MapEntry(${_cast(arg1, 'k')},${_cast(arg2, 'v')}))'; } else { - return '$suffix.cast<${_displayString(arg1)}, ' - '${_displayString(arg2)}>()'; + return '$suffix.cast<${arg1.getDisplayString()}, ' + '${arg2.getDisplayString()}>()'; } } @@ -212,16 +214,8 @@ String _accessorSuffixFromType(DartType type) { /// Suffix to use when casting a value to [type]. /// $variable as $type$suffix String _suffixFromType(DartType type) { - if (type.nullabilitySuffix == NullabilitySuffix.star) { - return ''; - } - if (type.nullabilitySuffix == NullabilitySuffix.question) { - return '?'; - } - return ''; -} - -String _displayString(DartType e) { - final suffix = _suffixFromType(e); - return '${e.getDisplayString()}$suffix'; + return switch (type.nullabilitySuffix) { + NullabilitySuffix.question => '?', + _ => '', + }; } diff --git a/hive_generator/lib/src/enum_builder.dart b/hive_generator/lib/src/enum_builder.dart index 820e8066..3f9d2ec8 100644 --- a/hive_generator/lib/src/enum_builder.dart +++ b/hive_generator/lib/src/enum_builder.dart @@ -20,7 +20,7 @@ class EnumBuilder extends Builder { } final defaultField = getters.firstWhere( - (it) => it.defaultValue?.toBoolValue() == true, + (it) => it.annotationDefault?.toBoolValue() == true, orElse: () => getters.first, ); code.writeln(''' diff --git a/hive_generator/lib/src/registrar_generator.dart b/hive_generator/lib/src/registrar_generator.dart index af171fb5..96b57e07 100644 --- a/hive_generator/lib/src/registrar_generator.dart +++ b/hive_generator/lib/src/registrar_generator.dart @@ -14,8 +14,6 @@ class RegistrarBuilder implements Builder { @override Future build(BuildStep buildStep) async { - final buffer = StringBuffer("import 'package:hive_ce/hive.dart';\n"); - final uris = []; final adapters = []; await for (final input @@ -26,6 +24,11 @@ class RegistrarBuilder implements Builder { adapters.addAll((data['adapters'] as List).cast()); } + // Do not create the registrar if there are no adapters + if (adapters.isEmpty) return; + + final buffer = StringBuffer("import 'package:hive_ce/hive.dart';\n"); + for (final uri in uris) { buffer.writeln("import '$uri';"); } diff --git a/hive_generator/lib/src/type_adapter_generator.dart b/hive_generator/lib/src/type_adapter_generator.dart index 0cdc42f8..9de6dcec 100644 --- a/hive_generator/lib/src/type_adapter_generator.dart +++ b/hive_generator/lib/src/type_adapter_generator.dart @@ -87,43 +87,40 @@ class TypeAdapterGenerator extends GeneratorForAnnotation { ) { final accessorNames = getAllAccessorNames(cls); + final constructor = cls.constructors.firstWhere((e) => e.name.isEmpty); + final parameterDefaults = { + for (final param in constructor.parameters) + param.name: param.defaultValueCode, + }; + + AdapterField? accessorToField(PropertyAccessorElement? element) { + if (element == null) return null; + + final annotation = + getHiveFieldAnn(element.variable2) ?? getHiveFieldAnn(element); + if (annotation == null) return null; + + final field = element.variable2!; + return AdapterField( + annotation.index, + field.name, + field.type, + annotation.defaultValue, + parameterDefaults[field.name], + ); + } + final getters = []; final setters = []; for (final name in accessorNames) { final getter = cls.augmented.lookUpGetter(name: name, library: library); - if (getter != null) { - final getterAnn = - getHiveFieldAnn(getter.variable2) ?? getHiveFieldAnn(getter); - if (getterAnn != null) { - final field = getter.variable2!; - getters.add( - AdapterField( - getterAnn.index, - field.name, - field.type, - getterAnn.defaultValue, - ), - ); - } - } + final getterField = accessorToField(getter); + if (getterField != null) getters.add(getterField); final setter = cls.augmented.lookUpSetter(name: '$name=', library: library); - if (setter != null) { - final setterAnn = - getHiveFieldAnn(setter.variable2) ?? getHiveFieldAnn(setter); - if (setterAnn != null) { - final field = setter.variable2!; - setters.add( - AdapterField( - setterAnn.index, - field.name, - field.type, - setterAnn.defaultValue, - ), - ); - } - } + final setterField = accessorToField(setter); + if (setterField != null) setters.add(setterField); } return [getters, setters]; diff --git a/hive_generator/pubspec.yaml b/hive_generator/pubspec.yaml index 44d480c6..2c89ba6f 100644 --- a/hive_generator/pubspec.yaml +++ b/hive_generator/pubspec.yaml @@ -1,6 +1,6 @@ name: hive_ce_generator description: Extension for Hive. Automatically generates TypeAdapters to store any class. -version: 1.4.0 +version: 1.5.0 homepage: https://github.com/IO-Design-Team/hive_ce/tree/main/hive_generator documentation: https://docs.hivedb.dev/