gql-dart / ferry Goto Github PK
View Code? Open in Web Editor NEWStream-based strongly typed GraphQL client for Dart
Home Page: https://ferrygraphql.com/
License: MIT License
Stream-based strongly typed GraphQL client for Dart
Home Page: https://ferrygraphql.com/
License: MIT License
Currently, each operation gets normalized underneath its root type in the cache.
For example, the following query
query TestQuery($first: Int, $offset: Int) {
posts(first: $first, offset: $offset) {
__typename
id
title
}
}
Might result in the following normalized cache:
final Map<String, dynamic> sharedNormalizedMap = {
'Query': {
'__typename': 'Query'
'posts({"first": 1, "offset":0})': [
{'\$ref': 'Post:123'}
]
},
'Post:123': {
'id': '123',
'__typename': 'Post',
'title': 'My awesome blog post',
},
};
Since all queries exist under the root Query
key, individual queries cannot be easily evicted.
I propose we flatten root operations. The same example above would then look like this:
final Map<String, dynamic> sharedNormalizedMap = {
'Query:posts({"first": 1, "offset":0})': {
'__typename': 'Query'
'posts({"first": 1, "offset":0})': [
{'\$ref': 'Post:123'}
]
},
'Post:123': {
'id': '123',
'__typename': 'Post',
'title': 'My awesome blog post',
},
};
If we were to execute the same query with different args, our cache might look like this:
final Map<String, dynamic> sharedNormalizedMap = {
'Query:posts({"first": 1, "offset":0})': {
'__typename': 'Query'
'posts({"first": 1, "offset":0})': [
{'\$ref': 'Post:123'}
]
},
'Query:posts({"first": 1, "offset":1})': {
'__typename': 'Query'
'posts({"first": 1, "offset":1})': [
{'\$ref': 'Post:456'}
]
},
'Post:123': {
'id': '123',
'__typename': 'Post',
'title': 'My awesome blog post',
},
'Post:456': {
'id': '456',
'__typename': 'Post',
'title': 'My second blog post',
},
};
targets:
$default:
builders:
gql_build|schema_builder:
enabled: true
options:
type_overrides:
jsonb:
name: DateTime
timestamp:
name: DateTime
gql_build|ast_builder:
enabled: true
gql_build|data_builder:
enabled: true
options:
schema: app|lib/schema.graphql
gql_build|var_builder:
enabled: true
options:
schema: app|lib/schema.graphql
gql_build|serializer_builder:
enabled: true
options:
schema: app|lib/schema.graphql
ferry_generator|req_builder:
enabled: true
options:
schema: app|lib/schema.graphql
Error in BuiltValueGenerator for abstract class Ginsert_missionVars implements Built<Ginsert_missionVars, dynamic>.
Please make the following changes to use BuiltValue:
1. Make field end_time have non-dynamic type. If you are already specifying a type, please make sure the type is correctly imported.
Hi!
In app I use FetchPolicy.CacheAndNetwork for query.
When I disable internet on phone or internet very bad, but data is set in cache, I get this error.
It is normal logic for CacheAndNetwork?
The getter 'loading' was called on null.
Receiver: null
Tried calling: loading
When I use query without FetchPolicy, data is set in cache and disable internet, it is ok.
The example pokemon details page doesn't load. It may be an issue with the Dgraph slash server
When I run ferry_graphql, get a error.
../../development/flutter/.pub-cache/hosted/pub.flutter-io.cn/ferry-0.7.4/lib/src/cache.dart:284:23: Error: Method not found: 'reachableDataIds'.
final reachable = utils.reachableDataIds(
^^^^^^^^^^^^^^^^
FAILURE: Build failed with an exception.
* Where:
Script '/Users/huangzheng/development/flutter/packages/flutter_tools/gradle/flutter.gradle' line: 904
* What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.
I recommend making normalize version 0.5
Current hit ratio is very low on CloudFront
Apollo uses an "identify" function which automatically builds the dataId based on the ID fields defined for that type.
https://www.apollographql.com/docs/react/caching/cache-interaction/#obtaining-an-objects-custom-id
I'm wondering whether the 'initial' request performed within the Client.responseStream method is required or can be made controllable.
In my use case I want to setup a response stream listener when a screen is displayed, without implicitly triggering a request. The initial request is particular annoying when its a mutation the user first has to provide arguments for.
As far as I can tell, making the initial request disableable, but enabled by default for backwards compatibility, would hurt, right?
There is currently no way to refetch a query manually with the same variables.
Even if the fetch policy includes the network i.e. CacheAndNetwork, I currently have to use a key to force the parent widget of the query to reload when refetch is required.
Ideally, the network policy could be set to CacheFirst and then the query manually refetched as required.
Hello, I've started implementing your package and have difficulties with updating the client token for Firebase.
They issue a new token every 3600 seconds. So, I have to have a reliable way to update it in the app.
Right now you in your example you suggest using such an approach
import 'package:gql_http_link/gql_http_link.dart';
import 'package:ferry/ferry.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
Future<Client> initClient() async {
await Hive.initFlutter();
final box = await Hive.openBox("graphql");
final store = HiveStore(box);
final cache = Cache(dataStore: store);
final link = HttpLink("https://graphql-pokemon.now.sh/graphql");
final client = Client(
link: link,
cache: cache,
);
return client;
}
I tried to make reliable updating for connecting with the short living token, but I failed. If you have some best practices for this, can you please share?
Maybe, it could be useful to add update() method to Client
class Client {
final Link link;
final Cache cache;
final ClientOptions options;
Thank you for such a nice plugin!
output after run pub run build_runner build --delete-conflicting-outputs
[INFO] Generating build script completed, took 483ms
[WARNING] Configuring `gql_build:serializer_builder` in target `app:app` but this is not a known Builder
[INFO] Reading cached asset graph completed, took 73ms
[INFO] Checking for updates since last build completed, took 1.0s
[INFO] Running build completed, took 23ms
[INFO] Caching finalized dependency graph completed, took 79ms
[INFO] Succeeded after 115ms with 0 outputs (0 actions)
error in the generated file test.req.gql.dart
Target of URI doesn't exist: 'package:app/gql/query/test.op.gql.dart'. Try creating the file referenced by the URI, or Try using a URI for a file that does exist
Any solutions?
Thanks
As per the GraphQL spec, subscriptions must include one and only one root field including introspection fields.
I have a MessageReceived
subscription with one root field:
subscription MessageReceived {
messageReceived {
prevMessageTimestamp
message {
...on TextMessage {
...FullTextMessage
}
...on RecordingMessage {
...FullRecordingMessage
}
...on TypingMessage {
...FullTypingMessage
}
...on PresenceMessage {
...FullPresenceMessage
}
}
}
}
and for some reason I get Subscription "MessageReceived" must select only one top level field.
error message.
I hight suspect that addTypename functionality automatically adds __typename to my subscription and therefore invalidating it.
Subscription
type.With optimistic cache make the mutation without the internet connection. After that turn on the connection.
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception:
#0 IOClient.send (package:http/src/io_client.dart:65:7)
<asynchronous suspension>
#1 BaseClient._sendUnstreamed (package:http/src/base_client.dart:176:38)
#2 BaseClient.post (package:http/src/base_client.dart:58:7)
#3 HttpLink.request (package:gql_http_link/src/link.dart:99:44)
<asynchronous suspension>
#4 Client._networkResponseStream (package:ferry/src/client/client.dart:146:12)
#5 Client._optimisticNetworkResponseStream (package:ferry/src/client/client.dart:128:13)
#6 Client._responseStream (package:ferry/src/client/client.dart:88:16)
#7 Client.responseStream.<anonymous closure> (package:ferry/src/client/client.dart:49:29)
#8 SwitchMapStreamTransformer._buildTransformer.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:rxdart/src/transformers/switch_map.dart:55:47)
#9 _rootRunUnary (dart:async/zone.dart:1134:38)
#10 _CustomZone.runUnary (dart:async/zone.dart:1031:19)
#11<…>
It took 60 seconds to get the issue, sorry for the long animated gif.
I'll explain this bug with an example:
type Person implements Node {
id: ID!
firstName: String!
lastName: String!
}
type Message implements Node {
id: ID!
content: String!
sender: Person!
}
type Viewer implements Node {
id: ID!
friends: [Person!]!
latestMessage: Message!
}
type Query {
viewer: Viewer!
}
And let's say in the main screen of my app I want to display a list of friends (first name + last name) and my latest message: (only first name is shown in the sender line of messages on my app)
query FetchMainScreen {
viewer {
friends {
id
firstName
lastName
}
latestMessage {
id
content
sender {
id
firstName
}
}
}
}
When I fetch this query the first time: _client.responseStream(GFetchMainScreenReq())
using a cache-enabled fetch policy, it will write the normalized data to the cache. But during this process it will override one sender with only firstName attached to it. (because the latestMessage's sender is parsed after the friends list, and it only contains firstName)
So if I run _client.cache.readQuery(GFetchMainScreenReq())
immediately after it will return null because a PartialDataException
is raised.
This can't be right, as I just executed this query, and now it's by-design stays partial in the cache.
If, say, I rewrite the query above like that: (latestMessage first, friends after)
query FetchMainScreen {
viewer {
latestMessage {
id
content
sender {
id
firstName
}
}
friends {
id
firstName
lastName
}
}
}
The cache works as expected (since the overwrite just added a lastName field to the sender)
The source of this issue to my understanding is at normalize_node.dart:75
if (fieldPolicy?.merge != null) {
return data
..[fieldName] = fieldPolicy.merge(
existingFieldData,
fieldData,
FieldFunctionOptions(
field: field,
config: config,
),
);
}
// ->>>>>>>>> This overrides the previous person that was normalized in this operation with less complete data.
return data..[fieldName] = fieldData;
I would suggest implementing a default deepMerge (as indeed happens in across-queries writes to the cache) even if I didn't implement a custom merge in a field policy.
Hi,
I think it would be nice if a custom Link would get notified when the Stream it is returning in it's request
method isn't being listened to anymore.
This would allow for the Link to cancel a Subscription automatically once no one is listening anymore, or to clean up other resources.
Currently, this is not the case.
This can be shown in this test case, which will time out:
import 'dart:async';
import 'package:ferry/ferry.dart';
import 'package:gql_exec/gql_exec.dart';
import 'package:gql_exec/src/response.dart';
import 'package:test/test.dart';
import './graphql/all_pokemon.req.gql.dart';
class _StreamCancelTestLink extends Link {
final Completer hasCanceledStreamCompleter = Completer();
@override
Stream<Response> request(Request request, [forward]) async* {
StreamController<Response> controller =
StreamController(onCancel: () => print("oncancel controller"));
StreamSubscription sub;
try {
//simulate events coming in, e.g. from a websocket
sub =
Stream.periodic(Duration(microseconds: 1), (_) => Response(data: {}))
.listen(controller.add);
//yield* should finish when the client stops listening
yield* controller.stream;
} finally {
//this gets called when the client stops listening to the stream
sub?.cancel();
controller.close();
hasCanceledStreamCompleter.complete();
}
}
}
void main() {
test("Can cleanup", () async {
final link = _StreamCancelTestLink();
final client = Client(link: link);
final req1 = AllPokemon(
fetchPolicy: FetchPolicy.NetworkOnly, buildVars: (b) => b..first = 3);
expect(link.hasCanceledStreamCompleter.isCompleted, isFalse);
StreamSubscription subscription;
subscription = client.responseStream(req1).skip(1).listen((event) async {
//cancel subscription after first item
//this ensures the the link.request() method is entered
await subscription.cancel();
});
// the link should complete its "yield*" statement when the subscription is cancelled
// and complete its completer
await link.hasCanceledStreamCompleter.future;
expect(link.hasCanceledStreamCompleter.isCompleted, isTrue);
});
}
I think with two small changes to the Ferry client we can get this behavior. I will open PRs with these changes shortly.
Loving the library so far but I have a couple questions...
I got the rest of my schema working properly, along with other custom scalars, but DateTime
still seems to default to using the default serializer which only returns a string, and its also converting it to GDateTime
. If I include a custom DateTimeSerializer
it ignores it. Is there a better way to ensure it gets properly deserialized into a proper DateTime
object? I'm pulling in a Prisma schema FYI.
abstract class GDateTime implements Built<GDateTime, GDateTimeBuilder> {
GDateTime._();
factory GDateTime([String value]) =>
_$GDateTime((b) => value != null ? (b..value = value) : b);
String get value;
@BuiltValueSerializer(custom: true)
static Serializer<GDateTime> get serializer =>
_i1.DefaultScalarSerializer<GDateTime>(
(Object serialized) => GDateTime(serialized));
}
import 'package:built_value/serializer.dart';
class DateTimeSerializer implements PrimitiveSerializer<DateTime> {
@override
DateTime deserialize(
Serializers serializers,
Object serialized, {
FullType specifiedType = FullType.unspecified,
}) {
assert(serialized is String,
"DateSerializer expected 'String' but got ${serialized.runtimeType}");
return DateTime.parse(serialized.toString());
}
@override
Object serialize(
Serializers serializers,
DateTime date, {
FullType specifiedType = FullType.unspecified,
}) =>
date.toIso8601String();
@override
Iterable<Type> get types => [DateTime];
@override
String get wireName => 'DateTime';
}
There's this bug (#81) that prevents me from using the published version of normalize (I override using direct GitHub reference)
The fix was already merged into master but was never released.
The expandFragments
function in the normalize package only includes fragments if their type name matches the data objects type name. This is a problem if the fragment is defined on an interface. GraphQL servers return concrete typed data even when a query contains an fragment that is defined on an interface.
As an example consider the following type, interface and query (slightly inspired by the github graphql api):
interface Actor {
id: ID!
avatarUrl: String!
}
type User implements Actor {
id: ID!
avatarUrl: String!
name: String!
}
query Users {
users {
... ActorInfo
}
}
fragment ActorInfo on Actor {
__typename
id
avatarUrl
}
A response to this query could look something like this:
"users": [
{
"__typename": "User",
"id": "1",
"avatarUrl": "http://example.com/avatar.png"
}
]
Running normalize
on it should return the following normalized map:
"Query": {
"users": [
{
"$ref": "UserType:1"
},
],
},
"User:1": {
"__typename": "User",
"id": "1",
"avatarUrl": "http://example.com/avatar.png",
}
In expandFragments
the normalized map (variable data
) is used to perform the following check:
// Only include this fragment if the type name matches
if (fragment.typeCondition.on.name.value == data["__typename"]) {
// ...
}
The fragments type name will be Actor
but the datas (concrete) type will be User
, thus the fragment wont't be included.
Hey guys,
as I discussed in the Feedback issue (#1) I suggested a better (IMO) way of structuring the widgets and data requirements based on the design of react-relay.
I will try to lay here the way I think it should work.
In relay, there is one object that manages the dispatching and processing of queries, subscriptions, mutations etc. It quite naturally translates to a GQLClientProvider
here that all widgets in the tree will know to reference when wanting to perform some graphql operation.
@override
Widget build(BuildContext context) {
return GQLClientProvider(
client: _buildClient();
child: MaterialApp(...)
);
}
The strength of relay, as stated in numerous lectures online, is its ability to localize and couple components and their data requirements. That way, it is less likely to add/remove component behaviour while forgetting to adjust the data requirements accordingly.
@query(r"""
query FetchArticle($articleId: ID!) {
article($articleId) {
title
publicationDate
...ArticleAuthor_author
...ArticleComments_comments
}
}
""")
class Article with $FetchArticleQuery extends StatelessWidget {
final String articleId;
const Article({Key key, this.articleId}) : super(key: key);
// The actual build method is generated and sits in $FetchArticleQuery
buildVars() => $FetchArticleQuery$Vars(articleId: this.articleId);
Widget buildLoading(BuildContext context) {
return CircularProgressIndicator();
}
Widget buildError(BuildContext, Error error) {
return Text("$error");
}
@override
Widget buildResult(BuildContext context, $FetchArticleQuery$Response data) {
// Note how I don't have access here to author and comments
// since they go directly through context to ArticleAuthor and ArticleComments.
// This is "data-masking"
return Column(
children: [
Text(data.article.title),
Text(data.article.publicationDate.toString()),
ArticleAuthor(),
ArticleComments(),
]
);
}
}
@fragment(r"""
fragment ArticleComments_comments {
title,
author {
name
}
}
""")
class ArticleComments with $ArticleComments_commentsFragment extends StatelessWidget {
const ArticleComments({Key key}) : super(key: key);
// Here we don't need loading and error since it's only rendered after parent query was executed
@override
Widget buildFragment(BuildContext context, ArticleComments_commentsFragment$Data data) {
return Column(
children: data.map((comment) => Text(comment.title + comment.author.name))
);
}
}
@fragment("""
fragment ArticleAuthor_author {
name
}
""")
class ArticleAuthor with $ArticleAuthor_authorFragment extends StatelessWidget {
const ArticleAuthor({Key key}) : super(key: key);
@override
Widget buildFragment(BuildContext context, ArticleComments_authorFragment$Data data) {
return Text(data.name);
}
}
It's just a quick thought process, I'm not sure how to handle pagination, caching, offline mutations and so on. but it's a start. LMK what you think.
I've been thinking about renaming this package to something more unique rather than descriptive. Since it's based on dart streams, I've been thinking about something stream-related.
One option is "ferry" since the package ferries data around through streams. It'd also be easy to create a memorable "ferry" icon.
Thoughts on this or other names?
".gql" is short and also a valid graphql schema format.
Can the generator recognize this extension too?
Following the instruction, for Flutter Web getting the below error. Suppose, this is because gql_build is not yet available for Flutter Web. Otherwise, please assist :
Launching lib/main.dart on Chrome in debug mode...
Building application for the web...
Configuring `gql_build:schema_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Configuring `gql_build:ast_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Configuring `gql_build:op_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Configuring `gql_build:data_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Configuring `gql_build:var_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Configuring `gql_build:fragment_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Configuring `gql_client:req_builder` in target `realspaceweb:realspaceweb` but this is not a known Builder
Error creating realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
Error creating kernel summary for module:realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
Response:--dart-sdk-output=/private/var/folders/nr/yvt4wkdn3p9_dy_6b5bc3zxh0000gn/T/scratch_space0jEMkm/packages/realspaceweb/widgets/search/SearchLocationButton.ddc.dill --packages-file=file:///var/folders/nr/yvt4wkdn3p9_dy_6b5bc3zxh0000gn/T/kernel_builder_3SGhES/.packages --multi-root-scheme=org-dartlang-app --exclude-non-sources --summary-only --target=ddc --libraries-file=file:///Users/user/Dropbox/BUSINESS/Soft/flutter/bin/cache/flutter_web_sdk/libraries.json --reuse-compiler-result --use-incremental-compiler --used-inputs=/var/folders/nr/yvt4wkdn3p9_dy_6b5bc3zxh0000gn/T/kernel_builder_XAvEiZ/used_inputs.txt --input-summary=org-dartlang-app:///packages/expandable/expandable.ddc.dill --input-summary=org-dartlang-app:///packages/gql_client/gql_client.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/material.ddc.dill --input-summary=org-dartlang-app:///packages/font_awesome_flutter/font_awesome_flutter.ddc.dill --input-summary=org-dartlang-app:///packages/gql_http_link/gql_http_link.ddc.dill --input-summary=org-dartlang-app:///packages/normalize/normalize.ddc.dill --input-summary=org-dartlang-app:///packages/gql_exec/gql_exec.ddc.dill --input-summary=org-dartlang-app:///packages/meta/meta.ddc.dill --input-summary=org-dartlang-app:///packages/hive/hive.ddc.dill --input-summary=org-dartlang-app:///packages/built_value/built_value.ddc.dill --input-summary=org-dartlang-app:///packages/gql/ast.ddc.dill --input-summary=org-dartlang-app:///packages/rxdart/rxdart.ddc.dill --input-summary=org-dartlang-app:///packages/gql_link/gql_link.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/gestures.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/foundation.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/cupertino.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/widgets.ddc.dill --input-summary=org-dartlang-app:///packages/vector_math/vector_math_64.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/semantics.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/rendering.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/animation.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/painting.ddc.dill --input-summary=org-dartlang-app:///packages/font_awesome_flutter/icon_data.ddc.dill --input-summary=org-dartlang-app:///packages/http/http.ddc.dill --input-summary=org-dartlang-app:///packages/gql_exec/exec/response.ddc.dill --input-summary=org-dartlang-app:///packages/gql_exec/exec/context.ddc.dill --input-summary=org-dartlang-app:///packages/gql_exec/exec/request.ddc.dill --input-summary=org-dartlang-app:///packages/gql_exec/exec/error.ddc.dill --input-summary=org-dartlang-app:///packages/gql_exec/exec/operation.ddc.dill --input-summary=org-dartlang-app:///packages/crypto/crypto.ddc.dill --input-summary=org-dartlang-app:///packages/gql/src/ast/ast.ddc.dill --input-summary=org-dartlang-app:///packages/rxdart/transformers.ddc.dill --input-summary=org-dartlang-app:///packages/rxdart/src/streams/never.ddc.dill --input-summary=org-dartlang-app:///packages/gql/language.ddc.dill --input-summary=org-dartlang-app:///packages/collection/collection.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/gestures/arena.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/foundation/_bitfield_web.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/cupertino/action_sheet.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/widgets/actions.ddc.dill --input-summary=org-dartlang-app:///packages/vector_math/hash.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/semantics/binding.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/rendering/animated_size.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/animation/animation.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/painting/_network_image_web.ddc.dill --input-summary=org-dartlang-app:///packages/http/src/base_client.ddc.dill --input-summary=org-dartlang-app:///packages/http_parser/http_parser.ddc.dill --input-summary=org-dartlang-app:///packages/typed_data/typed_data.ddc.dill --input-summary=org-dartlang-app:///packages/convert/convert.ddc.dill --input-summary=org-dartlang-app:///packages/source_span/source_span.ddc.dill --input-summary=org-dartlang-app:///packages/collection/src/algorithms.ddc.dill --input-summary=org-dartlang-app:///packages/collection/src/utils.ddc.dill --input-summary=org-dartlang-app:///packages/collection/src/iterable_zip.ddc.dill --input-summary=org-dartlang-app:///packages/collection/src/comparators.ddc.dill --input-summary=org-dartlang-app:///packages/collection/src/priority_queue.ddc.dill --input-summary=org-dartlang-app:///packages/collection/src/canonicalized_map.ddc.dill --input-summary=org-dartlang-app:///packages/typed_data/typed_buffers.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/physics.ddc.dill --input-summary=org-dartlang-app:///packages/pedantic/pedantic.ddc.dill --input-summary=org-dartlang-app:///packages/string_scanner/src/eager_span_scanner.ddc.dill --input-summary=org-dartlang-app:///packages/charcode/ascii.ddc.dill --input-summary=org-dartlang-app:///packages/path/path.ddc.dill --input-summary=org-dartlang-app:///packages/term_glyph/src/generated/ascii_glyph_set.ddc.dill --input-summary=org-dartlang-app:///packages/charcode/charcode.ddc.dill --input-summary=org-dartlang-app:///packages/flutter/src/physics/clamped_simulation.ddc.dill --input-summary=org-dartlang-app:///packages/charcode/html_entity.ddc.dill --source=package:realspaceweb/widgets/search/SearchLocationButton.dart
Crash when compiling package:realspaceweb/config/AppConfig.dart,
at character offset null:
Reference to root::package:gql_client/src/store//memory_store.dart is not bound to an AST node. A library was expected
#0 Reference.asLibrary (package:kernel/ast.dart:265:7)
#1 LibraryDependency.targetLibrary (package:kernel/ast.dart:642:57)
#2 SourceLoader.computeFullComponent (package:front_end/src/fasta/source/source_loader.dart:873:38)
#3 SourceLoader.computeHierarchy (package:front_end/src/fasta/source/source_loader.dart:890:38)
#4 KernelTarget.buildOutlines.<anonymous closure> (package:front_end/src/fasta/kernel/kernel_target.dart:275:14)
<asynchronous suspension>
#5 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24)
#6 KernelTarget.buildOutlines (package:front_end/src/fasta/kernel/kernel_target.dart:252:12)
#7 IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:462:52)
<asynchronous suspension>
#8 CompilerContext.runInContext.<anonymous closure>.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:46)
#9 new Future.sync (dart:async/future.dart:224:31)
#10 CompilerContext.runInContext.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:19)
#11 _rootRun (dart:async/zone.dart:1126:13)
#12 _CustomZone.run (dart:async/zone.dart:1023:19)
#13 _runZoned (dart:async/zone.dart:1518:10)
#14 runZoned (dart:async/zone.dart:1465:12)
#15 CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:122:12)
#16 IncrementalCompiler.computeDelta (package:front_end/src/fasta/incremental_compiler.dart:156:20)
#17 computeKernel (file:///b/s/w/ir/cache/builder/src/third_party/dart/utils/bazel/kernel_worker.dart:320:10)
<asynchronous suspension>
#18 KernelWorker.performRequest (file:///b/s/w/ir/cache/builder/src/third_party/dart/utils/bazel/kernel_worker.dart:69:26)
#19 AsyncWorkerLoop.run.<anonymous closure> (package:bazel_worker/src/worker/async_worker_loop.dart:33:41)
#20 _rootRun (dart:async/zone.dart:1126:13)
#21 _CustomZone.run (dart:async/zone.dart:1023:19)
#22 _runZoned (dart:async/zone.dart:1518:10)
#23 runZoned (dart:async/zone.dart:1465:12)
#24 AsyncWorkerLoop.run (package:bazel_worker/src/worker/async_worker_loop.dart:33:26)
<asynchronous suspension>
#25 main (file:///b/s/w/ir/cache/builder/src/third_party/dart/utils/bazel/kernel_worker.dart:38:48)
#26 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:303:32)
#27 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
#0 Reference.asLibrary (package:kernel/ast.dart:265:7)
#1 LibraryDependency.targetLibrary (package:kernel/ast.dart:642:57)
#2 SourceLoader.computeFullComponent (package:front_end/src/fasta/source/source_loader.dart:873:38)
#3 SourceLoader.computeHierarchy (package:front_end/src/fasta/source/source_loader.dart:890:38)
#4 KernelTarget.buildOutlines.<anonymous closure> (package:front_end/src/fasta/kernel/kernel_target.dart:275:14)
<asynchronous suspension>
#5 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24)
#6 KernelTarget.buildOutlines (package:front_end/src/fasta/kernel/kernel_target.dart:252:12)
#7 IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:462:52)
<asynchronous suspension>
#8 CompilerContext.runInContext.<anonymous closure>.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:46)
#9 new Future.sync (dart:async/future.dart:224:31)
#10 CompilerContext.runInContext.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:19)
#11 _rootRun (dart:async/zone.dart:1126:13)
#12 _CustomZone.run (dart:async/zone.dart:1023:19)
#13 _runZoned (dart:async/zone.dart:1518:10)
#14 runZoned (dart:async/zone.dart:1465:12)
#15 CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:122:12)
#16 IncrementalCompiler.computeDelta (package:front_end/src/fasta/incremental_compiler.dart:156:20)
#17 computeKernel (file:///b/s/w/ir/cache/builder/src/third_party/dart/utils/bazel/kernel_worker.dart:320:10)
<asynchronous suspension>
#18 KernelWorker.performRequest (file:///b/s/w/ir/cache/builder/src/third_party/dart/utils/bazel/kernel_worker.dart:69:26)
#19 AsyncWorkerLoop.run.<anonymous closure> (package:bazel_worker/src/worker/async_worker_loop.dart:33:41)
#20 _rootRun (dart:async/zone.dart:1126:13)
#21 _CustomZone.run (dart:async/zone.dart:1023:19)
#22 _runZoned (dart:async/zone.dart:1518:10)
#23 runZoned (dart:async/zone.dart:1465:12)
#24 AsyncWorkerLoop.run (package:bazel_worker/src/worker/async_worker_loop.dart:33:26)
<asynchronous suspension>
#25 main (file:///b/s/w/ir/cache/builder/src/third_party/dart/utils/bazel/kernel_worker.dart:38:48)
#26 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:303:32)
#27 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
AssetNotFoundException: realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
Error compiling dartdevc module:realspaceweb|lib/widgets/search/SearchLocationButton.ddc.js
We're sorry, you've found a bug in our compiler.
You can report this bug at:
https://github.com/dart-lang/sdk/issues/labels/web-dev-compiler
Please include the information below in your report, along with
any other information that may help us track it down. Thanks!
-------------------- %< --------------------
dartdevc -k arguments: --kernel --dart-sdk-dill --modules=amd --no-summarize -o packages/realspaceweb/widgets/search/SearchLocationButton.ddc.js --source-map --summary=packages/meta/meta.ddc.dill=packages/meta/meta --summary=packages/typed_data/typed_buffers.ddc.dill=packages/typed_data/typed_buffers --summary=packages/flutter/src/foundation/_bitfield_web.ddc.dill=packages/flutter/src/foundation/_bitfield_web --summary=packages/flutter/foundation.ddc.dill=packages/flutter/foundation --summary=packages/vector_math/hash.ddc.dill=packages/vector_math/hash --summary=packages/vector_math/vector_math_64.ddc.dill=packages/vector_math/vector_math_64 --summary=packages/flutter/src/physics/clamped_simulation.ddc.dill=packages/flutter/src/physics/clamped_simulation --summary=packages/flutter/physics.ddc.dill=packages/flutter/physics --summary=packages/collection/src/utils.ddc.dill=packages/collection/src/utils --summary=packages/collection/src/algorithms.ddc.dill=packages/collection/src/algorithms --summary=packages/collection/src/iterable_zip.ddc.dill=packages/collection/src/iterable_zip --summary=packages/collection/src/comparators.ddc.dill=packages/collection/src/comparators --summary=packages/collection/src/priority_queue.ddc.dill=packages/collection/src/priority_queue --summary=packages/collection/src/canonicalized_map.ddc.dill=packages/collection/src/canonicalized_map --summary=packages/collection/collection.ddc.dill=packages/collection/collection --summary=packages/flutter/src/gestures/arena.ddc.dill=packages/flutter/src/gestures/arena --summary=packages/flutter/gestures.ddc.dill=packages/flutter/gestures --summary=packages/flutter/src/painting/_network_image_web.ddc.dill=packages/flutter/src/painting/_network_image_web --summary=packages/flutter/painting.ddc.dill=packages/flutter/painting --summary=packages/flutter/src/semantics/binding.ddc.dill=packages/flutter/src/semantics/binding --summary=packages/flutter/semantics.ddc.dill=packages/flutter/semantics --summary=packages/flutter/src/animation/animation.ddc.dill=packages/flutter/src/animation/animation --summary=packages/flutter/animation.ddc.dill=packages/flutter/animation --summary=packages/flutter/src/rendering/animated_size.ddc.dill=packages/flutter/src/rendering/animated_size --summary=packages/flutter/rendering.ddc.dill=packages/flutter/rendering --summary=packages/flutter/src/widgets/actions.ddc.dill=packages/flutter/src/widgets/actions --summary=packages/flutter/widgets.ddc.dill=packages/flutter/widgets --summary=packages/flutter/src/cupertino/action_sheet.ddc.dill=packages/flutter/src/cupertino/action_sheet --summary=packages/flutter/cupertino.ddc.dill=packages/flutter/cupertino --summary=packages/flutter/material.ddc.dill=packages/flutter/material --summary=packages/realspaceweb/constants/constants.ddc.dill=packages/realspaceweb/constants/constants --summary=packages/gql_exec/exec/context.ddc.dill=packages/gql_exec/exec/context --summary=packages/gql_exec/exec/error.ddc.dill=packages/gql_exec/exec/error --summary=packages/gql_exec/exec/response.ddc.dill=packages/gql_exec/exec/response --summary=packages/path/path.ddc.dill=packages/path/path --summary=packages/term_glyph/src/generated/ascii_glyph_set.ddc.dill=packages/term_glyph/src/generated/ascii_glyph_set --summary=packages/charcode/ascii.ddc.dill=packages/charcode/ascii --summary=packages/charcode/html_entity.ddc.dill=packages/charcode/html_entity --summary=packages/charcode/charcode.ddc.dill=packages/charcode/charcode --summary=packages/source_span/source_span.ddc.dill=packages/source_span/source_span --summary=packages/gql/src/ast/ast.ddc.dill=packages/gql/src/ast/ast --summary=packages/gql/ast.ddc.dill=packages/gql/ast --summary=packages/gql_exec/exec/operation.ddc.dill=packages/gql_exec/exec/operation --summary=packages/gql_exec/exec/request.ddc.dill=packages/gql_exec/exec/request --summary=packages/gql_exec/gql_exec.ddc.dill=packages/gql_exec/gql_exec --summary=packages/gql/language.ddc.dill=packages/gql/language --summary=packages/gql_link/gql_link.ddc.dill=packages/gql_link/gql_link --summary=packages/pedantic/pedantic.ddc.dill=packages/pedantic/pedantic --summary=packages/string_scanner/src/eager_span_scanner.ddc.dill=packages/string_scanner/src/eager_span_scanner --summary=packages/typed_data/typed_data.ddc.dill=packages/typed_data/typed_data --summary=packages/http_parser/http_parser.ddc.dill=packages/http_parser/http_parser --summary=packages/http/src/base_client.ddc.dill=packages/http/src/base_client --summary=packages/http/http.ddc.dill=packages/http/http --summary=packages/gql_http_link/gql_http_link.ddc.dill=packages/gql_http_link/gql_http_link --summary=packages/realspaceweb/widgets/search/SearchSectionTitle.ddc.dill=packages/realspaceweb/widgets/search/SearchSectionTitle --summary=packages/realspaceweb/widgets/search/SearchSection.ddc.dill=packages/realspaceweb/widgets/search/SearchSection --summary=packages/font_awesome_flutter/icon_data.ddc.dill=packages/font_awesome_flutter/icon_data --summary=packages/font_awesome_flutter/font_awesome_flutter.ddc.dill=packages/font_awesome_flutter/font_awesome_flutter --summary=packages/realspaceweb/utils/Utils.ddc.dill=packages/realspaceweb/utils/Utils --summary=packages/realspaceweb/config/AppConfig.ddc.dill=packages/realspaceweb/config/AppConfig --summary=packages/normalize/normalize.ddc.dill=packages/normalize/normalize --summary=packages/convert/convert.ddc.dill=packages/convert/convert --summary=packages/crypto/crypto.ddc.dill=packages/crypto/crypto --summary=packages/hive/hive.ddc.dill=packages/hive/hive --summary=packages/built_value/built_value.ddc.dill=packages/built_value/built_value --summary=packages/rxdart/src/streams/never.ddc.dill=packages/rxdart/src/streams/never --summary=packages/rxdart/transformers.ddc.dill=packages/rxdart/transformers --summary=packages/rxdart/rxdart.ddc.dill=packages/rxdart/rxdart --summary=packages/gql_client/gql_client.ddc.dill=packages/gql_client/gql_client --summary=packages/realspaceweb/widgets/DropdownStringWidget.ddc.dill=packages/realspaceweb/widgets/DropdownStringWidget --summary=packages/expandable/expandable.ddc.dill=packages/expandable/expandable --packages=file:///var/folders/nr/yvt4wkdn3p9_dy_6b5bc3zxh0000gn/T/kernel_builder_ptIly3/.packages --module-name=packages/realspaceweb/widgets/search/SearchLocationButton --multi-root-scheme=org-dartlang-app --multi-root=. --track-widget-creation --inline-source-map --libraries-file=file:///Users/user/Dropbox/BUSINESS/Soft/flutter/bin/cache/flutter_web_sdk/libraries.json --used-inputs-file=/var/folders/nr/yvt4wkdn3p9_dy_6b5bc3zxh0000gn/T/ddk_builder_N3Q6uB/used_inputs.txt package:realspaceweb/widgets/search/SearchLocationButton.dart
dart --version: 2.8.0-dev.0.0.flutter-c547f5d933 (Fri Dec 27 00:43:14 2019 +0000) on "macos_x64"
Crash when compiling null,
at character offset null:
Reference to root::package:gql_client/src/store//memory_store.dart is not bound to an AST node. A library was expected
#0 Reference.asLibrary (package:kernel/ast.dart:265:7)
#1 LibraryDependency.targetLibrary (package:kernel/ast.dart:642:57)
#2 SourceLoader.computeFullComponent (package:front_end/src/fasta/source/source_loader.dart:873:38)
#3 SourceLoader.computeHierarchy (package:front_end/src/fasta/source/source_loader.dart:890:38)
#4 KernelTarget.buildOutlines.<anonymous closure> (package:front_end/src/fasta/kernel/kernel_target.dart:275:14)
<asynchronous suspension>
#5 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24)
#6 KernelTarget.buildOutlines (package:front_end/src/fasta/kernel/kernel_target.dart:252:12)
#7 IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:462:52)
<asynchronous suspension>
#8 CompilerContext.runInContext.<anonymous closure>.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:46)
#9 new Future.sync (dart:async/future.dart:224:31)
#10 CompilerContext.runInContext.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:19)
#11 _rootRun (dart:async/zone.dart:1126:13)
#12 _CustomZone.run (dart:async/zone.dart:1023:19)
#13 _runZoned (dart:async/zone.dart:1518:10)
#14 runZoned (dart:async/zone.dart:1465:12)
#15 CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:122:12)
#16 IncrementalCompiler.computeDelta (package:front_end/src/fasta/incremental_compiler.dart:156:20)
#17 _compile (package:dev_compiler/src/kernel/command.dart:333:64)
<asynchronous suspension>
#18 compile (package:dev_compiler/src/kernel/command.dart:46:18)
#19 compile (package:dev_compiler/src/compiler/shared_command.dart:410:10)
#20 _CompilerWorker.performRequest.<anonymous closure> (file:///b/s/w/ir/cache/builder/src/third_party/dart/pkg/dev_compiler/bin/dartdevc.dart:64:13)
#21 _rootRun (dart:async/zone.dart:1126:13)
#22 _CustomZone.run (dart:async/zone.dart:1023:19)
#23 _runZoned (dart:async/zone.dart:1518:10)
#24 runZoned (dart:async/zone.dart:1465:12)
#25 _CompilerWorker.performRequest (file:///b/s/w/ir/cache/builder/src/third_party/dart/pkg/dev_compiler/bin/dartdevc.dart:62:24)
#26 AsyncWorkerLoop.run.<anonymous closure> (package:bazel_worker/src/worker/async_worker_loop.dart:33:41)
#27 _rootRun (dart:async/zone.dart:1126:13)
#28 _CustomZone.run (dart:async/zone.dart:1023:19)
#29 _runZoned (dart:async/zone.dart:1518:10)
#30 runZoned (dart:async/zone.dart:1465:12)
#31 AsyncWorkerLoop.run (package:bazel_worker/src/worker/async_worker_loop.dart:33:26)
<asynchronous suspension>
#32 main (file:///b/s/w/ir/cache/builder/src/third_party/dart/pkg/dev_compiler/bin/dartdevc.dart:28:57)
#33 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:303:32)
#34 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
#0 Reference.asLibrary (package:kernel/ast.dart:265:7)
#1 LibraryDependency.targetLibrary (package:kernel/ast.dart:642:57)
#2 SourceLoader.computeFullComponent (package:front_end/src/fasta/source/source_loader.dart:873:38)
#3 SourceLoader.computeHierarchy (package:front_end/src/fasta/source/source_loader.dart:890:38)
#4 KernelTarget.buildOutlines.<anonymous closure> (package:front_end/src/fasta/kernel/kernel_target.dart:275:14)
<asynchronous suspension>
#5 withCrashReporting (package:front_end/src/fasta/crash.dart:122:24)
#6 KernelTarget.buildOutlines (package:front_end/src/fasta/kernel/kernel_target.dart:252:12)
#7 IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:462:52)
<asynchronous suspension>
#8 CompilerContext.runInContext.<anonymous closure>.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:46)
#9 new Future.sync (dart:async/future.dart:224:31)
#10 CompilerContext.runInContext.<anonymous closure> (package:front_end/src/fasta/compiler_context.dart:123:19)
#11 _rootRun (dart:async/zone.dart:1126:13)
#12 _CustomZone.run (dart:async/zone.dart:1023:19)
#13 _runZoned (dart:async/zone.dart:1518:10)
#14 runZoned (dart:async/zone.dart:1465:12)
#15 CompilerContext.runInContext (package:front_end/src/fasta/compiler_context.dart:122:12)
#16 IncrementalCompiler.computeDelta (package:front_end/src/fasta/incremental_compiler.dart:156:20)
#17 _compile (package:dev_compiler/src/kernel/command.dart:333:64)
<asynchronous suspension>
#18 compile (package:dev_compiler/src/kernel/command.dart:46:18)
#19 compile (package:dev_compiler/src/compiler/shared_command.dart:410:10)
#20 _CompilerWorker.performRequest.<anonymous closure> (file:///b/s/w/ir/cache/builder/src/third_party/dart/pkg/dev_compiler/bin/dartdevc.dart:64:13)
#21 _rootRun (dart:async/zone.dart:1126:13)
#22 _CustomZone.run (dart:async/zone.dart:1023:19)
#23 _runZoned (dart:async/zone.dart:1518:10)
#24 runZoned (dart:async/zone.dart:1465:12)
#25 _CompilerWorker.performRequest (file:///b/s/w/ir/cache/builder/src/third_party/dart/pkg/dev_compiler/bin/dartdevc.dart:62:24)
#26 AsyncWorkerLoop.run.<anonymous closure> (package:bazel_worker/src/worker/async_worker_loop.dart:33:41)
#27 _rootRun (dart:async/zone.dart:1126:13)
#28 _CustomZone.run (dart:async/zone.dart:1023:19)
#29 _runZoned (dart:async/zone.dart:1518:10)
#30 runZoned (dart:async/zone.dart:1465:12)
#31 AsyncWorkerLoop.run (package:bazel_worker/src/worker/async_worker_loop.dart:33:26)
<asynchronous suspension>
#32 main (file:///b/s/w/ir/cache/builder/src/third_party/dart/pkg/dev_compiler/bin/dartdevc.dart:28:57)
#33 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:303:32)
#34 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
AssetNotFoundException: realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
AssetNotFoundException: realspaceweb|lib/main_prod_web_entrypoint.ddc.js
AssetNotFoundException: realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
AssetNotFoundException: realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
AssetNotFoundException: realspaceweb|lib/widgets/search/SearchLocationButton.ddc.dill
AssetNotFoundException: realspaceweb|lib/main_web_entrypoint.ddc.js
Failed after 382ms
Finished with error: Failed to build application for the Web.
Hi
I have a request to fetch a list of items, and a loadMore function for pagination, sane as in the example https://ferrygraphql.com/docs/pagination
The initial request will call the UpdateCacheHandler, but any loadMore calls will not call it!
Is this expected behavior?
extra information about the app ligic:
What I am doing with UpdateCacheHandler?
I want to write each item from the results of getItems(limit, offset)
to cache, so
getItem(id)
will be from cacheHello guys, one more question - after we make a mutation, what is the best way to update the cache?
Right now in your documentation is example
final updateCacheHandlers = <dynamic, Function>{
"MyHandlerKey": MyUpdateCacheHandler,
};
final options = ClientOptions(updateCacheHandlers: updateCacheHandlers);
final client = Client(
link: link,
options: options,
);
But for me, it is not clear, how to implement it. Maybe there are obvious approaches, but I just started to use graphql and will be appreciated for example.
Documentation. When I finished things in my app I ready to create one more example for your package for demonstrating mutations, links updates, and cache updates. I quests, that it will be topical questions from your users.
I'd like to keep the API footprint as minimal as possible without sacrificing core functionality.
The Query
widget is a very light wrapper around StreamBuilder
. StreamBuilder
re-subscribes whenever the stream changes. The only value that Query
is adding currently over using StreamBuilder
directly is that it prevents re-subscribing whenever the parent widget rebuilds. Since QueryRequest
doesn't currently override "==", if the QueryRequest
is created within the build method of the parent widget, it will have a new identity on every build and will cause StreamBuilder
to re-subscribe.
By simply overriding "==" in QueryRequest
(either directly or by implementing built_value
) we should be able to just use StreamBuilder
directly and remove the Query
Widget altogether.
This should reduce the API footprint and make it more transparent to the user how the library works.
During diving into the code for #18, I found some problems with the cache update with optimisticResponse.
If we make the mutation with Optimistic Response
final mutation = ProfileBmiMutation2(
buildVars: (b) => b..input = profileInput,
updateCacheHandlerKey: IdCacheHandlers.profileBmiMutation,
optimisticResponse: optimisticRequest,
).copyWith(
context: Context.fromList(
[
HttpLinkHeaders(
headers: idToken,
),
],
),
);
client
.responseStream(mutation)
.firstWhere((response) => response.optimistic)
.then((response) {});
cache updates incorrectly.
Maybe it is connected with code here /lib/src/cache/cache_proxy.dart
, because if we change optimistic: _optimistic,
to optimistic: false,
it starts to work correctly (in this exact use-case).
I guess, there is more logic. I just pointed out what I've found.
void writeQuery(
Request request,
Map<String, dynamic> data,
) =>
_cache.writeQuery(
request,
data,
optimistic: false,
queryId: _queryId,
);
Hello, as you recommended, I made an optimisticResponse, and it works just fine. I got data from this response and can use it before I get updates from API.
This question is about best practices.
In the app, we made a mutation and passes there the 'resultObjectFromApp'. For the optimisticResponse we should create a 'mapFromApp' with structure
{QueryName:
{__typename: TypeName,
height: xx,
weight: xx,
birthday: xx}
}
where all the data except {**QueryName**: {__typename: **TypeName**,
duplicate resultObjectFromApp
data.
So, the question is - are there any ways to create this map outside widgets or, maybe, it is possible to implement the automatic creation of this map?
final mutation = SomeMutation(
buildVars: (b) => b..input = resultObjectFromApp,
updateCacheHandlerKey:
IdCacheHandlers.someMutation,
optimisticResponse: mapFromApp,
).copyWith(
context: Context.fromList(
[
HttpLinkHeaders(
headers: idToken,
),
],
),
);
client
.responseStream(mutation)
.firstWhere((response) => response.optimistic)
.then((response) {
});
As the title says I want to upload a pictures, but I don't know how to use scalar Upload
.
Please tell me the way, thanks.
I'm looking at adding some handlers in graphql/client.dart
to check for / distinguish between malformed response data and cache misconfigurations, and I'm wondering if there's a better way than what I'm currently thinking.
Current thinking:
denormalizeOperation
already validates all subtree structure right? So we can create a thin wrapper validateResponseStructure
that ignores denormalization, or extract the traversal logic into its own helperwriteQuery
/readQuery
. If it returns null
, we then:
MismatchedDataStructureException
if validateResponseStructure
is null
CacheRoundTripException
otherwise (could be broken down further later).The main idea is to validateResponseStructure
independent of the cache. Might be a util better suited for gql
.
Hi!
A few questions:
I think we should automatically assign queryIds (possibly using https://github.com/Daegalus/dart-uuid) in the req_builder.
This issue is a bit of a data dump for later consideration.
Looking through Ferrys documentation, I haven't been able to find how to send JWT header token to the client for GraphQL requests that need authentication.
https://ferrygraphql.com/docs/queries
I have a data layer for my GraphQL queries which is then used in my view models to read/write data.
Any help or would be appreciated.
I can't seem to figure out how to convert a custom scalar to a List
or BuiltList
of a local model.
type_overrides:
DateTime:
name: DateTime
MyModels:
name: BuiltList<MyModel>
# import: 'package:name/path/to/model.dart'
Ive implemented a MyModelsSerializer
which returns BuiltList<MyModel>
. Ive also tried importing the model file that. defines MyModel
(a freezed class)
It doesn't seem to resolve the types properly so build_runner
keeps throwing `Make field [name] have non-dynamic type. Is there a naming convention I'm missing for the config?
The bug appears when I trying to update the cache in the example app.
The results are printed in the code, when we use deleteTodoMutationHandler
https://github.com/awaik/todo_ferry_example/blob/master/lib/src/client.dart
print('resMap --- ${resMap}');
proxy.writeQuery(query, resMap);
print('proxy.readQuery(query) --- ${proxy.readQuery(query)}');
proxy.readQuery(query);
returns the old, not updated value.
So, the line proxy.writeQuery(query, SomeMap);
doesn't change the cache.
Didn't test to see if it only happens when nesting fragments or not, but if you have have a nested graph with ONLY a fragment, when normalized, it gets nulled...
foobar{
...fragment
}
i can work around by always asking for a typename
foobar{
__typename,
...fragment
}
Hey man! Thanks for working on this project! I just have 1 quick question out of curiosity and due to some problems I meet every day in other graphql package.
What is your motivation and how do you see the future of this project?
And also, why did you decide to build this package instead of contributing to the original package?
Thanks for your answers, sorry for creating an issue, IDK where else can I ping you.
Cheers!
Please make such refactors backward compatible as it makes it super hard to update. (no responseStream method?)
In general a library such as this that is so central to every app using it must keep the number of breaking changes to a minimum.
It appears that UpdateCacheHandlers are run any time a data event is received, including in response to updates made within the UpdateCacheHandler itself.
There is an issue with the denormalizeNode
function in the normalize
package.
It denormalizes all fragments in a query one by one. The values of the fields requested by a fragment are then stored in a result
map under the key of the queried field. If the same field is queried again by another fragment, the value stored before is replaced.
This is problematic if multiple fragments query an object, but query different fields of that object. In that case only the object data of the last processed fragment is present in the result.
Here is an example. Consider the following query and fragments.
fragment MovieStarComponent on MovieType {
__typename
id
name
starRole {
__typename
id
name
age
haircolor
}
}
fragment MovieTitleComponent on MovieType {
__typename
id
name
starRole {
__typename
id
name
}
}
query MovieByID($movieID: ID!) {
movie(id: $movieID) {
... MovieStarComponent
... MovieTitleComponent
}
}
Running denormalize
on this query will result in the following map:
{
movie {
__typename: MovieType,
id: 1,
name: Rocky,
starRole {
__typename: ActorType,
id: 1,
name: Sylvester Stallone,
}
}
}
Notice that the starRole
objects age
and haircolor
fields are not returned, even though they are queried by the MovieStarComponent
fragment.
Here the MovieStarComponent
fragment is processed first. The result
map now contains the queried movies starRole
object and all fields queried by the MovieStarComponent
fragment.
Next the MovieTitleComponent
fragment is processed. It queries the same starRole
object but less fields than the MovieStarComponent
fragment.
Due to the bug described before, the data queried by the MovieStarComponent
fragment is replaced with the data of the MovieTitleComponent
fragment.
Changing the order of the fragments in this particular query would "fix" the issue in this situation.
One solution to fix this problem would be to deepmerge the data of denormalized fragments on the same level, instead of just keeping the data of the last processed fragment. I will create an PR in a minute with such changes.
Apollo allows subfields to be used in keyFields:
const cache = new InMemoryCache({
typePolicies: {
Book: {
keyFields: ["title", "author", ["name"]],
},
},
});
In this case, the title and author name are used as the unique identifiers for a Book.
We currently only support a single level of depth in normalize
. I propose adjusting the API to use a Map of booleans for keyFields
. For example:
final cache = Cache(
typePolicies: {
'Book': TypePolicy(
keyFields: {
'title': true,
'author': {
'name': true
}
},
),
},
);
Although this is a divergence from the Apollo API, I think it more accurately describes the keyFields.
Hi!
How get input data from mutation in body UpdateCacheHandler?
final UpdateCacheHandler<$MyMutation> myMutationHandler = (
CacheProxy proxy,
QueryResponse<$MyMutation> response,
) {
final query = MyQueryToUpdate();
final result = proxy.readQuery(query);
/// update the result
proxy.writeQuery(query, result);
};
What is the roadmap regarding graphql subscriptions using the websocket transport?
It seems reasonable to expect a streams-based graphql client to support subscriptions. Is it of much work?
Hey, I have been trying out Ferry after getting very frustrated with graphql_flutter. So far the project looks like it is designed better but I have not spent much time with it yet.
One of the issues I am running into is the lack of documentation. There is currently one very thin example to go off. The large number of dependencies is also very confusing and will potentially be a nightmare to keep versions in sync (I've already run into conflicts). It would be ideal if the ferry flutter client could be installed as a single package which would include all required codegen/gql packages etc. I think that will be key to increasing adoption of Ferry.
Also, as a side note, it would be awesome if there was a hooks API. Coming from React/Apollo client, working with GraphQL in Flutter is currently extremely clunky. I think this library has the potential to change that.
This would allow for Store
implementations not stored in memory, such as:
Rather than switchmapping, we should use a streamtransformer to combine streams if the request has an update result callback
We should explore adding an error policy and error link, similar to apollo.
I'm getting this error while trying to use latest ferry (0.4.0) with ferry_flutter:
ferry_flutter ^0.1.0 which depends on ferry ^0.3.1+2, ferry ^0.3.1+2 is required.
So, because test_project depends on ferry ^0.4.0, version solving failed.
Also, it causes conflicts while running the usage provided here, since objects and functions are declared in multiple libraries
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.