From 0b35a54ccb21c970f985b0583b8e3bfd91b2cce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rge=20N=C3=A6ss?= Date: Thu, 26 Sep 2024 10:59:45 +0200 Subject: [PATCH] fix(sanity): lazy read cached value from either memory or local store --- .../document/document-pair/editState.ts | 66 +++++++++++++------ .../document/document-pair/validation.ts | 5 +- .../store/_legacy/document/document-store.ts | 5 +- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/packages/sanity/src/core/store/_legacy/document/document-pair/editState.ts b/packages/sanity/src/core/store/_legacy/document/document-pair/editState.ts index 711d486bc1ca..d2fc4c7d246a 100644 --- a/packages/sanity/src/core/store/_legacy/document/document-pair/editState.ts +++ b/packages/sanity/src/core/store/_legacy/document/document-pair/editState.ts @@ -1,13 +1,14 @@ import {type SanityClient} from '@sanity/client' import {type SanityDocument, type Schema} from '@sanity/types' -import {combineLatest, type Observable} from 'rxjs' +import {combineLatest, defer, merge, type Observable, of} from 'rxjs' import {finalize, map, publishReplay, refCount, startWith, switchMap, tap} from 'rxjs/operators' import {type IdPair, type PendingMutationsEvent} from '../types' import {memoize} from '../utils/createMemoizer' +import {memoizeKeyGen} from './memoizeKeyGen' import {snapshotPair} from './snapshotPair' import {isLiveEditEnabled} from './utils/isLiveEditEnabled' -import {savePairToLocalStorage} from './utils/localStoragePOC' +import {getPairFromLocalStorage, savePairToLocalStorage} from './utils/localStoragePOC' interface TransactionSyncLockState { enabled: boolean @@ -38,13 +39,32 @@ export const editState = memoize( }, idPair: IdPair, typeName: string, - localStoragePair: {draft: SanityDocument | null; published: SanityDocument | null} | undefined, ): Observable => { const liveEdit = isLiveEditEnabled(ctx.schema, typeName) - let documentPair: { + const INITIAL = { + id: idPair.publishedId, + type: typeName, + draft: null, + published: null, + liveEdit, + ready: false, + transactionSyncLock: null, + } + + let cachedDocumentPair: { draft: SanityDocument | null published: SanityDocument | null } | null = null + + function getCachedPair() { + // try first read it from memory + // if we haven't got it in memory, see if it's in localstorage + if (cachedDocumentPair) { + return cachedDocumentPair + } + return getPairFromLocalStorage(idPair) + } + return snapshotPair(ctx.client, idPair, typeName, ctx.serverActionsEnabled).pipe( switchMap((versions) => combineLatest([ @@ -58,7 +78,7 @@ export const editState = memoize( ]), ), tap(([draft, published]) => { - documentPair = {draft, published} + cachedDocumentPair = {draft, published} }), map(([draftSnapshot, publishedSnapshot, transactionSyncLock]) => ({ id: idPair.publishedId, @@ -69,24 +89,32 @@ export const editState = memoize( ready: true, transactionSyncLock, })), - startWith({ - id: idPair.publishedId, - type: typeName, - draft: localStoragePair?.draft || null, - published: localStoragePair?.published || null, - liveEdit, - ready: false, - transactionSyncLock: null, - }), + // todo: turn this into a proper operator function - It's like startWith only that it takes a function that will be invoked upon subscription + (input$) => { + return defer(() => { + const cachedPair = getCachedPair() + return merge( + cachedPair + ? of({ + id: idPair.publishedId, + type: typeName, + draft: cachedPair.draft, + published: cachedPair.published, + liveEdit, + ready: false, + transactionSyncLock: null, + }) + : of(INITIAL), + input$, + ) + }) + }, finalize(() => { - savePairToLocalStorage(documentPair) + savePairToLocalStorage(cachedDocumentPair) }), publishReplay(1), refCount(), ) }, - (ctx, idPair, typeName, lsPair) => { - const config = ctx.client.config() - return `${config.dataset ?? ''}-${config.projectId ?? ''}-${idPair.publishedId}-${typeName}-${lsPair?.draft?._rev}-${lsPair?.published?._rev}` - }, + (ctx, idPair, typeName) => memoizeKeyGen(ctx.client, idPair, typeName), ) diff --git a/packages/sanity/src/core/store/_legacy/document/document-pair/validation.ts b/packages/sanity/src/core/store/_legacy/document/document-pair/validation.ts index cd62be3a9071..8cf895fe80ac 100644 --- a/packages/sanity/src/core/store/_legacy/document/document-pair/validation.ts +++ b/packages/sanity/src/core/store/_legacy/document/document-pair/validation.ts @@ -1,5 +1,5 @@ import {type SanityClient} from '@sanity/client' -import {type SanityDocument, type Schema} from '@sanity/types' +import {type Schema} from '@sanity/types' import {omit} from 'lodash' import {asyncScheduler, type Observable} from 'rxjs' import {distinctUntilChanged, map, shareReplay, throttleTime} from 'rxjs/operators' @@ -34,9 +34,8 @@ export const validation = memoize( }, {draftId, publishedId}: IdPair, typeName: string, - localStoragePair: {draft: SanityDocument | null; published: SanityDocument | null}, ): Observable => { - const document$ = editState(ctx, {draftId, publishedId}, typeName, localStoragePair).pipe( + const document$ = editState(ctx, {draftId, publishedId}, typeName).pipe( map(({draft, published}) => draft || published), throttleTime(DOC_UPDATE_DELAY, asyncScheduler, {trailing: true}), distinctUntilChanged((prev, next) => { diff --git a/packages/sanity/src/core/store/_legacy/document/document-store.ts b/packages/sanity/src/core/store/_legacy/document/document-store.ts index 4e0a3a1233b6..e21c1b24b1ed 100644 --- a/packages/sanity/src/core/store/_legacy/document/document-store.ts +++ b/packages/sanity/src/core/store/_legacy/document/document-store.ts @@ -22,7 +22,6 @@ import { type OperationSuccess, } from './document-pair/operationEvents' import {type OperationsAPI} from './document-pair/operations' -import {getPairFromLocalStorage} from './document-pair/utils/localStoragePOC' import {validation} from './document-pair/validation' import {getInitialValueStream, type InitialValueMsg, type InitialValueOptions} from './initialValue' import {listenQuery, type ListenQueryOptions} from './listenQuery' @@ -159,7 +158,7 @@ export function createDocumentStore({ editState(publishedId, type) { const idPair = getIdPairFromPublished(publishedId) - const edit = editState(ctx, idPair, type, getPairFromLocalStorage(idPair)) + const edit = editState(ctx, idPair, type) return edit }, operationEvents(publishedId, type) { @@ -183,7 +182,7 @@ export function createDocumentStore({ }, validation(publishedId, type) { const idPair = getIdPairFromPublished(publishedId) - return validation(ctx, idPair, type, getPairFromLocalStorage(idPair)) + return validation(ctx, idPair, type) }, }, }