/// /// /** Based on 'LokiJS - A lightweight document oriented javascript database' by Joe Minichino * retrieved 2015-06-08 from https://github.com/borisyankov/DefinitelyTyped/tree/master/lokijs * based on Type definitions for lokijs v1.2.5 (https://github.com/techfort/LokiJS) */ /** Collection management */ interface MemDbCollectionSet { /** Get a list of all available collections */ listCollections(): MemDbCollection[]; /** add a new collection */ addCollection(name: string, options?: MemDbCollectionOptions): MemDbCollection; /** Clear all of the data from a specified collection by collection name */ clearCollection(collectionName: string, dstMetaData?: Changes.CollectionChangeTracker): void; /** Remove a collection by name */ removeCollection(collectionName: string, dstMetaData?: Changes.CollectionChangeTracker): void; /** Retrieve a collection by name */ getCollection(collectionName: string, autoCreate: true): MemDbCollection; getCollection(collectionName: string, autoCreate?: boolean): MemDbCollection | null; /** Clear all of the data from a specified collection */ clearCollection(collection: MemDbCollection, dstMetaData?: Changes.CollectionChangeTracker): void; /** Remove a collection */ removeCollection(collection: MemDbCollection, dstMetaData?: Changes.CollectionChangeTracker): void; } /** An in-memory database interface, containing: * - data collections (i.e. tables) * - data collection management, including clearing or deleting a data collection * - model definitions (i.e. table schemas/meta-data) * - functions for all the basic CRUD operations, such as find(), add(), update(), updateWhere(), remove(), and removeWhere() */ interface MemDb extends MemDbCollectionSet, MemDbCollectionProxy { name: string; collections: MemDbCollection[]; databaseVersion: number; environment: string; readonly settings: ReadWritePermission & StorageFormatSettings; events: TsEventEmitter<{ 'init': any[]; 'flushChanges': any[]; 'close': any[]; 'changes': any[]; 'warning': any[]; }>; getName(): string; listCollections(): MemDbCollection[]; getCollection(collectionName: string, autoCreate: true): MemDbCollection; getCollection(collectionName: string, autoCreate?: boolean): MemDbCollection | null; addCollection(name: string, options?: MemDbCollectionOptions): MemDbCollection; loadCollection(collection: MemDbCollection): void; removeCollection(collectionName: string | MemDbCollection, dstMetaData?: Changes.CollectionChangeTracker): void; getModelDefinitions(): ModelDefinitions; getModelKeys(): ModelKeys; } /** Add, Remove, Update operations for collections */ interface MemDbCollectionProxy { /** Query a collection and return the results as an array rather than a result set, allowing for optimizations find might not be able to make */ data(collection: MemDbCollection, dataModel: DataCollectionModel, query: any, queryProps?: string[]): T[]; /** Query a collection, find items based on query parameters * @param query a Lokijs/MongoDB style query * @param queryProps optional list of properties from the query to use. An optimization and/or way to apply only part of a query * @returns a result set of items which match the query */ find(collection: MemDbCollection, dataModel: DataCollectionModel, query: any, queryProps?: string[]): ResultSetLike; /** Query a collection, similar to find(), except that exactly one result is expected * @return a single object matching the query specified * @throws Error if the query results in more than one or no results */ first(collection: MemDbCollection, dataModel: DataCollectionModel, query: any, queryProps?: string[], throwIfNone?: boolean, throwIfMultiple?: boolean): T; /** Add an object to the specified collection, with optional flag to not modify the model (no constraint checks), and an optional change tracker to log results to */ add(collection: MemDbCollection, dataModel: DataCollectionModel, docs: T, noModify: boolean, dstMetaData?: Changes.CollectionChangeTracker): T; addAll(collection: MemDbCollection, dataModel: DataCollectionModel, docs: T[], noModify: boolean, dstMetaData?: Changes.CollectionChangeTracker): T[]; // the number of items added and the number modified addOrUpdateWhere(collection: MemDbCollection, dataModel: DataCollectionModel, dataModelFuncs: DtoFuncs, query: any, obj: Partial, noModify: boolean, dstMetaData?: Changes.CollectionChangeTracker): void; addOrUpdateAll(collection: MemDbCollection, dataModel: DataCollectionModel, dataModelFuncs: DtoFuncs, keyName: keyof T, updatesArray: Partial[], noModify: boolean, dstMetaData?: Changes.CollectionChangeTracker): void; update(collection: MemDbCollection, dataModel: DataCollectionModel, doc: Partial | Partial[], dstMetaData?: Changes.CollectionChangeTracker): void; // the number of items modified updateWhere(collection: MemDbCollection, dataModel: DataCollectionModel, query: any, obj: Partial, dstMetaData?: Changes.CollectionChangeTracker): void; remove(collection: MemDbCollection, dataModel: DataCollectionModel, doc: T, dstMetaData?: Changes.CollectionChangeTracker): void; removeWhere(collection: MemDbCollection, dataModel: DataCollectionModel, query: any, dstMetaData?: Changes.CollectionChangeTracker): void; } /**-------------------------+ | Changes API | +---------------------------* * The Changes API enables the tracking the changes occurred in the collections since the beginning of the session, * so it's possible to create a differential dataset for synchronization purposes (possibly to a remote db) */ interface MemDbChanges { /** takes all the changes stored in each * collection and creates a single array for the entire database. If an array of names * of collections is passed then only the included collections will be tracked. * @param collectionNames optional array of collection names. No arg means all collections are processed. * @returns array of changes * @see private method createChange() in Collection */ generateChangesNotification(collectionNames?: string[]): MemDbCollectionChange[]; /** stringify changes for network transmission * @returns string representation of the changes */ serializeChanges(collectionNames?: string[]): string; /** clears all the changes in all collections. */ clearChanges(): void; } /** TsEventEmitter is a minimalist version of EventEmitter. It enables any * constructor that inherits EventEmitter to emit events and trigger * listeners that have been added to the event through the on(event, callback) method * @template T a map associating event names with arrays of the listener function type handled by each event */ interface TsEventEmitter { /** @prop Events property is a hashmap, with each property being an array of callbacks */ events: T; /** adds a listener to the queue of callbacks associated to an event * @returns the index of the callback in the array of listeners for a particular event */ on(eventName: keyof T, listener: (...args: any[]) => void): (...args: any[]) => void; /** removes the listener at position 'index' from the event 'eventName' */ removeListener(eventName: keyof T, listener: (...args: any[]) => void): void; /** emits a particular event * with the option of passing optional parameters which are going to be processed by the callback * provided signatures match (i.e. if passing emit(event, arg0, arg1) the listener should take two parameters) * @param eventName the name of the event * @param data optional, data passed to event listeners with the event */ emit(eventName: keyof T, data?: any): void; } /* Adapter interface for persisting/restoring an in-memory database to/from long-term* storage, (*longer than browser session or program lifetime) * Data persist read/write interface for MemDb */ interface DataPersister { /** Get a list of collections in this data persister */ getCollectionNames(): PsPromise; /** Save this in-memory database to some form of persistent storage * Removes tables from store that don't exist in in-memory db */ persist(defaultOptions?: DataPersister.WriteOptions, getCollectionSpecificOptions?: ((collName: string) => DataPersister.WriteOptions)): PsPromise; /** Restore in-memory database from persistent store * All in memory tables are dropped and re-added */ restore(defaultOptions?: DataPersister.ReadOptions, getCollectionSpecificOptions?: ((collName: string) => DataPersister.ReadOptions)): PsPromise; /** Get all data from a specific collection */ getCollectionRecords(collectionName: string, options?: DataPersister.ReadOptions): PsPromise; /** Add data to a specific collection */ addCollectionRecords(collectionName: string, options: DataPersister.WriteOptions, records: any[], removeExisting?: boolean): PsPromise; /** Remove all data from a specific collection */ clearCollections(collectionNames: string[]): PsPromise; /** Delete all data related this database from persistent storage */ clearPersistentDb(): PsPromise; } declare module DataPersister { interface CollectionRawStats { /** The number of objects in the collection */ size: number; /** The total size in bytes of all the objects in the collection */ dataSizeBytes: number | null; } /** Information about a set of collections */ interface CollectionData { collections: { [index: string]: CollectionRawStats; }; } export interface PersistResult extends CollectionData { } export interface RestoreResult extends CollectionData { } export interface ReadOptions { /** name of the persistent column where stringified object data is stored in each row */ dataColumnName?: string; /** (currently unsupported) whether to decompress stringified object data */ decompress?: boolean; /** whether 'WriteOptions.groupByKey' or 'WriteOptions.maxObjectsPerChunk' were provided when the collection was 'persist()'ed */ isChunks?: boolean; } /** Most basic fields needed to persist and restore a full 'DataCollection' */ export interface SimpleDataCollection { name: string; data: any[]; dirty?: boolean; } export interface SimpleDeferred { promise: PsPromise; resolve(value?: T | PsPromise): void; reject(reason: any): void; } export interface DbLogger { log(...args: any[]): any; error?(...args: any[]): any; text?(...args: any[]): any; } export interface UtilConfig { defer(): SimpleDeferred; whenAll(promises: ArrayLike>): PsPromise; trace?: DbLogger; verbosity?: number; logTimings?: boolean; } export interface WriteOptions { /** whether to auto-generate the 'keyColumn' */ keyAutoGenerate?: boolean; /** property name of data model primary key, or a function which takes an object and returns a primary key string */ keyGetter?: string | ((obj: any) => string); /** name of the persistent key column to store value from 'keyGetter', or null to not include key column */ keyColumn?: { name: string; type: string; }; /** flag indicating whether 'keyGetter' may have the same value for two objects and whether those objects should be grouped together */ groupByKey?: boolean; /** name of the persistent column where stringified object data is stored in each row */ dataColumnName?: string; /** if 'keyGetter' is null, this is the number of objects to store in each persistent data row */ maxObjectsPerChunk?: number; /** (currently unsupported) whether to compress stringified object data */ compress?: boolean; /** whether to delete existing table and recreate it */ deleteIfExists?: boolean; } export interface Factory { /** * @param dbInst the in-memory database that the persister pulls data from * @param getCollections returns a list of data collections that contain the data to persist/restore to * @param getSaveItemTransformFunc a conversion function to pass items from getDataCollections() through before persisting them * @param getRestoreItemTransformFunc a conversion function to pass items through after restoring them and * before storing them in getDataCollections() */ (dbInst: MemDb, getCollections: () => MemDbCollection[], getSaveItemTransformFunc?: (collName: string) => ((item: any) => any) | null, getRestoreItemTransformFunc?: (collName: string) => ((item: any) => any) | null): DataPersister; } } interface MemDbOps { // comparison operators $eq: (a: any, b: any) => boolean; $aeq: (a: any, b: any) => boolean; $gt: (a: any, b: any) => boolean; $gte: (a: any, b: any) => boolean; $lt: (a: any, b: any) => boolean; $lte: (a: any, b: any) => boolean; $ne: (a: any, b: any) => boolean; $regex: (a: string, b: { test(string: string): boolean }) => boolean; $in: (a: any, b: { indexOf(value: any): number }) => boolean; $containsAny: (a: any, b: any[] | any) => boolean; $contains: (a: any, b: any[] | any) => boolean; } interface MemDbUniqueIndex { field: keyof E; keyMap: { [id: string]: E | undefined }; lokiMap: { [id: number]: any }; // 'field' map set(obj: E): void; get(key: string): E | null; byId(id: number): E; update(obj: E): void; remove(key: string): void; clear(): void; } interface MemDbExactIndex { index: { [id: string]: E[] | undefined }; field: string; /** add the value you want returned to the key in the index */ set(key: string, val: E): void; /** remove the value from the index, if the value was the last one, remove the key */ remove(key: string, val: E): void; /** get the values related to the key, could be more than one */ get(key: string): E[] | null; /** clear will zap the index */ clear(): void; } interface ReadWritePermission { readAllow: boolean; writeAllow: boolean; } interface StorageFormatSettings { compressLocalStores: boolean; } interface MemDbPersistenceInterface { loadDatabase: (fileName: string, func: (dbString: string) => void) => void; saveDatabase: (fileName: string, content: string, func: () => void) => void; } interface MemDbCollectionChange { name: string; operation: ("I"/*Insert*/ | "U"/*Update*/ | "R"/*Remove*/); obj: any; } interface MemDbCollectionIndex { name: string; dirty: boolean; values: number[]; } /** See CloneUtil.ts */ type CloneType = "for-in-if" | "keys-for-if" | "keys-excluding-for" | "clone-delete" | "parse-stringify"; interface MemDbCollectionOptions { /** whether to make collection insert/update/delete operations transactional */ transactional?: boolean; /** overriden by non-null 'cloneFunc', if true, CloneUtil type 'parse-stringify' is used as the 'insert()' clone function */ clone?: boolean; /** a clone function to clone objects passed to the 'insert()' method of a Collection */ cloneFunc?: CloneFunc; /** disable track changes */ disableChangesApi?: boolean; indices?: (keyof T & string)[]; exact?: (keyof T & string)[]; unique?: (keyof T & string)[]; } interface MemDbObj { $loki: number; meta: { /** timestamp */ created: number; /** number that gets incremented each time the object is updated */ revision: number; /** timestamp */ updated?: number; }; } interface MemDbQuery { }