src/memoz.ts
The Memoz class is an in-memory document store with optional persistence to disk. It supports transactional operations, querying, indexing, and caching.
Properties |
|
Methods |
|
constructor(memozOptions: MemozOptions)
|
||||||||
Defined in src/memoz.ts:74
|
||||||||
Parameters :
|
Private db |
Type : Map<MEMOZID | DocumentWithId<T>>
|
Default value : new Map()
|
Defined in src/memoz.ts:35
|
In-memory database storing documents keyed by MEMOZID. |
Private indexManager |
Type : IndexManager<T>
|
Defined in src/memoz.ts:56
|
Manages indexing for efficient querying. |
Private mutex |
Type : Mutex | null
|
Default value : null
|
Defined in src/memoz.ts:72
|
Private persistenceManager |
Type : PersistenceManager<T>
|
Defined in src/memoz.ts:49
|
Manages persistence of the database to disk. |
Private queryCache |
Type : QueryCache<DocumentWithId<T>>
|
Defined in src/memoz.ts:63
|
Caches query results for performance optimization. |
Public ready |
Type : Promise<void>
|
Defined in src/memoz.ts:70
|
A promise that resolves when the database is ready for use. |
Private searchEngine |
Type : SearchEngine<DocumentWithId<T>>
|
Defined in src/memoz.ts:74
|
Private transactionManager |
Type : TransactionManager<T>
|
Defined in src/memoz.ts:42
|
Manages transactions for the database. |
Public Async beginTransaction |
beginTransaction()
|
Defined in src/memoz.ts:100
|
Returns :
Promise<void>
|
Public Async commitTransaction |
commitTransaction()
|
Defined in src/memoz.ts:105
|
Returns :
Promise<void>
|
Public Async countDocuments | ||||||||
countDocuments(query?: ConditionNode<Partial<T>>)
|
||||||||
Defined in src/memoz.ts:618
|
||||||||
Counts the number of documents in the database, optionally filtered by a query.
Parameters :
Returns :
Promise<number>
|
Public Async createMany | |||||||||||||||
createMany(documents: T[], batchSize: number)
|
|||||||||||||||
Defined in src/memoz.ts:204
|
|||||||||||||||
Inserts multiple documents into the database in batches, assigning each one a unique ID, and updating relevant indexes and cache. This method handles transactional operations and ensures that documents are saved persistently to disk in chunks to avoid performance issues. Example :
This method processes documents in batches to avoid performance bottlenecks. The batch size is configurable, with a default of 100 documents per batch.
Parameters :
Returns :
Promise<DocumentWithId[]>
|
Public Async createOne | ||||||||
createOne(document: T)
|
||||||||
Defined in src/memoz.ts:151
|
||||||||
Inserts a new document into the database, assigning it a unique ID, and updating relevant indexes and cache. This method handles transactional operations and ensures that the document is saved persistently to disk. Example :
This method uses a mutex to prevent race conditions in concurrent environments. If a transaction is active, the document is inserted into the transactional database.
Parameters :
Returns :
Promise<DocumentWithId<T>>
|
Public Async deleteAll |
deleteAll()
|
Defined in src/memoz.ts:548
|
Deletes all documents from the database.
Returns :
Promise<literal type>
|
Public Async deleteById | ||||||||
deleteById(id: MEMOZID)
|
||||||||
Defined in src/memoz.ts:515
|
||||||||
Deletes a document from the database based on the provided ID.
Parameters :
Returns :
Promise<DocumentWithId | undefined>
|
Public Async deleteMany | ||||||||
deleteMany(query: ConditionNode<Partial<T>>)
|
||||||||
Defined in src/memoz.ts:596
|
||||||||
Deletes multiple documents from the database based on the provided query.
Parameters :
Returns :
Promise<literal type>
|
Public Async deleteOne | ||||||||
deleteOne(query: ConditionNode<Partial<T>>)
|
||||||||
Defined in src/memoz.ts:570
|
||||||||
Deletes a single document from the database based on the provided query.
Parameters :
Returns :
Promise<DocumentWithId | undefined>
|
Public Async fuzzySearch | |||||||||||||||||||||||||
fuzzySearch(searchTerm: string, fields: ()[], options: FuzzySearchOptions, limit: number)
|
|||||||||||||||||||||||||
Defined in src/memoz.ts:124
|
|||||||||||||||||||||||||
Performs a fuzzy search on the documents in the database.
Parameters :
Returns :
Promise<literal type[]>
Array of results with relevance score. |
Public Async getById | ||||||||
getById(id: MEMOZID)
|
||||||||
Defined in src/memoz.ts:275
|
||||||||
Retrieves a document from the database using its unique identifier (MEMOZID). document with the specified ID if found, or undefined if no document matches the ID. Example :
Ensure that the provided ID follows the expected MEMOZID format.
Parameters :
Returns :
Promise<DocumentWithId | undefined>
|
Private getFromIndex | ||||||
getFromIndex(query: any)
|
||||||
Defined in src/memoz.ts:647
|
||||||
Parameters :
Returns :
DocumentWithId[]
|
Public getMany | ||||||||
getMany(query?: ConditionNode<Partial<T>>)
|
||||||||
Defined in src/memoz.ts:360
|
||||||||
Retrieves multiple documents from the database that match the provided query. Supports sorting, pagination, and caching with chainable methods.
Parameters :
Returns :
QueryBuilder<DocumentWithId<T>>
|
Public Async getOne | ||||||||
getOne(query?: ConditionNode<Partial<T>>)
|
||||||||
Defined in src/memoz.ts:315
|
||||||||
Retrieves a single document from the database that matches the provided query. This method first checks the query cache for a result. If a cached result is found, it returns that. If no cached result exists, it checks the index for matching documents. If none are found, it retrieves the document directly from the database. If not provided, the first document from the current database is returned. or undefined if no document is found. Example :
Ensure that the provided query object is structured correctly to match documents in the database. If no query is provided, the method will return the first document in the database or undefined if the database is empty. Caching is utilized to optimize subsequent retrievals of the same document.
Parameters :
Returns :
Promise<DocumentWithId | undefined>
|
Static id |
id()
|
Defined in src/memoz.ts:633
|
Generates and returns a new unique identifier (MEMOZID).
Returns :
MEMOZID
|
Static isValidId | ||||||||
isValidId(id: MEMOZID)
|
||||||||
Defined in src/memoz.ts:643
|
||||||||
Validates whether the provided ID is a valid MEMOZID.
Parameters :
Returns :
boolean
|
Public Async rollbackTransaction |
rollbackTransaction()
|
Defined in src/memoz.ts:111
|
Returns :
Promise<void>
|
Public Async updateById | ||||||||||||
updateById(id: MEMOZID, newData: Partial
|
||||||||||||
Defined in src/memoz.ts:410
|
||||||||||||
Updates an existing object by its ID with the provided new data. This method retrieves the object associated with the given ID, merges it with the new data, updates the database, reindexes the object, and persists the changes to disk. Example :
Parameters :
Returns :
Promise<DocumentWithId<T>>
|
Public Async updateMany | ||||||||||||
updateMany(query: ConditionNode<Partial<T>>, newData: Partial
|
||||||||||||
Defined in src/memoz.ts:489
|
||||||||||||
Updates multiple documents in the database based on the provided query and new data.
Parameters :
Returns :
Promise<UpdateManyResult<T>>
|
Public Async updateOne | ||||||||||||
updateOne(query: ConditionNode<Partial<T>>, newData: Partial
|
||||||||||||
Defined in src/memoz.ts:447
|
||||||||||||
Updates a single document in the database based on the provided query and new data.
Parameters :
Returns :
Promise<DocumentWithId<T>>
|
import { memozId } from './utils/memoz-id';
import { isObject } from './utils/is-object';
import { isValidMemozId } from './utils/is-valid-memoz-id';
import { QueryCache } from './utils/query-cache';
import { TransactionManager } from './utils/transaction-manager';
import { PersistenceManager } from './utils/persistence-manager';
import { IndexManager } from './utils/index-manager';
import {
ConditionNode,
DocumentWithId,
FuzzySearchOptions,
MEMOZID,
MemozOptions,
UpdateManyResult,
} from './types';
import getOne from './utils/get-one';
import getMany from './utils/get-many';
import Mutex from './utils/mutex';
import chunkArray from './utils/helper';
import { createQueryBuilderProxy, QueryBuilder } from './utils/get-many-query-builder';
import SearchEngine from './utils/search-engine';
/**
* The Memoz class is an in-memory document store with optional persistence to disk.
* It supports transactional operations, querying, indexing, and caching.
*
* @template T - The type of documents being stored.
*/
export class Memoz<T> {
/**
* In-memory database storing documents keyed by MEMOZID.
* @private
* @type {Map<MEMOZID, DocumentWithId<T>>}
*/
private db: Map<MEMOZID, DocumentWithId<T>> = new Map();
/**
* Manages transactions for the database.
* @private
* @type {TransactionManager<T>}
*/
private transactionManager: TransactionManager<T>;
/**
* Manages persistence of the database to disk.
* @private
* @type {PersistenceManager<T>}
*/
private persistenceManager: PersistenceManager<T>;
/**
* Manages indexing for efficient querying.
* @private
* @type {IndexManager<T>}
*/
private indexManager: IndexManager<T>;
/**
* Caches query results for performance optimization.
* @private
* @type {QueryCache<DocumentWithId<T>>}
*/
private queryCache: QueryCache<DocumentWithId<T>>;
/**
* A promise that resolves when the database is ready for use.
* @public
* @type {Promise<void>}
*/
public ready: Promise<void>;
private mutex: Mutex | null = null; // Nullable mutex (null if not used)
private searchEngine: SearchEngine<DocumentWithId<T>>; // Add a search engine instance
/**
*
* @param memozOptions - Options for the Memoz instance
* @param memozOptions.filePath - The file path to save the database to -default is in-memory
* @param memozOptions.persistToDisk - Whether to persist the database to disk - default is false
* @param memozOptions.useMutex - Whether to use a mutex for thread safety - default is false
*/
constructor(memozOptions: MemozOptions = {}) {
const { storagePath, useMutex = false, persistToDisk = false } = memozOptions;
if (useMutex) {
this.mutex = new Mutex(); // Only initialize mutex if enabled
}
this.transactionManager = new TransactionManager(this.db);
this.persistenceManager = new PersistenceManager(this.db, storagePath, persistToDisk);
this.indexManager = new IndexManager();
this.queryCache = new QueryCache();
// Initialize the search engine with the db
this.searchEngine = new SearchEngine(this.db);
this.ready = persistToDisk ? this.persistenceManager.loadFromDisk() : Promise.resolve();
}
public async beginTransaction(): Promise<void> {
await this.ready;
this.transactionManager.beginTransaction();
}
public async commitTransaction(): Promise<void> {
await this.ready;
this.transactionManager.commitTransaction();
await this.persistenceManager.saveToDisk();
}
public async rollbackTransaction(): Promise<void> {
await this.ready;
this.transactionManager.rollbackTransaction();
}
/**
* Performs a fuzzy search on the documents in the database.
* @param searchTerm - The term to search for.
* @param fields - The fields to search within the documents.
* @param options - Options to configure max distance, field weights, etc.
* @param limit - The maximum number of results to return.
* @returns Array of results with relevance score.
*/
public async fuzzySearch(
searchTerm: string,
fields: (keyof T)[],
options: FuzzySearchOptions,
limit: number = Number.MAX_SAFE_INTEGER,
): Promise<{ item: DocumentWithId<T>; score: number; }[]> {
await this.ready;
return this.searchEngine.limit(limit).search(searchTerm, fields, options);
}
/**
* Inserts a new document into the database, assigning it a unique ID, and updating relevant indexes and cache.
* This method handles transactional operations and ensures that the document is saved persistently to disk.
*
* @template T - The type of the document being inserted.
* @param {T} document - The document to insert into the database.
* @returns {Promise<DocumentWithId<T>>} - A promise that resolves to the document with an added unique ID.
*
* @throws {Error} If the provided document is not a valid object.
*
* @example
* const newDocument = await db.createOne({ name: 'Sample Document' });
*
* @remarks
* This method uses a mutex to prevent race conditions in concurrent environments.
* If a transaction is active, the document is inserted into the transactional database.
*/
public async createOne(document: T): Promise<DocumentWithId<T>> {
const operation = async () => {
await this.ready;
// Invalidate cache before inserting the document
this.queryCache.invalidate();
// Ensure the document is a valid object
if (!isObject(document)) {
throw new Error('The document must be a valid object');
}
// Generate a unique ID for the document
const id = memozId();
const dbDocument: DocumentWithId<T> = { ...document, id };
// Use transactional database if available
const targetDb = this.transactionManager.getCurrentDb();
targetDb.set(id, dbDocument);
// Update indexes for the new document
this.indexManager.updateIndexes(dbDocument);
// Persist the document to disk
await this.persistenceManager.saveToDisk();
// Return the newly created document with its ID
return dbDocument;
};
// Execute the operation with mutex lock if available
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Inserts multiple documents into the database in batches, assigning each one a unique ID,
* and updating relevant indexes and cache. This method handles transactional operations
* and ensures that documents are saved persistently to disk in chunks to avoid performance issues.
*
* @template T - The type of the documents being inserted.
* @param {T[]} documents - The array of documents to insert into the database.
* @param {number} [batchSize=100] - The maximum number of documents to process in each batch.
* @returns {Promise<DocumentWithId<T>[]>} - A promise that resolves to an array of documents, each with a unique ID assigned.
*
* @throws {Error} If any document in the provided array is not a valid object.
*
* @example
* const newDocuments = await db.createMany([{ name: 'Doc 1' }, { name: 'Doc 2' }], 50);
*
* @remarks
* This method processes documents in batches to avoid performance bottlenecks.
* The batch size is configurable, with a default of 100 documents per batch.
*/
public async createMany(documents: T[], batchSize: number = 100): Promise<DocumentWithId<T>[]> {
const operation = async () => {
await this.ready;
// Invalidate cache before inserting the documents
this.queryCache.invalidate();
// Validate all documents first to avoid partial batch processing
documents.forEach((document) => {
if (!isObject(document)) {
throw new Error('Each document must be a valid object');
}
});
// Chunk documents into batches and process each batch
const allCreatedDocuments: DocumentWithId<T>[] = [];
const chunks = chunkArray(documents, batchSize);
// Process each chunk with async/await in sequence
await chunks.reduce(async (prevPromise, chunk) => {
await prevPromise; // Ensure sequential execution of batches
const createdDocuments = chunk.map((document) => {
const id = memozId(); // Generate unique ID for each document
return { ...document, id };
});
// Insert each document in the current chunk into the database
createdDocuments.forEach((doc) => {
const targetDb = this.transactionManager.getCurrentDb();
targetDb.set(doc.id, doc); // Set document in DB
this.indexManager.updateIndexes(doc); // Update index for each document
});
// Persist chunk to disk
await this.persistenceManager.saveToDisk();
// Collect all created documents
allCreatedDocuments.push(...createdDocuments);
}, Promise.resolve()); // Start the chain with an immediately resolved Promise
// Return all the created documents with IDs
return allCreatedDocuments;
};
// Execute the operation with mutex lock if available
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Retrieves a document from the database using its unique identifier (MEMOZID).
*
* @template T - The type of the document being retrieved.
* @param {MEMOZID} id - The unique identifier of the document to retrieve.
* @returns {Promise<DocumentWithId<T> | undefined>} - A promise that resolves to the
* document with the specified ID if found, or undefined if no document matches the ID.
*
* @throws {Error} If the provided ID is not valid.
*
* @example
* const document = await db.getById('some-valid-id');
* if (document) {
* console.log('Document found:', document);
* } else {
* console.log('No document found with that ID.');
* }
*
* @remarks
* Ensure that the provided ID follows the expected MEMOZID format.
*/
public async getById(id: MEMOZID): Promise<DocumentWithId<T> | undefined> {
await this.ready;
// Validate the provided ID
if (!isValidMemozId(id)) {
throw new Error('The ID must be valid');
}
// Retrieve the document from the current database
return this.transactionManager.getCurrentDb().get(id);
}
/**
* Retrieves a single document from the database that matches the provided query.
*
* This method first checks the query cache for a result. If a cached result is found, it returns that.
* If no cached result exists, it checks the index for matching documents. If none are found,
* it retrieves the document directly from the database.
*
* @template T - The type of the document being retrieved.
* @param {ConditionNode<Partial<T>>} [query] - The optional query condition used to find the document.
* If not provided, the first document from the current database is returned.
* @returns {Promise<DocumentWithId<T> | undefined>} - A promise that resolves to the document that matches the query,
* or undefined if no document is found.
*
* @throws {Error} If the provided query is not a valid object.
*
* @example
* const document = await db.getOne({ name: 'Example Document' });
* if (document) {
* console.log('Document found:', document);
* } else {
* console.log('No document found matching the query.');
* }
*
* @remarks
* Ensure that the provided query object is structured correctly to match documents in the database.
* If no query is provided, the method will return the first document in the database or undefined
* if the database is empty. Caching is utilized to optimize subsequent retrievals of the same document.
*/
public async getOne(query?: ConditionNode<Partial<T>>): Promise<DocumentWithId<T> | undefined> {
await this.ready;
// Handle optional query
if (query === undefined) {
// If no query is provided, return the first document or undefined if not found
const firstDocument = this.transactionManager.getCurrentDb().values().next().value; // Adjust based on your data structure
return firstDocument || undefined; // Return the first document or undefined if not found
}
const queryKey = JSON.stringify(query);
const cachedResult = this.queryCache.get(queryKey);
if (cachedResult) {
return cachedResult[0]; // Return the first cached result if available
}
// Validate the provided query
if (!isObject(query)) {
throw new Error('Invalid query: The query must be a valid object');
}
const indexedResults = this.getFromIndex(query);
const result = indexedResults.length > 0 ? indexedResults[0] : getOne([...this.transactionManager.getCurrentDb().values()], query);
if (result) {
this.queryCache.set(queryKey, [result]); // Cache the result for future use
}
return result; // Return the retrieved document or undefined if not found
}
/**
* Retrieves multiple documents from the database that match the provided query.
* Supports sorting, pagination, and caching with chainable methods.
*
* @param {ConditionNode<Partial<T>>} query - The query condition to match documents.
* @returns {QueryBuilder<DocumentWithId<T>>} - A QueryBuilder instance with chaining support.
*/
/**
* Retrieves multiple documents from the database that match the provided query.
* Supports sorting, pagination, and caching with chainable methods.
*
* @param {ConditionNode<Partial<T>>} [query] - The optional query condition to match documents.
* @returns {QueryBuilder<DocumentWithId<T>>} - A QueryBuilder instance with chaining support.
*/
public getMany(query?: ConditionNode<Partial<T>>): QueryBuilder<DocumentWithId<T>> {
const operation = async (): Promise<DocumentWithId<T>[]> => {
await this.ready;
const queryKey = query ? JSON.stringify(query) : 'default-query-key';
if (query && !isObject(query)) {
throw new Error('Invalid query: The query must be a valid object');
}
let initialResult: DocumentWithId<T>[];
// If query is provided, use it, otherwise return all documents
if (query) {
initialResult = this.getFromIndex(query).length > 0
? this.getFromIndex(query)
: getMany([...this.transactionManager.getCurrentDb().values()], query);
} else {
// Fetch all documents if no query is provided
initialResult = [...this.transactionManager.getCurrentDb().values()];
}
this.queryCache.set(queryKey, initialResult);
return initialResult;
};
const resultsPromise = operation();
// Return the QueryBuilder with the promise result
return createQueryBuilderProxy(new QueryBuilder<DocumentWithId<T>>(resultsPromise, this.queryCache, query ? JSON.stringify(query) : 'default-query-key'));
}
/**
* Updates an existing object by its ID with the provided new data.
*
* This method retrieves the object associated with the given ID, merges it with the
* new data, updates the database, reindexes the object, and persists the changes to disk.
*
* @template T - The type of the object being updated.
* @param {MEMOZID} id - The unique identifier of the object to update.
* @param {Partial<T>} newData - The partial object containing the new data to update the object with.
* @returns {Promise<DocumentWithId<T>>} - A promise that resolves to the updated object with its ID.
* @throws {Error} If the provided ID is not valid.
* @throws {Error} If the new data is not a valid object.
* @throws {Error} If the object with the provided ID does not exist.
*
* @example
* const updatedObject = await updateById('someId', { name: 'Updated Name' });
* console.log(updatedObject);
*/
public async updateById(id: MEMOZID, newData: Partial<T>): Promise<DocumentWithId<T>> {
const operation = async () => {
await this.ready;
this.queryCache.invalidate();
if (!isValidMemozId(id)) {
throw new Error('The ID must be valid');
}
if (!isObject(newData)) {
throw new Error('The new data must be a valid object');
}
const existingObject = await this.getById(id);
if (!existingObject) {
throw new Error('This ID does not exist');
}
const updatedObject = { ...existingObject, ...newData };
this.transactionManager.getCurrentDb().set(id, updatedObject);
this.indexManager.updateIndexes(updatedObject);
await this.persistenceManager.saveToDisk();
return updatedObject;
};
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Updates a single document in the database based on the provided query and new data.
*
* @param {ConditionNode<Partial<T>>} query - The query used to find the document to update.
* @param {Partial<T>} newData - The new data to merge with the existing document.
* @returns {Promise<DocumentWithId<T>>} - A promise that resolves to the updated document.
* @throws {Error} - Throws an error if the query or newData is not a valid object, or if no document matches the query.
*/
public async updateOne(query: ConditionNode<Partial<T>>, newData: Partial<T>): Promise<DocumentWithId<T>> {
const operation = async () => {
await this.ready;
this.queryCache.invalidate();
if (!isObject(query)) {
throw new Error('The query must be a valid object');
}
if (!isObject(newData)) {
throw new Error('The new data must be a valid object');
}
const existingObject = await this.getOne(query);
if (!existingObject) {
throw new Error('No document matches the query');
}
const updatedObject = { ...existingObject, ...newData };
const targetDb = this.transactionManager.getCurrentDb();
targetDb.set(existingObject.id, updatedObject);
this.indexManager.updateIndexes(updatedObject); // Update indexes after modifying
await this.persistenceManager.saveToDisk();
return updatedObject;
};
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Updates multiple documents in the database based on the provided query and new data.
*
* @param {ConditionNode<Partial<T>>} query - The query used to find the documents to update.
* @param {Partial<T>} newData - The new data to merge with the existing documents.
* @returns {Promise<UpdateManyResult<T>>} - A promise that resolves to an object containing update results, including:
* - `updated`: A boolean indicating if the update was successful.
* - `n`: The number of documents that were updated.
* - `documents`: An array of the updated documents.
* @throws {Error} - Throws an error if either the query or newData is not a valid object.
*/
public async updateMany(query: ConditionNode<Partial<T>>, newData: Partial<T>): Promise<UpdateManyResult<T>> {
const operation = async () => {
await this.ready;
this.queryCache.invalidate();
if (!isObject(query) || !isObject(newData)) {
throw new Error('Both query and new data must be valid objects');
}
const documents = await this.getMany(query);
documents.forEach((document) => this.updateById(document.id, newData));
await this.persistenceManager.saveToDisk();
return { updated: true, n: documents.length, documents };
};
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Deletes a document from the database based on the provided ID.
*
* @param {MEMOZID} id - The ID of the document to be deleted. Must be a valid ID.
* @returns {Promise<DocumentWithId<T> | undefined>} - A promise that resolves to the deleted document, or undefined if no document was found with the given ID.
* @throws {Error} - Throws an error if the provided ID is not valid.
*/
public async deleteById(id: MEMOZID): Promise<DocumentWithId<T> | undefined> {
const operation = async () => {
await this.ready;
this.queryCache.invalidate();
if (!isValidMemozId(id)) {
throw new Error('The ID must be valid');
}
const targetDb = this.transactionManager.getCurrentDb();
const documentToDelete = targetDb.get(id);
if (documentToDelete) {
// Update indexes efficiently
this.indexManager.updateIndexes(documentToDelete);
// Remove the document from the main database
targetDb.delete(id);
await this.persistenceManager.saveToDisk();
}
return documentToDelete;
};
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Deletes all documents from the database.
*
* @returns {Promise<{ deleted: boolean; n: number; }>} - A promise that resolves to an object containing:
* - `deleted`: A boolean indicating that the deletion was successful.
* - `n`: The number of documents that were deleted.
*/
public async deleteAll(): Promise<{ deleted: boolean; n: number; }> {
const operation = async () => {
await this.ready;
const targetDb = this.transactionManager.getCurrentDb();
const { size } = targetDb;
targetDb.clear();
this.indexManager.clear();
await this.persistenceManager.saveToDisk();
return { deleted: true, n: size };
};
return this.mutex ? this.mutex.lock(operation) : operation();
}
/**
* Deletes a single document from the database based on the provided query.
*
* @param {ConditionNode<Partial<T>>} query - The query used to find the document to delete. Must be a valid object.
* @returns {Promise<DocumentWithId<T> | undefined>} - A promise that resolves to the deleted document, or undefined if no document was found matching the query.
* @throws {Error} - Throws an error if the query is not a valid object.
*/
public async deleteOne(query: ConditionNode<Partial<T>>): Promise<DocumentWithId<T> | undefined> {
await this.ready;
this.queryCache.invalidate();
if (!isObject(query)) {
throw new Error('The query must be a valid object');
}
const objectToDelete = await this.getOne(query);
if (!objectToDelete) return undefined;
this.deleteById(objectToDelete.id);
await this.persistenceManager.saveToDisk();
return objectToDelete;
}
/**
* Deletes multiple documents from the database based on the provided query.
*
* @param {ConditionNode<Partial<T>>} query - The query used to find the documents to delete. Must be a valid object.
* @returns {Promise<{ deleted: boolean; n: number; }>} - A promise that resolves to an object containing:
* - `deleted`: A boolean indicating that the deletion was successful.
* - `n`: The number of documents that were deleted.
* @throws {Error} - Throws an error if the query is not a valid object.
*/
public async deleteMany(query: ConditionNode<Partial<T>>): Promise<{ deleted: boolean; n: number; }> {
await this.ready;
this.queryCache.invalidate();
if (!isObject(query)) {
throw new Error('The query must be a valid object');
}
const documents = await this.getMany(query);
documents.forEach((doc) => this.deleteById(doc.id));
await this.persistenceManager.saveToDisk();
return { deleted: true, n: documents.length };
}
/**
* Counts the number of documents in the database, optionally filtered by a query.
*
* @param {ConditionNode<Partial<T>>} [query] - An optional query to filter the documents to count. Must be a valid object if provided.
* @returns {Promise<number>} - A promise that resolves to the number of documents matching the query, or the total number of documents if no query is provided.
* @throws {Error} - Throws an error if the query is provided and is not a valid object.
*/
public async countDocuments(query?: ConditionNode<Partial<T>>): Promise<number> {
await this.ready;
if (query && !isObject(query)) {
throw new Error('The query must be a valid object');
}
return query && Object.keys(query).length ? (await this.getMany(query)).length : this.transactionManager.getCurrentDb().size;
}
/**
* Generates and returns a new unique identifier (MEMOZID).
*
* @returns {MEMOZID} - A newly generated unique identifier.
*/
public static id(): MEMOZID {
return memozId();
}
/**
* Validates whether the provided ID is a valid MEMOZID.
*
* @param {MEMOZID} id - The ID to validate.
* @returns {boolean} - Returns true if the ID is valid, otherwise false.
*/
public static isValidId(id: MEMOZID): boolean {
return isValidMemozId(id);
}
private getFromIndex(query: any): DocumentWithId<T>[] {
return this.indexManager.getFromIndex(query, this.transactionManager.getCurrentDb());
}
}
export default Memoz;