@contentstack/datasync-mongodb-sdk 1.0.9-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/codeql-analysis.yml +68 -0
- package/.github/workflows/jira.yml +33 -0
- package/.github/workflows/release.yml +77 -0
- package/.github/workflows/sast-scan.yml +11 -0
- package/.github/workflows/sca-scan.yml +15 -0
- package/.talismanrc +4 -0
- package/CODEOWNERS +1 -0
- package/LICENCE +21 -0
- package/README.md +191 -0
- package/SECURITY.md +27 -0
- package/contentstack-datasync-mongodb-sdk-1.0.9-beta.1.tgz +0 -0
- package/dist/config.js +47 -0
- package/dist/index.js +42 -0
- package/dist/stack.js +2272 -0
- package/dist/util.js +86 -0
- package/docs/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/docs/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/docs/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Light-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/docs/fonts/OpenSans-Light-webfont.woff +0 -0
- package/docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/docs/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/docs/global.html +7520 -0
- package/docs/global.html#Stack +1070 -0
- package/docs/index.html +291 -0
- package/docs/index.js.html +92 -0
- package/docs/scripts/linenumber.js +25 -0
- package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/scripts/prettify/lang-css.js +2 -0
- package/docs/stack.js.html +2244 -0
- package/docs/styles/jsdoc-default.css +358 -0
- package/docs/styles/prettify-jsdoc.css +111 -0
- package/docs/styles/prettify-tomorrow.css +132 -0
- package/example/index.js +56 -0
- package/package.json +59 -0
- package/test/comparison-operators.ts +257 -0
- package/test/conditional-operators.ts +106 -0
- package/test/config.ts +12 -0
- package/test/core.ts +333 -0
- package/test/count.ts +98 -0
- package/test/data/assets.ts +35 -0
- package/test/data/author.ts +168 -0
- package/test/data/blog.ts +138 -0
- package/test/data/category.ts +20 -0
- package/test/data/content_types.ts +164 -0
- package/test/data/products.ts +64 -0
- package/test/expressions.ts +108 -0
- package/test/include-exclude.ts +176 -0
- package/test/logical-operators.ts +140 -0
- package/test/projections.ts +109 -0
- package/test/queries.ts +143 -0
- package/test/references.ts +162 -0
- package/test/skip-limit.ts +150 -0
- package/test/sorting.ts +177 -0
- package/tslint.json +45 -0
- package/typings/config.d.ts +42 -0
- package/typings/index.d.ts +36 -0
- package/typings/stack.d.ts +1097 -0
- package/typings/util.d.ts +28 -0
|
@@ -0,0 +1,2244 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>JSDoc: Source: stack.js</title>
|
|
6
|
+
|
|
7
|
+
<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js" integrity="sha384-hDHlUtmnjnJimeAhT+DpLqjLdp8vFgSFHhZO1zq2EtqpwFsNM7H5cpSUYqT1Uh2E" crossorigin="anonymous"> </script>
|
|
8
|
+
<script src="scripts/prettify/lang-css.js" integrity="=sha384-ZVW4Q90WP44LAxvcmnOQ3FYYiuBwyy/plPaSRSP9g4z61NRCtowdPA4A2to4Ui9A%" crossorigin="anonymous"> </script>
|
|
9
|
+
<!--[if lt IE 9]>
|
|
10
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js" integrity="sha384-hDHlUtmnjnJimeAhT+DpLqjLdp8vFgSFHhZO1zq2EtqpwFsNM7H5cpSUYqT1Uh2E" crossorigin="anonymous"></script>
|
|
11
|
+
<![endif]-->
|
|
12
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
|
13
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
|
14
|
+
</head>
|
|
15
|
+
|
|
16
|
+
<body>
|
|
17
|
+
|
|
18
|
+
<div id="main">
|
|
19
|
+
|
|
20
|
+
<h1 class="page-title">Source: stack.js</h1>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
<section>
|
|
28
|
+
<article>
|
|
29
|
+
<pre class="prettyprint source linenums"><code>"use strict";
|
|
30
|
+
/*!
|
|
31
|
+
* Contentstack DataSync Mongodb SDK
|
|
32
|
+
* Copyright (c) 2019 Contentstack LLC
|
|
33
|
+
* MIT Licensed
|
|
34
|
+
*/
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
37
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
38
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
39
|
+
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
40
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
44
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
const lodash_1 = require("lodash");
|
|
48
|
+
const mongodb_1 = require("mongodb");
|
|
49
|
+
const sift_1 = __importDefault(require("sift"));
|
|
50
|
+
const config_1 = require("./config");
|
|
51
|
+
const util_1 = require("./util");
|
|
52
|
+
/**
|
|
53
|
+
* @class Stack
|
|
54
|
+
* @descriptionExpose SDK query methods on Stack
|
|
55
|
+
* @constructor
|
|
56
|
+
* @descriptionProvides a range of connection/disconnect, filters and projections on mongodb
|
|
57
|
+
* @returns {Stack} Returns an instance of `Stack`
|
|
58
|
+
*/
|
|
59
|
+
class Stack {
|
|
60
|
+
constructor(stackConfig, existingDB) {
|
|
61
|
+
this.config = lodash_1.merge(config_1.config, stackConfig);
|
|
62
|
+
// validates config.locales property
|
|
63
|
+
util_1.validateConfig(this.config);
|
|
64
|
+
this.contentStore = this.config.contentStore;
|
|
65
|
+
this.collectionNames = this.contentStore.collection;
|
|
66
|
+
this.types = this.contentStore.internal.types;
|
|
67
|
+
this.q = {};
|
|
68
|
+
this.internal = {};
|
|
69
|
+
this.db = existingDB;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* @public
|
|
73
|
+
* @method ascending
|
|
74
|
+
* @summary Sorts the documents based on the 'sort' key
|
|
75
|
+
* @description
|
|
76
|
+
* The sort function requires that the entire sort be able to complete within 32 megabytes.
|
|
77
|
+
* When the sort option consumes more than 32 megabytes, MongoDB will return an error.
|
|
78
|
+
* @param {string} field The field to sort in ascending order
|
|
79
|
+
* @example
|
|
80
|
+
* Stack
|
|
81
|
+
* .contentType('')
|
|
82
|
+
* .entries()
|
|
83
|
+
* .ascending()
|
|
84
|
+
* .find()
|
|
85
|
+
* .then((result) => {
|
|
86
|
+
* // result sorted in ascending manner with respect to 'published_at' field (by default)
|
|
87
|
+
* })
|
|
88
|
+
* .catch((error) => {
|
|
89
|
+
* // handle query errors
|
|
90
|
+
* })
|
|
91
|
+
*
|
|
92
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
93
|
+
*/
|
|
94
|
+
ascending(field) {
|
|
95
|
+
if (typeof this.q.content_type_uid !== 'string' || typeof field !== 'string' || field.length === 0) {
|
|
96
|
+
throw new Error('Kindly provide valid parameters for .ascending!');
|
|
97
|
+
}
|
|
98
|
+
else if (this.internal.sort && typeof this.internal.sort === 'object') {
|
|
99
|
+
this.internal.sort[field] = 1;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
this.internal.sort = {
|
|
103
|
+
[field]: 1,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* @public
|
|
110
|
+
* @method descending
|
|
111
|
+
* @summary Sorts the documents based on the 'sort' key
|
|
112
|
+
* @description
|
|
113
|
+
* The sort function requires that the entire sort be able to complete within 32 megabytes.
|
|
114
|
+
* When the sort option consumes more than 32 megabytes, MongoDB will return an error.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} field The field to sort in descending order
|
|
117
|
+
* @example
|
|
118
|
+
* Stack
|
|
119
|
+
* .contentType('')
|
|
120
|
+
* .entries()
|
|
121
|
+
* .descending('title')
|
|
122
|
+
* .find()
|
|
123
|
+
* .then((result) => {
|
|
124
|
+
* // result sorted in descending manner with respect to 'title' field
|
|
125
|
+
* })
|
|
126
|
+
* .catch((error) => {
|
|
127
|
+
* // handle query errors
|
|
128
|
+
* })
|
|
129
|
+
*
|
|
130
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
131
|
+
*/
|
|
132
|
+
descending(field) {
|
|
133
|
+
if (typeof this.q.content_type_uid !== 'string' || typeof field !== 'string' || field.length === 0) {
|
|
134
|
+
throw new Error('Kindly provide valid parameters for .descending()!');
|
|
135
|
+
}
|
|
136
|
+
else if (this.internal.sort && typeof this.internal.sort === 'object') {
|
|
137
|
+
this.internal.sort[field] = -1;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
this.internal.sort = {
|
|
141
|
+
[field]: -1,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* @public
|
|
148
|
+
* @method connect
|
|
149
|
+
* @summary
|
|
150
|
+
* Establish connection to mongodb
|
|
151
|
+
*
|
|
152
|
+
* @param {object} overrides Config overrides/mongodb specific config
|
|
153
|
+
* @example
|
|
154
|
+
* Stack
|
|
155
|
+
* .connect({overrides})
|
|
156
|
+
* .then((result) => {
|
|
157
|
+
* // mongodb connection object
|
|
158
|
+
* // indexes will be created on the collection in the background if provided in config
|
|
159
|
+
* })
|
|
160
|
+
* .catch((error) => {
|
|
161
|
+
* // handle query errors
|
|
162
|
+
* })
|
|
163
|
+
*
|
|
164
|
+
* @returns {object} Mongodb 'db' instance
|
|
165
|
+
*/
|
|
166
|
+
connect(overrides = {}) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
const dbConfig = lodash_1.merge({}, this.config, overrides).contentStore;
|
|
169
|
+
const url = util_1.validateURI(dbConfig.url);
|
|
170
|
+
const options = dbConfig.options;
|
|
171
|
+
const dbName = dbConfig.dbName;
|
|
172
|
+
const client = new mongodb_1.MongoClient(url, options);
|
|
173
|
+
this.client = client;
|
|
174
|
+
yield client.connect();
|
|
175
|
+
this.db = client.db(dbName);
|
|
176
|
+
return this.db;
|
|
177
|
+
// // Create indexes in the background
|
|
178
|
+
// const bucket: any = []
|
|
179
|
+
// const indexes = this.config.contentStore.indexes
|
|
180
|
+
// const collectionName = this.config.contentStore.collectionName
|
|
181
|
+
// for (let index in indexes) {
|
|
182
|
+
// if (indexes[index] === 1 || indexes[index] === -1) {
|
|
183
|
+
// bucket.push(this.createIndexes(this.config.contentStore.collectionName, index, indexes[index]))
|
|
184
|
+
// }
|
|
185
|
+
// }
|
|
186
|
+
// Promise.all(bucket)
|
|
187
|
+
// .then(() => {
|
|
188
|
+
// console.info(`Indexes created successfully in '${collectionName}' collection`)
|
|
189
|
+
// })
|
|
190
|
+
// .catch((error) => {
|
|
191
|
+
// console.error(`Failed while creating indexes in '${collectionName}' collection`)
|
|
192
|
+
// console.error(error)
|
|
193
|
+
// })
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// private createIndexes(collectionId, index, type) {
|
|
197
|
+
// return this.db.collection(collectionId)
|
|
198
|
+
// .createIndex({
|
|
199
|
+
// [index]: type
|
|
200
|
+
// })
|
|
201
|
+
// .then(() => {
|
|
202
|
+
// return
|
|
203
|
+
// })
|
|
204
|
+
// }
|
|
205
|
+
/**
|
|
206
|
+
* @public
|
|
207
|
+
* @method close
|
|
208
|
+
* @summary Closes connection with mongodb
|
|
209
|
+
*/
|
|
210
|
+
close() {
|
|
211
|
+
this.client.close();
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* @method language
|
|
215
|
+
* @description
|
|
216
|
+
* Locale to query on
|
|
217
|
+
*
|
|
218
|
+
* @param {string} code Query locale's code
|
|
219
|
+
* @example
|
|
220
|
+
* Stack
|
|
221
|
+
* .contentType('')
|
|
222
|
+
* .entries()
|
|
223
|
+
* .language('es-es')
|
|
224
|
+
* .find()
|
|
225
|
+
* .then((result) => {
|
|
226
|
+
* // results in entries fetched from 'es-es' locale
|
|
227
|
+
* // if not provided, defaults to the 1st locale provided in the 'locales' key, provided in config
|
|
228
|
+
* })
|
|
229
|
+
* .catch((error) => {
|
|
230
|
+
* // handle query errors
|
|
231
|
+
* })
|
|
232
|
+
*
|
|
233
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
234
|
+
*/
|
|
235
|
+
language(code) {
|
|
236
|
+
if (typeof code !== 'string' || code.length === 0) {
|
|
237
|
+
throw new Error('Kindly pass valid parameters for .language()!');
|
|
238
|
+
}
|
|
239
|
+
this.q.locale = code;
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* @public
|
|
244
|
+
* @method and
|
|
245
|
+
* @summary Logical AND query wrapper
|
|
246
|
+
* @descriptionAccepts 2 queries and returns only those documents, that satisfy both the query conditions
|
|
247
|
+
* @param {object} queries Query filter
|
|
248
|
+
* @example
|
|
249
|
+
* Stack
|
|
250
|
+
* .contentType('')
|
|
251
|
+
* .entries()
|
|
252
|
+
* .and([
|
|
253
|
+
* {
|
|
254
|
+
* title: 'John'
|
|
255
|
+
* },
|
|
256
|
+
* {
|
|
257
|
+
* age: 30
|
|
258
|
+
* }
|
|
259
|
+
* ])
|
|
260
|
+
* .find()
|
|
261
|
+
* .then((result) => {
|
|
262
|
+
* // filtered entries, where { title: 'John', age: 30 }
|
|
263
|
+
* })
|
|
264
|
+
* .catch((error) => {
|
|
265
|
+
* // handle query errors
|
|
266
|
+
* })
|
|
267
|
+
*
|
|
268
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
269
|
+
*/
|
|
270
|
+
and(queries) {
|
|
271
|
+
if (this.q.query && typeof this.q.query === 'object') {
|
|
272
|
+
this.q.query = lodash_1.merge(this.q.query, {
|
|
273
|
+
$and: queries,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
this.q.query = {
|
|
278
|
+
$and: queries,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* @public
|
|
285
|
+
* @method or
|
|
286
|
+
* @summary Logical OR query wrapper
|
|
287
|
+
* @descriptionAccepts 2 queries and returns only those documents, that satisfy either of the query conditions
|
|
288
|
+
* @param {object} queries Query filter
|
|
289
|
+
* @example
|
|
290
|
+
* Stack
|
|
291
|
+
* .contentType('')
|
|
292
|
+
* .entries()
|
|
293
|
+
* .or([
|
|
294
|
+
* {
|
|
295
|
+
* title: 'John'
|
|
296
|
+
* },
|
|
297
|
+
* {
|
|
298
|
+
* title: 'Jane'
|
|
299
|
+
* }
|
|
300
|
+
* ])
|
|
301
|
+
* .find()
|
|
302
|
+
* .then((result) => {
|
|
303
|
+
* // filtered entries, where { title: 'John' } OR { title: 'Jane' }
|
|
304
|
+
* })
|
|
305
|
+
* .catch((error) => {
|
|
306
|
+
* // handle query errors
|
|
307
|
+
* })
|
|
308
|
+
*
|
|
309
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
310
|
+
*/
|
|
311
|
+
or(queries) {
|
|
312
|
+
if (this.q.query && typeof this.q.query === 'object') {
|
|
313
|
+
this.q.query = lodash_1.merge(this.q.query, {
|
|
314
|
+
$or: queries,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
this.q.query = {
|
|
319
|
+
$or: queries,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
return this;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* @public
|
|
326
|
+
* @method lessThan
|
|
327
|
+
* @summary Comparison $lt query wrapper
|
|
328
|
+
* @description
|
|
329
|
+
* Compares the field/key provided against the provided value.
|
|
330
|
+
* Only documents that have lower value than the one provided are returned.
|
|
331
|
+
* Check https://docs.mongodb.com/manual/reference/operator/query/lt/
|
|
332
|
+
* and https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing for more info
|
|
333
|
+
* @param {string} key Field to compare against
|
|
334
|
+
* @param {*} value Value to compare with
|
|
335
|
+
* @example
|
|
336
|
+
* Stack
|
|
337
|
+
* .contentType('')
|
|
338
|
+
* .entries()
|
|
339
|
+
* .lessThan('age', 18)
|
|
340
|
+
* .find()
|
|
341
|
+
* .then((result) => {
|
|
342
|
+
* // filtered entries, where { age < 18 }
|
|
343
|
+
* })
|
|
344
|
+
* .catch((error) => {
|
|
345
|
+
* // handle query errors
|
|
346
|
+
* })
|
|
347
|
+
*
|
|
348
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
349
|
+
*/
|
|
350
|
+
lessThan(key, value) {
|
|
351
|
+
if (typeof key !== 'string' || typeof value === 'undefined') {
|
|
352
|
+
throw new Error('Kindly pass valid key and value parameters for \'.lessThan()\'');
|
|
353
|
+
}
|
|
354
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
355
|
+
this.q.query[key] = {
|
|
356
|
+
$lt: value,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
this.q.query = {
|
|
361
|
+
[key]: {
|
|
362
|
+
$lt: value,
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
return this;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* @public
|
|
370
|
+
* @method lessThanOrEqualTo
|
|
371
|
+
* @summary Comparison $lte query wrapper
|
|
372
|
+
* @description
|
|
373
|
+
* Compares the field/key provided against the provided value.
|
|
374
|
+
* Only documents that have lower or equal value than the one provided are returned.
|
|
375
|
+
* Check https://docs.mongodb.com/manual/reference/operator/query/lte/
|
|
376
|
+
* and https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing for more info
|
|
377
|
+
* @param {string} key Field to compare against
|
|
378
|
+
* @param {*} value Value to compare with
|
|
379
|
+
* @example
|
|
380
|
+
* Stack
|
|
381
|
+
* .contentType('')
|
|
382
|
+
* .entries()
|
|
383
|
+
* .lessThanOrEqualTo('age', 18)
|
|
384
|
+
* .find()
|
|
385
|
+
* .then((result) => {
|
|
386
|
+
* // filtered entries, where { age <= 18 }
|
|
387
|
+
* })
|
|
388
|
+
* .catch((error) => {
|
|
389
|
+
* // handle query errors
|
|
390
|
+
* })
|
|
391
|
+
*
|
|
392
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
393
|
+
*/
|
|
394
|
+
lessThanOrEqualTo(key, value) {
|
|
395
|
+
if (typeof key !== 'string' || typeof value === 'undefined') {
|
|
396
|
+
throw new Error('Kindly pass valid key and value parameters for \'.lessThanOrEqualTo()\'');
|
|
397
|
+
}
|
|
398
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
399
|
+
this.q.query[key] = {
|
|
400
|
+
$lte: value,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
this.q.query = {
|
|
405
|
+
[key]: {
|
|
406
|
+
$lte: value,
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
return this;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* @public
|
|
414
|
+
* @method greaterThan
|
|
415
|
+
* @summary Comparison $gt query wrapper
|
|
416
|
+
* @description
|
|
417
|
+
* Compares the field/key provided against the provided value.
|
|
418
|
+
* Only documents that have greater value than the one provided are returned.
|
|
419
|
+
* Check {@link https://docs.mongodb.com/manual/reference/operator/query/gt/ }
|
|
420
|
+
* and https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing for more info
|
|
421
|
+
* @param {string} key Field to compare against
|
|
422
|
+
* @param {*} value Value to compare with
|
|
423
|
+
* @example
|
|
424
|
+
* Stack
|
|
425
|
+
* .contentType('')
|
|
426
|
+
* .entries()
|
|
427
|
+
* .greaterThan('age', 60)
|
|
428
|
+
* .find()
|
|
429
|
+
* .then((result) => {
|
|
430
|
+
* // filtered entries, where { age > 60 }
|
|
431
|
+
* })
|
|
432
|
+
* .catch((error) => {
|
|
433
|
+
* // handle query errors
|
|
434
|
+
* })
|
|
435
|
+
*
|
|
436
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
437
|
+
*/
|
|
438
|
+
greaterThan(key, value) {
|
|
439
|
+
if (typeof key !== 'string' || typeof value === 'undefined') {
|
|
440
|
+
throw new Error('Kindly pass valid key and value parameters for \'.greaterThan()\'');
|
|
441
|
+
}
|
|
442
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
443
|
+
this.q.query[key] = {
|
|
444
|
+
$gt: value,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
this.q.query = {
|
|
449
|
+
[key]: {
|
|
450
|
+
$gt: value,
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
return this;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* @public
|
|
458
|
+
* @method greaterThanOrEqualTo
|
|
459
|
+
* @summary Comparison $gte query wrapper
|
|
460
|
+
* @description
|
|
461
|
+
* Compares the field/key provided against the provided value.
|
|
462
|
+
* Only documents that have greater than or equal value than the one provided are returned.
|
|
463
|
+
* Check https://docs.mongodb.com/manual/reference/operator/query/gte/ and
|
|
464
|
+
* https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing for more info
|
|
465
|
+
* @param {string} key - Field to compare against
|
|
466
|
+
* @param {*} value - Value to compare with
|
|
467
|
+
* @example
|
|
468
|
+
* Stack
|
|
469
|
+
* .contentType('')
|
|
470
|
+
* .entries()
|
|
471
|
+
* .greaterThanOrEqualTo('age', 60)
|
|
472
|
+
* .find()
|
|
473
|
+
* .then((result) => {
|
|
474
|
+
* // filtered entries, where { age >= 60 }
|
|
475
|
+
* })
|
|
476
|
+
* .catch((error) => {
|
|
477
|
+
* // handle query errors
|
|
478
|
+
* })
|
|
479
|
+
*
|
|
480
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
481
|
+
*/
|
|
482
|
+
greaterThanOrEqualTo(key, value) {
|
|
483
|
+
if (typeof key !== 'string' || typeof value === 'undefined') {
|
|
484
|
+
throw new Error('Kindly pass valid key and value parameters for \'.greaterThanOrEqualTo()\'');
|
|
485
|
+
}
|
|
486
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
487
|
+
this.q.query[key] = {
|
|
488
|
+
$gte: value,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
this.q.query = {
|
|
493
|
+
[key]: {
|
|
494
|
+
$gte: value,
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
return this;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* @public
|
|
502
|
+
* @method notEqualTo
|
|
503
|
+
* @summary Comparison $ne query wrapper
|
|
504
|
+
* @description
|
|
505
|
+
* Compares the field/key provided against the provided value.
|
|
506
|
+
* Only documents that have value not equals than the one provided are returned.
|
|
507
|
+
*
|
|
508
|
+
* Check mongodb query here: {@link https://docs.mongodb.com/manual/reference/operator/query/ne/}.
|
|
509
|
+
*
|
|
510
|
+
* Res: {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing}.
|
|
511
|
+
*
|
|
512
|
+
* Comparison ordering
|
|
513
|
+
* {@link https://docs.mongodb.com/manual/reference/bson-type-comparison-order/#bson-types-comparison-order}
|
|
514
|
+
* @param {string} key Field to compare against
|
|
515
|
+
* @param {*} value Value to compare with
|
|
516
|
+
* @example
|
|
517
|
+
* Stack
|
|
518
|
+
* .contentType('')
|
|
519
|
+
* .entries()
|
|
520
|
+
* .notEqualTo('age', 25)
|
|
521
|
+
* .find()
|
|
522
|
+
* .then((result) => {
|
|
523
|
+
* // filtered entries, where { age != 25 }
|
|
524
|
+
* })
|
|
525
|
+
* .catch((error) => {
|
|
526
|
+
* // handle query errors
|
|
527
|
+
* })
|
|
528
|
+
*
|
|
529
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
530
|
+
*/
|
|
531
|
+
notEqualTo(key, value) {
|
|
532
|
+
if (typeof key !== 'string' || typeof value === 'undefined') {
|
|
533
|
+
throw new Error('Kindly pass valid key and value parameters for \'.notEqualTo()\'');
|
|
534
|
+
}
|
|
535
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
536
|
+
this.q.query[key] = {
|
|
537
|
+
$ne: value,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
this.q.query = {
|
|
542
|
+
[key]: {
|
|
543
|
+
$ne: value,
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
return this;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* @public
|
|
551
|
+
* @method containedIn
|
|
552
|
+
* @summary Comparison $in query wrapper
|
|
553
|
+
* @description
|
|
554
|
+
* Compares the field/key provided against the provided value.
|
|
555
|
+
* Only documents that have value contained in the field/key provided are returned.
|
|
556
|
+
*
|
|
557
|
+
* Check mongodb query here: {@link https://docs.mongodb.com/manual/reference/operator/query/in/}.
|
|
558
|
+
*
|
|
559
|
+
* Res: {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing}.
|
|
560
|
+
*
|
|
561
|
+
* Comparison ordering
|
|
562
|
+
* {@link https://docs.mongodb.com/manual/reference/bson-type-comparison-order/#bson-types-comparison-order}
|
|
563
|
+
* @param {string} key Field to compare against
|
|
564
|
+
* @param {*} value Value to compare with
|
|
565
|
+
*
|
|
566
|
+
* @example
|
|
567
|
+
* Stack
|
|
568
|
+
* .contentType('')
|
|
569
|
+
* .entries()
|
|
570
|
+
* .containedIn('emails', 'john.doe@some.com')
|
|
571
|
+
* .find()
|
|
572
|
+
* .then((result) => {
|
|
573
|
+
* // filtered entries, where 'john.doe@some.com' exists in 'emails' field (array)
|
|
574
|
+
* })
|
|
575
|
+
* .catch((error) => {
|
|
576
|
+
* // handle query errors
|
|
577
|
+
* })
|
|
578
|
+
*
|
|
579
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
580
|
+
*/
|
|
581
|
+
containedIn(key, value) {
|
|
582
|
+
if (typeof key !== 'string' || typeof value !== 'object' || !(value instanceof Array)) {
|
|
583
|
+
throw new Error('Kindly pass valid key and value parameters for \'.containedIn()\'');
|
|
584
|
+
}
|
|
585
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
586
|
+
this.q.query[key] = {
|
|
587
|
+
$in: value,
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
this.q.query = {
|
|
592
|
+
[key]: {
|
|
593
|
+
$in: value,
|
|
594
|
+
},
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
return this;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* @public
|
|
601
|
+
* @method notContainedIn
|
|
602
|
+
* @summary Comparison $nin query wrapper
|
|
603
|
+
* @description
|
|
604
|
+
* Compares the field/key provided against the provided value.
|
|
605
|
+
* Only documents that have value not contained in the field/key provided are returned.
|
|
606
|
+
*
|
|
607
|
+
* Check mongodb query here: {@link https://docs.mongodb.com/manual/reference/operator/query/nin/}.
|
|
608
|
+
*
|
|
609
|
+
* Res: {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing}.
|
|
610
|
+
*
|
|
611
|
+
* Comparison ordering
|
|
612
|
+
* {@link https://docs.mongodb.com/manual/reference/bson-type-comparison-order/#bson-types-comparison-order}
|
|
613
|
+
* @param {string} key Field to compare against
|
|
614
|
+
* @param {*} value Value to compare with
|
|
615
|
+
*
|
|
616
|
+
* @example
|
|
617
|
+
* Stack
|
|
618
|
+
* .contentType('')
|
|
619
|
+
* .entries()
|
|
620
|
+
* .notContainedIn('emails', 'john.doe@some.com')
|
|
621
|
+
* .find()
|
|
622
|
+
* .then((result) => {
|
|
623
|
+
* // filtered entries, where 'john.doe@some.com' does not exist in 'emails' field (array)
|
|
624
|
+
* })
|
|
625
|
+
* .catch((error) => {
|
|
626
|
+
* // handle query errors
|
|
627
|
+
* })
|
|
628
|
+
*
|
|
629
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
630
|
+
*/
|
|
631
|
+
notContainedIn(key, value) {
|
|
632
|
+
if (typeof key !== 'string' || typeof value !== 'object' || !(value instanceof Array)) {
|
|
633
|
+
throw new Error('Kindly pass valid key and value parameters for \'.notContainedIn()\'');
|
|
634
|
+
}
|
|
635
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
636
|
+
this.q.query[key] = {
|
|
637
|
+
$nin: value,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
this.q.query = {
|
|
642
|
+
[key]: {
|
|
643
|
+
$nin: value,
|
|
644
|
+
},
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
return this;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* @public
|
|
651
|
+
* @method exists
|
|
652
|
+
* @summary Element $exists query wrapper, checks if a field exists
|
|
653
|
+
* @description
|
|
654
|
+
* Compares the field / key provided against the provided value.Only documents that have the field /
|
|
655
|
+
* key specified are returned.
|
|
656
|
+
*
|
|
657
|
+
* Check mongodb query here: {@link https://docs.mongodb.com/manual/reference/operator/query/exists/}.
|
|
658
|
+
*
|
|
659
|
+
* Res: {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing}.
|
|
660
|
+
*
|
|
661
|
+
* Comparison ordering{
|
|
662
|
+
* @link https: //docs.mongodb.com/manual/reference/bson-type-comparison-order/#bson-types-comparison-order}
|
|
663
|
+
* @param {string} key Field to compare against
|
|
664
|
+
* @param {*} value Value to compare with
|
|
665
|
+
*
|
|
666
|
+
* @example
|
|
667
|
+
* Stack
|
|
668
|
+
* .contentType('')
|
|
669
|
+
* .entries()
|
|
670
|
+
* .exists('emails')
|
|
671
|
+
* .find()
|
|
672
|
+
* .then((result) => {
|
|
673
|
+
* // filtered entries, where 'emails' property exists
|
|
674
|
+
* })
|
|
675
|
+
* .catch((error) => {
|
|
676
|
+
* // handle query errors
|
|
677
|
+
* })
|
|
678
|
+
*
|
|
679
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
680
|
+
*/
|
|
681
|
+
exists(key) {
|
|
682
|
+
if (typeof key !== 'string') {
|
|
683
|
+
throw new Error('Kindly pass valid key for \'.exists()\'');
|
|
684
|
+
}
|
|
685
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
686
|
+
this.q.query[key] = {
|
|
687
|
+
$exists: true,
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
this.q.query = {
|
|
692
|
+
[key]: {
|
|
693
|
+
$exists: true,
|
|
694
|
+
},
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
return this;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* @public
|
|
701
|
+
* @method notExists
|
|
702
|
+
* @summary
|
|
703
|
+
* Property $exists query wrapper, checks if a field does not exists
|
|
704
|
+
* @description
|
|
705
|
+
* Compares the field/key provided against the provided value. Only documents that do not have the key are returned.
|
|
706
|
+
*
|
|
707
|
+
* Check mongodb query here: {@link https://docs.mongodb.com/manual/reference/operator/query/exists/}.
|
|
708
|
+
*
|
|
709
|
+
* Res: {@link https://docs.mongodb.com/manual/reference/method/db.collection.find/#type-bracketing}.
|
|
710
|
+
*
|
|
711
|
+
* Comparison ordering{
|
|
712
|
+
* @link https: //docs.mongodb.com/manual/reference/bson-type-comparison-order/#bson-types-comparison-order}
|
|
713
|
+
* @param {string} key Field to compare against
|
|
714
|
+
* @param {*} value Value to compare with
|
|
715
|
+
* @example
|
|
716
|
+
* Stack
|
|
717
|
+
* .contentType('')
|
|
718
|
+
* .entries()
|
|
719
|
+
* .notExists('emails')
|
|
720
|
+
* .find()
|
|
721
|
+
* .then((result) => {
|
|
722
|
+
* // filtered entries, where 'emails' property does not exist
|
|
723
|
+
* })
|
|
724
|
+
* .catch((error) => {
|
|
725
|
+
* // handle query errors
|
|
726
|
+
* })
|
|
727
|
+
*
|
|
728
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
729
|
+
*/
|
|
730
|
+
notExists(key) {
|
|
731
|
+
if (typeof key !== 'string') {
|
|
732
|
+
throw new Error('Kindly pass valid key for \'.notExists()\'');
|
|
733
|
+
}
|
|
734
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
735
|
+
this.q.query[key] = {
|
|
736
|
+
$exists: false,
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
this.q.query = {
|
|
741
|
+
[key]: {
|
|
742
|
+
$exists: false,
|
|
743
|
+
},
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
return this;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* @public
|
|
750
|
+
* @method contentType
|
|
751
|
+
* @summary Content type to query on
|
|
752
|
+
* @param {string} uid Content type uid
|
|
753
|
+
* @example
|
|
754
|
+
* Stack
|
|
755
|
+
* .contentType('blog')
|
|
756
|
+
* .entries()
|
|
757
|
+
* .find()
|
|
758
|
+
* .then((result) => {
|
|
759
|
+
* // returns entries filtered based on 'blog' content type
|
|
760
|
+
* })
|
|
761
|
+
* .catch((error) => {
|
|
762
|
+
* // handle query errors
|
|
763
|
+
* })
|
|
764
|
+
*
|
|
765
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
766
|
+
*/
|
|
767
|
+
contentType(uid) {
|
|
768
|
+
// create new instances, instead of re-using the old one
|
|
769
|
+
const stack = new Stack(this.config, this.db);
|
|
770
|
+
if (uid && typeof uid === 'string') {
|
|
771
|
+
stack.q.content_type_uid = uid;
|
|
772
|
+
return stack;
|
|
773
|
+
}
|
|
774
|
+
throw new Error('Kindly pass the content type\'s uid');
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* @public
|
|
778
|
+
* @method entry
|
|
779
|
+
* @summary Query for a single entry
|
|
780
|
+
* @param {string} uid Entry uid to be found, if not provided,
|
|
781
|
+
* by default returns the 1st element in the content type.
|
|
782
|
+
* Useful for `singleton` content types
|
|
783
|
+
* @example
|
|
784
|
+
* Stack
|
|
785
|
+
* .contentType('blog')
|
|
786
|
+
* .entry()
|
|
787
|
+
* .find()
|
|
788
|
+
* .then((result) => {
|
|
789
|
+
* // returns the entry based on its 'uid',
|
|
790
|
+
* // if not provided, it would return the 1st entry found in 'blog' content type
|
|
791
|
+
* })
|
|
792
|
+
* .catch((error) => {
|
|
793
|
+
* // handle query errors
|
|
794
|
+
* })
|
|
795
|
+
*
|
|
796
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
797
|
+
*/
|
|
798
|
+
entry(uid) {
|
|
799
|
+
if (!(this.q.content_type_uid)) {
|
|
800
|
+
throw new Error('Kindly call \'contentType()\' before \'entry()\'!');
|
|
801
|
+
}
|
|
802
|
+
if (uid && typeof uid === 'string') {
|
|
803
|
+
this.q.uid = uid;
|
|
804
|
+
}
|
|
805
|
+
this.internal.limit = 1;
|
|
806
|
+
this.internal.single = true;
|
|
807
|
+
return this;
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* @public
|
|
811
|
+
* @method entries
|
|
812
|
+
* @description
|
|
813
|
+
* Query for a set of entries on a content type
|
|
814
|
+
*
|
|
815
|
+
* @example
|
|
816
|
+
* Stack
|
|
817
|
+
* .contentType('blog')
|
|
818
|
+
* .entries()
|
|
819
|
+
* .find()
|
|
820
|
+
* .then((result) => {
|
|
821
|
+
* // returns entries filtered based on 'blog' content type
|
|
822
|
+
* })
|
|
823
|
+
* .catch((error) => {
|
|
824
|
+
* // handle query errors
|
|
825
|
+
* })
|
|
826
|
+
*
|
|
827
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
828
|
+
*/
|
|
829
|
+
entries() {
|
|
830
|
+
if (this.q.content_type_uid && typeof this.q.content_type_uid === 'string') {
|
|
831
|
+
return this;
|
|
832
|
+
}
|
|
833
|
+
throw new Error('Kindly call \'contentType()\' before \'entries()\'!');
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* @public
|
|
837
|
+
* @method asset
|
|
838
|
+
* @description
|
|
839
|
+
* Query for a single asset
|
|
840
|
+
*
|
|
841
|
+
* @param {string} uid Asset uid to be found, if not provided,
|
|
842
|
+
* by default returns the 1st element from assets.
|
|
843
|
+
* @example
|
|
844
|
+
* Stack
|
|
845
|
+
* .asset()
|
|
846
|
+
* .find()
|
|
847
|
+
* .then((result) => {
|
|
848
|
+
* // returns the asset based on its 'uid', if not provided, it would return the 1st asset found
|
|
849
|
+
* })
|
|
850
|
+
* .catch((error) => {
|
|
851
|
+
* // handle query errors
|
|
852
|
+
* })
|
|
853
|
+
*
|
|
854
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
855
|
+
*/
|
|
856
|
+
asset(uid) {
|
|
857
|
+
const stack = new Stack(this.config, this.db);
|
|
858
|
+
if (uid && typeof uid === 'string') {
|
|
859
|
+
stack.q.uid = uid;
|
|
860
|
+
}
|
|
861
|
+
stack.q.content_type_uid = this.types.assets;
|
|
862
|
+
// stack.collection = stack.db.collection(stack.contentStore.collectionName)
|
|
863
|
+
stack.internal.limit = 1;
|
|
864
|
+
stack.internal.single = true;
|
|
865
|
+
return stack;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* @public
|
|
869
|
+
* @method assets
|
|
870
|
+
* @description
|
|
871
|
+
* Query for a set of assets
|
|
872
|
+
*
|
|
873
|
+
* @example
|
|
874
|
+
* Stack
|
|
875
|
+
* .assets()
|
|
876
|
+
* .find()
|
|
877
|
+
* .then((result) => {
|
|
878
|
+
* // returns assets filtered based on 'blog' content type
|
|
879
|
+
* })
|
|
880
|
+
* .catch((error) => {
|
|
881
|
+
* // handle query errors
|
|
882
|
+
* })
|
|
883
|
+
*
|
|
884
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
885
|
+
*/
|
|
886
|
+
assets() {
|
|
887
|
+
const stack = new Stack(this.config, this.db);
|
|
888
|
+
stack.q.content_type_uid = this.types.assets;
|
|
889
|
+
// stack.collection = stack.db.collection(stack.contentStore.collectionName)
|
|
890
|
+
return stack;
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* @public
|
|
894
|
+
* @method schema
|
|
895
|
+
* @description
|
|
896
|
+
* Query for a single content type's schema
|
|
897
|
+
*
|
|
898
|
+
* @param {string} uid Content type uid to be found, if not provided,
|
|
899
|
+
* by default returns the 1st element from content types
|
|
900
|
+
*
|
|
901
|
+
* @example
|
|
902
|
+
* Stack
|
|
903
|
+
* .schema('blog')
|
|
904
|
+
* .find()
|
|
905
|
+
* .then((result) => {
|
|
906
|
+
* // returns content 'blog' content type's schema
|
|
907
|
+
* })
|
|
908
|
+
* .catch((error) => {
|
|
909
|
+
* // handle query errors
|
|
910
|
+
* })
|
|
911
|
+
*
|
|
912
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
913
|
+
*/
|
|
914
|
+
schema(uid) {
|
|
915
|
+
const stack = new Stack(this.config, this.db);
|
|
916
|
+
if (uid && typeof uid === 'string') {
|
|
917
|
+
stack.q.uid = uid;
|
|
918
|
+
}
|
|
919
|
+
stack.q.content_type_uid = this.types.content_types;
|
|
920
|
+
// stack.collection = stack.db.collection(stack.contentStore.collectionName)
|
|
921
|
+
stack.internal.limit = 1;
|
|
922
|
+
stack.internal.single = true;
|
|
923
|
+
return stack;
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* @public
|
|
927
|
+
* @method schemas
|
|
928
|
+
* @description
|
|
929
|
+
* Query for a set of content type schemas
|
|
930
|
+
* @example
|
|
931
|
+
* Stack
|
|
932
|
+
* .schemas()
|
|
933
|
+
* .find()
|
|
934
|
+
* .then((result) => {
|
|
935
|
+
* // returns a set of content type schemas
|
|
936
|
+
* })
|
|
937
|
+
* .catch((error) => {
|
|
938
|
+
* // handle query errors
|
|
939
|
+
* })
|
|
940
|
+
*
|
|
941
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
942
|
+
*/
|
|
943
|
+
schemas() {
|
|
944
|
+
const stack = new Stack(this.config, this.db);
|
|
945
|
+
stack.q.content_type_uid = this.types.content_types;
|
|
946
|
+
// stack.collection = stack.db.collection(stack.contentStore.collectionName)
|
|
947
|
+
return stack;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* @public
|
|
951
|
+
* @method contentTypes
|
|
952
|
+
* @description
|
|
953
|
+
* Query for a set of content type schemas
|
|
954
|
+
* @example
|
|
955
|
+
* Stack
|
|
956
|
+
* .contentTypes()
|
|
957
|
+
* .find()
|
|
958
|
+
* .then((result) => {
|
|
959
|
+
* // returns a set of content type schemas
|
|
960
|
+
* })
|
|
961
|
+
* .catch((error) => {
|
|
962
|
+
* // handle query errors
|
|
963
|
+
* })
|
|
964
|
+
*
|
|
965
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
966
|
+
*/
|
|
967
|
+
contentTypes() {
|
|
968
|
+
const stack = new Stack(this.config, this.db);
|
|
969
|
+
stack.q.content_type_uid = this.types.content_types;
|
|
970
|
+
// stack.collection = stack.db.collection(stack.contentStore.collectionName)
|
|
971
|
+
return stack;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* @public
|
|
975
|
+
* @method limit
|
|
976
|
+
* @description
|
|
977
|
+
* Parameter - used to limit the total no of items returned/scanned
|
|
978
|
+
* Defaults to 100 (internally, which is overridden)
|
|
979
|
+
* @param {number} no Max count of the 'items' returned
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* Stack
|
|
983
|
+
* .contentType('blog')
|
|
984
|
+
* .entries()
|
|
985
|
+
* .limit(20)
|
|
986
|
+
* .find()
|
|
987
|
+
* .then((result) => {
|
|
988
|
+
* // returns a maximum of 20 entries
|
|
989
|
+
* // if not provided, by default - the limit specified in config is returned
|
|
990
|
+
* })
|
|
991
|
+
* .catch((error) => {
|
|
992
|
+
* // handle query errors
|
|
993
|
+
* })
|
|
994
|
+
*
|
|
995
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
996
|
+
*/
|
|
997
|
+
limit(no) {
|
|
998
|
+
if (typeof no === 'number' && (no >= 0) && typeof this.q.content_type_uid === 'string') {
|
|
999
|
+
this.internal.limit = no;
|
|
1000
|
+
return this;
|
|
1001
|
+
}
|
|
1002
|
+
throw new Error('Kindly provide a valid \'numeric\' value for \'limit()\'');
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* @public
|
|
1006
|
+
* @method skip
|
|
1007
|
+
* @description
|
|
1008
|
+
* Parameter - used to skip initial no of items scanned
|
|
1009
|
+
* Defaults to 0 (internally, which is overridden)
|
|
1010
|
+
* @param {number} no Min count of the 'items' to be scanned
|
|
1011
|
+
*
|
|
1012
|
+
* @example
|
|
1013
|
+
* Stack
|
|
1014
|
+
* .contentType('blog')
|
|
1015
|
+
* .entries()
|
|
1016
|
+
* .skip(10)
|
|
1017
|
+
* .find()
|
|
1018
|
+
* .then((result) => {
|
|
1019
|
+
* // returnes entries, after first skipping 20 entries of 'blog' content type
|
|
1020
|
+
* // if not provided, by default - the skip value provided in config is considered
|
|
1021
|
+
* })
|
|
1022
|
+
* .catch((error) => {
|
|
1023
|
+
* // handle query errors
|
|
1024
|
+
* })
|
|
1025
|
+
*
|
|
1026
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1027
|
+
*/
|
|
1028
|
+
skip(no) {
|
|
1029
|
+
if (typeof no === 'number' && (no >= 0) && typeof this.q.content_type_uid === 'string') {
|
|
1030
|
+
this.internal.skip = no;
|
|
1031
|
+
return this;
|
|
1032
|
+
}
|
|
1033
|
+
throw new Error('Kindly provide a valid \'numeric\' value for \'skip()\'');
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* @public
|
|
1037
|
+
* @method query
|
|
1038
|
+
* @description
|
|
1039
|
+
* Wrapper around a raw query wrapper
|
|
1040
|
+
* @param {object} queryObject Query filter
|
|
1041
|
+
*
|
|
1042
|
+
* @example
|
|
1043
|
+
* Stack
|
|
1044
|
+
* .contentType('blog')
|
|
1045
|
+
* .entries()
|
|
1046
|
+
* .query({"group.heading": "Tab 1"})
|
|
1047
|
+
* .find()
|
|
1048
|
+
* .then((result) => {
|
|
1049
|
+
* // returns entries that have - {"group.heading": "Tab 1"}
|
|
1050
|
+
* })
|
|
1051
|
+
* .catch((error) => {
|
|
1052
|
+
* // handle query errors
|
|
1053
|
+
* })
|
|
1054
|
+
*
|
|
1055
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1056
|
+
*/
|
|
1057
|
+
query(queryObject = {}) {
|
|
1058
|
+
if (this.q.query && typeof this.q.query === 'object') {
|
|
1059
|
+
this.q.query = lodash_1.merge(this.q.query, queryObject);
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
this.q.query = queryObject;
|
|
1063
|
+
}
|
|
1064
|
+
return this;
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* @public
|
|
1068
|
+
* @method only
|
|
1069
|
+
* @description
|
|
1070
|
+
* Projections - returns only the fields passed here
|
|
1071
|
+
*
|
|
1072
|
+
* @param {array} fields Array of 'fields', separated by dot ('.') notation for embedded document query
|
|
1073
|
+
*
|
|
1074
|
+
* @example
|
|
1075
|
+
* Stack
|
|
1076
|
+
* .contentType('blog')
|
|
1077
|
+
* .entries()
|
|
1078
|
+
* .only(["title", "url", "links"])
|
|
1079
|
+
* .find()
|
|
1080
|
+
* .then((result) => {
|
|
1081
|
+
* // returns entries and projects only their - ["title", "url", "links"] properties
|
|
1082
|
+
* })
|
|
1083
|
+
* .catch((error) => {
|
|
1084
|
+
* // handle query errors
|
|
1085
|
+
* })
|
|
1086
|
+
*
|
|
1087
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1088
|
+
*/
|
|
1089
|
+
only(fields) {
|
|
1090
|
+
if (!fields || typeof fields !== 'object' || !(fields instanceof Array) || fields.length === 0) {
|
|
1091
|
+
throw new Error('Kindly provide valid \'field\' values for \'only()\'');
|
|
1092
|
+
}
|
|
1093
|
+
this.internal.only = this.internal.only || {};
|
|
1094
|
+
this.internal.only._id = 0;
|
|
1095
|
+
fields.forEach((field) => {
|
|
1096
|
+
if (typeof field === 'string') {
|
|
1097
|
+
this.internal.only[field] = 1;
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
return this;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* @public
|
|
1104
|
+
* @method except
|
|
1105
|
+
* @description
|
|
1106
|
+
* Projections - returns fields except the ones passed here
|
|
1107
|
+
*
|
|
1108
|
+
* @param {array} fields Array of 'fields', separated by dot ('.') notation for embedded document query
|
|
1109
|
+
* @example
|
|
1110
|
+
* Stack
|
|
1111
|
+
* .contentType('blog')
|
|
1112
|
+
* .entries()
|
|
1113
|
+
* .except(["title", "url", "links"])
|
|
1114
|
+
* .find()
|
|
1115
|
+
* .then((result) => {
|
|
1116
|
+
* // returns entries and projects all of their properties, except - ["title", "url", "links"]
|
|
1117
|
+
* })
|
|
1118
|
+
* .catch((error) => {
|
|
1119
|
+
* // handle query errors
|
|
1120
|
+
* })
|
|
1121
|
+
*
|
|
1122
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1123
|
+
*/
|
|
1124
|
+
except(fields) {
|
|
1125
|
+
if (!fields || typeof fields !== 'object' || !(fields instanceof Array) || fields.length === 0) {
|
|
1126
|
+
throw new Error('Kindly provide valid \'field\' values for \'except()\'');
|
|
1127
|
+
}
|
|
1128
|
+
this.internal.except = this.internal.except || {};
|
|
1129
|
+
fields.forEach((field) => {
|
|
1130
|
+
if (typeof field === 'string') {
|
|
1131
|
+
this.internal.except[field] = 0;
|
|
1132
|
+
}
|
|
1133
|
+
});
|
|
1134
|
+
this.internal.except = lodash_1.merge(this.contentStore.projections, this.internal.except);
|
|
1135
|
+
return this;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* @public
|
|
1139
|
+
* @method regex
|
|
1140
|
+
* @description
|
|
1141
|
+
* Raw regex to be applied on a field - wrapper
|
|
1142
|
+
*
|
|
1143
|
+
* @param {string} field Field on which the regex is to be applied on
|
|
1144
|
+
* @param {pattern} pattern Regex pattern
|
|
1145
|
+
* @param {options} options Options to be applied while evaluating the regex
|
|
1146
|
+
* @example
|
|
1147
|
+
* Stack
|
|
1148
|
+
* .contentType('blog')
|
|
1149
|
+
* .entries()
|
|
1150
|
+
* .regex("name", "^J")
|
|
1151
|
+
* .find()
|
|
1152
|
+
* .then((result) => {
|
|
1153
|
+
* // returns entries who's name properties start with "J"
|
|
1154
|
+
* })
|
|
1155
|
+
* .catch((error) => {
|
|
1156
|
+
* // handle query errors
|
|
1157
|
+
* })
|
|
1158
|
+
*
|
|
1159
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1160
|
+
*/
|
|
1161
|
+
regex(field, pattern, options = 'i') {
|
|
1162
|
+
if (!(field) || !(pattern) || typeof field !== 'string' || typeof pattern !== 'string') {
|
|
1163
|
+
throw new Error('Kindly provide a valid field and pattern value for \'.regex()\'');
|
|
1164
|
+
}
|
|
1165
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
1166
|
+
this.q.query = lodash_1.merge(this.q.query, {
|
|
1167
|
+
[field]: {
|
|
1168
|
+
$options: options,
|
|
1169
|
+
$regex: pattern,
|
|
1170
|
+
},
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
this.q.query = {
|
|
1175
|
+
[field]: {
|
|
1176
|
+
$options: options,
|
|
1177
|
+
$regex: pattern,
|
|
1178
|
+
},
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
return this;
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* @public
|
|
1185
|
+
* @method tags
|
|
1186
|
+
* @summary Match entries that match a specific tags
|
|
1187
|
+
*
|
|
1188
|
+
* @param {array} values Array of tag values
|
|
1189
|
+
* @example
|
|
1190
|
+
* Stack
|
|
1191
|
+
* .contentType('blog')
|
|
1192
|
+
* .entries()
|
|
1193
|
+
* .tags(["new", "fresh"])
|
|
1194
|
+
* .find()
|
|
1195
|
+
* .then((result) => {
|
|
1196
|
+
* // returns entries filtered based on their tag fields
|
|
1197
|
+
* })
|
|
1198
|
+
* .catch((error) => {
|
|
1199
|
+
* // handle query errors
|
|
1200
|
+
* })
|
|
1201
|
+
*
|
|
1202
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1203
|
+
*/
|
|
1204
|
+
tags(values) {
|
|
1205
|
+
if (!values || typeof values !== 'object' || !(values instanceof Array) || values.length === 0) {
|
|
1206
|
+
throw new Error('Kindly provide valid \'field\' values for \'tags()\'');
|
|
1207
|
+
}
|
|
1208
|
+
// filter non-string keys
|
|
1209
|
+
lodash_1.remove(values, (value) => {
|
|
1210
|
+
return typeof value !== 'string';
|
|
1211
|
+
});
|
|
1212
|
+
if (this.q.query && typeof this.q.query === 'object') {
|
|
1213
|
+
this.q.query.tags = {
|
|
1214
|
+
$in: values,
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
this.q.query = {
|
|
1219
|
+
tags: {
|
|
1220
|
+
$in: values,
|
|
1221
|
+
},
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
return this;
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* @public
|
|
1228
|
+
* @method where
|
|
1229
|
+
* @summary Pass JS expression or a full function to the query system
|
|
1230
|
+
* @description
|
|
1231
|
+
* Use the $where operator to pass either a string containing a JavaScript expression or a full JavaScript
|
|
1232
|
+
* function to the query system.
|
|
1233
|
+
* The $where provides greater flexibility, but requires that the database processes the JavaScript expression or
|
|
1234
|
+
* function for each document in the collection.
|
|
1235
|
+
* Reference the document in the JavaScript expression or function using either this or obj.
|
|
1236
|
+
* Only apply the $where query operator to top-level documents.
|
|
1237
|
+
* The $where query operator will not work inside a nested document, for instance, in an $elemMatch query.
|
|
1238
|
+
* Ref. - https://docs.mongodb.com/manual/reference/operator/query/where/index.html
|
|
1239
|
+
* @param { * } expr Pass either a string containing a JavaScript expression or a full JavaScript
|
|
1240
|
+
* function to the query system.
|
|
1241
|
+
* @example
|
|
1242
|
+
* Stack
|
|
1243
|
+
* .contentType('blog')
|
|
1244
|
+
* .entries()
|
|
1245
|
+
* .where(function() {
|
|
1246
|
+
* return (hex_md5(this.name) === "9b53e667f30cd329dca1ec9e6a83e994")
|
|
1247
|
+
* })
|
|
1248
|
+
* .find()
|
|
1249
|
+
* .then((result) => {
|
|
1250
|
+
* // returns entries filtered based on the $where condition provided
|
|
1251
|
+
* })
|
|
1252
|
+
* .catch((error) => {
|
|
1253
|
+
* // handle query errors
|
|
1254
|
+
* })
|
|
1255
|
+
*
|
|
1256
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1257
|
+
*/
|
|
1258
|
+
where(expr) {
|
|
1259
|
+
if (!(expr)) {
|
|
1260
|
+
throw new Error('Kindly provide a valid field and expr/fn value for \'.where()\'');
|
|
1261
|
+
}
|
|
1262
|
+
else if (this.q.query && typeof this.q.query === 'object') {
|
|
1263
|
+
if (typeof expr === 'function') {
|
|
1264
|
+
expr = expr.toString();
|
|
1265
|
+
}
|
|
1266
|
+
this.q.query = lodash_1.merge(this.q.query, {
|
|
1267
|
+
$where: expr,
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
else {
|
|
1271
|
+
if (typeof expr === 'function') {
|
|
1272
|
+
expr = expr.toString();
|
|
1273
|
+
}
|
|
1274
|
+
this.q.query = {
|
|
1275
|
+
$where: expr,
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
return this;
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* @public
|
|
1282
|
+
* @method includeCount
|
|
1283
|
+
* @description
|
|
1284
|
+
* Includes 'count' key in response, which is the total count of the items being returned
|
|
1285
|
+
*
|
|
1286
|
+
* @example
|
|
1287
|
+
* Stack
|
|
1288
|
+
* .contentType('blog')
|
|
1289
|
+
* .entries()
|
|
1290
|
+
* .includeCount()
|
|
1291
|
+
* .find()
|
|
1292
|
+
* .then((result) => {
|
|
1293
|
+
* // returns entries, along with a 'count' property, with the total count of entries being returned
|
|
1294
|
+
* })
|
|
1295
|
+
* .catch((error) => {
|
|
1296
|
+
* // handle query errors
|
|
1297
|
+
* })
|
|
1298
|
+
*
|
|
1299
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1300
|
+
*/
|
|
1301
|
+
includeCount() {
|
|
1302
|
+
this.internal.includeCount = true;
|
|
1303
|
+
return this;
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* @description
|
|
1307
|
+
* Includes 'content_type' key in response, which is the content type schema of the entries filtered/scanned
|
|
1308
|
+
* @example
|
|
1309
|
+
* Stack
|
|
1310
|
+
* .contentType('blog')
|
|
1311
|
+
* .entries()
|
|
1312
|
+
* .includeSchema()
|
|
1313
|
+
* .find()
|
|
1314
|
+
* .then((result) => {
|
|
1315
|
+
* // returns entries, along with a 'content_type' property, which is 'blog' content type's schema
|
|
1316
|
+
* })
|
|
1317
|
+
* .catch((error) => {
|
|
1318
|
+
* // handle query errors
|
|
1319
|
+
* })
|
|
1320
|
+
*
|
|
1321
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1322
|
+
*/
|
|
1323
|
+
includeSchema() {
|
|
1324
|
+
this.internal.includeSchema = true;
|
|
1325
|
+
return this;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* @public
|
|
1329
|
+
* @method includeContentType
|
|
1330
|
+
* @description
|
|
1331
|
+
* Includes 'content_type' key in response, which is the content type schema of the entries filtered/scanned
|
|
1332
|
+
* @example
|
|
1333
|
+
* Stack
|
|
1334
|
+
* .contentType('blog')
|
|
1335
|
+
* .entries()
|
|
1336
|
+
* .includeContentType()
|
|
1337
|
+
* .find()
|
|
1338
|
+
* .then((result) => {
|
|
1339
|
+
* // returns entries, along with a 'content_type' property, which is 'blog' content type's schema
|
|
1340
|
+
* })
|
|
1341
|
+
* .catch((error) => {
|
|
1342
|
+
* // handle query errors
|
|
1343
|
+
* })
|
|
1344
|
+
*
|
|
1345
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1346
|
+
*/
|
|
1347
|
+
includeContentType() {
|
|
1348
|
+
this.internal.includeSchema = true;
|
|
1349
|
+
return this;
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* @public
|
|
1353
|
+
* @method excludeReferences
|
|
1354
|
+
* @description
|
|
1355
|
+
* Excludes all references of the entries being scanned.
|
|
1356
|
+
* Note: On calling this, assets will not be binded in the result being returned.
|
|
1357
|
+
*
|
|
1358
|
+
* @example
|
|
1359
|
+
* Stack
|
|
1360
|
+
* .contentType('blog')
|
|
1361
|
+
* .entries()
|
|
1362
|
+
* .excludeReferences()
|
|
1363
|
+
* .find()
|
|
1364
|
+
* .then((result) => {
|
|
1365
|
+
* // returns entries, without any of its assets Or references
|
|
1366
|
+
* })
|
|
1367
|
+
* .catch((error) => {
|
|
1368
|
+
* // handle query errors
|
|
1369
|
+
* })
|
|
1370
|
+
*
|
|
1371
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1372
|
+
*/
|
|
1373
|
+
excludeReferences() {
|
|
1374
|
+
this.internal.excludeReferences = true;
|
|
1375
|
+
return this;
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* @public
|
|
1379
|
+
* @method queryReferences
|
|
1380
|
+
* @description
|
|
1381
|
+
* Wrapper, that allows querying on the entry's references.
|
|
1382
|
+
* Note: This is a slow method, since it scans all documents and fires the `reference`
|
|
1383
|
+
* query on them.Once the references are binded, the query object passed is used
|
|
1384
|
+
* for filtering
|
|
1385
|
+
* Use `.query()` filters to reduce the total no of documents being scanned
|
|
1386
|
+
*
|
|
1387
|
+
* @example
|
|
1388
|
+
* Stack
|
|
1389
|
+
* .contentType('blog')
|
|
1390
|
+
* .entries()
|
|
1391
|
+
* .queryReferences({"authors.name": "John Doe"})
|
|
1392
|
+
* .find()
|
|
1393
|
+
* .then((result) => {
|
|
1394
|
+
* // returns entries, who's reference author's name equals "John Doe"
|
|
1395
|
+
* })
|
|
1396
|
+
* .catch((error) => {
|
|
1397
|
+
* // handle query errors
|
|
1398
|
+
* })
|
|
1399
|
+
*
|
|
1400
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1401
|
+
*/
|
|
1402
|
+
queryReferences(query) {
|
|
1403
|
+
if (query && typeof query === 'object') {
|
|
1404
|
+
this.internal.queryReferences = query;
|
|
1405
|
+
return this;
|
|
1406
|
+
}
|
|
1407
|
+
throw new Error('Kindly pass a query object for \'.queryReferences()\'');
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* @public
|
|
1411
|
+
* @method getQuery
|
|
1412
|
+
* @description
|
|
1413
|
+
* Returns the query build thusfar
|
|
1414
|
+
* @example
|
|
1415
|
+
* const query = Stack
|
|
1416
|
+
* .contentType('blog')
|
|
1417
|
+
* .entries()
|
|
1418
|
+
* .getQuery()
|
|
1419
|
+
* // exposes details of the queries formed inside the SDK
|
|
1420
|
+
*
|
|
1421
|
+
* @returns {Stack} Returns an instance of 'stack'
|
|
1422
|
+
*/
|
|
1423
|
+
getQuery() {
|
|
1424
|
+
return Object.assign({}, this.q);
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* @public
|
|
1428
|
+
* @method includeReferences
|
|
1429
|
+
* @description
|
|
1430
|
+
* This method would return all the references of your queried entries (until depth 2)
|
|
1431
|
+
* Note: If you wish to increase the depth of the references fetched, call pass a numeric parameter
|
|
1432
|
+
* @example
|
|
1433
|
+
* Stack
|
|
1434
|
+
* .contentType('blog')
|
|
1435
|
+
* .entries()
|
|
1436
|
+
* .includeReferences(3)
|
|
1437
|
+
* @returns {Stack} Returns 'this' instance (of Stack)
|
|
1438
|
+
*/
|
|
1439
|
+
includeReferences(depth) {
|
|
1440
|
+
console.warn('.includeReferences() is a relatively slow query..!');
|
|
1441
|
+
if (typeof depth === 'number') {
|
|
1442
|
+
this.q.referenceDepth = depth;
|
|
1443
|
+
}
|
|
1444
|
+
this.internal.includeAllReferences = true;
|
|
1445
|
+
return this;
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* @public
|
|
1449
|
+
* @method include
|
|
1450
|
+
* @description
|
|
1451
|
+
* Pass in reference field uids, that you want included in your result.
|
|
1452
|
+
* If you want all the references, use .includeReferences()
|
|
1453
|
+
* @example
|
|
1454
|
+
* Stack.contentType('blog')
|
|
1455
|
+
* .entries()
|
|
1456
|
+
* .include(['related_blogs', 'authors.blogs']) // here related_blogs and authors.blogs are reference field uids
|
|
1457
|
+
* @param {object} fields An array of reference field uids
|
|
1458
|
+
* @returns {Stack} Returns 'this' instance (of Stack)
|
|
1459
|
+
*/
|
|
1460
|
+
include(fields) {
|
|
1461
|
+
if (fields.length === 0) {
|
|
1462
|
+
throw new Error('Kindly pass a valid reference field path to \'.include()\' ');
|
|
1463
|
+
}
|
|
1464
|
+
else if (typeof fields === 'string') {
|
|
1465
|
+
this.internal.includeSpecificReferences = [fields];
|
|
1466
|
+
}
|
|
1467
|
+
else {
|
|
1468
|
+
this.internal.includeSpecificReferences = fields;
|
|
1469
|
+
}
|
|
1470
|
+
return this;
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* @public
|
|
1474
|
+
* @method find
|
|
1475
|
+
* @description
|
|
1476
|
+
* Queries the db using the query built/passed
|
|
1477
|
+
* Does all the processing, filtering, referencing after querying the DB
|
|
1478
|
+
* @param {object} query Optional query object, that overrides all the
|
|
1479
|
+
* previously build queries
|
|
1480
|
+
* @public
|
|
1481
|
+
* @example
|
|
1482
|
+
* Stack
|
|
1483
|
+
* .contentType('blog')
|
|
1484
|
+
* .entries()
|
|
1485
|
+
* .find()
|
|
1486
|
+
* .then((result) => {
|
|
1487
|
+
* // returns blog content type's entries
|
|
1488
|
+
* })
|
|
1489
|
+
* .catch((error) => {
|
|
1490
|
+
* // handle query errors
|
|
1491
|
+
* })
|
|
1492
|
+
*
|
|
1493
|
+
* @returns {object} - Returns a objects, that have been processed, filtered and referenced
|
|
1494
|
+
*/
|
|
1495
|
+
find(query = {}) {
|
|
1496
|
+
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
1497
|
+
const queryFilters = this.preProcess(query);
|
|
1498
|
+
if (this.internal.sort) {
|
|
1499
|
+
this.collection = this.collection
|
|
1500
|
+
.find(queryFilters)
|
|
1501
|
+
.sort(this.internal.sort);
|
|
1502
|
+
}
|
|
1503
|
+
else {
|
|
1504
|
+
this.collection = this.collection
|
|
1505
|
+
.find(queryFilters);
|
|
1506
|
+
}
|
|
1507
|
+
if (this.internal.queryReferences) {
|
|
1508
|
+
this.collection = this.collection
|
|
1509
|
+
.project(this.internal.projections)
|
|
1510
|
+
.toArray();
|
|
1511
|
+
}
|
|
1512
|
+
else {
|
|
1513
|
+
this.collection = this.collection
|
|
1514
|
+
.project(this.internal.projections)
|
|
1515
|
+
.limit(this.internal.limit)
|
|
1516
|
+
.skip(this.internal.skip)
|
|
1517
|
+
.toArray();
|
|
1518
|
+
}
|
|
1519
|
+
return this.collection
|
|
1520
|
+
.then((result) => __awaiter(this, void 0, void 0, function* () {
|
|
1521
|
+
// Ignore references include, for empty list, exclude call, content type & assets
|
|
1522
|
+
if (result.length === 0 || this.internal.excludeReferences || this.q.content_type_uid === this
|
|
1523
|
+
.types.content_types || this.q.content_type_uid
|
|
1524
|
+
=== this.types.assets || (this.internal.onlyCount && !this.internal.queryReferences)) {
|
|
1525
|
+
// Do nothing
|
|
1526
|
+
}
|
|
1527
|
+
else if (this.internal.includeSpecificReferences) {
|
|
1528
|
+
yield this.includeSpecificReferences(result, this.q.content_type_uid, this.q.locale, this
|
|
1529
|
+
.internal.includeSpecificReferences);
|
|
1530
|
+
}
|
|
1531
|
+
else if (this.internal.includeAllReferences) {
|
|
1532
|
+
yield this.bindReferences(result, this.q.content_type_uid, this.q.locale);
|
|
1533
|
+
}
|
|
1534
|
+
else {
|
|
1535
|
+
yield this.includeAssetsOnly(result, this.q.content_type_uid, this.q.locale);
|
|
1536
|
+
}
|
|
1537
|
+
if (this.internal.queryReferences) {
|
|
1538
|
+
result = result.filter(sift_1.default(this.internal.queryReferences));
|
|
1539
|
+
if (this.internal.skip) {
|
|
1540
|
+
result = result.splice(this.internal.skip, this.internal.limit);
|
|
1541
|
+
}
|
|
1542
|
+
else if (this.internal.limit) {
|
|
1543
|
+
result = result.splice(0, this.internal.limit);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
result = yield this.postProcess(result);
|
|
1547
|
+
return resolve(result);
|
|
1548
|
+
}))
|
|
1549
|
+
.catch((error) => {
|
|
1550
|
+
this.cleanup();
|
|
1551
|
+
return reject(error);
|
|
1552
|
+
});
|
|
1553
|
+
}));
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* @public
|
|
1557
|
+
* @method count
|
|
1558
|
+
* @descriptionReturns the count of the entries/assets that match the filter
|
|
1559
|
+
* @param {object} query Optional query filter object
|
|
1560
|
+
* @public
|
|
1561
|
+
* @example
|
|
1562
|
+
* Stack
|
|
1563
|
+
* .contentType('blog')
|
|
1564
|
+
* .entries()
|
|
1565
|
+
* .count()
|
|
1566
|
+
* .then((result) => {
|
|
1567
|
+
* // returns entries, without any of its assets Or references
|
|
1568
|
+
* })
|
|
1569
|
+
* .catch((error) => {
|
|
1570
|
+
* // handle query errors
|
|
1571
|
+
* })
|
|
1572
|
+
*
|
|
1573
|
+
* @returns {object} Returns count of the entries/asset's matched
|
|
1574
|
+
*/
|
|
1575
|
+
count(query) {
|
|
1576
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1577
|
+
this.internal.onlyCount = true;
|
|
1578
|
+
return this.find(query);
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* @public
|
|
1583
|
+
* @method findOne
|
|
1584
|
+
* @deprecated - Use .fetch() instead
|
|
1585
|
+
* @description
|
|
1586
|
+
* Queries the db using the query built/passed. Returns a single entry/asset/content type object
|
|
1587
|
+
* Does all the processing, filtering, referencing after querying the DB
|
|
1588
|
+
* @param {object} query Optional query object, that overrides all the previously build queries
|
|
1589
|
+
*
|
|
1590
|
+
* @example
|
|
1591
|
+
* Stack
|
|
1592
|
+
* .contentType('blog')
|
|
1593
|
+
* .entries()
|
|
1594
|
+
* .findOne()
|
|
1595
|
+
*
|
|
1596
|
+
* @returns {object} - Returns an object, that has been processed, filtered and referenced
|
|
1597
|
+
*/
|
|
1598
|
+
findOne(query = {}) {
|
|
1599
|
+
this.internal.single = true;
|
|
1600
|
+
return this.find(query);
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* @public
|
|
1604
|
+
* @method fetch
|
|
1605
|
+
* @description
|
|
1606
|
+
* Queries the db using the query built/passed. Returns a single entry/asset/content type object
|
|
1607
|
+
* Does all the processing, filtering, referencing after querying the DB
|
|
1608
|
+
* @param {object} query Optional query object, that overrides all the previously build queries
|
|
1609
|
+
*
|
|
1610
|
+
* @example
|
|
1611
|
+
* Stack
|
|
1612
|
+
* .contentType('blog')
|
|
1613
|
+
* .entries()
|
|
1614
|
+
* .fetch()
|
|
1615
|
+
*
|
|
1616
|
+
* @returns {object} - Returns an object, that has been processed, filtered and referenced
|
|
1617
|
+
*/
|
|
1618
|
+
fetch(query = {}) {
|
|
1619
|
+
this.internal.single = true;
|
|
1620
|
+
return this.find(query);
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* @private
|
|
1624
|
+
* @method preProcess
|
|
1625
|
+
* @summary Internal method, that executes and formats the queries built/passed
|
|
1626
|
+
* @param {object} query Query filter/process object
|
|
1627
|
+
* @returns {object} Returns a query object, that has been processed to be queried in mongodb
|
|
1628
|
+
*/
|
|
1629
|
+
preProcess(query) {
|
|
1630
|
+
let queryFilters;
|
|
1631
|
+
if (this.q.query && typeof this.q.query === 'object') {
|
|
1632
|
+
this.q.query = lodash_1.merge(this.q.query, query);
|
|
1633
|
+
}
|
|
1634
|
+
else {
|
|
1635
|
+
this.q.query = {};
|
|
1636
|
+
}
|
|
1637
|
+
// tslint:disable-next-line: max-line-length
|
|
1638
|
+
this.q.referenceDepth = (typeof this.q.referenceDepth === 'number') ? this.q.referenceDepth : this.contentStore.referenceDepth;
|
|
1639
|
+
if (this.internal.only) {
|
|
1640
|
+
this.internal.projections = this.internal.only;
|
|
1641
|
+
}
|
|
1642
|
+
else {
|
|
1643
|
+
this.internal.projections = lodash_1.merge(this.contentStore.projections, this.internal.except);
|
|
1644
|
+
}
|
|
1645
|
+
// set default limit, if .limit() hasn't been called
|
|
1646
|
+
if (!(this.internal.limit)) {
|
|
1647
|
+
this.internal.limit = this.contentStore.limit;
|
|
1648
|
+
}
|
|
1649
|
+
// set default skip, if .skip() hasn't been called
|
|
1650
|
+
if (!(this.internal.skip)) {
|
|
1651
|
+
this.internal.skip = this.contentStore.skip;
|
|
1652
|
+
}
|
|
1653
|
+
// set default locale, if no locale has been passed
|
|
1654
|
+
if (!(this.q.locale)) {
|
|
1655
|
+
this.q.locale = this.contentStore.locale;
|
|
1656
|
+
}
|
|
1657
|
+
// by default, sort by latest content
|
|
1658
|
+
if (!this.internal.sort) {
|
|
1659
|
+
this.internal.sort = {
|
|
1660
|
+
updated_at: -1,
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
const filters = Object.assign({ _content_type_uid: this.q.content_type_uid, locale: this.q.locale }, this.q.query);
|
|
1664
|
+
if (this.q.content_type_uid === this.types.assets) {
|
|
1665
|
+
// allow querying only on published assets..!
|
|
1666
|
+
queryFilters = {
|
|
1667
|
+
$and: [
|
|
1668
|
+
filters,
|
|
1669
|
+
{
|
|
1670
|
+
_version: {
|
|
1671
|
+
$exists: true,
|
|
1672
|
+
},
|
|
1673
|
+
},
|
|
1674
|
+
],
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
else {
|
|
1678
|
+
queryFilters = filters;
|
|
1679
|
+
}
|
|
1680
|
+
this.collection = this.db.collection(util_1.getCollectionName({
|
|
1681
|
+
content_type_uid: this.q.content_type_uid,
|
|
1682
|
+
locale: this.q.locale,
|
|
1683
|
+
}, this.collectionNames));
|
|
1684
|
+
return queryFilters;
|
|
1685
|
+
}
|
|
1686
|
+
/**
|
|
1687
|
+
* @private
|
|
1688
|
+
* @method cleanup
|
|
1689
|
+
* @summary Does GC, so memory doesn't stackup
|
|
1690
|
+
*/
|
|
1691
|
+
cleanup() {
|
|
1692
|
+
this.collection = null;
|
|
1693
|
+
this.internal = null;
|
|
1694
|
+
this.q = null;
|
|
1695
|
+
}
|
|
1696
|
+
/**
|
|
1697
|
+
* @private
|
|
1698
|
+
* @method postProcess
|
|
1699
|
+
* @summary Internal method, that executes and formats the result, which the user and use
|
|
1700
|
+
* @param {object} result Result, which's to be manipulated
|
|
1701
|
+
* @returns {object} Returns the formatted version of the `result` object
|
|
1702
|
+
*/
|
|
1703
|
+
postProcess(result) {
|
|
1704
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1705
|
+
const count = (result === null) ? 0 : result.length;
|
|
1706
|
+
const output = {
|
|
1707
|
+
locale: this.q.locale,
|
|
1708
|
+
};
|
|
1709
|
+
if (this.internal.onlyCount) {
|
|
1710
|
+
output.content_type_uid = (this.q.content_type_uid === this.types.assets) ? 'assets' : ((this.q.content_type_uid
|
|
1711
|
+
=== this.types.content_types) ? 'content_types' : this.q.content_type_uid);
|
|
1712
|
+
output.count = count;
|
|
1713
|
+
return output;
|
|
1714
|
+
}
|
|
1715
|
+
switch (this.q.content_type_uid) {
|
|
1716
|
+
case this.types.assets:
|
|
1717
|
+
if (this.internal.single) {
|
|
1718
|
+
output.asset = (result === null) ? result : result[0];
|
|
1719
|
+
}
|
|
1720
|
+
else {
|
|
1721
|
+
output.assets = result;
|
|
1722
|
+
}
|
|
1723
|
+
output.content_type_uid = 'assets';
|
|
1724
|
+
break;
|
|
1725
|
+
case this.types.content_types:
|
|
1726
|
+
if (this.internal.single) {
|
|
1727
|
+
output.content_type = (result === null) ? result : result[0];
|
|
1728
|
+
}
|
|
1729
|
+
else {
|
|
1730
|
+
output.content_types = result;
|
|
1731
|
+
}
|
|
1732
|
+
output.content_type_uid = 'content_types';
|
|
1733
|
+
break;
|
|
1734
|
+
default:
|
|
1735
|
+
if (this.internal.single) {
|
|
1736
|
+
output.entry = (result === null) ? result : result[0];
|
|
1737
|
+
}
|
|
1738
|
+
else {
|
|
1739
|
+
output.entries = result;
|
|
1740
|
+
}
|
|
1741
|
+
output.content_type_uid = this.q.content_type_uid;
|
|
1742
|
+
break;
|
|
1743
|
+
}
|
|
1744
|
+
if (this.internal.includeCount) {
|
|
1745
|
+
output.count = yield this.db.collection(util_1.getCollectionName({
|
|
1746
|
+
content_type_uid: this.q.content_type_uid,
|
|
1747
|
+
locale: this.q.locale,
|
|
1748
|
+
}, this.collectionNames))
|
|
1749
|
+
.count({
|
|
1750
|
+
_content_type_uid: this.q.content_type_uid,
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
if (this.internal.includeSchema) {
|
|
1754
|
+
output.content_type = yield this.db.collection(util_1.getCollectionName({
|
|
1755
|
+
content_type_uid: this.types.content_types,
|
|
1756
|
+
locale: this.q.locale,
|
|
1757
|
+
}, this.collectionNames))
|
|
1758
|
+
.findOne({
|
|
1759
|
+
uid: this.q.content_type_uid,
|
|
1760
|
+
}, {
|
|
1761
|
+
_assets: 0,
|
|
1762
|
+
_content_type_uid: 0,
|
|
1763
|
+
_id: 0,
|
|
1764
|
+
_references: 0,
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
this.cleanup();
|
|
1768
|
+
return output;
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
includeAssetsOnly(entries, contentTypeUid, locale) {
|
|
1772
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1773
|
+
const schema = yield this.db
|
|
1774
|
+
.collection(util_1.getCollectionName({
|
|
1775
|
+
content_type_uid: this.types.content_types,
|
|
1776
|
+
locale,
|
|
1777
|
+
}, this.collectionNames))
|
|
1778
|
+
.findOne({
|
|
1779
|
+
_content_type_uid: this.types.content_types,
|
|
1780
|
+
uid: contentTypeUid,
|
|
1781
|
+
}, {
|
|
1782
|
+
_assets: 1,
|
|
1783
|
+
_id: 0,
|
|
1784
|
+
});
|
|
1785
|
+
if (schema === null || schema[this.types.assets] !== 'object') {
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
const paths = Object.keys(schema[this.types.assets]);
|
|
1789
|
+
const shelf = [];
|
|
1790
|
+
const queryBucket = {
|
|
1791
|
+
$or: [],
|
|
1792
|
+
};
|
|
1793
|
+
for (let i = 0, j = paths.length; i < j; i++) {
|
|
1794
|
+
this.fetchPathDetails(entries, locale, paths[i].split('.'), queryBucket, shelf, true, entries, 0);
|
|
1795
|
+
}
|
|
1796
|
+
if (shelf.length === 0) {
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
const assets = yield this.db.collection(util_1.getCollectionName({
|
|
1800
|
+
content_type_uid: this.types.assets,
|
|
1801
|
+
locale,
|
|
1802
|
+
}, this.collectionNames))
|
|
1803
|
+
.find(queryBucket)
|
|
1804
|
+
.project({
|
|
1805
|
+
_content_type_uid: 0,
|
|
1806
|
+
_id: 0,
|
|
1807
|
+
})
|
|
1808
|
+
.toArray();
|
|
1809
|
+
for (let l = 0, m = shelf.length; l < m; l++) {
|
|
1810
|
+
for (let n = 0, o = assets.length; n < o; n++) {
|
|
1811
|
+
if (shelf[l].uid === assets[n].uid) {
|
|
1812
|
+
shelf[l].path[shelf[l].position] = assets[n];
|
|
1813
|
+
break;
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
return;
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* @summary
|
|
1822
|
+
* Internal method, that iteratively calls itself and binds entries reference
|
|
1823
|
+
* @param {Object} entry - An entry or a collection of entries, who's references are to be found
|
|
1824
|
+
* @param {String} contentTypeUid - Content type uid
|
|
1825
|
+
* @param {String} locale - Locale, in which the reference is to be found
|
|
1826
|
+
* @param {Object} include - Array of field paths, to be included
|
|
1827
|
+
* @returns {Object} - Returns `entries`, that has all of its reference binded
|
|
1828
|
+
*/
|
|
1829
|
+
includeSpecificReferences(entries, contentTypeUid, locale, include) {
|
|
1830
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1831
|
+
const ctQuery = {
|
|
1832
|
+
_content_type_uid: this.types.content_types,
|
|
1833
|
+
uid: contentTypeUid,
|
|
1834
|
+
};
|
|
1835
|
+
const { paths, // ref. fields in the current content types
|
|
1836
|
+
pendingPath, // left over of *paths*
|
|
1837
|
+
schemaList, } = yield this.getReferencePath(ctQuery, locale, include);
|
|
1838
|
+
const queries = {
|
|
1839
|
+
$or: [],
|
|
1840
|
+
}; // reference field paths
|
|
1841
|
+
const shelf = []; // a mapper object, that holds pointer to the original element
|
|
1842
|
+
// iterate over each path in the entries and fetch the references
|
|
1843
|
+
// while fetching, keep track of their location
|
|
1844
|
+
for (let i = 0, j = paths.length; i < j; i++) {
|
|
1845
|
+
this.fetchPathDetails(entries, locale, paths[i].split('.'), queries, shelf, true, entries, 0);
|
|
1846
|
+
}
|
|
1847
|
+
// even after traversing, if no references were found, simply return the entries found thusfar
|
|
1848
|
+
if (shelf.length === 0) {
|
|
1849
|
+
return entries;
|
|
1850
|
+
}
|
|
1851
|
+
// else, self-recursively iterate and fetch references
|
|
1852
|
+
// Note: Shelf is the one holding `pointers` to the actual entry
|
|
1853
|
+
// Once the pointer has been used, for GC, point the object to null
|
|
1854
|
+
return this.includeReferenceIteration(queries, schemaList, locale, pendingPath, shelf);
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
fetchPathDetails(data, locale, pathArr, queryBucket, shelf, assetsOnly = false, parent, pos, counter = 0) {
|
|
1858
|
+
if (counter === (pathArr.length)) {
|
|
1859
|
+
if (data && typeof data === 'object') {
|
|
1860
|
+
if (data instanceof Array && data.length) {
|
|
1861
|
+
data.forEach((elem, idx) => {
|
|
1862
|
+
if (typeof elem === 'string') {
|
|
1863
|
+
queryBucket.$or.push({
|
|
1864
|
+
_content_type_uid: this.types.assets,
|
|
1865
|
+
_version: { $exists: true },
|
|
1866
|
+
locale,
|
|
1867
|
+
uid: elem,
|
|
1868
|
+
});
|
|
1869
|
+
shelf.push({
|
|
1870
|
+
path: data,
|
|
1871
|
+
position: idx,
|
|
1872
|
+
uid: elem,
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
else if (elem && typeof elem === 'object' && elem.hasOwnProperty('_content_type_uid')) {
|
|
1876
|
+
queryBucket.$or.push({
|
|
1877
|
+
_content_type_uid: elem._content_type_uid,
|
|
1878
|
+
locale,
|
|
1879
|
+
uid: elem.uid,
|
|
1880
|
+
});
|
|
1881
|
+
shelf.push({
|
|
1882
|
+
path: data,
|
|
1883
|
+
position: idx,
|
|
1884
|
+
uid: elem.uid,
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
else if (typeof data === 'object') {
|
|
1890
|
+
if (data.hasOwnProperty('_content_type_uid')) {
|
|
1891
|
+
queryBucket.$or.push({
|
|
1892
|
+
_content_type_uid: data._content_type_uid,
|
|
1893
|
+
locale,
|
|
1894
|
+
uid: data.uid,
|
|
1895
|
+
});
|
|
1896
|
+
shelf.push({
|
|
1897
|
+
path: parent,
|
|
1898
|
+
position: pos,
|
|
1899
|
+
uid: data.uid,
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
else if (typeof data === 'string') {
|
|
1905
|
+
queryBucket.$or.push({
|
|
1906
|
+
_content_type_uid: this.types.assets,
|
|
1907
|
+
_version: { $exists: true },
|
|
1908
|
+
locale,
|
|
1909
|
+
uid: data,
|
|
1910
|
+
});
|
|
1911
|
+
shelf.push({
|
|
1912
|
+
path: parent,
|
|
1913
|
+
position: pos,
|
|
1914
|
+
uid: data,
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
else {
|
|
1919
|
+
const currentField = pathArr[counter];
|
|
1920
|
+
counter++;
|
|
1921
|
+
if (data instanceof Array) {
|
|
1922
|
+
// tslint:disable-next-line: prefer-for-of
|
|
1923
|
+
for (let i = 0; i < data.length; i++) {
|
|
1924
|
+
if (data[i][currentField]) {
|
|
1925
|
+
this.fetchPathDetails(data[i][currentField], locale, pathArr, queryBucket, shelf, assetsOnly, data[i], currentField, counter);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
else {
|
|
1930
|
+
if (data[currentField]) {
|
|
1931
|
+
this.fetchPathDetails(data[currentField], locale, pathArr, queryBucket, shelf, assetsOnly, data, currentField, counter);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
// since we've reached last of the paths, return!
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
includeReferenceIteration(eQuery, ctQuery, locale, include, oldShelf) {
|
|
1939
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1940
|
+
if (oldShelf.length === 0 || ctQuery.$or.length === 0) {
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
const { paths, pendingPath, schemaList, } = yield this.getReferencePath(ctQuery, locale, include);
|
|
1944
|
+
const { result, queries, shelf, } = yield this.fetchEntries(eQuery, locale, paths, include);
|
|
1945
|
+
// GC to avoid mem leaks!
|
|
1946
|
+
eQuery = null;
|
|
1947
|
+
for (let i = 0, j = oldShelf.length; i < j; i++) {
|
|
1948
|
+
const element = oldShelf[i];
|
|
1949
|
+
let flag = true;
|
|
1950
|
+
for (let k = 0, l = result.length; k < l; k++) {
|
|
1951
|
+
if (result[k].uid === element.uid) {
|
|
1952
|
+
element.path[element.position] = result[k];
|
|
1953
|
+
flag = false;
|
|
1954
|
+
break;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
if (flag) {
|
|
1958
|
+
for (let e = 0, f = oldShelf[i].path.length; e < f; e++) {
|
|
1959
|
+
// tslint:disable-next-line: max-line-length
|
|
1960
|
+
if (oldShelf[i].path[e].hasOwnProperty('_content_type_uid') && Object.keys(oldShelf[i].path[e]).length === 2) {
|
|
1961
|
+
oldShelf[i].path.splice(e, 1);
|
|
1962
|
+
break;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
// GC to avoid mem leaks!
|
|
1968
|
+
oldShelf = null;
|
|
1969
|
+
// Iterative loops, that traverses paths and binds them onto entries
|
|
1970
|
+
yield this.includeReferenceIteration(queries, schemaList, locale, pendingPath, shelf);
|
|
1971
|
+
return;
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
getReferencePath(query, locale, currentInclude) {
|
|
1975
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1976
|
+
const schemas = yield this.db.collection(util_1.getCollectionName({
|
|
1977
|
+
content_type_uid: this.types.content_types,
|
|
1978
|
+
locale,
|
|
1979
|
+
}, this.collectionNames))
|
|
1980
|
+
.find(query)
|
|
1981
|
+
.project({
|
|
1982
|
+
_assets: 1,
|
|
1983
|
+
_id: 0,
|
|
1984
|
+
_references: 1,
|
|
1985
|
+
})
|
|
1986
|
+
.toArray();
|
|
1987
|
+
const pendingPath = [];
|
|
1988
|
+
const schemasReferred = [];
|
|
1989
|
+
const paths = [];
|
|
1990
|
+
const schemaList = {
|
|
1991
|
+
$or: [],
|
|
1992
|
+
};
|
|
1993
|
+
if (schemas.length === 0) {
|
|
1994
|
+
return {
|
|
1995
|
+
paths,
|
|
1996
|
+
pendingPath,
|
|
1997
|
+
schemaList,
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
let entryReferences = {};
|
|
2001
|
+
schemas.forEach((schema) => {
|
|
2002
|
+
// Entry references
|
|
2003
|
+
entryReferences = lodash_1.merge(entryReferences, schema[this.types.references]);
|
|
2004
|
+
// tslint:disable-next-line: forin
|
|
2005
|
+
for (const path in schema[this.types.assets]) {
|
|
2006
|
+
paths.push(path);
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
for (let i = 0, j = currentInclude.length; i < j; i++) {
|
|
2010
|
+
const includePath = currentInclude[i];
|
|
2011
|
+
// tslint:disable-next-line: forin
|
|
2012
|
+
for (const path in entryReferences) {
|
|
2013
|
+
const subStr = includePath.slice(0, path.length);
|
|
2014
|
+
if (subStr === path) {
|
|
2015
|
+
let subPath;
|
|
2016
|
+
// Its the complete path!! Hurrah!
|
|
2017
|
+
if (path.length !== includePath.length) {
|
|
2018
|
+
subPath = subStr;
|
|
2019
|
+
pendingPath.push(includePath.slice(path.length + 1));
|
|
2020
|
+
}
|
|
2021
|
+
else {
|
|
2022
|
+
subPath = includePath;
|
|
2023
|
+
}
|
|
2024
|
+
if (typeof entryReferences[path] === 'string') {
|
|
2025
|
+
schemasReferred.push({
|
|
2026
|
+
_content_type_uid: this.types.content_types,
|
|
2027
|
+
uid: entryReferences[path],
|
|
2028
|
+
});
|
|
2029
|
+
}
|
|
2030
|
+
else if (entryReferences[path].length) {
|
|
2031
|
+
entryReferences[path].forEach((contentTypeUid) => {
|
|
2032
|
+
schemasReferred.push({
|
|
2033
|
+
_content_type_uid: this.types.content_types,
|
|
2034
|
+
uid: contentTypeUid,
|
|
2035
|
+
});
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
paths.push(subPath);
|
|
2039
|
+
break;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
schemaList.$or = schemasReferred;
|
|
2044
|
+
return {
|
|
2045
|
+
// path, that's possible in the current schema
|
|
2046
|
+
paths,
|
|
2047
|
+
// paths, that's yet to be traversed
|
|
2048
|
+
pendingPath,
|
|
2049
|
+
// schemas, to be loaded!
|
|
2050
|
+
schemaList,
|
|
2051
|
+
};
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
fetchEntries(query, locale, paths, include, includeAll = false) {
|
|
2055
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2056
|
+
const result = yield this.db.collection(util_1.getCollectionName({
|
|
2057
|
+
content_type_uid: 'entries',
|
|
2058
|
+
locale,
|
|
2059
|
+
}, this.collectionNames))
|
|
2060
|
+
.find(query)
|
|
2061
|
+
.project({
|
|
2062
|
+
_content_type_uid: 0,
|
|
2063
|
+
_id: 0,
|
|
2064
|
+
_synced_at: 0,
|
|
2065
|
+
event_at: 0,
|
|
2066
|
+
})
|
|
2067
|
+
.toArray();
|
|
2068
|
+
const queries = {
|
|
2069
|
+
$or: [],
|
|
2070
|
+
};
|
|
2071
|
+
const shelf = [];
|
|
2072
|
+
if (result.length === 0) {
|
|
2073
|
+
return {
|
|
2074
|
+
queries,
|
|
2075
|
+
result,
|
|
2076
|
+
shelf,
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
if (include.length || includeAll) {
|
|
2080
|
+
paths.forEach((path) => {
|
|
2081
|
+
this.fetchPathDetails(result, locale, path.split('.'), queries, shelf, false, result, 0);
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
else {
|
|
2085
|
+
// if there are no includes, only fetch assets)
|
|
2086
|
+
paths.forEach((path) => {
|
|
2087
|
+
this.fetchPathDetails(result, locale, path.split('.'), queries, shelf, true, result, 0);
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2090
|
+
return {
|
|
2091
|
+
queries,
|
|
2092
|
+
result,
|
|
2093
|
+
shelf,
|
|
2094
|
+
};
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
bindReferences(entries, contentTypeUid, locale) {
|
|
2098
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2099
|
+
const ctQuery = {
|
|
2100
|
+
$or: [{
|
|
2101
|
+
_content_type_uid: this.types.content_types,
|
|
2102
|
+
uid: contentTypeUid,
|
|
2103
|
+
}],
|
|
2104
|
+
};
|
|
2105
|
+
const { paths, // ref. fields in the current content types
|
|
2106
|
+
ctQueries, } = yield this.getAllReferencePaths(ctQuery, locale);
|
|
2107
|
+
const queries = {
|
|
2108
|
+
$or: [],
|
|
2109
|
+
}; // reference field paths
|
|
2110
|
+
const objectPointerList = []; // a mapper object, that holds pointer to the original element
|
|
2111
|
+
// iterate over each path in the entries and fetch the references
|
|
2112
|
+
// while fetching, keep track of their location
|
|
2113
|
+
for (let i = 0, j = paths.length; i < j; i++) {
|
|
2114
|
+
this.fetchPathDetails(entries, locale, paths[i].split('.'), queries, objectPointerList, true, entries, 0);
|
|
2115
|
+
}
|
|
2116
|
+
// even after traversing, if no references were found, simply return the entries found thusfar
|
|
2117
|
+
if (objectPointerList.length === 0) {
|
|
2118
|
+
return entries;
|
|
2119
|
+
}
|
|
2120
|
+
// else, self-recursively iterate and fetch references
|
|
2121
|
+
// Note: Shelf is the one holding `pointers` to the actual entry
|
|
2122
|
+
// Once the pointer has been used, for GC, point the object to null
|
|
2123
|
+
return this.includeAllReferencesIteration(queries, ctQueries, locale, objectPointerList);
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
includeAllReferencesIteration(oldEntryQueries, oldCtQueries, locale, oldObjectPointerList, depth = 0) {
|
|
2127
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2128
|
+
if (depth > this.q.referenceDepth || oldObjectPointerList.length === 0 || oldCtQueries.$or.length === 0) {
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
const { ctQueries, paths, } = yield this.getAllReferencePaths(oldCtQueries, locale);
|
|
2132
|
+
// GC to aviod mem leaks
|
|
2133
|
+
oldCtQueries = null;
|
|
2134
|
+
const { result, queries, shelf, } = yield this.fetchEntries(oldEntryQueries, locale, paths, [], true);
|
|
2135
|
+
// GC to avoid mem leaks!
|
|
2136
|
+
oldEntryQueries = null;
|
|
2137
|
+
for (let i = 0, j = oldObjectPointerList.length; i < j; i++) {
|
|
2138
|
+
const element = oldObjectPointerList[i];
|
|
2139
|
+
let flag = true;
|
|
2140
|
+
for (let k = 0, l = result.length; k < l; k++) {
|
|
2141
|
+
if (result[k].uid === element.uid) {
|
|
2142
|
+
element.path[element.position] = result[k];
|
|
2143
|
+
flag = false;
|
|
2144
|
+
break;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
if (flag) {
|
|
2148
|
+
for (let e = 0, f = oldObjectPointerList[i].path.length; e < f; e++) {
|
|
2149
|
+
// tslint:disable-next-line: max-line-length
|
|
2150
|
+
if (oldObjectPointerList[i].path[e].hasOwnProperty('_content_type_uid') && Object.keys(oldObjectPointerList[i].path[e]).length === 2) {
|
|
2151
|
+
oldObjectPointerList[i].path.splice(e, 1);
|
|
2152
|
+
break;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
// GC to avoid mem leaks!
|
|
2158
|
+
oldObjectPointerList = null;
|
|
2159
|
+
++depth;
|
|
2160
|
+
// Iterative loops, that traverses paths and binds them onto entries
|
|
2161
|
+
yield this.includeAllReferencesIteration(queries, ctQueries, locale, shelf, depth);
|
|
2162
|
+
return;
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
getAllReferencePaths(contentTypeQueries, locale) {
|
|
2166
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2167
|
+
const contents = yield this.db
|
|
2168
|
+
.collection(util_1.getCollectionName({
|
|
2169
|
+
content_type_uid: this.types.content_types,
|
|
2170
|
+
locale,
|
|
2171
|
+
}, this.collectionNames))
|
|
2172
|
+
.find(contentTypeQueries)
|
|
2173
|
+
.project({
|
|
2174
|
+
_assets: 1,
|
|
2175
|
+
_references: 1,
|
|
2176
|
+
})
|
|
2177
|
+
.toArray();
|
|
2178
|
+
const ctQueries = {
|
|
2179
|
+
$or: [],
|
|
2180
|
+
};
|
|
2181
|
+
let paths = [];
|
|
2182
|
+
for (let i = 0, j = contents.length; i < j; i++) {
|
|
2183
|
+
let assetFieldPaths;
|
|
2184
|
+
let entryReferencePaths;
|
|
2185
|
+
if (contents[i].hasOwnProperty(this.types.assets)) {
|
|
2186
|
+
assetFieldPaths = Object.keys(contents[i][this.types.assets]);
|
|
2187
|
+
paths = paths.concat(assetFieldPaths);
|
|
2188
|
+
}
|
|
2189
|
+
if (contents[i].hasOwnProperty('_references')) {
|
|
2190
|
+
entryReferencePaths = Object.keys(contents[i][this.types.references]);
|
|
2191
|
+
paths = paths.concat(entryReferencePaths);
|
|
2192
|
+
for (let k = 0, l = entryReferencePaths.length; k < l; k++) {
|
|
2193
|
+
if (typeof contents[i][this.types.references][entryReferencePaths[k]] === 'string') {
|
|
2194
|
+
ctQueries.$or.push({
|
|
2195
|
+
_content_type_uid: this.types.content_types,
|
|
2196
|
+
// this would probably make it slow in FS, avoid this there?
|
|
2197
|
+
// locale,
|
|
2198
|
+
uid: contents[i][this.types.references][entryReferencePaths[k]],
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
else if (contents[i][this.types.references][entryReferencePaths[k]].length) {
|
|
2202
|
+
contents[i][this.types.references][entryReferencePaths[k]].forEach((uid) => {
|
|
2203
|
+
ctQueries.$or.push({
|
|
2204
|
+
_content_type_uid: this.types.content_types,
|
|
2205
|
+
// avoiding locale here, not sure if its required
|
|
2206
|
+
// locale,
|
|
2207
|
+
uid,
|
|
2208
|
+
});
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
return {
|
|
2215
|
+
ctQueries,
|
|
2216
|
+
paths,
|
|
2217
|
+
};
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
exports.Stack = Stack;
|
|
2222
|
+
</code></pre>
|
|
2223
|
+
</article>
|
|
2224
|
+
</section>
|
|
2225
|
+
|
|
2226
|
+
|
|
2227
|
+
|
|
2228
|
+
|
|
2229
|
+
</div>
|
|
2230
|
+
|
|
2231
|
+
<nav>
|
|
2232
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="global.html#Stack">Stack</a></li></ul><h3>Global</h3><ul><li><a href="global.html#and">and</a></li><li><a href="global.html#ascending">ascending</a></li><li><a href="global.html#asset">asset</a></li><li><a href="global.html#assets">assets</a></li><li><a href="global.html#close">close</a></li><li><a href="global.html#connect">connect</a></li><li><a href="global.html#containedIn">containedIn</a></li><li><a href="global.html#contentType">contentType</a></li><li><a href="global.html#contentTypes">contentTypes</a></li><li><a href="global.html#count">count</a></li><li><a href="global.html#descending">descending</a></li><li><a href="global.html#entries">entries</a></li><li><a href="global.html#entry">entry</a></li><li><a href="global.html#except">except</a></li><li><a href="global.html#excludeReferences">excludeReferences</a></li><li><a href="global.html#exists">exists</a></li><li><a href="global.html#fetch">fetch</a></li><li><a href="global.html#find">find</a></li><li><a href="global.html#findOne">findOne</a></li><li><a href="global.html#getQuery">getQuery</a></li><li><a href="global.html#greaterThan">greaterThan</a></li><li><a href="global.html#greaterThanOrEqualTo">greaterThanOrEqualTo</a></li><li><a href="global.html#include">include</a></li><li><a href="global.html#includeContentType">includeContentType</a></li><li><a href="global.html#includeCount">includeCount</a></li><li><a href="global.html#includeReferences">includeReferences</a></li><li><a href="global.html#language">language</a></li><li><a href="global.html#lessThan">lessThan</a></li><li><a href="global.html#lessThanOrEqualTo">lessThanOrEqualTo</a></li><li><a href="global.html#limit">limit</a></li><li><a href="global.html#notContainedIn">notContainedIn</a></li><li><a href="global.html#notEqualTo">notEqualTo</a></li><li><a href="global.html#notExists">notExists</a></li><li><a href="global.html#only">only</a></li><li><a href="global.html#or">or</a></li><li><a href="global.html#query">query</a></li><li><a href="global.html#queryReferences">queryReferences</a></li><li><a href="global.html#regex">regex</a></li><li><a href="global.html#schema">schema</a></li><li><a href="global.html#schemas">schemas</a></li><li><a href="global.html#skip">skip</a></li><li><a href="global.html#tags">tags</a></li><li><a href="global.html#where">where</a></li></ul>
|
|
2233
|
+
</nav>
|
|
2234
|
+
|
|
2235
|
+
<br class="clear">
|
|
2236
|
+
|
|
2237
|
+
<footer>
|
|
2238
|
+
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Sat Aug 03 2019 21:26:39 GMT+0530 (India Standard Time)
|
|
2239
|
+
</footer>
|
|
2240
|
+
|
|
2241
|
+
<script> prettyPrint(); </script>
|
|
2242
|
+
<script src="scripts/linenumber.js" integrity="gjKEaAtJoBN94tFHTJO/QMWm2iZN7DSXY/EAGrHzx30=%" crossorigin="anonymous"> </script>
|
|
2243
|
+
</body>
|
|
2244
|
+
</html>
|