UNPKG

mingo

Version:

MongoDB query language for in-memory objects

141 lines (140 loc) 4.43 kB
import { ProcessingMode } from "./core/_internal"; import { concat, Lazy } from "./lazy"; import { $limit } from "./operators/pipeline/limit"; import { $project } from "./operators/pipeline/project"; import { $skip } from "./operators/pipeline/skip"; import { $sort } from "./operators/pipeline/sort"; import { cloneDeep, has } from "./util"; const OPERATORS = { $sort, $skip, $limit }; class Cursor { #source; #predicate; #projection; #options; #operators = {}; #result = null; #buffer = []; /** * Creates an instance of the Cursor class. * * @param source - The source of data to be iterated over. * @param predicate - A function or condition to filter the data. * @param projection - An object specifying the fields to include or exclude in the result. * @param options - Optional settings to customize the behavior of the cursor. */ constructor(source, predicate, projection, options) { this.#source = source; this.#predicate = predicate; this.#projection = projection; this.#options = options; } /** Returns the iterator from running the query */ fetch() { if (this.#result) return this.#result; this.#result = Lazy(this.#source).filter(this.#predicate); const mode = this.#options.processingMode; if (mode & ProcessingMode.CLONE_INPUT) this.#result.map((o) => cloneDeep(o)); for (const op of ["$sort", "$skip", "$limit"]) { if (has(this.#operators, op)) { this.#result = OPERATORS[op]( this.#result, this.#operators[op], this.#options ); } } if (Object.keys(this.#projection).length) { this.#result = $project(this.#result, this.#projection, this.#options); } if (mode & ProcessingMode.CLONE_OUTPUT) this.#result.map((o) => cloneDeep(o)); return this.#result; } /** Returns an iterator with the buffered data included */ fetchAll() { const buffered = Lazy(Array.from(this.#buffer)); this.#buffer.length = 0; return concat(buffered, this.fetch()); } /** * Return remaining objects in the cursor as an array. This method exhausts the cursor * @returns {Array} */ all() { return this.fetchAll().collect(); } /** * Returns a cursor that begins returning results only after passing or skipping a number of documents. * @param {Number} n the number of results to skip. * @return {Cursor} Returns the cursor, so you can chain this call. */ skip(n) { this.#operators["$skip"] = n; return this; } /** * Limits the number of items returned by the cursor. * * @param n - The maximum number of items to return. * @returns The current cursor instance for chaining. */ limit(n) { this.#operators["$limit"] = n; return this; } /** * Returns results ordered according to a sort specification. * @param {AnyObject} modifier an object of key and values specifying the sort order. 1 for ascending and -1 for descending * @return {Cursor} Returns the cursor, so you can chain this call. */ sort(modifier) { this.#operators["$sort"] = modifier; return this; } /** * Sets the collation options for the cursor. * Collation allows users to specify language-specific rules for string comparison, * such as case sensitivity and accent marks. * * @param spec - The collation specification to apply. * @returns The current cursor instance for chaining. */ collation(spec) { this.#options = { ...this.#options, collation: spec }; return this; } /** * Retrieves the next item in the cursor. */ next() { if (this.#buffer.length > 0) { return this.#buffer.pop(); } const o = this.fetch().next(); if (o.done) return; return o.value; } /** * Determines if there are more elements available in the cursor. * * @returns {boolean} `true` if there are more elements to iterate over, otherwise `false`. */ hasNext() { if (this.#buffer.length > 0) return true; const o = this.fetch().next(); if (o.done) return false; this.#buffer.push(o.value); return true; } /** * Returns an iterator for the cursor, allowing it to be used in `for...of` loops. * The iterator fetches all the results from the cursor. * * @returns {Iterator} An iterator over the fetched results. */ [Symbol.iterator]() { return this.fetchAll(); } } export { Cursor };