UNPKG

@signaldb/core

Version:

SignalDB is a client-side database that provides a simple MongoDB-like interface to the data with first-class typescript support to achieve an optimistic UI. Data persistence can be achieved by using storage providers that store the data through a JSON in

282 lines (281 loc) 14.3 kB
import type MemoryAdapter from '../types/MemoryAdapter'; import type ReactivityAdapter from '../types/ReactivityAdapter'; import type PersistenceAdapter from '../types/PersistenceAdapter'; import EventEmitter from '../utils/EventEmitter'; import type Selector from '../types/Selector'; import type Modifier from '../types/Modifier'; import type IndexProvider from '../types/IndexProvider'; import Cursor from './Cursor'; import type { BaseItem, FindOptions, Transform } from './types'; export type { BaseItem, Transform, SortSpecifier, FieldSpecifier, FindOptions } from './types'; export type { CursorOptions } from './Cursor'; export type { ObserveCallbacks } from './Observer'; export { default as createIndex } from './createIndex'; export interface CollectionOptions<T extends BaseItem<I>, I, U = T> { name?: string; memory?: MemoryAdapter; reactivity?: ReactivityAdapter; transform?: Transform<T, U>; persistence?: PersistenceAdapter<T, I>; indices?: IndexProvider<T, I>[]; enableDebugMode?: boolean; fieldTracking?: boolean; } interface CollectionEvents<T extends BaseItem, U = T> { 'added': (item: T) => void; 'changed': (item: T, modifier: Modifier<T>) => void; 'removed': (item: T) => void; 'persistence.init': () => void; 'persistence.error': (error: Error) => void; 'persistence.transmitted': () => void; 'persistence.received': () => void; 'persistence.pullStarted': () => void; 'persistence.pullCompleted': () => void; 'persistence.pushStarted': () => void; 'persistence.pushCompleted': () => void; 'observer.created': <O extends FindOptions<T>>(selector?: Selector<T>, options?: O) => void; 'observer.disposed': <O extends FindOptions<T>>(selector?: Selector<T>, options?: O) => void; 'getItems': (selector: Selector<T> | undefined) => void; 'find': <O extends FindOptions<T>>(selector: Selector<T> | undefined, options: O | undefined, cursor: Cursor<T, U>) => void; 'findOne': <O extends FindOptions<T>>(selector: Selector<T>, options: O | undefined, item: U | undefined) => void; 'insert': (item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => void; 'updateOne': (selector: Selector<T>, modifier: Modifier<T>) => void; 'updateMany': (selector: Selector<T>, modifier: Modifier<T>) => void; 'replaceOne': (selector: Selector<T>, item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => void; 'removeOne': (selector: Selector<T>) => void; 'removeMany': (selector: Selector<T>) => void; 'validate': (item: T) => void; '_debug.getItems': (callstack: string, selector: Selector<T> | undefined, measuredTime: number) => void; '_debug.find': <O extends FindOptions<T>>(callstack: string, selector: Selector<T> | undefined, options: O | undefined, cursor: Cursor<T, U>) => void; '_debug.findOne': <O extends FindOptions<T>>(callstack: string, selector: Selector<T>, options: O | undefined, item: U | undefined) => void; '_debug.insert': (callstack: string, item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => void; '_debug.updateOne': (callstack: string, selector: Selector<T>, modifier: Modifier<T>) => void; '_debug.updateMany': (callstack: string, selector: Selector<T>, modifier: Modifier<T>) => void; '_debug.replaceOne': (callstack: string, selector: Selector<T>, item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>) => void; '_debug.removeOne': (callstack: string, selector: Selector<T>) => void; '_debug.removeMany': (callstack: string, selector: Selector<T>) => void; } /** * Represents a collection of data items with support for in-memory operations, * persistence, reactivity, and event-based notifications. The collection provides * CRUD operations, observer patterns, and batch operations. * @template T - The type of the items stored in the collection. * @template I - The type of the unique identifier for the items. * @template U - The transformed item type after applying transformations (default is T). */ export default class Collection<T extends BaseItem<I> = BaseItem, I = any, U = T> extends EventEmitter<CollectionEvents<T, U>> { private static collections; private static debugMode; private static batchOperationInProgress; private static fieldTracking; private static onCreationCallbacks; private static onDisposeCallbacks; static getCollections(): Collection<any, any, any>[]; static onCreation(callback: (collection: Collection<any>) => void): void; static onDispose(callback: (collection: Collection<any>) => void): void; /** * Enables debug mode for all collections. */ static enableDebugMode: () => void; /** * Enables field tracking for all collections. * @param enable - A boolean indicating whether to enable field tracking. */ static setFieldTracking: (enable: boolean) => void; /** * Executes a batch operation, allowing multiple modifications to the collection * while deferring index rebuilding until all operations in the batch are completed. * This improves performance by avoiding repetitive index recalculations and * provides atomicity for the batch of operations. * @param callback - The batch operation to execute. */ static batch(callback: () => void): void; readonly name: string; private options; private persistenceAdapter; private isPullingSignal; private isPushingSignal; private indexProviders; private indicesOutdated; private idIndex; private debugMode; private batchOperationInProgress; private isDisposed; private postBatchCallbacks; private fieldTracking; private persistenceReadyPromise; /** * Initializes a new instance of the `Collection` class with optional configuration. * Sets up memory, persistence, reactivity, and indices as specified in the options. * @template T - The type of the items stored in the collection. * @template I - The type of the unique identifier for the items. * @template U - The transformed item type after applying transformations (default is T). * @param options - Optional configuration for the collection. * @param options.name - An optional name for the collection. * @param options.memory - The in-memory adapter for storing items. * @param options.reactivity - The reactivity adapter for observing changes in the collection. * @param options.transform - A transformation function to apply to items when retrieving them. * @param options.persistence - The persistence adapter for saving and loading items. * @param options.indices - An array of index providers for optimized querying. * @param options.enableDebugMode - A boolean to enable or disable debug mode. * @param options.fieldTracking - A boolean to enable or disable field tracking by default. */ constructor(options?: CollectionOptions<T, I, U>); /** * Checks whether the collection is currently performing a pull operation * ⚡️ this function is reactive! * (loading data from the persistence adapter). * @returns A boolean indicating if the collection is in the process of pulling data. */ isPulling(): boolean; /** * Checks whether the collection is currently performing a push operation * ⚡️ this function is reactive! * (saving data to the persistence adapter). * @returns A boolean indicating if the collection is in the process of pushing data. */ isPushing(): boolean; /** * Checks whether the collection is currently performing either a pull or push operation, * ⚡️ this function is reactive! * indicating that it is loading or saving data. * @returns A boolean indicating if the collection is in the process of loading or saving data. */ isLoading(): boolean; /** * Retrieves the current debug mode status of the collection. * @returns A boolean indicating whether debug mode is enabled for the collection. */ getDebugMode(): boolean; /** * Enables or disables debug mode for the collection. * When debug mode is enabled, additional debugging information and events are emitted. * @param enable - A boolean indicating whether to enable (`true`) or disable (`false`) debug mode. */ setDebugMode(enable: boolean): void; /** * Enables or disables field tracking for the collection. * @param enable - A boolean indicating whether to enable (`true`) or disable (`false`) field tracking. */ setFieldTracking(enable: boolean): void; /** * Resolves when the persistence adapter finished initializing * and the collection is ready to be used. * @returns A promise that resolves when the collection is ready. * @example * ```ts * const collection = new Collection({ * persistence: // ... * }) * await collection.isReady() * * collection.insert({ name: 'Item 1' }) */ isReady(): Promise<void>; private profile; private executeInDebugMode; private rebuildIndices; private rebuildAllIndices; private getIndexInfo; private getItemAndIndex; private deleteFromIdIndex; private memory; private memoryArray; private transform; private getItems; /** * Disposes the collection, unregisters persistence adapters, clears memory, and * cleans up all resources used by the collection. * @returns A promise that resolves when the collection is disposed. */ dispose(): Promise<void>; /** * Finds multiple items in the collection based on a selector and optional options. * Returns a cursor for reactive data queries. * @template O - The options type for the find operation. * @param [selector] - The criteria to select items. * @param [options] - Options for the find operation, such as limit and sort. * @returns A cursor to fetch and observe the matching items. */ find<O extends FindOptions<T>>(selector?: Selector<T>, options?: O): Cursor<T, U>; /** * Finds a single item in the collection based on a selector and optional options. * ⚡️ this function is reactive! * Returns the found item or undefined if no item matches. * @template O - The options type for the find operation. * @param selector - The criteria to select the item. * @param [options] - Options for the find operation, such as projection. * @returns The found item or `undefined`. */ findOne<O extends Omit<FindOptions<T>, 'limit'>>(selector: Selector<T>, options?: O): NonNullable<U> | undefined; /** * Performs a batch operation, deferring index rebuilds and allowing multiple * modifications to be made atomically. Executes any post-batch callbacks afterwards. * @param callback - The batch operation to execute. */ batch(callback: () => void): void; /** * Inserts a single item into the collection. Generates a unique ID if not provided. * @param item - The item to insert. * @returns The ID of the inserted item. * @throws {Error} If the collection is disposed or the item has an invalid ID. */ insert(item: Omit<T, 'id'> & Partial<Pick<T, 'id'>>): I; /** * Inserts multiple items into the collection. Generates unique IDs for items if not provided. * @param items - The items to insert. * @returns An array of IDs of the inserted items. * @throws {Error} If the collection is disposed or the items are invalid. */ insertMany(items: Array<Omit<T, 'id'> & Partial<Pick<T, 'id'>>>): I[]; /** * Updates a single item in the collection that matches the given selector. * @param selector - The criteria to select the item to update. * @param modifier - The modifications to apply to the item. * @param [options] - Optional settings for the update operation. * @param [options.upsert] - If `true`, creates a new item if no item matches the selector. * @returns The number of items updated (0 or 1). * @throws {Error} If the collection is disposed or invalid arguments are provided. */ updateOne(selector: Selector<T>, modifier: Modifier<T>, options?: { upsert?: boolean; }): 0 | 1; /** * Updates multiple items in the collection that match the given selector. * @param selector - The criteria to select the items to update. * @param modifier - The modifications to apply to the items. * @param [options] - Optional settings for the update operation. * @param [options.upsert] - If `true`, creates new items if no items match the selector. * @returns The number of items updated. * @throws {Error} If the collection is disposed or invalid arguments are provided. */ updateMany(selector: Selector<T>, modifier: Modifier<T>, options?: { upsert?: boolean; }): number; /** * Replaces a single item in the collection that matches the given selector. * @param selector - The criteria to select the item to replace. * @param replacement - The item to replace the selected item with. * @param [options] - Optional settings for the replace operation. * @param [options.upsert] - If `true`, creates a new item if no item matches the selector. * @returns The number of items replaced (0 or 1). * @throws {Error} If the collection is disposed or invalid arguments are provided. */ replaceOne(selector: Selector<T>, replacement: Omit<T, 'id'> & Partial<Pick<T, 'id'>>, options?: { upsert?: boolean; }): 0 | 1; /** * Removes a single item from the collection that matches the given selector. * @param selector - The criteria to select the item to remove. * @returns The number of items removed (0 or 1). * @throws {Error} If the collection is disposed or invalid arguments are provided. */ removeOne(selector: Selector<T>): 0 | 1; /** * Removes multiple items from the collection that match the given selector. * @param selector - The criteria to select the items to remove. * @returns The number of items removed. * @throws {Error} If the collection is disposed or invalid arguments are provided. */ removeMany(selector: Selector<T>): number; }