From cefab9e1659fc0eb7920d1c4cfcffaeb14897154 Mon Sep 17 00:00:00 2001 From: Andrey Lunyov Date: Fri, 8 Jul 2022 09:44:10 -0700 Subject: [PATCH] Support for @required and client-edges Summary: This diff adds runtime support for `required` directives on client-edge fields. In the codegen: - client-edge is wrapped with required field In typegen: - we are generating the correct flow-types for client-edge reader field. In runtime: - ReaderNode updated to reflect that `RequiredField` can have `ReaderClientEdgeToClientObject | ReaderClientEdgeToServerObject` as nodes. Reviewed By: captbaritone Differential Revision: D37187696 fbshipit-source-id: a11eae113dfbaff1a9e60053cd6a8337f5b3deac --- .../crates/relay-codegen/src/build_ast.rs | 38 ++- ...esolver-with-required-client-edge.expected | 25 +- .../relay-transforms/src/client_edges.rs | 29 +- .../relay-transforms/src/relay_resolvers.rs | 4 +- compiler/crates/relay-typegen/src/visit.rs | 2 +- .../react-relay/__tests__/ClientEdges-test.js | 294 ++++++++++++++++++ ...EdgesTest1Query_me__client_node.graphql.js | 145 +++++++++ ...EdgesTest2Query_me__client_node.graphql.js | 145 +++++++++ ...EdgesTest3Query_me__client_node.graphql.js | 145 +++++++++ .../ClientEdgesTest1Query.graphql.js | 176 +++++++++++ .../ClientEdgesTest2Query.graphql.js | 176 +++++++++++ .../ClientEdgesTest3Query.graphql.js | 181 +++++++++++ .../ClientEdgesTest4Query.graphql.js | 174 +++++++++++ ...EdgesTest1Query_me__client_node.graphql.js | 83 +++++ ...EdgesTest2Query_me__client_node.graphql.js | 83 +++++ ...EdgesTest3Query_me__client_node.graphql.js | 83 +++++ packages/relay-runtime/store/RelayReader.js | 6 + .../UserClientEdgeClientObjectResolver.js | 29 ++ .../resolvers/UserClientEdgeNodeResolver.js | 26 ++ packages/relay-runtime/util/ReaderNode.js | 5 +- .../schema-extensions/ClientObject.graphql | 3 + 21 files changed, 1822 insertions(+), 30 deletions(-) create mode 100644 packages/react-relay/__tests__/ClientEdges-test.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgesTest1Query.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgesTest2Query.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgesTest3Query.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/ClientEdgesTest4Query.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js create mode 100644 packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js create mode 100644 packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeClientObjectResolver.js create mode 100644 packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js create mode 100644 packages/relay-test-utils-internal/schema-extensions/ClientObject.graphql diff --git a/compiler/crates/relay-codegen/src/build_ast.rs b/compiler/crates/relay-codegen/src/build_ast.rs index 938f1267bd008..ecd29a5ffcf35 100644 --- a/compiler/crates/relay-codegen/src/build_ast.rs +++ b/compiler/crates/relay-codegen/src/build_ast.rs @@ -1072,9 +1072,10 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { &mut self, context: &mut ContextualMetadata, client_edge_metadata: ClientEdgeMetadata<'_>, + required_metadata: Option, ) -> Primitive { context.has_client_edges = true; - let backing_field = match client_edge_metadata.backing_field { + let backing_field = match &client_edge_metadata.backing_field { Selection::FragmentSpread(fragment_spread) => { self.build_fragment_spread(fragment_spread) } @@ -1095,11 +1096,32 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { }; let selections_item = match client_edge_metadata.selections { - Selection::LinkedField(linked_field) => self.build_linked_field(context, linked_field), + Selection::LinkedField(linked_field) => { + if required_metadata.is_none() { + self.build_linked_field(context, linked_field) + } else { + let next_directives = linked_field + .directives + .iter() + .filter(|directive| { + directive.name.item != RequiredMetadataDirective::directive_name() + }) + .cloned() + .collect(); + + self.build_linked_field( + context, + &LinkedField { + directives: next_directives, + ..linked_field.as_ref().clone() + }, + ) + } + } _ => panic!("Expected Client Edge selections to be a LinkedField"), }; - match client_edge_metadata.metadata_directive { + let field = match client_edge_metadata.metadata_directive { ClientEdgeMetadataDirective::ServerObject { query_name, .. } => { Primitive::Key(self.object(object! { kind: Primitive::String(CODEGEN_CONSTANTS.client_edge_to_server_object), @@ -1116,6 +1138,12 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { client_edge_selections_key: selections_item, })) } + }; + + if let Some(required_metadata) = required_metadata { + self.build_required_field(&required_metadata, field) + } else { + field } } @@ -1127,7 +1155,9 @@ impl<'schema, 'builder, 'config> CodegenBuilder<'schema, 'builder, 'config> { match inline_frag.type_condition { None => { if let Some(client_edge_metadata) = ClientEdgeMetadata::find(inline_frag) { - self.build_client_edge(context, client_edge_metadata) + let required_metadata = + RequiredMetadataDirective::find(&inline_frag.directives).cloned(); + self.build_client_edge(context, client_edge_metadata, required_metadata) } else if // TODO(T63388023): Use typed custom directives inline_frag.directives.len() == 1 diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/relay-resolver-with-required-client-edge.expected b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/relay-resolver-with-required-client-edge.expected index 73fb00b9d292b..885dbfedbe336 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/relay-resolver-with-required-client-edge.expected +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/relay-resolver-with-required-client-edge.expected @@ -165,11 +165,11 @@ fragment RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me_ "plural": false, "selections": [ { - "kind": "ClientEdgeToServerObject", - "operation": require('ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend.graphql'), - "backingField": { - "kind": "RequiredField", - "field": { + "kind": "RequiredField", + "field": { + "kind": "ClientEdgeToServerObject", + "operation": require('ClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me__best_friend.graphql'), + "backingField": { "alias": null, "args": null, "fragment": { @@ -182,12 +182,7 @@ fragment RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me_ "resolverModule": require('BestFriendResolver'), "path": "me.best_friend" }, - "action": "THROW", - "path": "me.best_friend" - }, - "linkedField": { - "kind": "RequiredField", - "field": { + "linkedField": { "alias": null, "args": null, "concreteType": "User", @@ -204,10 +199,10 @@ fragment RefetchableClientEdgeQuery_relayResolverWithRequiredClientEdgeQuery_me_ } ], "storageKey": null - }, - "action": "THROW", - "path": "me.best_friend" - } + } + }, + "action": "THROW", + "path": "me.best_friend" } ], "storageKey": null diff --git a/compiler/crates/relay-transforms/src/client_edges.rs b/compiler/crates/relay-transforms/src/client_edges.rs index f7f75d644c154..4d1bb291d2c30 100644 --- a/compiler/crates/relay-transforms/src/client_edges.rs +++ b/compiler/crates/relay-transforms/src/client_edges.rs @@ -81,7 +81,7 @@ pub struct ClientEdgeGeneratedQueryMetadataDirective { associated_data_impl!(ClientEdgeGeneratedQueryMetadataDirective); pub struct ClientEdgeMetadata<'a> { - pub backing_field: &'a Selection, + pub backing_field: Selection, pub selections: &'a Selection, pub metadata_directive: ClientEdgeMetadataDirective, } @@ -108,12 +108,19 @@ impl<'a> ClientEdgeMetadata<'a> { fragment.selections.len() == 2, "Expected Client Edge inline fragment to have exactly two selections. This is a bug in the Relay compiler." ); + let mut backing_field = fragment + .selections + .get(0) + .expect("Client Edge inline fragments have exactly two selections").clone(); + + let backing_field_directives = backing_field.directives().iter().filter(|directive| + directive.name.item != RequiredMetadataDirective::directive_name() + ).cloned().collect(); + backing_field.set_directives(backing_field_directives); + ClientEdgeMetadata { metadata_directive: metadata_directive.clone(), - backing_field: fragment - .selections - .get(0) - .expect("Client Edge inline fragments have exactly two selections"), + backing_field, selections: fragment .selections .get(1) @@ -390,6 +397,14 @@ impl<'program, 'sc> ClientEdgesTransform<'program, 'sc> { unique_id: self.get_key(), } }; + let mut inline_fragment_directives: Vec = vec![metadata_directive.into()]; + if let Some(required_directive_metadata) = field + .directives + .named(RequiredMetadataDirective::directive_name()) + .cloned() + { + inline_fragment_directives.push(required_directive_metadata); + } let transformed_field = Arc::new(LinkedField { selections: new_selections, @@ -398,7 +413,7 @@ impl<'program, 'sc> ClientEdgesTransform<'program, 'sc> { let inline_fragment = InlineFragment { type_condition: None, - directives: vec![metadata_directive.into()], + directives: inline_fragment_directives, selections: vec![ Selection::LinkedField(transformed_field.clone()), Selection::LinkedField(transformed_field), @@ -520,7 +535,7 @@ impl Transformer for ClientEdgesCleanupTransform { let new_selection = metadata.backing_field; Transformed::Replace( - self.transform_selection(new_selection) + self.transform_selection(&new_selection) .unwrap_or_else(|| new_selection.clone()), ) } diff --git a/compiler/crates/relay-transforms/src/relay_resolvers.rs b/compiler/crates/relay-transforms/src/relay_resolvers.rs index 9b61c36d2eaaa..dbaba22821ad2 100644 --- a/compiler/crates/relay-transforms/src/relay_resolvers.rs +++ b/compiler/crates/relay-transforms/src/relay_resolvers.rs @@ -192,7 +192,7 @@ impl<'program> Transformer for RelayResolverSpreadTransform<'program> { match ClientEdgeMetadata::find(fragment) { Some(client_edge_metadata) => { let backing_id_field = self - .transform_selection(client_edge_metadata.backing_field) + .transform_selection(&client_edge_metadata.backing_field) .unwrap_or_else(|| client_edge_metadata.backing_field.clone()); let selections_field = match client_edge_metadata.selections { @@ -380,7 +380,7 @@ impl Transformer for RelayResolverFieldTransform<'_> { let transformed = match ClientEdgeMetadata::find(fragment) { Some(client_edge_metadata) => { let backing_id_field = self - .transform_selection(client_edge_metadata.backing_field) + .transform_selection(&client_edge_metadata.backing_field) .unwrap_or_else(|| client_edge_metadata.backing_field.clone()); let selections_field = match client_edge_metadata.selections { diff --git a/compiler/crates/relay-typegen/src/visit.rs b/compiler/crates/relay-typegen/src/visit.rs index 07aa68ba1ecf4..0f40c378ffa29 100644 --- a/compiler/crates/relay-typegen/src/visit.rs +++ b/compiler/crates/relay-typegen/src/visit.rs @@ -472,7 +472,7 @@ fn visit_client_edge( runtime_imports: &mut RuntimeImports, enclosing_linked_field_concrete_type: Option, ) { - let (resolver_metadata, fragment_name) = match client_edge_metadata.backing_field { + let (resolver_metadata, fragment_name) = match &client_edge_metadata.backing_field { Selection::FragmentSpread(fragment_spread) => ( RelayResolverMetadata::find(&fragment_spread.directives), Some(fragment_spread.fragment.item), diff --git a/packages/react-relay/__tests__/ClientEdges-test.js b/packages/react-relay/__tests__/ClientEdges-test.js new file mode 100644 index 0000000000000..a551bb56a7597 --- /dev/null +++ b/packages/react-relay/__tests__/ClientEdges-test.js @@ -0,0 +1,294 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails oncall+relay + * @flow strict-local + * @format + */ + +'use strict'; + +const React = require('react'); +const {RelayEnvironmentProvider, useLazyLoadQuery} = require('react-relay'); +const TestRenderer = require('react-test-renderer'); +const { + Environment, + Network, + RecordSource, + RelayFeatureFlags, + graphql, +} = require('relay-runtime'); +const RelayObservable = require('relay-runtime/network/RelayObservable'); +const LiveResolverStore = require('relay-runtime/store/experimental-live-resolvers/LiveResolverStore'); +const { + disallowConsoleErrors, + disallowWarnings, +} = require('relay-test-utils-internal'); + +disallowWarnings(); +disallowConsoleErrors(); + +beforeEach(() => { + RelayFeatureFlags.ENABLE_RELAY_RESOLVERS = true; + RelayFeatureFlags.ENABLE_CLIENT_EDGES = true; +}); + +afterEach(() => { + RelayFeatureFlags.ENABLE_RELAY_RESOLVERS = false; + RelayFeatureFlags.ENABLE_CLIENT_EDGES = false; +}); + +describe('ClientEdges', () => { + let networkSink; + let environment; + let fetchFn; + beforeEach(() => { + fetchFn = jest.fn(() => + RelayObservable.create(sink => { + networkSink = sink; + }), + ); + + environment = new Environment({ + store: new LiveResolverStore( + new RecordSource({ + 'client:root': { + __id: 'client:root', + __typename: '__Root', + me: {__ref: '1'}, + }, + '1': { + __id: '1', + id: '1', + __typename: 'User', + }, + }), + ), + network: Network.create(fetchFn), + }); + }); + + it('should fetch and render client-edge query', () => { + function TestComponent() { + return ( + + + + + + ); + } + + const variables = {id: '4'}; + function InnerComponent() { + const data = useLazyLoadQuery( + graphql` + query ClientEdgesTest1Query($id: ID!) { + me { + client_node(id: $id) @waterfall { + ... on User { + name + } + } + } + } + `, + variables, + ); + return data.me?.client_node?.name; + } + + let renderer; + TestRenderer.act(() => { + renderer = TestRenderer.create(); + }); + expect(fetchFn.mock.calls.length).toEqual(1); + // We should send the client-edge query + expect(fetchFn.mock.calls[0][0].name).toBe( + 'ClientEdgeQuery_ClientEdgesTest1Query_me__client_node', + ); + // Check variables + expect(fetchFn.mock.calls[0][1]).toEqual(variables); + expect(renderer?.toJSON()).toBe('Loading'); + + TestRenderer.act(() => { + // This should resolve client-edge query + networkSink.next({ + data: { + node: { + id: '4', + __typename: 'User', + name: 'Alice', + }, + }, + }); + jest.runAllImmediates(); + }); + expect(renderer?.toJSON()).toBe('Alice'); + }); + + it('should fetch and render `null` for client-edge query that returns `null`.', () => { + function TestComponent() { + return ( + + + + + + ); + } + + const variables = {id: '4'}; + function InnerComponent() { + const data = useLazyLoadQuery( + graphql` + query ClientEdgesTest2Query($id: ID!) { + me { + client_node(id: $id) @waterfall { + ... on User { + name + } + } + } + } + `, + variables, + ); + return data.me?.client_node?.name ?? 'MISSING'; + } + + let renderer; + TestRenderer.act(() => { + renderer = TestRenderer.create(); + }); + expect(fetchFn.mock.calls.length).toEqual(1); + // We should send the client-edge query + expect(fetchFn.mock.calls[0][0].name).toBe( + 'ClientEdgeQuery_ClientEdgesTest2Query_me__client_node', + ); + // Check variables + expect(fetchFn.mock.calls[0][1]).toEqual(variables); + expect(renderer?.toJSON()).toBe('Loading'); + + TestRenderer.act(() => { + // This should resolve client-edge query + networkSink.next({ + data: { + node: null, + }, + }); + // It is important to complete network request here, + // otherwise, client-edge query will think that the query is still in progress + // and will show a suspense placeholder + networkSink.complete(); + jest.runAllImmediates(); + }); + expect(renderer?.toJSON()).toBe('MISSING'); + }); + + it('should throw for missing client-edge field data marked with @required', () => { + function TestComponent() { + return ( + + + + + + ); + } + + const variables = {id: '4'}; + function InnerComponent() { + const data = useLazyLoadQuery( + graphql` + query ClientEdgesTest3Query($id: ID!) { + me { + client_node(id: $id) @waterfall @required(action: THROW) { + ... on User { + name + } + } + } + } + `, + variables, + ); + return data.me?.client_node?.name; + } + + let renderer; + TestRenderer.act(() => { + renderer = TestRenderer.create(); + }); + expect(fetchFn.mock.calls.length).toEqual(1); + // We should send the client-edge query + expect(fetchFn.mock.calls[0][0].name).toBe( + 'ClientEdgeQuery_ClientEdgesTest3Query_me__client_node', + ); + // Check variables + expect(fetchFn.mock.calls[0][1]).toEqual(variables); + expect(renderer?.toJSON()).toBe('Loading'); + + TestRenderer.act(() => { + networkSink.next({ + data: { + node: null, + }, + }); + jest.runAllImmediates(); + }); + // Still waiting, maybe the data will be there + expect(renderer?.toJSON()).toBe('Loading'); + + expect(() => { + TestRenderer.act(() => { + // This should resolve client-edge query + networkSink.complete(); + jest.runAllImmediates(); + }); + }).toThrow( + "Relay: Missing @required value at path 'me.client_node' in 'ClientEdgesTest3Query'.", + ); + expect(renderer?.toJSON()).toBe(null); + }); + + it('should throw for missing client-edge (client object) field data marked with @required', () => { + function TestComponent() { + return ( + + + + + + ); + } + // See UserClientEdgeClientObjectResolver: for `0` we should return `null` for `client_object`. + const variables = {id: '0'}; + function InnerComponent() { + const data = useLazyLoadQuery( + graphql` + query ClientEdgesTest4Query($id: ID!) { + me { + client_object(id: $id) @required(action: THROW) { + description + } + } + } + `, + variables, + ); + return data.me?.client_object?.description; + } + expect(() => { + TestRenderer.act(() => { + TestRenderer.create(); + }); + }).toThrow( + "Relay: Missing @required value at path 'me.client_object' in 'ClientEdgesTest4Query'.", + ); + expect(fetchFn.mock.calls.length).toEqual(0); + }); +}); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js new file mode 100644 index 0000000000000..40e236f16aeae --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js @@ -0,0 +1,145 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +type RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$fragmentType = any; +export type ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$variables = {| + id: string, +|}; +export type ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$data = {| + +node: ?{| + +$fragmentSpreads: RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$fragmentType, + |}, +|}; +export type ClientEdgeQuery_ClientEdgesTest1Query_me__client_node = {| + response: ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$data, + variables: ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ClientEdgeQuery_ClientEdgesTest1Query_me__client_node", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgeQuery_ClientEdgesTest1Query_me__client_node", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "TypeDiscriminator", + "abstractKey": "__isNode" + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "8ab0c0b9d0c5840aa3bd05b7424dadd3", + "id": null, + "metadata": {}, + "name": "ClientEdgeQuery_ClientEdgesTest1Query_me__client_node", + "operationKind": "query", + "text": "query ClientEdgeQuery_ClientEdgesTest1Query_me__client_node(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node\n id\n }\n}\n\nfragment RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node on Node {\n __isNode: __typename\n ... on User {\n name\n }\n id\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "69d7fa3908eedb4d634799d1252e80a7"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$variables, + ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js new file mode 100644 index 0000000000000..f8610689eea52 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js @@ -0,0 +1,145 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<<777bde0c8af9c7071925f2a9b78c0e3c>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +type RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$fragmentType = any; +export type ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$variables = {| + id: string, +|}; +export type ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$data = {| + +node: ?{| + +$fragmentSpreads: RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$fragmentType, + |}, +|}; +export type ClientEdgeQuery_ClientEdgesTest2Query_me__client_node = {| + response: ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$data, + variables: ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ClientEdgeQuery_ClientEdgesTest2Query_me__client_node", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgeQuery_ClientEdgesTest2Query_me__client_node", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "TypeDiscriminator", + "abstractKey": "__isNode" + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "8428eea6e29788ed026381db89365e51", + "id": null, + "metadata": {}, + "name": "ClientEdgeQuery_ClientEdgesTest2Query_me__client_node", + "operationKind": "query", + "text": "query ClientEdgeQuery_ClientEdgesTest2Query_me__client_node(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node\n id\n }\n}\n\nfragment RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node on Node {\n __isNode: __typename\n ... on User {\n name\n }\n id\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "eba9115dcb295cf32d8aacc9a815da6b"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$variables, + ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js new file mode 100644 index 0000000000000..3f990f8febd62 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js @@ -0,0 +1,145 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +type RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$fragmentType = any; +export type ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$variables = {| + id: string, +|}; +export type ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$data = {| + +node: ?{| + +$fragmentSpreads: RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$fragmentType, + |}, +|}; +export type ClientEdgeQuery_ClientEdgesTest3Query_me__client_node = {| + response: ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$data, + variables: ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "ClientEdgeQuery_ClientEdgesTest3Query_me__client_node", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgeQuery_ClientEdgesTest3Query_me__client_node", + "selections": [ + { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "TypeDiscriminator", + "abstractKey": "__isNode" + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "2c706fefd151ac8cb06a7d7edaf37acc", + "id": null, + "metadata": {}, + "name": "ClientEdgeQuery_ClientEdgesTest3Query_me__client_node", + "operationKind": "query", + "text": "query ClientEdgeQuery_ClientEdgesTest3Query_me__client_node(\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node\n id\n }\n}\n\nfragment RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node on Node {\n __isNode: __typename\n ... on User {\n name\n }\n id\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "4834e4d5990c86914b1ca32970e43811"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$variables, + ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgesTest1Query.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgesTest1Query.graphql.js new file mode 100644 index 0000000000000..3b12ce0d70e2b --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgesTest1Query.graphql.js @@ -0,0 +1,176 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<<805135c5f768b11583b75d08baf703b6>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import userClientNodeResolver from "../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js"; +// Type assertion validating that `userClientNodeResolver` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userClientNodeResolver: ( + args: {| + id: string, + |}, +) => mixed); +export type ClientEdgesTest1Query$variables = {| + id: string, +|}; +export type ClientEdgesTest1Query$data = {| + +me: ?{| + +client_node: ?{| + +name?: ?string, + |}, + |}, +|}; +export type ClientEdgesTest1Query = {| + response: ClientEdgesTest1Query$data, + variables: ClientEdgesTest1Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "ClientEdgesTest1Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "kind": "ClientEdgeToServerObject", + "operation": require('./ClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql'), + "backingField": { + "alias": null, + "args": (v1/*: any*/), + "fragment": null, + "kind": "RelayResolver", + "name": "client_node", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js'), + "path": "me.client_node" + }, + "linkedField": { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "client_node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgesTest1Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "be96c6717c5e660108e52e314b021c9b", + "id": null, + "metadata": {}, + "name": "ClientEdgesTest1Query", + "operationKind": "query", + "text": "query ClientEdgesTest1Query {\n me {\n id\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "69d7fa3908eedb4d634799d1252e80a7"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgesTest1Query$variables, + ClientEdgesTest1Query$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgesTest2Query.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgesTest2Query.graphql.js new file mode 100644 index 0000000000000..10bc73392336b --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgesTest2Query.graphql.js @@ -0,0 +1,176 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import userClientNodeResolver from "../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js"; +// Type assertion validating that `userClientNodeResolver` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userClientNodeResolver: ( + args: {| + id: string, + |}, +) => mixed); +export type ClientEdgesTest2Query$variables = {| + id: string, +|}; +export type ClientEdgesTest2Query$data = {| + +me: ?{| + +client_node: ?{| + +name?: ?string, + |}, + |}, +|}; +export type ClientEdgesTest2Query = {| + response: ClientEdgesTest2Query$data, + variables: ClientEdgesTest2Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "ClientEdgesTest2Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "kind": "ClientEdgeToServerObject", + "operation": require('./ClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql'), + "backingField": { + "alias": null, + "args": (v1/*: any*/), + "fragment": null, + "kind": "RelayResolver", + "name": "client_node", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js'), + "path": "me.client_node" + }, + "linkedField": { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "client_node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": null + } + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgesTest2Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "e05d01bfdda30ecc1de8aec45abf1bf8", + "id": null, + "metadata": {}, + "name": "ClientEdgesTest2Query", + "operationKind": "query", + "text": "query ClientEdgesTest2Query {\n me {\n id\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "eba9115dcb295cf32d8aacc9a815da6b"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgesTest2Query$variables, + ClientEdgesTest2Query$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgesTest3Query.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgesTest3Query.graphql.js new file mode 100644 index 0000000000000..32a7603d2d8d6 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgesTest3Query.graphql.js @@ -0,0 +1,181 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<<07f741d692148205c025cb195cbca657>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import userClientNodeResolver from "../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js"; +// Type assertion validating that `userClientNodeResolver` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userClientNodeResolver: ( + args: {| + id: string, + |}, +) => mixed); +export type ClientEdgesTest3Query$variables = {| + id: string, +|}; +export type ClientEdgesTest3Query$data = {| + +me: ?{| + +client_node: {| + +name?: ?string, + |}, + |}, +|}; +export type ClientEdgesTest3Query = {| + response: ClientEdgesTest3Query$data, + variables: ClientEdgesTest3Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "ClientEdgesTest3Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "kind": "RequiredField", + "field": { + "kind": "ClientEdgeToServerObject", + "operation": require('./ClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql'), + "backingField": { + "alias": null, + "args": (v1/*: any*/), + "fragment": null, + "kind": "RelayResolver", + "name": "client_node", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js'), + "path": "me.client_node" + }, + "linkedField": { + "alias": null, + "args": (v1/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "client_node", + "plural": false, + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + } + ], + "storageKey": null + } + }, + "action": "THROW", + "path": "me.client_node" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgesTest3Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "3972a9748eef642faafd81e456ee2399", + "id": null, + "metadata": {}, + "name": "ClientEdgesTest3Query", + "operationKind": "query", + "text": "query ClientEdgesTest3Query {\n me {\n id\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "4834e4d5990c86914b1ca32970e43811"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgesTest3Query$variables, + ClientEdgesTest3Query$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/ClientEdgesTest4Query.graphql.js b/packages/react-relay/__tests__/__generated__/ClientEdgesTest4Query.graphql.js new file mode 100644 index 0000000000000..aa7893deff91c --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/ClientEdgesTest4Query.graphql.js @@ -0,0 +1,174 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import userClientObjectResolver from "../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeClientObjectResolver.js"; +// Type assertion validating that `userClientObjectResolver` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userClientObjectResolver: ( + args: {| + id: string, + |}, +) => mixed); +export type ClientEdgesTest4Query$variables = {| + id: string, +|}; +export type ClientEdgesTest4Query$data = {| + +me: ?{| + +client_object: {| + +description: ?string, + |}, + |}, +|}; +export type ClientEdgesTest4Query = {| + response: ClientEdgesTest4Query$data, + variables: ClientEdgesTest4Query$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" + } +], +v1 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": { + "hasClientEdges": true + }, + "name": "ClientEdgesTest4Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "kind": "RequiredField", + "field": { + "kind": "ClientEdgeToClientObject", + "concreteType": "ClientObject", + "backingField": { + "alias": null, + "args": (v1/*: any*/), + "fragment": null, + "kind": "RelayResolver", + "name": "client_object", + "resolverModule": require('./../../../relay-runtime/store/__tests__/resolvers/UserClientEdgeClientObjectResolver.js'), + "path": "me.client_object" + }, + "linkedField": { + "alias": null, + "args": (v1/*: any*/), + "concreteType": "ClientObject", + "kind": "LinkedField", + "name": "client_object", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + } + ], + "storageKey": null + } + }, + "action": "THROW", + "path": "me.client_object" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "ClientEdgesTest4Query", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "me", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "b367e70b936e993fc60d585a6ae3f4f8", + "id": null, + "metadata": {}, + "name": "ClientEdgesTest4Query", + "operationKind": "query", + "text": "query ClientEdgesTest4Query {\n me {\n id\n }\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "acb202133f9bd8681e05bbbba9508ae6"; +} + +module.exports = ((node/*: any*/)/*: Query< + ClientEdgesTest4Query$variables, + ClientEdgesTest4Query$data, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js b/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js new file mode 100644 index 0000000000000..32f53cb4547bf --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql.js @@ -0,0 +1,83 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$fragmentType: FragmentType; +type ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$variables = any; +export type RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$data = {| + +id: string, + +name?: ?string, + +$fragmentType: RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$fragmentType, +|}; +export type RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$key = { + +$data?: RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$data, + +$fragmentSpreads: RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "refetch": { + "connection": null, + "fragmentPathInResult": [ + "node" + ], + "operation": require('./ClientEdgeQuery_ClientEdgesTest1Query_me__client_node.graphql'), + "identifierField": "id" + } + }, + "name": "RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node", + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "type": "Node", + "abstractKey": "__isNode" +}; + +if (__DEV__) { + (node/*: any*/).hash = "69d7fa3908eedb4d634799d1252e80a7"; +} + +module.exports = ((node/*: any*/)/*: RefetchableFragment< + RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$fragmentType, + RefetchableClientEdgeQuery_ClientEdgesTest1Query_me__client_node$data, + ClientEdgeQuery_ClientEdgesTest1Query_me__client_node$variables, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js b/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js new file mode 100644 index 0000000000000..0b4c46730a60f --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql.js @@ -0,0 +1,83 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$fragmentType: FragmentType; +type ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$variables = any; +export type RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$data = {| + +id: string, + +name?: ?string, + +$fragmentType: RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$fragmentType, +|}; +export type RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$key = { + +$data?: RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$data, + +$fragmentSpreads: RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "refetch": { + "connection": null, + "fragmentPathInResult": [ + "node" + ], + "operation": require('./ClientEdgeQuery_ClientEdgesTest2Query_me__client_node.graphql'), + "identifierField": "id" + } + }, + "name": "RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node", + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "type": "Node", + "abstractKey": "__isNode" +}; + +if (__DEV__) { + (node/*: any*/).hash = "eba9115dcb295cf32d8aacc9a815da6b"; +} + +module.exports = ((node/*: any*/)/*: RefetchableFragment< + RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$fragmentType, + RefetchableClientEdgeQuery_ClientEdgesTest2Query_me__client_node$data, + ClientEdgeQuery_ClientEdgesTest2Query_me__client_node$variables, +>*/); diff --git a/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js b/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js new file mode 100644 index 0000000000000..cc9f347ff6219 --- /dev/null +++ b/packages/react-relay/__tests__/__generated__/RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql.js @@ -0,0 +1,83 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$fragmentType: FragmentType; +type ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$variables = any; +export type RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$data = {| + +id: string, + +name?: ?string, + +$fragmentType: RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$fragmentType, +|}; +export type RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$key = { + +$data?: RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$data, + +$fragmentSpreads: RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "refetch": { + "connection": null, + "fragmentPathInResult": [ + "node" + ], + "operation": require('./ClientEdgeQuery_ClientEdgesTest3Query_me__client_node.graphql'), + "identifierField": "id" + } + }, + "name": "RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node", + "selections": [ + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "type": "Node", + "abstractKey": "__isNode" +}; + +if (__DEV__) { + (node/*: any*/).hash = "4834e4d5990c86914b1ca32970e43811"; +} + +module.exports = ((node/*: any*/)/*: RefetchableFragment< + RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$fragmentType, + RefetchableClientEdgeQuery_ClientEdgesTest3Query_me__client_node$data, + ClientEdgeQuery_ClientEdgesTest3Query_me__client_node$variables, +>*/); diff --git a/packages/relay-runtime/store/RelayReader.js b/packages/relay-runtime/store/RelayReader.js index be3b4e1217093..cb125550a93dc 100644 --- a/packages/relay-runtime/store/RelayReader.js +++ b/packages/relay-runtime/store/RelayReader.js @@ -498,6 +498,12 @@ class RelayReader { throw new Error('Relay Resolver fields are not yet supported.'); } return this._readResolverField(selection.field, record, data); + case CLIENT_EDGE_TO_CLIENT_OBJECT: + case CLIENT_EDGE_TO_SERVER_OBJECT: + if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) { + throw new Error('Relay Resolver fields are not yet supported.'); + } + return this._readClientEdge(selection.field, record, data); default: (selection.field.kind: empty); invariant( diff --git a/packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeClientObjectResolver.js b/packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeClientObjectResolver.js new file mode 100644 index 0000000000000..e3d3e477cf022 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeClientObjectResolver.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + * @emails oncall+relay + */ + +'use strict'; + +import type {DataID} from 'relay-runtime'; + +/** + * @RelayResolver + * @fieldName client_object(id: ID!) + * @edgeTo ClientObject + * @onType User + */ +function UserClientEdgeClientObjectResolver(args: {id: string}): ?DataID { + if (args.id === '0') { + return null; + } + return args.id; +} + +module.exports = UserClientEdgeClientObjectResolver; diff --git a/packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js b/packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js new file mode 100644 index 0000000000000..ea185329582f2 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/resolvers/UserClientEdgeNodeResolver.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + * @emails oncall+relay + */ + +'use strict'; + +import type {DataID} from 'relay-runtime'; + +/** + * @RelayResolver + * @fieldName client_node(id: ID!) + * @edgeTo Node + * @onType User + */ +function UserClientEdgeResolver(args: {id: string}): DataID { + return args.id; +} + +module.exports = UserClientEdgeResolver; diff --git a/packages/relay-runtime/util/ReaderNode.js b/packages/relay-runtime/util/ReaderNode.js index 2ab7392e370ec..ddabb5883d094 100644 --- a/packages/relay-runtime/util/ReaderNode.js +++ b/packages/relay-runtime/util/ReaderNode.js @@ -232,7 +232,10 @@ export type RequiredFieldAction = 'NONE' | 'LOG' | 'THROW'; export type ReaderRequiredField = { +kind: 'RequiredField', - +field: ReaderField, + +field: + | ReaderField + | ReaderClientEdgeToClientObject + | ReaderClientEdgeToServerObject, +action: RequiredFieldAction, +path: string, }; diff --git a/packages/relay-test-utils-internal/schema-extensions/ClientObject.graphql b/packages/relay-test-utils-internal/schema-extensions/ClientObject.graphql new file mode 100644 index 0000000000000..188e900ad80c9 --- /dev/null +++ b/packages/relay-test-utils-internal/schema-extensions/ClientObject.graphql @@ -0,0 +1,3 @@ +type ClientObject { + description: String +}