@bjoerge/mutiny
Version:
Tiny toolkit for working with Sanity mutations in JavaScript & TypeScript
1 lines • 11.5 kB
Source Map (JSON)
{"version":3,"file":"_unstable_apply.cjs","sources":["../src/apply/applyInCollection.ts","../src/apply/store/store.ts","../src/apply/applyInIndex.ts"],"sourcesContent":["import {\n type CreateIfNotExistsMutation,\n type CreateMutation,\n type CreateOrReplaceMutation,\n type DeleteMutation,\n type Mutation,\n type PatchMutation,\n type SanityDocumentBase,\n} from '../mutations/types'\nimport {arrify} from '../utils/arrify'\nimport {applyPatchMutation} from './applyPatchMutation'\nimport {splice} from './utils/array'\n\nexport function applyInCollection<Doc extends SanityDocumentBase>(\n collection: Doc[],\n mutations: Mutation | Mutation[],\n) {\n const a = arrify(mutations) as Mutation[]\n return a.reduce((prev, mutation) => {\n if (mutation.type === 'create') {\n return createIn(prev, mutation)\n }\n if (mutation.type === 'createIfNotExists') {\n return createIfNotExistsIn(prev, mutation)\n }\n if (mutation.type === 'delete') {\n return deleteIn(prev, mutation)\n }\n if (mutation.type === 'createOrReplace') {\n return createOrReplaceIn(prev, mutation)\n }\n if (mutation.type === 'patch') {\n return patchIn(prev, mutation)\n }\n // @ts-expect-error all cases should be covered\n throw new Error(`Invalid mutation type: ${mutation.type}`)\n }, collection)\n}\n\nfunction createIn<Doc extends SanityDocumentBase>(\n collection: Doc[],\n mutation: CreateMutation<Doc>,\n) {\n const currentIdx = collection.findIndex(\n doc => doc._id === mutation.document._id,\n )\n if (currentIdx !== -1) {\n throw new Error('Document already exist')\n }\n return collection.concat(mutation.document)\n}\n\nfunction createIfNotExistsIn<Doc extends SanityDocumentBase>(\n collection: Doc[],\n mutation: CreateIfNotExistsMutation<Doc>,\n) {\n const currentIdx = collection.findIndex(\n doc => doc._id === mutation.document._id,\n )\n return currentIdx === -1 ? collection.concat(mutation.document) : collection\n}\n\nfunction createOrReplaceIn<Doc extends SanityDocumentBase>(\n collection: Doc[],\n mutation: CreateOrReplaceMutation<Doc>,\n) {\n const currentIdx = collection.findIndex(\n doc => doc._id === mutation.document._id,\n )\n return currentIdx === -1\n ? collection.concat(mutation.document)\n : splice(collection, currentIdx, 1, [mutation.document])\n}\n\nfunction deleteIn<Doc extends SanityDocumentBase>(\n collection: Doc[],\n mutation: DeleteMutation,\n) {\n const currentIdx = collection.findIndex(doc => doc._id === mutation.id)\n return currentIdx === -1 ? collection : splice(collection, currentIdx, 1)\n}\n\nfunction patchIn<Doc extends SanityDocumentBase>(\n collection: Doc[],\n mutation: PatchMutation,\n): Doc[] {\n const currentIdx = collection.findIndex(doc => doc._id === mutation.id)\n if (currentIdx === -1) {\n throw new Error('Cannot apply patch on nonexistent document')\n }\n const current = collection[currentIdx]!\n\n const next = applyPatchMutation(mutation, current)\n\n return next === current\n ? collection\n : splice(collection, currentIdx, 1, [next])\n}\n","import {nanoid} from 'nanoid'\n\nimport {type DocumentIndex, type Format} from '../../apply'\nimport {type Mutation, type SanityDocumentBase} from '../../mutations/types'\nimport {arrify} from '../../utils/arrify'\nimport {applyInIndex, type ToIdentified, type ToStored} from '../applyInIndex'\nimport {assignId} from './utils'\n\nexport type RequiredSelect<T, K extends keyof T> = Omit<T, K> & {\n [P in K]-?: T[P]\n}\n\nfunction update<Doc extends ToIdentified<SanityDocumentBase>>(\n doc: Doc,\n revision: string,\n): ToStored<Doc> {\n return {\n ...doc,\n _rev: revision,\n _createdAt: doc._createdAt || new Date().toISOString(),\n _updatedAt: new Date().toISOString(),\n }\n}\n\nconst empty: DocumentIndex<any> = {}\n\nexport const createStore = <Doc extends SanityDocumentBase>(\n initialEntries?: Doc[],\n) => {\n let version = 0\n\n let index: DocumentIndex<Format<ToStored<Doc & SanityDocumentBase>>> =\n initialEntries && initialEntries?.length > 0\n ? Object.fromEntries(\n initialEntries.map(entry => {\n const doc = update(assignId(entry, nanoid), nanoid())\n return [doc._id, doc]\n }),\n )\n : empty\n\n return {\n get version() {\n return version\n },\n // todo: support listening for changes\n entries: () => Object.entries(index),\n get: <Id extends string>(\n id: Id,\n ): Format<Omit<(typeof index)[keyof typeof index], '_id'> & {_id: Id}> =>\n index[id] as any,\n apply: (mutations: Mutation[] | Mutation) => {\n const nextIndex = applyInIndex(index, arrify(mutations))\n if (nextIndex !== index) {\n index = nextIndex\n version++\n }\n },\n }\n}\n","import {nanoid} from 'nanoid'\n\nimport {\n type CreateIfNotExistsMutation,\n type CreateMutation,\n type CreateOrReplaceMutation,\n type DeleteMutation,\n type Mutation,\n type PatchMutation,\n type SanityDocumentBase,\n} from '../mutations/types'\nimport {applyPatchMutation} from './applyPatchMutation'\nimport {assignId, hasId, type RequiredSelect} from './store'\n\nexport type DocumentIndex<Doc extends SanityDocumentBase> = {[id: string]: Doc}\n\nexport function applyInIndex<\n Doc extends SanityDocumentBase,\n Index extends DocumentIndex<ToStored<Doc>>,\n>(index: Index, mutations: Mutation<Doc>[]): Index {\n return mutations.reduce((prev, mutation) => {\n if (mutation.type === 'create') {\n return createIn(prev, mutation)\n }\n if (mutation.type === 'createIfNotExists') {\n return createIfNotExistsIn(prev, mutation)\n }\n if (mutation.type === 'delete') {\n return deleteIn(prev, mutation)\n }\n if (mutation.type === 'createOrReplace') {\n return createOrReplaceIn(prev, mutation)\n }\n if (mutation.type === 'patch') {\n return patchIn(prev, mutation)\n }\n // @ts-expect-error all cases should be covered\n throw new Error(`Invalid mutation type: ${mutation.type}`)\n }, index)\n}\n\nexport type ToStored<Doc extends SanityDocumentBase> = Doc &\n Required<SanityDocumentBase>\n\nexport type ToIdentified<Doc extends SanityDocumentBase> = RequiredSelect<\n Doc,\n '_id'\n>\n\nexport type StoredDocument = ToStored<SanityDocumentBase>\n\nfunction createIn<\n Index extends DocumentIndex<Doc>,\n Doc extends SanityDocumentBase,\n>(index: Index, mutation: CreateMutation<Doc>): Index {\n const document = assignId(mutation.document, nanoid)\n\n if (document._id in index) {\n throw new Error('Document already exist')\n }\n return {...index, [document._id]: mutation.document}\n}\n\nfunction createIfNotExistsIn<\n Index extends DocumentIndex<Doc>,\n Doc extends SanityDocumentBase,\n>(index: Index, mutation: CreateIfNotExistsMutation<Doc>): Index {\n if (!hasId(mutation.document)) {\n throw new Error('Cannot createIfNotExists on document without _id')\n }\n return mutation.document._id in index\n ? index\n : {...index, [mutation.document._id]: mutation.document}\n}\n\nfunction createOrReplaceIn<\n Index extends DocumentIndex<Doc>,\n Doc extends SanityDocumentBase,\n>(index: Index, mutation: CreateOrReplaceMutation<Doc>): Index {\n if (!hasId(mutation.document)) {\n throw new Error('Cannot createIfNotExists on document without _id')\n }\n\n return {...index, [mutation.document._id]: mutation.document}\n}\n\nfunction deleteIn<Index extends DocumentIndex<SanityDocumentBase>>(\n index: Index,\n mutation: DeleteMutation,\n): Index {\n if (mutation.id in index) {\n const copy = {...index}\n delete copy[mutation.id]\n return copy\n } else {\n return index\n }\n}\n\nfunction patchIn<Index extends DocumentIndex<SanityDocumentBase>>(\n index: Index,\n mutation: PatchMutation,\n): Index {\n if (!(mutation.id in index)) {\n throw new Error('Cannot apply patch on nonexistent document')\n }\n const current = index[mutation.id]!\n const next = applyPatchMutation(mutation, current)\n\n return next === current ? index : {...index, [mutation.id]: next}\n}\n"],"names":["arrify","createIn","createIfNotExistsIn","deleteIn","createOrReplaceIn","patchIn","splice","applyPatchMutation","assignId","nanoid","hasId"],"mappings":"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"}