Skip to content

Commit 841ec49

Browse files
fix record level hooks (#311)
Co-authored-by: Moshe Dicker <dickermoshe@gmail.com>
1 parent 28efbb0 commit 841ec49

9 files changed

Lines changed: 182 additions & 18 deletions

File tree

packages/dart_mappable/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Unreleased
2+
3+
- Record mappers now correctly generate hooks specified on the record annotation itself, not just those on individual fields.
4+
15
# 4.6.0
26

37
- Add support for self-referencing generics (e.g. `T extends Comparable<T>`)

packages/dart_mappable/test/initializer/init_package_test.init.dart

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dart_mappable/test/records/mappable_record_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:math';
2+
13
import 'package:dart_mappable/dart_mappable.dart';
24
import 'package:test/test.dart';
35

@@ -22,6 +24,22 @@ class RoundingHook extends MappingHook {
2224
}
2325
}
2426

27+
class HypotenuseHook extends MappingHook {
28+
const HypotenuseHook();
29+
30+
@override
31+
Object? beforeDecode(Object? value) {
32+
final map = (value as Map).cast<String, dynamic>();
33+
final leg1 = map['x'] as num;
34+
final leg2 = map['y'] as num;
35+
map['hypotenuse'] = sqrt(leg1 * leg1 + leg2 * leg2);
36+
return map;
37+
}
38+
}
39+
40+
@MappableRecord(hook: HypotenuseHook())
41+
typedef Hypotenuse = ({double x, double y, double hypotenuse});
42+
2543
@MappableClass()
2644
class Location with LocationMappable {
2745
final Point point;
@@ -70,6 +88,20 @@ void main() {
7088
expect(encode(p), equals({'a': 1, 'y': 2}));
7189
});
7290

91+
test('can decode and encode record hook on record', () {
92+
var decode = MapperContainer.globals.fromMap;
93+
var encode = MapperContainer.globals.toMap;
94+
95+
HypotenuseMapper.ensureInitialized();
96+
97+
var h = decode<Hypotenuse>({'x': 3, 'y': 4});
98+
expect(h, equals((x: 3, y: 4, hypotenuse: sqrt(3 * 3 + 4 * 4))));
99+
expect(
100+
encode(h),
101+
equals({'x': 3, 'y': 4, 'hypotenuse': sqrt(3 * 3 + 4 * 4)}),
102+
);
103+
});
104+
73105
test('can decode and encode nested record', () {
74106
var decode = MapperContainer.globals.fromMap;
75107
var encode = MapperContainer.globals.toMap;

packages/dart_mappable/test/records/mappable_record_test.mapper.dart

Lines changed: 113 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dart_mappable_builder/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Unreleased
2+
3+
- Record mappers now correctly generate hooks specified on the record annotation itself, not just those on individual fields.
4+
15
# 4.6.0
26

37
- Migrate to new `element2` analyzer model.

packages/dart_mappable_builder/lib/src/elements/class/class_mapper_element.dart

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:analyzer/dart/ast/ast.dart';
21
import 'package:analyzer/dart/element/element.dart';
32
import 'package:dart_mappable/dart_mappable.dart';
43

@@ -76,21 +75,6 @@ abstract class ClassMapperElement extends InterfaceMapperElement<ClassElement>
7675
options.generateMethods ??
7776
GenerateMethods.all;
7877

79-
late final String? hookForClass = () {
80-
var hook = annotation.value?.read('hook');
81-
if (hook != null && !hook.isNull) {
82-
var node = annotation.getPropertyNode('hook');
83-
if (node != null) {
84-
var hook = node.toSource();
85-
if (node is InstanceCreationExpression) {
86-
hook = 'const $hook';
87-
}
88-
return hook;
89-
}
90-
}
91-
return null;
92-
}();
93-
9478
// --- Element properties ---
9579

9680
@override

packages/dart_mappable_builder/lib/src/elements/mapper_element.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,19 @@ abstract class InterfaceMapperElement<T extends Element>
6767
String get typeParamsDeclaration;
6868

6969
List<MapperFieldElement> get fields;
70+
71+
late final String? hookForElement = () {
72+
var hook = annotation.value?.read('hook');
73+
if (hook != null && !hook.isNull) {
74+
var node = annotation.getPropertyNode('hook');
75+
if (node != null) {
76+
var hook = node.toSource();
77+
if (node is InstanceCreationExpression) {
78+
hook = 'const $hook';
79+
}
80+
return hook;
81+
}
82+
}
83+
return null;
84+
}();
7085
}

packages/dart_mappable_builder/lib/src/generators/mixins/decoding_mixin.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mixin DecodingMixin on MapperGenerator<TargetClassMapperElement> {
99
Future<void> generateInstantiateMethod(StringBuffer output) async {
1010
output.write('\n');
1111

12-
var hook = element.hookForClass;
12+
var hook = element.hookForElement;
1313
if (hook != null) {
1414
output.write('''
1515
@override
@@ -89,7 +89,7 @@ mixin DecodingMixin on MapperGenerator<TargetClassMapperElement> {
8989
if (element.superElement == null) {
9090
return [];
9191
} else {
92-
var hook = element.superElement!.hookForClass;
92+
var hook = element.superElement!.hookForElement;
9393
return [if (hook != null) hook, ..._getSuperHooks(element.superElement!)];
9494
}
9595
}

packages/dart_mappable_builder/lib/src/generators/record_mapper_generator.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class RecordMapperGenerator extends MapperGenerator<RecordMapperElement> {
4242

4343
generateTypeFactory(output);
4444
generateApplyOverride(output);
45+
generateHook(output);
4546
generateInstantiate(output);
4647
generateStaticDecoders(output);
4748

@@ -130,4 +131,14 @@ class RecordMapperGenerator extends MapperGenerator<RecordMapperElement> {
130131
' }\n',
131132
);
132133
}
134+
135+
void generateHook(StringBuffer output) {
136+
var hook = element.hookForElement;
137+
if (hook != null) {
138+
output.write('''
139+
@override
140+
final MappingHook hook = $hook;
141+
''');
142+
}
143+
}
133144
}

0 commit comments

Comments
 (0)