diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralFragment.graphql.js new file mode 100644 index 0000000000000..ba317d7cf63f9 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralFragment.graphql.js @@ -0,0 +1,65 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<<80e54ca26f89d2d71c3bb618efa15d49>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestMissingRequiredPluralFragment$fragmentType: FragmentType; +export type observeFragmentTestMissingRequiredPluralFragment$data = $ReadOnlyArray<{| + +name: string, + +$fragmentType: observeFragmentTestMissingRequiredPluralFragment$fragmentType, +|}>; +export type observeFragmentTestMissingRequiredPluralFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestMissingRequiredPluralFragment$data, + +$fragmentSpreads: observeFragmentTestMissingRequiredPluralFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "observeFragmentTestMissingRequiredPluralFragment", + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + "action": "THROW" + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "0a62ca17583bf06a225f706e103dc11e"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestMissingRequiredPluralFragment$fragmentType, + observeFragmentTestMissingRequiredPluralFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralQuery.graphql.js new file mode 100644 index 0000000000000..d14055391be61 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestMissingRequiredPluralQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<<0ee8f9cd4d1a4269af40172b0c55884d>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestMissingRequiredPluralFragment$fragmentType } from "./observeFragmentTestMissingRequiredPluralFragment.graphql"; +export type observeFragmentTestMissingRequiredPluralQuery$variables = {||}; +export type observeFragmentTestMissingRequiredPluralQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestMissingRequiredPluralQuery = {| + response: observeFragmentTestMissingRequiredPluralQuery$data, + variables: observeFragmentTestMissingRequiredPluralQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestMissingRequiredPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestMissingRequiredPluralFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestMissingRequiredPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "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": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "d1213ecc01790c61de1e12d97a40c349", + "id": null, + "metadata": {}, + "name": "observeFragmentTestMissingRequiredPluralQuery", + "operationKind": "query", + "text": "query observeFragmentTestMissingRequiredPluralQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestMissingRequiredPluralFragment\n id\n }\n}\n\nfragment observeFragmentTestMissingRequiredPluralFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "1eb9c5256c37c4d0e28695bb4dd64fa8"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestMissingRequiredPluralQuery$variables, + observeFragmentTestMissingRequiredPluralQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralFragment.graphql.js new file mode 100644 index 0000000000000..f5d80766c2a15 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralFragment.graphql.js @@ -0,0 +1,61 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestPluralFragment$fragmentType: FragmentType; +export type observeFragmentTestPluralFragment$data = $ReadOnlyArray<{| + +name: ?string, + +$fragmentType: observeFragmentTestPluralFragment$fragmentType, +|}>; +export type observeFragmentTestPluralFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestPluralFragment$data, + +$fragmentSpreads: observeFragmentTestPluralFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "observeFragmentTestPluralFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "3b473578ee9b2f35ed7214e714f68334"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestPluralFragment$fragmentType, + observeFragmentTestPluralFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralQuery.graphql.js new file mode 100644 index 0000000000000..d6ed1fc180fc6 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<<8ed3e238203c49288429f434ff0ef253>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestPluralFragment$fragmentType } from "./observeFragmentTestPluralFragment.graphql"; +export type observeFragmentTestPluralQuery$variables = {||}; +export type observeFragmentTestPluralQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestPluralQuery = {| + response: observeFragmentTestPluralQuery$data, + variables: observeFragmentTestPluralQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestPluralFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestPluralQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "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": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "ccff1412490c5e62d70031d41db0c7e4", + "id": null, + "metadata": {}, + "name": "observeFragmentTestPluralQuery", + "operationKind": "query", + "text": "query observeFragmentTestPluralQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestPluralFragment\n id\n }\n}\n\nfragment observeFragmentTestPluralFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "c1a2f68df2ec25bc00b077d6cdecdce4"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestPluralQuery$variables, + observeFragmentTestPluralQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorFragment.graphql.js new file mode 100644 index 0000000000000..122853d5c2de7 --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorFragment.graphql.js @@ -0,0 +1,62 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<<73dfa993cd14eb071971ec8ae446eea0>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType: FragmentType; +export type observeFragmentTestPluralThrowOnFieldErrorFragment$data = $ReadOnlyArray<{| + +name: ?string, + +$fragmentType: observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType, +|}>; +export type observeFragmentTestPluralThrowOnFieldErrorFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestPluralThrowOnFieldErrorFragment$data, + +$fragmentSpreads: observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "throwOnFieldError": true + }, + "name": "observeFragmentTestPluralThrowOnFieldErrorFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "531291e1335ff8e4ffacf60c7a6064ed"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType, + observeFragmentTestPluralThrowOnFieldErrorFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..a7a23d3f32ffe --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestPluralThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,137 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestPluralThrowOnFieldErrorFragment$fragmentType } from "./observeFragmentTestPluralThrowOnFieldErrorFragment.graphql"; +export type observeFragmentTestPluralThrowOnFieldErrorQuery$variables = {||}; +export type observeFragmentTestPluralThrowOnFieldErrorQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestPluralThrowOnFieldErrorQuery = {| + response: observeFragmentTestPluralThrowOnFieldErrorQuery$data, + variables: observeFragmentTestPluralThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "1", + "2" + ] + } +]; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestPluralThrowOnFieldErrorFragment" + } + ], + "storageKey": "nodes(ids:[\"1\",\"2\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "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": "nodes(ids:[\"1\",\"2\"])" + } + ] + }, + "params": { + "cacheID": "1e83abfe97b66be09a6642b3332e4d09", + "id": null, + "metadata": {}, + "name": "observeFragmentTestPluralThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query observeFragmentTestPluralThrowOnFieldErrorQuery {\n nodes(ids: [\"1\", \"2\"]) {\n __typename\n ...observeFragmentTestPluralThrowOnFieldErrorFragment\n id\n }\n}\n\nfragment observeFragmentTestPluralThrowOnFieldErrorFragment on User {\n name\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "36cd146fd2db4ac80dfe226a3e20dd3e"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestPluralThrowOnFieldErrorQuery$variables, + observeFragmentTestPluralThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql.js new file mode 100644 index 0000000000000..3bd37816c2c5f --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql.js @@ -0,0 +1,78 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { UserAlwaysThrowsResolver$key } from "./../resolvers/__generated__/UserAlwaysThrowsResolver.graphql"; +import type { FragmentType } from "relay-runtime"; +import {always_throws as userAlwaysThrowsResolverType} from "../resolvers/UserAlwaysThrowsResolver.js"; +import type { TestResolverContextType } from "../../../mutations/__tests__/TestResolverContextType"; +// Type assertion validating that `userAlwaysThrowsResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userAlwaysThrowsResolverType: ( + rootKey: UserAlwaysThrowsResolver$key, + args: void, + context: TestResolverContextType, +) => ?string); +declare export opaque type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType: FragmentType; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$data = $ReadOnlyArray<{| + +always_throws: ?string, + +$fragmentType: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType, +|}>; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$key = $ReadOnlyArray<{ + +$data?: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$data, + +$fragmentSpreads: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType, + ... +}>; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "throwOnFieldError": true + }, + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment", + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "UserAlwaysThrowsResolver" + }, + "kind": "RelayResolver", + "name": "always_throws", + "resolverModule": require('./../resolvers/UserAlwaysThrowsResolver').always_throws, + "path": "always_throws" + } + ], + "type": "User", + "abstractKey": null +}; + +if (__DEV__) { + (node/*: any*/).hash = "59a6f5ddf61e54affd5726b8cf322183"; +} + +module.exports = ((node/*: any*/)/*: Fragment< + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType, + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery.graphql.js b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery.graphql.js new file mode 100644 index 0000000000000..924a7c4f2ce5a --- /dev/null +++ b/packages/relay-runtime/store/__tests__/__generated__/observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery.graphql.js @@ -0,0 +1,146 @@ +/** + * 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. + * + * @oncall relay + * + * @generated SignedSource<<88f631a8a727158afc72c5ed15b804a4>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { ConcreteRequest, Query } from 'relay-runtime'; +import type { observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment$fragmentType } from "./observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment.graphql"; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$variables = {||}; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$data = {| + +nodes: ?$ReadOnlyArray, +|}; +export type observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery = {| + response: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$data, + variables: observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$variables, +|}; +*/ + +var node/*: ConcreteRequest*/ = (function(){ +var v0 = [ + { + "kind": "Literal", + "name": "ids", + "value": [ + "7", + "8" + ] + } +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + { + "args": null, + "kind": "FragmentSpread", + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment" + } + ], + "storageKey": "nodes(ids:[\"7\",\"8\"])" + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery", + "selections": [ + { + "alias": null, + "args": (v0/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "nodes", + "plural": true, + "selections": [ + (v1/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + { + "name": "always_throws", + "args": null, + "fragment": { + "kind": "InlineFragment", + "selections": [ + (v1/*: any*/) + ], + "type": "User", + "abstractKey": null + }, + "kind": "RelayResolver", + "storageKey": null, + "isOutputType": true + } + ], + "type": "User", + "abstractKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ], + "storageKey": "nodes(ids:[\"7\",\"8\"])" + } + ] + }, + "params": { + "cacheID": "cda0054b75d8a0bc0abaacbb14186b4a", + "id": null, + "metadata": {}, + "name": "observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery", + "operationKind": "query", + "text": "query observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery {\n nodes(ids: [\"7\", \"8\"]) {\n __typename\n ...observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment\n id\n }\n}\n\nfragment UserAlwaysThrowsResolver on User {\n __typename\n}\n\nfragment observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment on User {\n ...UserAlwaysThrowsResolver\n}\n" + } +}; +})(); + +if (__DEV__) { + (node/*: any*/).hash = "412492582875c8c7b44e67794ed55763"; +} + +module.exports = ((node/*: any*/)/*: Query< + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$variables, + observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery$data, +>*/); diff --git a/packages/relay-runtime/store/__tests__/observeFragment-test.js b/packages/relay-runtime/store/__tests__/observeFragment-test.js index 484a74009c32c..909f1847e38b2 100644 --- a/packages/relay-runtime/store/__tests__/observeFragment-test.js +++ b/packages/relay-runtime/store/__tests__/observeFragment-test.js @@ -337,6 +337,189 @@ test('read deferred fragment', async () => { }); }); +test('observes a plural fragment', async () => { + const query = graphql` + query observeFragmentTestPluralQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestPluralFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestPluralFragment on User @relay(plural: true) { + name + } + `; + + const environment = createMockEnvironment({ + store: new LiveResolverStore(new RelayRecordSource()), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + {id: '1', __typename: 'User', name: 'Alice'}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + const result = await observable.toPromise(); + expect(result).toEqual({ + state: 'ok', + value: [{name: 'Alice'}, {name: 'Bob'}], + }); +}); + +test('Missing required data on plural fragment', async () => { + const query = graphql` + query observeFragmentTestMissingRequiredPluralQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestMissingRequiredPluralFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestMissingRequiredPluralFragment on User + @relay(plural: true) { + name @required(action: THROW) + } + `; + + const environment = createMockEnvironment(); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + // Name is null despite being required + {id: '1', __typename: 'User', name: null}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }); + + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + { + error: new Error( + "Relay: Missing @required value at path 'name' in 'observeFragmentTestMissingRequiredPluralFragment'.", + ), + state: 'error', + }, + ]); + }); +}); + +test('Field error with @relay(plural: true) @throwOnFieldError', async () => { + const query = graphql` + query observeFragmentTestPluralThrowOnFieldErrorQuery { + nodes(ids: ["1", "2"]) { + ...observeFragmentTestPluralThrowOnFieldErrorFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestPluralThrowOnFieldErrorFragment on User + @relay(plural: true) + @throwOnFieldError { + name + } + `; + + let dataSource: Sink; + const fetch = ( + _query: RequestParameters, + _variables: Variables, + _cacheConfig: CacheConfig, + ) => { + // $FlowFixMe[missing-local-annot] Error found while enabling LTI on this file + return RelayObservable.create(sink => { + dataSource = sink; + }); + }; + + const environment = createMockEnvironment({ + network: RelayNetwork.create(fetch), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + + environment.execute({operation}).subscribe({}); + invariant(dataSource != null, 'Expected data source to be set'); + dataSource.next({ + data: { + nodes: [ + {id: '1', __typename: 'User', name: null}, + {id: '2', __typename: 'User', name: 'Bob'}, + ], + }, + errors: [{message: 'error', path: ['nodes', 0, 'name']}], + }); + + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + { + error: new Error( + 'Relay: Unexpected response payload - check server logs for details.', + ), + state: 'error', + }, + ]); + }); +}); + +test('Resolver error with @relay(plural: true) @throwOnFieldError', async () => { + const query = graphql` + query observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorQuery { + nodes(ids: ["7", "8"]) { + ...observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment + } + } + `; + + const fragment = graphql` + fragment observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment on User + @relay(plural: true) + @throwOnFieldError { + always_throws + } + `; + + const environment = createMockEnvironment({ + store: new LiveResolverStore(new RelayRecordSource()), + }); + const variables = {}; + const operation = createOperationDescriptor(query, variables); + environment.commitPayload(operation, { + nodes: [ + {id: '7', __typename: 'User'}, + {id: '8', __typename: 'User'}, + ], + }); + const {data} = environment.lookup(operation.fragment); + // $FlowFixMe Data is untyped + const observable = observeFragment(environment, fragment, data.nodes); + withObservableValues(observable, results => { + expect(results).toEqual([ + { + error: new Error( + "Relay: Resolver error at path 'always_throws' in 'observeFragmentTestResolverErrorWithPluralThrowOnFieldErrorFragment'.", + ), + state: 'error', + }, + ]); + }); +}); + test('data goes missing due to unrelated query response', async () => { const query = graphql` query observeFragmentTestMissingDataQuery { diff --git a/packages/relay-runtime/store/observeFragmentExperimental.js b/packages/relay-runtime/store/observeFragmentExperimental.js index e84a00855c944..c578117e6578b 100644 --- a/packages/relay-runtime/store/observeFragmentExperimental.js +++ b/packages/relay-runtime/store/observeFragmentExperimental.js @@ -9,7 +9,7 @@ * @oncall relay */ -import type {RequestDescriptor} from './RelayStoreTypes'; +import type {PluralReaderSelector, RequestDescriptor} from './RelayStoreTypes'; import type { Fragment, FragmentType, @@ -47,8 +47,7 @@ export type HasSpread = { /** * EXPERIMENTAL: This API is experimental and does not yet support all Relay - * features. Notably, it does not correectly handle plural fragments or some - * features of Relay Resolvers. + * features. Notably, it does not correctly handle some features of Relay Resolvers. * * Given a fragment and a fragment reference, returns a promise that resolves * once the fragment data is available, or rejects if the fragment has an error. @@ -63,7 +62,9 @@ export type HasSpread = { async function waitForFragmentData( environment: IEnvironment, fragment: Fragment, - fragmentRef: HasSpread, + fragmentRef: + | HasSpread + | $ReadOnlyArray>, ): Promise { let subscription: ?Subscription; @@ -94,13 +95,14 @@ async function waitForFragmentData( declare function observeFragment( environment: IEnvironment, fragment: Fragment, - fragmentRef: HasSpread, + fragmentRef: + | HasSpread + | $ReadOnlyArray>, ): Observable>; /** * EXPERIMENTAL: This API is experimental and does not yet support all Relay - * features. Notably, it does not correectly handle plural fragments or some - * features of Relay Resolvers. + * features. Notably, it does not correctly handle some features of Relay Resolvers. * * Given a fragment and a fragment reference, returns an observable that emits * the state of the fragment over time. The observable will emit the following @@ -114,7 +116,7 @@ function observeFragment( environment: IEnvironment, fragment: Fragment, fragmentRef: mixed, -): Observable> { +): mixed { const fragmentNode = getFragment(fragment); const fragmentSelector = getSelector(fragmentNode, fragmentRef); invariant( @@ -124,24 +126,19 @@ function observeFragment( invariant(fragmentSelector != null, 'Expected a selector, got null.'); switch (fragmentSelector.kind) { case 'SingularReaderSelector': - return observeSelector(environment, fragment, fragmentSelector); + return observeSingularSelector(environment, fragment, fragmentSelector); case 'PluralReaderSelector': { - // TODO: We could use something like this RXJS's combineLatest to create - // an observable for each selector and merge them. - // https://github.com/ReactiveX/rxjs/blob/master/packages/rxjs/src/internal/observable/combineLatest.ts - // - // Note that this problem is a bit tricky because Relay currently only - // lets you subscribe at a singular fragment granularity. This makes it - // hard to batch updates such that when a store update causes multiple - // fragments to change, we can only publish a single update to the - // fragment owner. - invariant(false, 'Plural fragments are not supported'); + return observePluralSelector( + environment, + (fragment: $FlowFixMe), + fragmentSelector, + ); } } invariant(false, 'Unsupported fragment selector kind'); } -function observeSelector( +function observeSingularSelector( environment: IEnvironment, fragmentNode: Fragment, fragmentSelector: SingularReaderSelector, @@ -173,6 +170,67 @@ function observeSelector( }); } +function observePluralSelector< + TFragmentType: FragmentType, + TData: Array, +>( + environment: IEnvironment, + fragmentNode: Fragment, + fragmentSelector: PluralReaderSelector, +): Observable> { + const snapshots = fragmentSelector.selectors.map(selector => + environment.lookup(selector), + ); + + return Observable.create(sink => { + const states = snapshots.map((snapshot, index) => + snapshotToFragmentState( + environment, + fragmentNode, + fragmentSelector.selectors[0].owner, + snapshot, + ), + ); + + const reduceState = () => + states.reduce>( + (acc, state) => { + if (acc.state !== 'ok') { + return acc; + } + + if (state.state === 'ok') { + acc.value.push(state.value); + return acc; + } else { + return state; + } + }, + { + state: 'ok', + // $FlowFixMe[incompatible-cast]: TData is enforced to be an array + value: ([]: TData), + }, + ); + + sink.next(reduceState()); + + const subscriptions = snapshots.map((snapshot, index) => + environment.subscribe(snapshot, latestSnapshot => { + states[index] = snapshotToFragmentState( + environment, + fragmentNode, + fragmentSelector.selectors[0].owner, + latestSnapshot, + ); + sink.next(reduceState()); + }), + ); + + return () => subscriptions.forEach(subscription => subscription.dispose()); + }); +} + function snapshotToFragmentState( environment: IEnvironment, fragmentNode: Fragment, diff --git a/packages/relay-runtime/store/waitForFragmentExperimental.js b/packages/relay-runtime/store/waitForFragmentExperimental.js index 53ba061e85ec5..e1ad597178d86 100644 --- a/packages/relay-runtime/store/waitForFragmentExperimental.js +++ b/packages/relay-runtime/store/waitForFragmentExperimental.js @@ -21,8 +21,7 @@ const {observeFragment} = require('./observeFragmentExperimental'); /** * EXPERIMENTAL: This API is experimental and does not yet support all Relay - * features. Notably, it does not correectly handle plural fragments or some - * features of Relay Resolvers. + * features. Notably, it does not correctly handle some features of Relay Resolvers. * * Given a fragment and a fragment reference, returns a promise that resolves * once the fragment data is available, or rejects if the fragment has an error. @@ -37,7 +36,9 @@ const {observeFragment} = require('./observeFragmentExperimental'); async function waitForFragmentData( environment: IEnvironment, fragment: Fragment, - fragmentRef: HasSpread, + fragmentRef: + | HasSpread + | $ReadOnlyArray>, ): Promise { let subscription: ?Subscription;