import { UpdateOptions } from "mingo/core"; import { UpdateExpression } from "mingo/updater"; import { Observable, Subject, Subscription } from "rxjs"; import { observe, observeOne } from "./observe/mod.ts"; import { ChangeEvent, InsertManyResult, InsertOneResult, Options, RemoveResult, Storage, UpdateResult, } from "./storage/mod.ts"; import { Document, Filter, WithId } from "./types.ts"; /* |-------------------------------------------------------------------------------- | Collection |-------------------------------------------------------------------------------- */ export class Collection { constructor( readonly name: string, readonly storage: Storage, ) {} get observable(): { change: Subject>; flush: Subject; } { return this.storage.observable; } /* |-------------------------------------------------------------------------------- | Mutators |-------------------------------------------------------------------------------- */ async insertOne(document: Partial>): Promise { return this.storage.resolve().then((storage) => storage.insertOne(document)); } async insertMany(documents: Partial>[]): Promise { return this.storage.resolve().then((storage) => storage.insertMany(documents)); } async updateOne( filter: Filter>, expr: UpdateExpression, arrayFilters?: Filter>[], condition?: Filter>, options?: UpdateOptions, ): Promise { return this.storage.resolve().then((storage) => storage.updateOne(filter, expr, arrayFilters, condition, options)); } async updateMany( filter: Filter>, expr: UpdateExpression, arrayFilters?: Filter>[], condition?: Filter>, options?: UpdateOptions, ): Promise { return this.storage.resolve().then((storage) => storage.updateMany(filter, expr, arrayFilters, condition, options)); } async replaceOne(filter: Filter>, document: TSchema): Promise { return this.storage.resolve().then((storage) => storage.replace(filter, document)); } async remove(filter: Filter>): Promise { return this.storage.resolve().then((storage) => storage.remove(filter)); } /* |-------------------------------------------------------------------------------- | Observers |-------------------------------------------------------------------------------- */ subscribe( filter?: Filter>, options?: SubscribeToSingle, next?: (document: WithId | undefined) => void, ): Subscription; subscribe( filter?: Filter>, options?: SubscribeToMany, next?: (documents: WithId[], changed: WithId[], type: ChangeEvent["type"]) => void, ): Subscription; subscribe(filter: Filter> = {}, options?: Options, next?: (...args: any[]) => void): Subscription { if (options?.limit === 1) { return this.#observeOne(filter).subscribe({ next }); } return this.#observe(filter, options).subscribe({ next: (value: [WithId[], WithId[], ChangeEvent["type"]]) => next?.(...value), }); } #observe( filter: Filter> = {}, options?: Options, ): Observable<[WithId[], WithId[], ChangeEvent["type"]]> { return new Observable<[WithId[], WithId[], ChangeEvent["type"]]>((subscriber) => { return observe(this as any, filter, options, (values, changed, type) => subscriber.next([values, changed, type] as any), ); }); } #observeOne(filter: Filter> = {}): Observable | undefined> { return new Observable | undefined>((subscriber) => { return observeOne(this as any, filter, (values) => subscriber.next(values as any)); }); } /* |-------------------------------------------------------------------------------- | Queries |-------------------------------------------------------------------------------- */ /** * Retrieve a record by the document 'id' key. */ async findById(id: string): Promise | undefined> { return this.storage.resolve().then((storage) => storage.findById(id)); } /** * Performs a mingo filter search over the collection data and returns * a single document if one was found matching the filter and options. */ async findOne(filter: Filter> = {}, options?: Options): Promise | undefined> { return this.find(filter, options).then(([document]) => document); } /** * Performs a mingo filter search over the collection data and returns any * documents matching the provided filter and options. */ async find(filter: Filter> = {}, options?: Options): Promise[]> { return this.storage.resolve().then((storage) => storage.find(filter, options)); } /** * Performs a mingo filter search over the collection data and returns * the count of all documents found matching the filter and options. */ async count(filter?: Filter>): Promise { return this.storage.resolve().then((storage) => storage.count(filter)); } /** * Removes all documents from the storage instance. */ flush(): void { this.storage.resolve().then((storage) => { storage.broadcast("flush"); storage.flush(); }); } } /* |-------------------------------------------------------------------------------- | Types |-------------------------------------------------------------------------------- */ export type SubscriptionOptions = { sort?: Options["sort"]; skip?: Options["skip"]; range?: Options["range"]; offset?: Options["offset"]; limit?: Options["limit"]; index?: Options["index"]; }; export type SubscribeToSingle = Options & { limit: 1; }; export type SubscribeToMany = Options & { limit?: number; };