From 8cce449a11c8e4b4df07cf63ce7cc95b51bfa2bb Mon Sep 17 00:00:00 2001 From: Tianyu Yao Date: Wed, 5 Jun 2024 13:59:09 -0700 Subject: [PATCH] A RelayResolverValue generic Reviewed By: evanyeung Differential Revision: D58156313 fbshipit-source-id: 776c27e1f120e808320cbe0f789f2f808900d816 --- .../crates/relay-schema-generation/src/lib.rs | 16 +- .../return-relay-resolver-value.expected | 229 ++++++++++++++++++ .../return-relay-resolver-value.input | 40 +++ .../tests/docblock_test.rs | 9 +- packages/relay-runtime/experimental.js | 5 + packages/relay-runtime/index.js | 2 +- 6 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected create mode 100644 compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.input diff --git a/compiler/crates/relay-schema-generation/src/lib.rs b/compiler/crates/relay-schema-generation/src/lib.rs index 891325a594118..564f4e817b4db 100644 --- a/compiler/crates/relay-schema-generation/src/lib.rs +++ b/compiler/crates/relay-schema-generation/src/lib.rs @@ -826,7 +826,7 @@ fn return_type_to_type_annotation( source_location: SourceLocationKey, return_type: &FlowTypeAnnotation, ) -> DiagnosticsResult { - let (return_type, is_optional) = schema_extractor::unwrap_nullable_type(return_type); + let (return_type, mut is_optional) = schema_extractor::unwrap_nullable_type(return_type); let location = to_location(source_location, return_type); let type_annotation = match return_type { FlowTypeAnnotation::GenericTypeAnnotation(node) => { @@ -871,6 +871,20 @@ fn return_type_to_type_annotation( )]); } } + "RelayResolverValue" => { + // Special case for `RelayResolverValue`, it is always optional + is_optional = true; + TypeAnnotation::Named(NamedTypeAnnotation { + name: Identifier { + span: location.span(), + token: Token { + span: location.span(), + kind: TokenKind::Identifier, + }, + value: intern!("RelayResolverValue"), + }, + }) + } _ => { return Err(vec![Diagnostic::error( SchemaGenerationError::UnSupportedGeneric { diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected new file mode 100644 index 0000000000000..a0de3c7ec9912 --- /dev/null +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.expected @@ -0,0 +1,229 @@ +==================================== INPUT ==================================== +//- module.js + +/** + * 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. + */ + +import type CatFlowType from 'Cat'; + +import type { RelayResolverValue } from 'relay-runtime'; + +/** + * @RelayResolver + */ +export function Cat(id: DataID): CatFlowType { + return {}; +} + +/** + * @RelayResolver + */ +export function complexValue(cat: CatFlowType): RelayResolverValue<{a: 1, b: 2}> { + return {a: 1, b: 2}; +} + +/** + * @RelayResolver + */ +export function optionalRelayResolverValue(cat: CatFlowType): ?RelayResolverValue<{a: 1, b: 2}> { + return null; +} + +/** + * @RelayResolver + */ +export function relayResolveValueOverridesAllOtherAnnotation(cat: CatFlowType): ?RelayResolverValue> { + return {id: '1'}; +} +==================================== OUTPUT =================================== +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 419:431, + token: Token { + span: 419:431, + kind: Identifier, + }, + value: "complexValue", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 451:483, + token: Token { + span: 451:483, + kind: Identifier, + }, + value: "RelayResolverValue", + }, + }, + ), + arguments: None, + directives: [], + description: None, + hack_source: None, + span: 419:431, + }, + type_: WithLocation { + location: :330:333, + item: "Cat", + }, + root_fragment: None, + deprecated: None, + semantic_non_null: None, + live: None, + location: module.js:419:431, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "fc15c065174264428a3632fe9cf329d6", + ), + }, + ), +) +extend type Cat { + complexValue: RelayResolverValue @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", has_output_type: true, import_name: "complexValue", import_path: "module.js") @resolver_source_hash(value: "fc15c065174264428a3632fe9cf329d6") +} + + +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 554:580, + token: Token { + span: 554:580, + kind: Identifier, + }, + value: "optionalRelayResolverValue", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 601:633, + token: Token { + span: 601:633, + kind: Identifier, + }, + value: "RelayResolverValue", + }, + }, + ), + arguments: None, + directives: [], + description: None, + hack_source: None, + span: 554:580, + }, + type_: WithLocation { + location: :330:333, + item: "Cat", + }, + root_fragment: None, + deprecated: None, + semantic_non_null: None, + live: None, + location: module.js:554:580, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "fc15c065174264428a3632fe9cf329d6", + ), + }, + ), +) +extend type Cat { + optionalRelayResolverValue: RelayResolverValue @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", has_output_type: true, import_name: "optionalRelayResolverValue", import_path: "module.js") @resolver_source_hash(value: "fc15c065174264428a3632fe9cf329d6") +} + + +Field( + TerseRelayResolver( + TerseRelayResolverIr { + field: FieldDefinition { + name: Identifier { + span: 696:740, + token: Token { + span: 696:740, + kind: Identifier, + }, + value: "relayResolveValueOverridesAllOtherAnnotation", + }, + type_: Named( + NamedTypeAnnotation { + name: Identifier { + span: 761:792, + token: Token { + span: 761:792, + kind: Identifier, + }, + value: "RelayResolverValue", + }, + }, + ), + arguments: None, + directives: [], + description: None, + hack_source: None, + span: 696:740, + }, + type_: WithLocation { + location: :330:333, + item: "Cat", + }, + root_fragment: None, + deprecated: None, + semantic_non_null: None, + live: None, + location: module.js:696:740, + fragment_arguments: None, + source_hash: ResolverSourceHash( + "fc15c065174264428a3632fe9cf329d6", + ), + }, + ), +) +extend type Cat { + relayResolveValueOverridesAllOtherAnnotation: RelayResolverValue @relay_resolver(fragment_name: "Cat____relay_model_instance", generated_fragment: true, inject_fragment_data: "__relay_model_instance", has_output_type: true, import_name: "relayResolveValueOverridesAllOtherAnnotation", import_path: "module.js") @resolver_source_hash(value: "fc15c065174264428a3632fe9cf329d6") +} + + +Type( + StrongObjectResolver( + StrongObjectIr { + type_name: Identifier { + span: 330:333, + token: Token { + span: 330:333, + kind: Identifier, + }, + value: "Cat", + }, + rhs_location: module.js:330:333, + root_fragment: WithLocation { + location: module.js:330:333, + item: FragmentDefinitionName( + "Cat__id", + ), + }, + description: None, + deprecated: None, + live: None, + semantic_non_null: None, + location: module.js:330:333, + implements_interfaces: [], + source_hash: ResolverSourceHash( + "fc15c065174264428a3632fe9cf329d6", + ), + }, + ), +) +type Cat @__RelayResolverModel { + id: ID! + __relay_model_instance: RelayResolverValue! @relay_resolver(generated_fragment: true, fragment_name: "Cat__id", import_name: "Cat", import_path: "module.js", inject_fragment_data: "id") @resolver_source_hash(value: "fc15c065174264428a3632fe9cf329d6") @unselectable(reason: "This field is intended only for Relay's internal use") +} diff --git a/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.input b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.input new file mode 100644 index 0000000000000..4ea710cfa4e2f --- /dev/null +++ b/compiler/crates/relay-schema-generation/tests/docblock/fixtures/return-relay-resolver-value.input @@ -0,0 +1,40 @@ +//- module.js + +/** + * 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. + */ + +import type CatFlowType from 'Cat'; + +import type { RelayResolverValue } from 'relay-runtime'; + +/** + * @RelayResolver + */ +export function Cat(id: DataID): CatFlowType { + return {}; +} + +/** + * @RelayResolver + */ +export function complexValue(cat: CatFlowType): RelayResolverValue<{a: 1, b: 2}> { + return {a: 1, b: 2}; +} + +/** + * @RelayResolver + */ +export function optionalRelayResolverValue(cat: CatFlowType): ?RelayResolverValue<{a: 1, b: 2}> { + return null; +} + +/** + * @RelayResolver + */ +export function relayResolveValueOverridesAllOtherAnnotation(cat: CatFlowType): ?RelayResolverValue> { + return {id: '1'}; +} diff --git a/compiler/crates/relay-schema-generation/tests/docblock_test.rs b/compiler/crates/relay-schema-generation/tests/docblock_test.rs index 5f26e4fb0a77e..388ee3a585fa0 100644 --- a/compiler/crates/relay-schema-generation/tests/docblock_test.rs +++ b/compiler/crates/relay-schema-generation/tests/docblock_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<8ea8d4359f6e14415e193be12974b772>> + * @generated SignedSource<<4de8fcba1c45e8cec09648c0767a6efe>> */ mod docblock; @@ -103,6 +103,13 @@ async fn return_optional_weak_object() { test_fixture(transform_fixture, file!(), "return-optional-weak-object.input", "docblock/fixtures/return-optional-weak-object.expected", input, expected).await; } +#[tokio::test] +async fn return_relay_resolver_value() { + let input = include_str!("docblock/fixtures/return-relay-resolver-value.input"); + let expected = include_str!("docblock/fixtures/return-relay-resolver-value.expected"); + test_fixture(transform_fixture, file!(), "return-relay-resolver-value.input", "docblock/fixtures/return-relay-resolver-value.expected", input, expected).await; +} + #[tokio::test] async fn root_fragment() { let input = include_str!("docblock/fixtures/root-fragment.input"); diff --git a/packages/relay-runtime/experimental.js b/packages/relay-runtime/experimental.js index 2cdb276926c41..4008ed9e59e1b 100644 --- a/packages/relay-runtime/experimental.js +++ b/packages/relay-runtime/experimental.js @@ -15,9 +15,14 @@ import type {DataID} from './util/RelayRuntimeTypes'; const resolverDataInjector = require('./store/experimental-live-resolvers/resolverDataInjector'); +// Annotates a strong object return type, where `A` is the GraphQL typename // eslint-disable-next-line no-unused-vars export type IdOf = DataID; +// Annotates a `RelayResolverValue` GraphQL return type +// eslint-disable-next-line no-unused-vars +export type RelayResolverValue = A; + module.exports = { resolverDataInjector, }; diff --git a/packages/relay-runtime/index.js b/packages/relay-runtime/index.js index f12ed670a4b23..45e3af0ea72ea 100644 --- a/packages/relay-runtime/index.js +++ b/packages/relay-runtime/index.js @@ -239,7 +239,7 @@ export type {Local3DPayload} from './util/createPayloadFor3DField'; export type {Direction} from './util/getPaginationVariables'; export type {RequestIdentifier} from './util/getRequestIdentifier'; export type {ResolverFunction} from './util/ReaderNode'; -export type {IdOf} from './experimental'; +export type {IdOf, RelayResolverValue} from './experimental'; // As early as possible, check for the existence of the JavaScript globals which // Relay Runtime relies upon, and produce a clear message if they do not exist.