Skip to content

Commit

Permalink
fix(sanity): lazy read cached value from either memory or local store
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoerge committed Sep 27, 2024
1 parent e659f8d commit 0b35a54
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -38,13 +39,32 @@ export const editState = memoize(
},
idPair: IdPair,
typeName: string,
localStoragePair: {draft: SanityDocument | null; published: SanityDocument | null} | undefined,
): Observable<EditStateFor> => {
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([
Expand All @@ -58,7 +78,7 @@ export const editState = memoize(
]),
),
tap(([draft, published]) => {
documentPair = {draft, published}
cachedDocumentPair = {draft, published}
}),
map(([draftSnapshot, publishedSnapshot, transactionSyncLock]) => ({
id: idPair.publishedId,
Expand All @@ -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),
)
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -34,9 +34,8 @@ export const validation = memoize(
},
{draftId, publishedId}: IdPair,
typeName: string,
localStoragePair: {draft: SanityDocument | null; published: SanityDocument | null},
): Observable<ValidationStatus> => {
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) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
},
},
}
Expand Down

0 comments on commit 0b35a54

Please sign in to comment.