146 lines
4.0 KiB
JavaScript
146 lines
4.0 KiB
JavaScript
import {
|
|
ProcessingMode
|
|
} from "./core";
|
|
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 = [];
|
|
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(cloneDeep);
|
|
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(cloneDeep);
|
|
return this.#result;
|
|
}
|
|
/** Returns an iterator with the buffered data included */
|
|
fetchAll() {
|
|
const buffered = Lazy([...this.#buffer]);
|
|
this.#buffer = [];
|
|
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().value();
|
|
}
|
|
/**
|
|
* Returns the number of objects return in the cursor. This method exhausts the cursor
|
|
* @returns {Number}
|
|
*/
|
|
count() {
|
|
return this.all().length;
|
|
}
|
|
/**
|
|
* 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;
|
|
}
|
|
/**
|
|
* Constrains the size of a cursor's result set.
|
|
* @param {Number} n the number of results to limit to.
|
|
* @return {Cursor} Returns the cursor, so you can chain this call.
|
|
*/
|
|
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;
|
|
}
|
|
/**
|
|
* Specifies the collation for the cursor returned by the `mingo.Query.find`
|
|
* @param {*} spec
|
|
*/
|
|
collation(spec) {
|
|
this.#options = { ...this.#options, collation: spec };
|
|
return this;
|
|
}
|
|
/**
|
|
* Returns the next document in a cursor.
|
|
* @returns {AnyObject | Boolean}
|
|
*/
|
|
next() {
|
|
if (this.#buffer.length > 0) {
|
|
return this.#buffer.pop();
|
|
}
|
|
const o = this.fetch().next();
|
|
if (o.done) return;
|
|
return o.value;
|
|
}
|
|
/**
|
|
* Returns true if the cursor has documents and can be iterated.
|
|
* @returns {boolean}
|
|
*/
|
|
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;
|
|
}
|
|
/**
|
|
* Applies a function to each document in a cursor and collects the return values in an array.
|
|
* @param fn
|
|
* @returns {Array}
|
|
*/
|
|
map(fn) {
|
|
return this.all().map(fn);
|
|
}
|
|
/**
|
|
* Applies a JavaScript function for every document in a cursor.
|
|
* @param fn
|
|
*/
|
|
forEach(fn) {
|
|
this.all().forEach(fn);
|
|
}
|
|
[Symbol.iterator]() {
|
|
return this.fetchAll();
|
|
}
|
|
}
|
|
export {
|
|
Cursor
|
|
};
|