Skip to content

Commit 11fed21

Browse files
committed
Add unwrapper
1 parent f60818a commit 11fed21

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

lib/src/robot/client.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class Discovery {
8383
return Discovery(
8484
subtype: proto.query.subtype,
8585
model: proto.query.model,
86-
results: proto.results.toMap(),
86+
results: proto.results.toMap().unwrap(),
8787
);
8888
}
8989

lib/src/utils.dart

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,84 @@ extension StructUtils on Struct {
3939
}
4040
}
4141

42+
extension UnwrapProtoMapUtils on Map<String, dynamic> {
43+
/// Deeply unwraps a nested proto map structure by removing unnecessary proto wrappers and
44+
/// converting all nested values to their primitive Dart types.
45+
///
46+
/// Handles:
47+
/// - Removes 'Kind' wrappers from proto Values
48+
/// - Removes 'fields' wrappers from proto Structs
49+
/// - Converts proto scalar types (String, Number, Bool, Null)
50+
/// - Converts proto complex types (List, Struct)
51+
/// - Preserves original structure minus wrappers
52+
Map<String, dynamic> unwrap() {
53+
final result = <String, dynamic>{};
54+
55+
// Core recursive function that processes each value in the structure
56+
dynamic unwrapValue(dynamic value) {
57+
// Handle maps - primary case for proto wrapper removal
58+
if (value is Map) {
59+
final mapValue = Map<String, dynamic>.from(value);
60+
61+
// Two main wrapper types to handle:
62+
63+
// 1. Kind wrapper (from proto Value)
64+
if (mapValue.containsKey('Kind')) {
65+
final kindValue = mapValue['Kind'];
66+
if (kindValue is Map) {
67+
final kindMap = Map<String, dynamic>.from(kindValue);
68+
69+
// Scalar types are direct conversions - base cases
70+
if (kindMap.containsKey('StringValue')) return kindMap['StringValue'];
71+
if (kindMap.containsKey('NumberValue')) return kindMap['NumberValue'];
72+
if (kindMap.containsKey('BoolValue')) return kindMap['BoolValue'];
73+
if (kindMap.containsKey('NullValue')) return null;
74+
75+
// Complex types need recursive handling - can be a base case when empty
76+
if (kindMap.containsKey('ListValue')) {
77+
final listValue = kindMap['ListValue'];
78+
if (listValue is Map && listValue.containsKey('values')) {
79+
return (listValue['values'] as List).map(unwrapValue).toList();
80+
}
81+
return [];
82+
}
83+
84+
if (kindMap.containsKey('StructValue')) {
85+
final structValue = kindMap['StructValue'];
86+
if (structValue is Map && structValue.containsKey('fields')) {
87+
return Map<String, dynamic>.from(structValue['fields']).unwrap();
88+
}
89+
}
90+
}
91+
return value;
92+
}
93+
94+
// 2. Fields wrapper (from proto Struct)
95+
if (mapValue.containsKey('fields')) {
96+
return Map<String, dynamic>.from(mapValue['fields']).unwrap();
97+
}
98+
99+
// Regular map - continue unwrapping all values
100+
return mapValue.map((key, val) => MapEntry(key, unwrapValue(val)));
101+
}
102+
103+
// Handle lists - unwrap each element
104+
if (value is List) {
105+
return value.map(unwrapValue).toList();
106+
}
107+
108+
return value; // base case: primitive value
109+
}
110+
111+
// Process each top-level key-value pair
112+
forEach((key, value) {
113+
result[key] = unwrapValue(value);
114+
});
115+
116+
return result;
117+
}
118+
}
119+
42120
extension ListValueUtils<T> on List<T> {
43121
Value toValue() {
44122
final values = map((e) {

0 commit comments

Comments
 (0)