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
TypeScript
//#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 };