UNPKG

scrivito

Version:

Scrivito is a professional, yet easy to use SaaS Enterprise Content Management Service, built for digital agencies and medium to large businesses. It is completely maintenance-free, cost-effective, and has unprecedented performance and security.

150 lines (122 loc) 4.18 kB
import { InternalError, computeCacheKey, isPresent } from 'scrivito_sdk/common'; import { LoadableData, LoadableState, createLoadableData, } from 'scrivito_sdk/loadable'; import { LoaderProcessParams } from 'scrivito_sdk/loadable/create_loader_process'; import { isAvailableState } from 'scrivito_sdk/loadable/loadable_state'; import { OfflineStore } from 'scrivito_sdk/loadable/offline_store'; import { StateContainer, createStateContainer } from 'scrivito_sdk/state'; interface LoadableCollectionState<LoadableType> { [index: string]: LoadableState<LoadableType>; } type LoadElementCallback<LoadableType, KeyType, LoaderHintType> = ( key: KeyType, hint?: LoaderHintType ) => LoaderProcessParams<LoadableType>; export type LoadableCollection< LoadableType, KeyType = string, LoaderHintType = undefined > = InstanceType< typeof LoadableCollectionImpl<LoadableType, KeyType, LoaderHintType> >; export function createLoadableCollection< LoadableType, KeyType = string, LoaderHintType = undefined >(params: { name?: string; loadElement: LoadElementCallback<LoadableType, KeyType, LoaderHintType>; }): LoadableCollection<LoadableType, KeyType, LoaderHintType> { return new LoadableCollectionImpl(params); } /** a collection of LoadableData, indexed by key */ class LoadableCollectionImpl< LoadableType, KeyType = string, LoaderHintType = undefined > { private state: StateContainer<LoadableCollectionState<LoadableType>>; private name?: string; private loadElement: LoadElementCallback< LoadableType, KeyType, LoaderHintType >; private readonly offlineStore?: OfflineStore<KeyType, LoadableType>; constructor({ name, loadElement, }: { name?: string; loadElement: LoadElementCallback<LoadableType, KeyType, LoaderHintType>; }) { this.name = name; this.state = createStateContainer(); this.loadElement = loadElement; if (name) { register(name, this); this.offlineStore = new OfflineStore<KeyType, LoadableType>(name); } } /** get a LoadableData instance from this collection */ get(key: KeyType, loaderHint?: LoaderHintType): LoadableData<LoadableType> { const stringifiedKey = stringifyKey(key); const params = this.loadElement(key, loaderHint); const paramsWithOfflineEntry = params.loader ? { ...params, offlineEntry: this.offlineStore?.getEntry(key) } : params; const data = createLoadableData({ ...paramsWithOfflineEntry, state: this.state.subState(stringifiedKey), affiliation: this.name ? { collectionName: this.name, key } : undefined, }); return data; } clear(): void { this.state.clear(); } /** this method is "dangerous" - it can be very, very bad for performance * use with care, and only if you know precisely what you are doing. * * it returns all current loaded data inside the collection, * but does not trigger any loading. */ dangerouslyGetRawValues(): LoadableType[] { const currentState = this.state.get(); if (!currentState) return []; return Object.keys(currentState) .map((key) => currentState[key]) .filter(isPresent) .filter(isAvailableState) .map((state) => state.value); } async findValuesInOfflineStore( selector: (data: LoadableType, key: KeyType) => boolean ): Promise<Array<[LoadableType, KeyType]>> { if (!this.offlineStore) throw new InternalError(); return this.offlineStore.findValues(selector); } } function stringifyKey(key: unknown): string { if (typeof key === 'string') { return key; } return computeCacheKey(key); } type UnknownCollection = LoadableCollection<unknown, unknown, unknown>; const namedCollections: { [name: string]: UnknownCollection | undefined } = {}; function register(name: string, collection: UnknownCollection) { if (namedCollections[name]) { // collection name registered twice throw new InternalError(); } namedCollections[name] = collection; } export function getCollection(name: string): UnknownCollection { const found = namedCollections[name]; if (!found) throw new InternalError(); return found; }