import { Query } from "mingo"; import { nanoid } from "nanoid"; import { addOptions, DuplicateDocumentError, getInsertManyResult, getInsertOneResult, InsertManyResult, InsertOneResult, Options, RemoveResult, Storage, update, UpdateResult } from "../Storage/mod.js"; import { Document, Filter, UpdateFilter, WithId } from "../Types.js"; export class MemoryStorage extends Storage { readonly #documents = new Map>(); async resolve() { return this; } async has(id: string): Promise { return this.#documents.has(id); } async insertOne(data: Partial): Promise { const document = { ...data, id: data.id ?? nanoid() } as WithId; if (await this.has(document.id)) { throw new DuplicateDocumentError(document, this as any); } this.#documents.set(document.id, document); this.broadcast("insertOne", document); return getInsertOneResult(document); } async insertMany(documents: Partial[]): Promise { const result: TSchema[] = []; for (const data of documents) { const document = { ...data, id: data.id ?? nanoid() } as WithId; result.push(document); this.#documents.set(document.id, document); } this.broadcast("insertMany", result); return getInsertManyResult(result); } async findById(id: string): Promise | undefined> { return this.#documents.get(id); } async find(filter?: Filter>, options?: Options): Promise[]> { let cursor = new Query(filter ?? {}).find(Array.from(this.#documents.values())); if (options !== undefined) { cursor = addOptions(cursor, options); } return cursor.all() as WithId[]; } async updateOne(filter: Filter>, operators: UpdateFilter): Promise { const query = new Query(filter); for (const current of Array.from(this.#documents.values())) { if (query.test(current) === true) { const { modified, document } = update(filter, operators, current); if (modified === true) { this.#documents.set(document.id, document); this.broadcast("updateOne", document); return new UpdateResult(1, 1); } return new UpdateResult(1, 0); } } return new UpdateResult(0, 0); } async updateMany(filter: Filter>, operators: UpdateFilter): Promise { const query = new Query(filter); const documents: WithId[] = []; let matchedCount = 0; let modifiedCount = 0; for (const current of Array.from(this.#documents.values())) { if (query.test(current) === true) { matchedCount += 1; const { modified, document } = update(filter, operators, current); if (modified === true) { modifiedCount += 1; documents.push(document); this.#documents.set(document.id, document); } } } this.broadcast("updateMany", documents); return new UpdateResult(matchedCount, modifiedCount); } async replace(filter: Filter>, document: WithId): Promise { const query = new Query(filter); const documents: WithId[] = []; let matchedCount = 0; let modifiedCount = 0; for (const current of Array.from(this.#documents.values())) { if (query.test(current) === true) { matchedCount += 1; modifiedCount += 1; documents.push(document); this.#documents.set(document.id, document); } } this.broadcast("updateMany", documents); return new UpdateResult(matchedCount, modifiedCount); } async remove(filter: Filter>): Promise { const documents = Array.from(this.#documents.values()); const query = new Query(filter); let count = 0; for (const document of documents) { if (query.test(document) === true) { this.#documents.delete(document.id); this.broadcast("remove", document); count += 1; } } return new RemoveResult(count); } async count(filter?: Filter>): Promise { return new Query(filter ?? {}).find(Array.from(this.#documents.values())).count(); } async flush(): Promise { this.#documents.clear(); } }