Skip to content

Commit c89ae1a

Browse files
committed
fix deserialize and http client
1 parent 2cb3f64 commit c89ae1a

File tree

6 files changed

+62
-69
lines changed

6 files changed

+62
-69
lines changed

lib/src/adapter/remote_adapter.dart

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ mixin _RemoteAdapter<T extends DataModelMixin<T>> on _SerializationAdapter<T> {
296296
/// as by default they are used once and then closed.
297297
@protected
298298
@visibleForTesting
299-
http.Client get httpClient => ref.read(httpClientProvider);
299+
http.Client get httpClient => ref.read(httpClientFactoryProvider).call();
300300

301301
/// The function used to perform an HTTP request and return an [R].
302302
///
@@ -498,8 +498,8 @@ mixin _RemoteAdapter<T extends DataModelMixin<T>> on _SerializationAdapter<T> {
498498
return label.model as R?;
499499
}
500500

501-
final data = await deserialize(body as Map<String, dynamic>,
502-
key: label.model!._key);
501+
final data =
502+
deserialize(body as Map<String, dynamic>, key: label.model!._key);
503503
final model = data.model!;
504504

505505
// if there has been a migration to a new key, delete the old one
@@ -530,8 +530,17 @@ mixin _RemoteAdapter<T extends DataModelMixin<T>> on _SerializationAdapter<T> {
530530
return response.body as R?;
531531
}
532532

533-
final deserialized = await deserializeAndSave(body);
534-
deserialized._log(adapter, label);
533+
final deserialized = await deserializeAsync(body, save: true);
534+
535+
adapter.log(
536+
label, '${deserialized.models.toShortLog()} fetched from remote');
537+
final groupedIncluded =
538+
deserialized.included.groupListsBy((m) => m._adapter.type);
539+
for (final e in groupedIncluded.entries) {
540+
if (e.value.isNotEmpty) {
541+
adapter.log(label, ' - with ${e.key} ${e.value.toShortLog()} ');
542+
}
543+
}
535544

536545
if (isFindAll || (isCustom && deserialized.model == null)) {
537546
late R? models;
@@ -647,4 +656,5 @@ mixin _RemoteAdapter<T extends DataModelMixin<T>> on _SerializationAdapter<T> {
647656
{'Content-Type': 'application/json'};
648657
}
649658

650-
final httpClientProvider = Provider<http.Client>((_) => http.Client());
659+
final httpClientFactoryProvider =
660+
Provider<http.Client Function()>((_) => () => http.Client());

lib/src/adapter/serialization_adapter.dart

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -97,37 +97,31 @@ mixin _SerializationAdapter<T extends DataModelMixin<T>> on _BaseAdapter<T> {
9797

9898
/// Returns a [DeserializedData] object when deserializing a given [data].
9999
///
100-
Future<DeserializedData<T>> deserialize(Object? data,
101-
{String? key, bool async = true}) async {
102-
final record = async
103-
? await runInIsolate(
104-
(adapter) => adapter._deserialize(adapter, data, key: key))
105-
: _deserialize(this as Adapter, data, key: key);
100+
DeserializedData<T> deserialize(Object? data, {String? key}) {
101+
final record = _deserialize(this as Adapter, data, key: key);
106102
return DeserializedData<T>(record.$1.cast<T>(), included: record.$2);
107103
}
108104

109-
Future<DeserializedData<T>> deserializeAndSave(Object? data,
110-
{String? key, bool notify = true, bool ignoreReturn = false}) async {
111-
final record = await runInIsolate<
112-
(
113-
List<DataModelMixin>,
114-
List<DataModelMixin>,
115-
List<String>
116-
)>((adapter) async {
117-
final emptyDm = <DataModelMixin>[];
118-
final r = adapter._deserialize(adapter, data, key: key);
119-
final models = [...r.$1, ...r.$2];
120-
if (models.isEmpty) return (emptyDm, emptyDm, <String>[]);
121-
final savedKeys = await adapter.saveManyLocal(models, async: false);
122-
return ignoreReturn
123-
? (emptyDm, emptyDm, savedKeys!)
124-
: (r.$1, r.$2, savedKeys!);
105+
Future<DeserializedData<T>> deserializeAsync(Object? data,
106+
{String? key,
107+
bool save = false,
108+
bool ignoreReturn = false,
109+
bool notify = true}) async {
110+
final record =
111+
await runInIsolate<(DeserializedData?, List<String>)>((adapter) async {
112+
final deserialized = adapter.deserialize(data, key: key);
113+
if (deserialized.models.isEmpty || save == false)
114+
return (deserialized, <String>[]);
115+
final savedKeys = await adapter.saveManyLocal(
116+
[...deserialized.models.cast(), ...deserialized.included],
117+
async: false);
118+
return ignoreReturn ? (null, savedKeys!) : (deserialized, savedKeys!);
125119
});
126-
final (models, included, savedKeys) = record;
120+
final (deserialized, savedKeys) = record;
127121
if (notify && savedKeys.isNotEmpty) {
128122
core._notify(savedKeys, type: DataGraphEventType.updateNode);
129123
}
130-
return DeserializedData<T>(models.cast<T>(), included: included);
124+
return (deserialized as DeserializedData<T>?) ?? DeserializedData<T>([]);
131125
}
132126
}
133127

@@ -137,14 +131,4 @@ class DeserializedData<T extends DataModelMixin<T>> {
137131
final List<T> models;
138132
final List<DataModelMixin> included;
139133
T? get model => models.singleOrNull;
140-
141-
void _log(Adapter adapter, DataRequestLabel label) {
142-
adapter.log(label, '${models.toShortLog()} fetched from remote');
143-
final groupedIncluded = included.groupListsBy((m) => m._adapter.type);
144-
for (final e in groupedIncluded.entries) {
145-
if (e.value.isNotEmpty) {
146-
adapter.log(label, ' - with ${e.key} ${e.value.toShortLog()} ');
147-
}
148-
}
149-
}
150134
}

lib/src/model/relationship/has_many.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class HasMany<E extends DataModelMixin<E>> extends Relationship<E, Set<E>> {
6767

6868
E get first => _iterable.first;
6969

70+
E? get safeFirst => isNotEmpty ? first : null;
71+
7072
bool get isEmpty => length == 0;
7173

7274
bool get isNotEmpty => length > 0;

test/_support/setup.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ final logging = [];
3333
Future<void> setUpFn() async {
3434
container = ProviderContainer(
3535
overrides: [
36-
httpClientProvider.overrideWith((ref) {
37-
return MockClient((req) async {
38-
final response = ref.watch(responseProvider);
39-
final text = await response.callback(req);
40-
if (text is String) {
41-
return http.Response(text, response.statusCode,
42-
headers: response.headers);
43-
}
44-
return http.Response.bytes(text as Uint8List, response.statusCode,
45-
headers: response.headers);
46-
});
36+
httpClientFactoryProvider.overrideWith((ref) {
37+
return () => MockClient((req) async {
38+
final response = ref.watch(responseProvider);
39+
final text = await response.callback(req);
40+
if (text is String) {
41+
return http.Response(text, response.statusCode,
42+
headers: response.headers);
43+
}
44+
return http.Response.bytes(text as Uint8List, response.statusCode,
45+
headers: response.headers);
46+
});
4747
}),
4848
coreNotifierThrottleDurationProvider.overrideWithValue(Duration.zero),
4949
// NOTE: Can't enable in-memory sqlite as it can't be shared across isolates

test/model/relationship/relationship_test.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,13 @@ void main() async {
192192
expect(familia2.persons.toSet(), {brian});
193193

194194
// new familia comes in from API (simulate) with no persons relationship information
195-
final familia3 =
196-
(await container.familia.deserialize({'id': '229', 'surname': 'Rose'}))
197-
.model!;
195+
final familia3 = (container.familia
196+
.deserialize({'id': '229', 'surname': 'Rose'})).model!;
198197
// it should keep the relationships unaltered
199198
expect(familia3.persons.toSet(), {brian});
200199

201200
// new familia comes in from API (simulate) with empty persons relationship
202-
final familia4 = (await container.familia
201+
final familia4 = (container.familia
203202
.deserialize({'id': '229', 'surname': 'Rose', 'persons': []}))
204203
.model!
205204
.saveLocal();

test/repository/remote_adapter_serialization_test.dart

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,14 @@ void main() async {
7171
});
7272

7373
test('serialize empty', () async {
74-
final data = await container.people.deserialize(null);
74+
final data = container.people.deserialize(null);
7575
expect(data.model, isNull);
76-
final data2 = await container.people.deserialize('');
76+
final data2 = container.people.deserialize('');
7777
expect(data2.model, isNull);
7878
});
7979

8080
test('deserialize multiple', () async {
81-
final data = await container.people.deserialize([
81+
final data = container.people.deserialize([
8282
{'_id': '23', 'name': 'Ko', 'age': 24},
8383
{'_id': '26', 'name': 'Ze', 'age': 58}
8484
]);
@@ -90,17 +90,15 @@ void main() async {
9090
});
9191

9292
test('deserialize with BelongsTo id', () async {
93-
final p = (await container.people.deserialize([
93+
final p = (container.people.deserialize([
9494
{'_id': '1', 'name': 'Na', 'age': 88, 'familia': null}
95-
]))
96-
.model!
97-
.saveLocal();
95+
])).model!.saveLocal();
9896

9997
Familia(id: '1', surname: 'Kong').saveLocal();
10098

10199
expect(p.familia.key, isNull);
102100

103-
final p1d = await container.people.deserialize([
101+
final p1d = container.people.deserialize([
104102
{'_id': '27', 'name': 'Ko', 'age': 24, 'familia': '332'}
105103
]);
106104
final p1 = p1d.model!.saveLocal();
@@ -124,14 +122,14 @@ void main() async {
124122
});
125123

126124
test('deserialize returns even if no ID is present', () async {
127-
final data = await container.familia.deserialize([
125+
final data = container.familia.deserialize([
128126
{'surname': 'Ko'}
129127
]);
130128
expect(data.model, isNotNull);
131129
});
132130

133131
test('deserialize with HasMany ids (including nulls)', () async {
134-
final data = await container.familia.deserialize([
132+
final data = container.familia.deserialize([
135133
{
136134
'id': '1',
137135
'surname': 'Ko',
@@ -150,7 +148,7 @@ void main() async {
150148
});
151149

152150
test('deserialize with complex-named relationship', () async {
153-
final data = await container.books.deserialize([
151+
final data = container.books.deserialize([
154152
{
155153
'id': 1,
156154
'name': 'Ludwig',
@@ -160,7 +158,7 @@ void main() async {
160158
});
161159

162160
test('deserialize with embedded relationships', () async {
163-
final data = await container.familia.deserialize(
161+
final data = container.familia.deserialize(
164162
[
165163
{
166164
'id': '1',
@@ -196,7 +194,7 @@ void main() async {
196194
});
197195

198196
test('deserialize with nested embedded relationships', () async {
199-
final data = await container.people.deserialize(
197+
final data = container.people.deserialize(
200198
[
201199
{
202200
'_id': '1',
@@ -223,7 +221,7 @@ void main() async {
223221
() async {
224222
BookAuthor(id: 332, name: 'Zhung', books: HasMany()).saveLocal();
225223

226-
final deserialized = await container.books.deserialize([
224+
final deserialized = container.books.deserialize([
227225
{'id': 27, 'title': 'Ko', 'original_author_id': 332}
228226
]);
229227
final book = deserialized.model!.saveLocal();

0 commit comments

Comments
 (0)