Comments (12)
You'd need to pass in the actual client into the offline mutation Link, so it can call the real request () method.
from ferry.
In my OfflineMutationTypedLink
I have this contructor:
OfflineMutationTypedLink({
required this.mutationQueueBox,
required this.serializers,
required this.cache,
required this.requestController,
// required this.client, <----- do I need to pass the client here? (client is OfflineClient type)
this.config = const OfflineClientConfig(),
});
If I pass it here, when I am declaring the OfflineClient
, has to be declared like this?
OfflineClient({
required this.link,
required this.storeBox,
required this.mutationQueueBox,
required this.serializers,
this.offlineConfig,
required this.requestController,
this.typePolicies = const {},
this.updateCacheHandlers = const {},
this.defaultFetchPolicies = const {},
this.addTypename = true,
}) : cache = Cache(
store: HiveStore(storeBox),
typePolicies: typePolicies,
addTypename: addTypename,
) {
_typedLink = TypedLink.from([
RequestControllerTypedLink(requestController),
OfflineMutationTypedLink(
cache: cache,
mutationQueueBox: mutationQueueBox,
serializers: serializers,
requestController: requestController,
config: offlineConfig,
// client: this <----- here adding this also enters in recursive
),
if (addTypename) const AddTypenameTypedLink(),
if (updateCacheHandlers.isNotEmpty)
UpdateCacheTypedLink(
cache: cache,
updateCacheHandlers: updateCacheHandlers,
),
FetchPolicyTypedLink(
link: link,
cache: cache,
defaultFetchPolicies: defaultFetchPolicies,
)
]);
}
Thanks
from ferry.
There is a chicken - and egg problem here, since the link needs the client and the client needs the link.
You could first create the link, then the client, and then set the Client in the link.
from ferry.
Okay, thank you @knaeckeKami ! Finally I also discovered that my code when I had connection I was setting always connect
to true and thus it was always calling request
making the infinite recursive loop. Adding instead a listener into the request handler solved the issue.
A part from that, now I am struggling with a type problem that it was also pointed on the same discussion (here).
So trying this:
void _handleOnConnect() async {
final queue = StreamQueue(Stream.fromIterable(mutationQueueBox.values));
while (await queue.hasNext) {
final json = await queue.next;
final req = serializers.deserialize(json) as OperationRequest<Object, Object>;
// Run unexecuted mutations
await client
.request(req)
.firstWhere((res) => res.dataSource == DataSource.Link && res.operationRequest == req);
}
}
results to an Unhandled Exception on the UpdateChaceTypedLink, since it does not match the expected Type:
[VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: type '(CacheProxy, OperationResponse<GUpsertObservationData, GUpsertObservationVars>) => void' is not a subtype of type '(CacheProxy, OperationResponse<Object, Object>) => void' in type cast
#0 UpdateCacheTypedLink._updateCache
#1 _DoStreamSink.onData
do.dart:31
#2 _RootZone.runUnaryGuarded (dart:async/zone.dart:1593:10)
#3 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
#4 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#5 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:774:19)
#6 _StreamController._add (dart:async/stream_controller.dart:648:7)
#7 _StreamController.add (dart:async/stream_controller.dart:596:5)
#8 _DoStreamSink.onData
do.dart:40
#9 _RootZone.runUnaryGuarded (dart:async/zone.dart:1593:10)
#10 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
#11 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#12 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:774:19)
#13 _StreamController._add (dart:async/stream_controller.dart:648:7)
#14 _StreamController.add (dart:async/stream_controller.dart:596:5)
#15 _DoStreamSink.onData
do.dart:40
#16 _RootZone.runUnaryGuarded (dart:async/zone.dart:1593:10)
I could infere the type depending on the mutation I am trying to deserialize, but it is possible that dart could assign the correct type?
Thank you beforehand!
from ferry.
unfortunately, that's an issue with variance here.
I don't have a good solution at the moment, but I think a workaround would be changing your cachehandlers to accept OperationResponse<Object?, Object?> and cast the results
from ferry.
Okay thank you. For the moment defining a cache handler type as UpdateCacheHandler<Object?, Object?>
and type casting inside the cache handler like for instance:
final responseUpsertObservation = response as OperationResponse<GUpsertObservationData, GUpsertObservationVars>;
Moves the error from the OfflineMutationTypedLink to the cache handler, but still cannot cast the subtype giving the same typecasting error:
Unhandled Exception: type 'OperationResponse<Object, Object>' is not a subtype of type 'OperationResponse<GUpsertObservationData, GUpsertObservationVars>' in type cast
I will try to investigate if it is possible to cast it somehow. Do you know if there's probably an internal issue (or using built_value underhood library?)
from ferry.
You can work around it by casting not the response, but the data:
void myCacheHandler(
CacheProxy proxy,
OperationResponse<dynamic, dynamic> response,
) {
//ignore: avoid_dynamic_calls
final myData = response.data as MyData?
}
Using dynamic
instead of Object? is usually a bad idea, but in this instance it will get Dart to shut up ;)
from ferry.
I will try to investigate if it is possible to cast it somehow. Do you know if there's probably an internal issue (or using built_value underhood library?)
This is not an issue in built_value. Actually, built_value is one of the only serialization libraries that support something like
serializers.deserialize(json);
which would deserialize to the correct type without you having to specify it. (Most would require you to write MyReq.fromJson(json)
but would not allow you to just deserialize any request without specifying which one ).
The issue is that after deserialization, we don't know the exact type. We just know it an OperationRequest<Object, Object>
, so we can cast it up to this type.
Which works fine in covariant positions (an OperationResponse<MyData, MyVars>
is an OperationResponse<Object, Object>
) for return types, but not in contravariant positions (a void Function(OperationResponse<MyData, MyVars>
) is NOT a void Function(OperationResponse<Object, Object>
),
So, even if all the runtime types match perfectly, Dart still checks the types before calling the function and because the generics type parameters are <Object, Object>
instead of <MyData, MyVars>
, it will throw an exception.
This is unfortunately more of an ugly corner of the Dart type system than an issue in built_value.
However, there would be ways around this.
We could add a new method to OperationRequest:
abstract class OperationRequest<TData, TVars> {
Stream<OperationResponse<TData, TVars> execute(TypedLink link) => link.request(this);
}
With this hack, we could get Dart to infer the correct type parameters.
This would require changes to the code generation though since OperationRequest is implemented, not extended at the moment.
from ferry.
Hmmm interesting... 🤔 Thank you for the clarification! I finally could get rid of the type error as you suggested casting the response.data
on my handler.
I was thinking that probably since I got the hands dirty with the OfflineMutationTypedLink try to push the PR #144 and close it since I am also trying to implement what @akinsho did in the past.
from ferry.
@francescreig please feel free to carry on with that PR, I've since moved project and role so am no longer able to push that PR forward. It's been quite a while since I looked at any of that code so not sure I can remember enough to provide any useful input
from ferry.
Hmmm interesting... 🤔 Thank you for the clarification! I finally could get rid of the type error as you suggested casting the
response.data
on my handler. I was thinking that probably since I got the hands dirty with the OfflineMutationTypedLink try to push the PR #144 and close it since I am also trying to implement what @akinsho did in the past.
Yeah, I was also running into this issue myself and did not really understand it, until the same thing happened when it added the feature to run the client in an Isolate (also there the requests are serialized and the receiver does not know the. generic types), and so I had to do something similar ->
create a command with the correct generic types, send the command over the isolate, and let the command call the request() method itself without the receiver needing to infer the types:
If you manage to improve the OfflineMutationTypedLink, I'd be grateful. As far as I understand, the currently shipped OfflineMutationLink does not work at all, right? (I was not the maintainer of ferry at the time this was written and did not use it myself yet so I may not fully understand what is happening there)
from ferry.
@francescreig can you share your solution? Or if possible add this to the open PR? Either would be very helpful.
from ferry.
Related Issues (20)
- Custom ISO serializer for DateTime HOT 5
- How to remove the `__typename` in the `toJson` of a fragment HOT 2
- Change in cache doesn't propagate HOT 28
- [Feature Request] Add `ContextEntries` to requests that can be retrieved in custom `gql` `Link` HOT 9
- [Feature Request] Access properties using Maps (ferry_generator) HOT 3
- [question]: Freezed support HOT 4
- [Feature Request] a CLI that output unused field/argument in the schema HOT 1
- Generating tristate_optionals generates invalid code with mixed up imports HOT 12
- Unable to Upload Multipart File with dio link HOT 2
- ferry_flutter: endless loading state after the cache has been cleared HOT 1
- Null check operator used on a null value and "Bad Element" HOT 1
- schema.schema.gql.dart not generated - "possibleTypesMap" missing HOT 3
- Ferry cannot decompose fragment on TypeCondition HOT 1
- Manually update the ferry data HOT 1
- TypePolicy is broken Or there is no clear documentation about it. HOT 12
- The relevant error-causing widget was:
- [Feature Request] Export request query to graphql HOT 1
- Non-dev dependency in ferry_generator package HOT 2
- Simple example calling a mutation on click and handling the response HOT 7
- How to create a request of Extends Query Type HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ferry.