helene
Version:
Real-time Web Apps for Node.js
147 lines • 5.08 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cursor = void 0;
const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
const omit_1 = __importDefault(require("lodash/omit"));
const model_1 = require("./model");
class Cursor {
db;
query;
_limit;
_skip;
_sort;
_projection;
constructor(db, query) {
this.db = db;
this.query = query || {};
}
limit(limit) {
this._limit = limit;
return this;
}
skip(skip) {
this._skip = skip;
return this;
}
sort(sortQuery) {
if (sortQuery) {
this._sort = sortQuery;
}
return this;
}
projection(projection) {
this._projection = projection;
return this;
}
project(candidates) {
const res = [];
if ((0, isEmpty_1.default)(this._projection)) {
return candidates;
}
const keepId = this._projection._id === 1 || this._projection._id === undefined;
this._projection = (0, omit_1.default)(this._projection, '_id');
const keys = Object.keys(this._projection);
let action = keys.length === 0 ? 1 : undefined;
for (const k of keys) {
if (action !== undefined && this._projection[k] !== action) {
throw new Error("Can't both keep and omit fields except for _id");
}
action = this._projection[k];
}
if (action === 1) {
for (const candidate of candidates) {
const modifier = { $set: {} };
for (const k of keys) {
const value = (0, model_1.getDotValue)(candidate, k);
if (value !== undefined) {
modifier.$set[k] = value;
}
}
res.push((0, model_1.modify)({
...(keepId && { _id: candidate._id }),
}, modifier));
}
}
else if (action === 0) {
for (const candidate of candidates) {
const modifier = { $unset: {} };
for (const k of keys) {
modifier.$unset[k] = true;
}
res.push((0, model_1.modify)(keepId ? candidate : (0, omit_1.default)(candidate, '_id'), modifier));
}
}
return res;
}
async exec() {
await this.db.ensureReady();
let res = [], added = 0, skipped = 0, i, keys, key;
const self = this;
const candidates = await this.db.getCandidates(this.query);
for (i = 0; i < candidates.length; i += 1) {
if ((0, model_1.match)(candidates[i], self.query)) {
// If a sort is defined, wait for the results to be sorted before applying limit and skip
if (!self._sort) {
if (self._skip && self._skip > skipped) {
skipped += 1;
}
else {
res.push(candidates[i]);
added += 1;
if (self._limit && self._limit <= added) {
break;
}
}
}
else {
res.push(candidates[i]);
}
}
}
// Apply all sorts
if (self._sort) {
keys = Object.keys(self._sort);
// Sorting
const criteria = [];
for (i = 0; i < keys.length; i++) {
key = keys[i];
criteria.push({ key: key, direction: self._sort[key] });
}
res.sort(function (a, b) {
let criterion, compare, i;
for (i = 0; i < criteria.length; i++) {
criterion = criteria[i];
compare =
criterion.direction *
(0, model_1.compareThings)((0, model_1.getDotValue)(a, criterion.key), (0, model_1.getDotValue)(b, criterion.key), self.db.compareStrings);
if (compare !== 0) {
return compare;
}
}
return 0;
});
// Applying limit and skip
const limit = self._limit || res.length, skip = self._skip || 0;
res = res.slice(skip, skip + limit);
}
res = self.project(res);
res = res.map(doc => (0, model_1.deepCopy)(doc));
return res;
}
async map(fn) {
const res = await this.exec();
const ret = [];
for (const item of res) {
ret.push(await fn(item));
}
return ret;
}
then(onfulfilled, onrejected) {
return this.exec().then(onfulfilled, onrejected);
}
}
exports.Cursor = Cursor;
//# sourceMappingURL=cursor.js.map