packages/relay-runtime/mutations/RelayRecordSourceSelectorProxy.js (120 lines of code) (raw):

/** * 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. * * @flow strict-local * @format */ // flowlint ambiguous-object-type:error 'use strict'; import type {GraphQLTaggedNode} from '../query/GraphQLTag'; import type { FragmentType, HasUpdatableSpread, RecordProxy, RecordSourceProxy, RecordSourceSelectorProxy, SingularReaderSelector, UpdatableData, } from '../store/RelayStoreTypes'; import type {ReaderLinkedField} from '../util/ReaderNode'; import type { DataID, UpdatableFragment, UpdatableQuery, Variables, } from '../util/RelayRuntimeTypes'; import type RelayRecordSourceMutator from './RelayRecordSourceMutator'; const {ROOT_TYPE, getStorageKey} = require('../store/RelayStoreUtils'); const { readUpdatableFragment_EXPERIMENTAL, } = require('./readUpdatableFragment_EXPERIMENTAL'); const { readUpdatableQuery_EXPERIMENTAL, } = require('./readUpdatableQuery_EXPERIMENTAL'); const invariant = require('invariant'); /** * @internal * * A subclass of RecordSourceProxy that provides convenience methods for * accessing the root fields of a given query/mutation. These fields accept * complex arguments and it can be tedious to re-construct the correct sets of * arguments to pass to e.g. `getRoot().getLinkedRecord()`. */ class RelayRecordSourceSelectorProxy implements RecordSourceSelectorProxy { __mutator: RelayRecordSourceMutator; __recordSource: RecordSourceProxy; _readSelector: SingularReaderSelector; constructor( mutator: RelayRecordSourceMutator, recordSource: RecordSourceProxy, readSelector: SingularReaderSelector, ) { this.__mutator = mutator; this.__recordSource = recordSource; this._readSelector = readSelector; } create(dataID: DataID, typeName: string): RecordProxy { return this.__recordSource.create(dataID, typeName); } delete(dataID: DataID): void { this.__recordSource.delete(dataID); } get(dataID: DataID): ?RecordProxy { return this.__recordSource.get(dataID); } getRoot(): RecordProxy { return this.__recordSource.getRoot(); } getOperationRoot(): RecordProxy { let root = this.__recordSource.get(this._readSelector.dataID); if (!root) { root = this.__recordSource.create(this._readSelector.dataID, ROOT_TYPE); } return root; } _getRootField( selector: SingularReaderSelector, fieldName: string, plural: boolean, ): ReaderLinkedField { let field = selector.node.selections.find( selection => (selection.kind === 'LinkedField' && selection.name === fieldName) || (selection.kind === 'RequiredField' && selection.field.name === fieldName), ); if (field && field.kind === 'RequiredField') { field = field.field; } invariant( field && field.kind === 'LinkedField', 'RelayRecordSourceSelectorProxy#getRootField(): Cannot find root ' + 'field `%s`, no such field is defined on GraphQL document `%s`.', fieldName, selector.node.name, ); invariant( field.plural === plural, 'RelayRecordSourceSelectorProxy#getRootField(): Expected root field ' + '`%s` to be %s.', fieldName, plural ? 'plural' : 'singular', ); return field; } getRootField(fieldName: string): ?RecordProxy { const field = this._getRootField(this._readSelector, fieldName, false); const storageKey = getStorageKey(field, this._readSelector.variables); return this.getOperationRoot().getLinkedRecord(storageKey); } getPluralRootField(fieldName: string): ?Array<?RecordProxy> { const field = this._getRootField(this._readSelector, fieldName, true); const storageKey = getStorageKey(field, this._readSelector.variables); return this.getOperationRoot().getLinkedRecords(storageKey); } invalidateStore(): void { this.__recordSource.invalidateStore(); } readUpdatableQuery_EXPERIMENTAL<TVariables: Variables, TData>( query: UpdatableQuery<TVariables, TData>, variables: TVariables, ): UpdatableData<TData> { return readUpdatableQuery_EXPERIMENTAL(query, variables, this); } readUpdatableFragment_EXPERIMENTAL<TFragmentType: FragmentType, TData>( fragment: UpdatableFragment<TFragmentType, TData>, fragmentReference: HasUpdatableSpread<TFragmentType>, ): UpdatableData<TData> { return readUpdatableFragment_EXPERIMENTAL( fragment, fragmentReference, this, ); } } module.exports = RelayRecordSourceSelectorProxy;