import { type CollectionId, type AnyDocument, CollectionIds, type Relationship, type DocumentId, type RelationshipId, type DbRecord, } from "./types"; export type CacheKey = `${C}:${string}`; export type CacheValue = { record: Promise>; subscriptions: ((record: DbRecord | null) => void)[]; }; type DocumentKey = CacheKey; type RelationshipKey = CacheKey; export class RecordCache { private cache: Record<`${CollectionId}:${string}`, CacheValue> = {}; static makeKey( collectionId: C, id: string, ): CacheKey { return `${collectionId}:${id}`; } static docKey = (id: DocumentId): DocumentKey => RecordCache.makeKey(CollectionIds.Documents, id); static relationKey = (id: RelationshipId): RelationshipKey => RecordCache.makeKey(CollectionIds.Relationships, id); get = ( key: CacheKey, ): Promise> | undefined => this.cache[key]?.record as Promise> | undefined; pending = ( key: CacheKey, record: Promise>, ) => { if (this.cache[key] === undefined) { this.cache[key] = { record: record, subscriptions: [], }; } const entry = this.cache[key]; entry.record = record; record.then((record) => { for (const subscription of entry.subscriptions) { subscription(record); } for (const doc of record.expand?.secondary ?? []) { this.set(doc); } for (const rel of record.expand?.relationships_via_primary ?? []) { this.set(rel); } }); }; set = (record: DbRecord) => { const key = RecordCache.makeKey( record.collectionName as CollectionId, record.id, ); if (this.cache[key] === undefined) { this.cache[key] = { record: Promise.resolve(record), subscriptions: [], }; } const entry = this.cache[key]; entry.record = Promise.resolve(record); for (const subscription of entry.subscriptions) { subscription(record); } for (const doc of record.expand?.secondary ?? []) { this.set(doc); } for (const rel of record.expand?.relationships_via_primary ?? []) { this.set(rel); } }; remove = (key: CacheKey) => { const entry = this.cache[key]; delete this.cache[key]; for (const subscription of entry.subscriptions) { subscription(null); } }; getDocument = (id: DocumentId): AnyDocument | undefined => this.get(RecordCache.docKey(id)) as AnyDocument | undefined; getRelationship = (id: RelationshipId): Relationship | undefined => this.get(RecordCache.relationKey(id)) as Relationship | undefined; removeDocument = (id: DocumentId) => this.remove(RecordCache.docKey(id)); removeRelationship = (id: RelationshipId) => this.remove(RecordCache.relationKey(id)); }