UNPKG

indexed-collection

Version:

A zero-dependency library of classes that make filtering, sorting and observing changes to arrays easier and more efficient.

355 lines 12.8 kB
//#region src/core/CollectionNature.d.ts declare enum CollectionNature { /** * The items in the collection should always be unique, and order does not matter * This option is always performant */ Set = "set", /** * The items in the collection should always preserve the order it is entered in the collection */ Array = "array", } //#endregion //#region src/core/ICollectionOption.d.ts interface ICollectionOption { nature: CollectionNature; } //#endregion //#region src/core/CollectionViewFilterFn.d.ts type CollectionViewFilterFn<T> = (item: T) => boolean; //#endregion //#region src/core/ICollectionViewOption.d.ts interface ICollectionViewOption<T> { filter: CollectionViewFilterFn<T>; sort: (a: T, b: T) => number; } //#endregion //#region src/core/IReadonlyCollection.d.ts interface IReadonlyCollection<T> { exists(item: T): boolean; readonly items: readonly T[]; readonly count: number; } //#endregion //#region src/core/IMutableCollection.d.ts interface IMutableCollection<T> extends IReadonlyCollection<T> { add(item: T): boolean; addRange(items: readonly T[] | IReadonlyCollection<T>): boolean[]; remove(item: T): boolean; } //#endregion //#region src/core/KeyExtract.d.ts /** * Delegate for extracting key from the given item */ type KeyExtract<T = unknown, KeyT = unknown> = SingleKeyExtract<T, KeyT> | MultipleKeyExtract<T, KeyT>; type SingleKeyExtract<T = unknown, KeyT = unknown> = { isMultiple?: boolean; (item: T): KeyT; }; type MultipleKeyExtract<T = unknown, KeyT = unknown> = { isMultiple: true; (item: T): readonly KeyT[] | ReadonlySet<KeyT>; }; //#endregion //#region src/core/Optional.d.ts type Optional<T> = T | undefined; type Nullable<T> = T | null; //#endregion //#region src/core/defaultCollectionOption.d.ts declare const defaultCollectionOption: Readonly<ICollectionOption>; //#endregion //#region src/core/defaultCollectionViewOption.d.ts declare const defaultFilter: () => boolean; declare const defaultSort: () => number; declare const defaultCollectionViewOption: ICollectionViewOption<any>; //#endregion //#region src/builders/keyExtractBuilder.d.ts declare function buildMultipleKeyExtract<T = unknown, KeyT = unknown>(getKeys: (item: T) => readonly KeyT[] | ReadonlySet<KeyT>): MultipleKeyExtract<T, KeyT>; //#endregion //#region src/signals/Signal.d.ts /** * Signal is a base class for all signals. * */ declare abstract class Signal { readonly type: symbol; readonly target: unknown; protected constructor(type: symbol, target: unknown); } type SignalType = Signal['type']; //#endregion //#region src/signals/ISignalObserver.d.ts type SignalHandler<T extends Signal> = (signal: T) => void; interface ISignalObserver { registerObserver<T extends Signal>(signalType: symbol, handler: SignalHandler<T>): void; unregisterObserver<T extends Signal>(handler: SignalHandler<T>, signalType?: symbol): void; notifyObservers(signal: Signal): void; } //#endregion //#region src/core/ICollectionAndView.d.ts interface ICollectionAndView<T> extends ISignalObserver { readonly items: readonly T[]; rebuild(deep?: boolean): void; exists(item: T): boolean; } //#endregion //#region src/core/ICollectionChangeDetail.d.ts interface ICollectionUpdateLineItem<T> { oldValue: T; newValue: T; } interface ICollectionChangeDetail<T> { readonly added: T[]; readonly removed: T[]; readonly updated: ICollectionUpdateLineItem<T>[]; } //#endregion //#region src/signals/CollectionChangeSignal.d.ts declare class CollectionChangeSignal<T> extends Signal { readonly detail: Readonly<ICollectionChangeDetail<T>>; static readonly type: unique symbol; constructor(target: IReadonlyCollection<T>, detail: Readonly<ICollectionChangeDetail<T>>); } //#endregion //#region src/signals/SignalObserver.d.ts /** * Signal observer is a class that can be used to observe signals * It supports multiple observers for a single signal type and vice versa */ declare class SignalObserver implements ISignalObserver { private readonly typeToHandleMap; private handlerToTypeMap; constructor(); /** * Notify all observers of a signal by the signal's type * @param signal */ notifyObservers(signal: Signal): void; /** * Register an observer for a signal type * @param type The type of a signal * @param handler The handler to be called when the signal is emitted */ registerObserver<T extends Signal>(type: symbol, handler: SignalHandler<T>): void; /** * Unregister an observer for a signal type * @param handler The handle to be unregistered * @param type (Optional) The type of a signal (if not provided, all types associated with the handle will be unregistered) */ unregisterObserver<T extends Signal>(handler: SignalHandler<T>, type?: symbol): void; } //#endregion //#region src/collections/CollectionViewBase.d.ts /** * CollectionView is a view onto a collection of data. Most common use case would be * having the collection reduced by filter and/or sorted according to various criteria * without modifying the underlying data. */ declare abstract class CollectionViewBase<T, SourceCollectionT extends ICollectionAndView<T>> extends SignalObserver implements IReadonlyCollection<T> { private readonly _source; private readonly _option; private _cachedItems; protected constructor(source: SourceCollectionT, option?: Partial<ICollectionViewOption<T>>); /** * Reindex the entire collection */ rebuild(deep?: boolean): void; protected rebuildCache(): void; protected applyFilterAndSort(list: readonly T[]): T[]; returnItemIfPassesFilter(item?: T): Optional<T>; protected source_onChange(signal: CollectionChangeSignal<T>): void; notifyChange(signal: CollectionChangeSignal<T>): void; get count(): number; get items(): readonly T[]; exists(item: T): boolean; get source(): SourceCollectionT; get filter(): ICollectionViewOption<T>['filter']; get sort(): ICollectionViewOption<T>['sort']; } //#endregion //#region src/core/IIndex.d.ts interface IIndex<T> { /** * Add an item into the index * @param item * @return true if the item has been added to the index successfully. */ index(item: T): boolean; /** * Remove an item from the index * @param item * @return true if the item has been removed to the index successfully. */ unIndex(item: T): boolean; reset(): void; } //#endregion //#region src/collections/IndexedCollectionBase.d.ts declare abstract class IndexedCollectionBase<T> extends SignalObserver implements IMutableCollection<T> { private _allItemList; protected indexes: Set<IIndex<T>>; private _pauseChangeSignal; private _hasPendingChangeSignal; private _pendingChange; readonly option: Readonly<ICollectionOption>; protected constructor(initialValues?: readonly T[], additionalIndexes?: ReadonlyArray<IIndex<T>>, option?: Partial<ICollectionOption>); rebuild(): void; protected reindex(): void; /** * Rebuild indexes * @param indexes * @param autoReindex if true, all items will be reindexed */ protected buildIndexes(indexes: readonly IIndex<T>[], autoReindex?: boolean): void; add(item: T): boolean; addRange(items: readonly T[] | IReadonlyCollection<T> | ReadonlySet<T>): boolean[]; exists(item: T): boolean; /** * Remove item from the collection * @param item * @returns */ remove(item: T): boolean; update(newItem: T, oldItem: T): boolean; /** * Move item before the specified item * @param item The item to move * @param before */ moveBefore(item: T, before: T): void; /** * Move item after the specified item * @param item The item to move * @param after */ moveAfter(item: T, after: T): void; get items(): readonly T[]; get count(): number; protected notifyChange(change: Partial<ICollectionChangeDetail<T>>): void; /** * Pause change signal when collection content has changed * This is useful when the collection is undergoing batch changes * that the collection would not cause too many down stream change reaction * during batch update. * * If there are any changes during pause period, resumeChangeEvent * will dispatch change event. */ pauseChangeSignal(): void; /** * Resume change signal from its pause state * if there are any pending changes, change signal will be notified */ resumeChangeSignal(): void; } //#endregion //#region src/core/internals/IInternalList.d.ts interface IInternalList<T> { /** * Add item to list regardless of existence of such item * @param item */ add(item: T): void; /** * Remove the first instance item to list regardless of existence of such item * @param item */ remove(item: T): void; /** * Whether the specified item exists in the list * @param item */ exists(item: T): boolean; /** * Signal that the list has changed so cached output should be regenerated. */ invalidate(): void; /** * Update the old item with the new item * @param newItem * @param oldItem */ update(newItem: T, oldItem: T): void; /** * Move the item before another item * @param item * @param before */ moveBefore(item: T, before: T): void; /** * Move the item after another item * @param item * @param after */ moveAfter(item: T, after: T): void; readonly output: readonly T[]; readonly count: number; } //#endregion //#region src/indexes/IndexBase.d.ts type SetOrArray<T> = Set<T> | T[]; type LeafMap<T, KeyT = unknown> = Map<KeyT, IInternalList<T>>; declare abstract class IndexBase<T> { protected readonly _keyFns: readonly KeyExtract<T>[]; protected readonly option: Readonly<ICollectionOption>; internalMap: Map<any, any>; protected constructor(keyFns: readonly KeyExtract<T>[], option?: Readonly<ICollectionOption>); index(item: T): boolean; unIndex(item: T): boolean; protected getValueInternal(keys: readonly unknown[]): readonly T[]; protected getKeys(item: T): SetOrArray<unknown>[]; protected getLeafMaps(keys: SetOrArray<unknown>[]): LeafMap<T>[]; reset(): void; } //#endregion //#region src/indexes/CollectionIndex.d.ts type KeyTypeArray = ReadonlyArray<unknown>; type KeyExtractArray<T, KeysT extends KeyTypeArray> = { [index in keyof KeysT]: KeyExtract<T, KeysT[index]> }; declare class CollectionIndex<T, KeysT extends KeyTypeArray> extends IndexBase<T> { constructor(keyFn: KeyExtractArray<T, KeysT>, option?: Readonly<ICollectionOption>); getValue(...keys: KeysT): readonly T[]; } //#endregion //#region src/collections/PrimaryKeyCollection.d.ts /** * A collection where every item contains a unique identifier key (aka primary key) */ declare class PrimaryKeyCollection<T, IdT = string> extends IndexedCollectionBase<T> { readonly primaryKeyExtract: SingleKeyExtract<T, IdT>; protected readonly idIndex: CollectionIndex<T, [IdT]>; constructor(primaryKeyExtract: SingleKeyExtract<T, IdT>, initialValues?: readonly T[], additionalIndexes?: ReadonlyArray<IIndex<T>>, option?: Readonly<ICollectionOption>); protected buildIndexes(indexes: readonly IIndex<T>[], autoReindex?: boolean): void; exists(item: T): boolean; /** * Get the item by its primary key * @param keyValue * @returns */ byPrimaryKey(keyValue: IdT): Optional<T>; update(newItem: T): boolean; } //#endregion //#region src/signals/CollectionAddSignal.d.ts declare class CollectionAddSignal<T> extends Signal { readonly added: readonly T[]; static readonly type: unique symbol; constructor(target: IReadonlyCollection<T>, added: readonly T[]); } //#endregion //#region src/signals/CollectionRemoveSignal.d.ts declare class CollectionRemoveSignal<T> extends Signal { readonly removed: readonly T[]; static readonly type: unique symbol; constructor(target: IReadonlyCollection<T>, removed: readonly T[]); } //#endregion //#region src/signals/CollectionUpdateSignal.d.ts declare class CollectionUpdateSignal<T> extends Signal { readonly updated: readonly Readonly<ICollectionUpdateLineItem<T>>[]; static readonly type: unique symbol; constructor(target: IReadonlyCollection<T>, updated: readonly Readonly<ICollectionUpdateLineItem<T>>[]); } //#endregion export { CollectionAddSignal, CollectionChangeSignal, CollectionIndex, CollectionNature, CollectionRemoveSignal, CollectionUpdateSignal, CollectionViewBase, ICollectionOption, ICollectionViewOption, IMutableCollection, IReadonlyCollection, IndexBase, IndexedCollectionBase, KeyExtract, MultipleKeyExtract, Nullable, Optional, PrimaryKeyCollection, Signal, SignalHandler, SignalObserver, SignalType, SingleKeyExtract, buildMultipleKeyExtract, defaultCollectionOption, defaultFilter as defaultCollectionViewFilter, defaultCollectionViewOption, defaultSort as defaultCollectionViewSort };