UNPKG

@sanity/client

Version:

Client for retrieving, creating and patching data from Sanity.io

81 lines (70 loc) 2.6 kB
import {createSourceDocumentResolver} from './createSourceDocumentResolver' import {parseJsonPath} from './jsonPath' import {resolveMapping} from './resolveMapping' import * as paths from './studioPath' import type { Any, ApplySourceDocumentsUpdateFunction, ClientPerspective, ContentSourceMap, ContentSourceMapDocuments, Path, SanityDocument, } from './types' import {walkMap} from './walkMap' /** * Optimistically applies source documents to a result, using the content source map to trace fields. * Can be used to apply mutations to documents being edited in a Studio, or any mutation on Content Lake, to a result with extremely low latency. * @alpha */ export function applySourceDocuments<Result = unknown>( result: Result, resultSourceMap: ContentSourceMap | undefined, getCachedDocument: ( sourceDocument: ContentSourceMapDocuments[number], ) => | (Partial<SanityDocument> & Required<Pick<SanityDocument, '_id' | '_type'>>) | null | undefined, updateFn: ApplySourceDocumentsUpdateFunction, perspective: Exclude<ClientPerspective, 'raw'>, ): Result { if (!resultSourceMap) return result const resolveDocument = createSourceDocumentResolver(getCachedDocument, perspective) const cachedDocuments = resultSourceMap.documents?.map?.(resolveDocument) || [] return walkMap(JSON.parse(JSON.stringify(result)), (value, path) => { const resolveMappingResult = resolveMapping(path, resultSourceMap) if (!resolveMappingResult) { return value } const {mapping, pathSuffix} = resolveMappingResult if (mapping.type !== 'value') { return value } if (mapping.source.type !== 'documentValue') { return value } const sourceDocument = resultSourceMap.documents[mapping.source.document] const sourcePath = resultSourceMap.paths[mapping.source.path] if (sourceDocument) { const parsedPath = parseJsonPath(sourcePath + pathSuffix) const stringifiedPath = paths.toString(parsedPath as Path) const cachedDocument = cachedDocuments[mapping.source.document] if (!cachedDocument) { return value } const changedValue = cachedDocument ? paths.get<Result[keyof Result]>(cachedDocument, stringifiedPath, value) : value return value === changedValue ? value : updateFn<Result[keyof Result]>(changedValue as Any, { cachedDocument, previousValue: value as Result[keyof Result], sourceDocument, sourcePath: parsedPath, }) } return value }) as Result }