/* eslint-disable @typescript-eslint/no-explicit-any */ import type { Filter, FilterJoinSelect, PersistenceModelType, Store, StoreConfig } from "./service.js" import { StoreMaker } from "./service.js" import { codeFilter, codeFilterJoinSelect, makeETag, makeUpdateETag } from "./utils.js" export function memFilter(filter: Filter, cursor?: { skip?: number; limit?: number }) { return ((c: Chunk): Chunk => { const skip = cursor?.skip const limit = cursor?.limit if (!skip && limit === 1) { return c.findFirstMap(codeFilter(filter)).map(Chunk.make).getOrElse(() => Chunk.empty()) } let r = c.filterMap(codeFilter(filter)) if (skip) { r = r.drop(skip) } if (limit !== undefined) { r = r.take(limit) } return r.toChunk }) } export const makeMemoryStore = () => ({ make: >( name: string, existing?: Effect>, _config?: StoreConfig ) => Effect.gen(function*($) { const updateETag = makeUpdateETag(name) const items = yield* $(existing ?? Effect(ROMap.empty)) const store = yield* $( Ref.make>( ROMap.make([...items.entries()].map(([id, e]) => [id, makeETag(e)])) ) ) const sem = Semaphore.unsafeMake(1) const withPermit = sem.withPermits(1) const values = store.get.map(s => s.values()) const all = values.map(Chunk.fromIterable) const batchSet = (items: NonEmptyReadonlyArray) => items .forEachEffect(i => s.find(i.id).flatMap(current => updateETag(i, current))) .tap(items => store.get .map(m => { const mut = ROMap.toMutable(m) items.forEach(e => mut.set(e.id, e)) return ROMap.fromMutable(mut) }) .flatMap(_ => store.set(_)) ) .map(_ => _.toReadonlyArray() as NonEmptyReadonlyArray) .apply(withPermit) const s: Store = { all, find: id => store.get.map(ROMap.lookup(id)), filter: (filter: Filter, cursor?: { skip?: number; limit?: number }) => all.map(memFilter(filter, cursor)), filterJoinSelect: (filter: FilterJoinSelect) => all.map(c => c.flatMap(codeFilterJoinSelect(filter))), set: e => s .find(e.id) .flatMap(current => updateETag(e, current)) .tap(e => store.get.map(ROMap.insert(e.id, e)).flatMap(_ => store.set(_))) .apply(withPermit), batchSet, bulkSet: batchSet, remove: (e: PM) => store.get.map(ROMap.remove(e.id)).flatMap(_ => store.set(_)).apply(withPermit) } return s }) }) export const MemoryStoreLive = StoreMaker.makeLayer(makeMemoryStore())