kuzzle 2.19.11 → 2.20.0

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.
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  * Kuzzle, a backend software, self-hostable and ready to use
3
4
  * to power modern apps
@@ -18,469 +19,383 @@
18
19
  * See the License for the specific language governing permissions and
19
20
  * limitations under the License.
20
21
  */
21
-
22
- "use strict";
23
-
24
- const Bluebird = require("bluebird");
25
-
26
- const cacheDbEnum = require("../cache/cacheDbEnum");
27
- const kerror = require("../../kerror");
28
-
29
- /**
30
- * @class Repository
31
- * @property {Kuzzle} kuzzle
32
- * @property {string} index
33
- * @property {number} ttl
34
- * @property {?string} collection
35
- * @property {function} ObjectConstructor
36
- * @property {cacheDbEnum} cacheDb
37
- * @property {Store} store
38
- */
39
- class Repository {
40
- /**
41
- * @param {{cache: cacheDbEnum, store: Store}} [options]
42
- * @constructor
43
- */
44
- constructor({ cache = cacheDbEnum.INTERNAL, store = null } = {}) {
45
- this.ttl = global.kuzzle.config.repositories.common.cacheTTL;
46
- this.collection = null;
47
- this.ObjectConstructor = null;
48
- this.store = store;
49
- this.index = store ? store.index : global.kuzzle.internalIndex.index;
50
- this.cacheDb = cache;
51
- }
52
-
53
- /**
54
- * @param {string} id
55
- * @returns {Promise} resolves on a new ObjectConstructor()
56
- */
57
- async loadOneFromDatabase(id) {
58
- let response;
59
-
60
- try {
61
- response = await this.store.get(this.collection, id);
62
- } catch (error) {
63
- if (error.status === 404) {
64
- throw kerror.get("services", "storage", "not_found", id);
65
- }
66
-
67
- throw error;
68
- }
69
-
70
- if (response._id) {
71
- const dto = {};
72
-
73
- if (response._source) {
74
- Object.assign(dto, response._source, { _id: response._id });
75
- } else {
76
- Object.assign(dto, response);
77
- }
78
-
79
- return this.fromDTO(dto);
22
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
80
27
  }
81
-
82
- return null;
83
- }
84
-
85
- /**
86
- *
87
- * @param {string[]|object[]} _ids
88
- * @returns {Promise<object>}
89
- */
90
- async loadMultiFromDatabase(ids) {
91
- const { items } = await this.store.mGet(this.collection, ids);
92
-
93
- if (items.length === 0) {
94
- return [];
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ var __importDefault = (this && this.__importDefault) || function (mod) {
46
+ return (mod && mod.__esModule) ? mod : { "default": mod };
47
+ };
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.Repository = void 0;
50
+ const cacheDbEnum_1 = __importDefault(require("../cache/cacheDbEnum"));
51
+ const kerror = __importStar(require("../../kerror"));
52
+ class Repository {
53
+ constructor({ cache = cacheDbEnum_1.default.INTERNAL, store = null } = {}) {
54
+ this.ttl = global.kuzzle.config.repositories.common.cacheTTL;
55
+ this.collection = null;
56
+ this.ObjectConstructor = null;
57
+ this.store = store;
58
+ this.index = store ? store.index : global.kuzzle.internalIndex.index;
59
+ this.cacheDb = cache;
95
60
  }
96
-
97
- return Bluebird.map(items, (doc) =>
98
- this.fromDTO(Object.assign({}, doc._source, { _id: doc._id }))
99
- );
100
- }
101
-
102
- /**
103
- * Search in database corresponding repository according to a query
104
- *
105
- * @param {object} searchBody
106
- * @param {object} [options] - optional search arguments (from, size, scroll)
107
- * @returns {Promise}
108
- */
109
- async search(searchBody, options = {}) {
110
- const response = await this.store.search(
111
- this.collection,
112
- searchBody,
113
- options
114
- );
115
-
116
- return this._formatSearchResults(response);
117
- }
118
-
119
- /**
120
- * Scroll over a paginated search request
121
- * @param {string} scrollId
122
- * @param {string} [ttl]
123
- */
124
- async scroll(scrollId, ttl) {
125
- const response = await this.store.scroll(scrollId, ttl);
126
-
127
- return this._formatSearchResults(response);
128
- }
129
-
130
- /**
131
- * Loads an object from Cache. Returns a promise that resolves either to the
132
- * retrieved object of null in case it is not found.
133
- *
134
- * The opts object currently accepts one optional parameter: key, which forces
135
- * the cache key to fetch.
136
- * In case the key is not provided, it defaults to repos/<index>/<collection>/<id>, i.e.: repos/%kuzzle/users/12
137
- *
138
- * @param {string} id - The id of the object to get
139
- * @param {object} [options] - Optional options.
140
- * @returns {Promise}
141
- */
142
- async loadFromCache(id, options = {}) {
143
- const key = options.key || this.getCacheKey(id);
144
- let response;
145
-
146
- try {
147
- response = await global.kuzzle.ask(`core:cache:${this.cacheDb}:get`, key);
148
-
149
- if (response === null) {
61
+ async loadOneFromDatabase(id) {
62
+ let response;
63
+ try {
64
+ response = await this.store.get(this.collection, id);
65
+ }
66
+ catch (error) {
67
+ if (error.status === 404) {
68
+ throw kerror.get("services", "storage", "not_found", id);
69
+ }
70
+ throw error;
71
+ }
72
+ if (response._id) {
73
+ const dto = {};
74
+ if (response._source) {
75
+ Object.assign(dto, response._source, { _id: response._id });
76
+ }
77
+ else {
78
+ Object.assign(dto, response);
79
+ }
80
+ return this.fromDTO(dto);
81
+ }
150
82
  return null;
151
- }
152
-
153
- return await this.fromDTO(Object.assign({}, JSON.parse(response)));
154
- } catch (err) {
155
- throw kerror.get("services", "cache", "read_failed", err.message);
156
83
  }
157
- }
158
-
159
- /**
160
- * Loads an object from Cache or from the Database if not available in Cache.
161
- * Returns a promise that resolves either to the
162
- * retrieved object of null in case it is not found.
163
- *
164
- * If the object is not found in Cache and found in the Database,
165
- * it will be written to cache also.
166
- *
167
- * The opts object currently accepts one optional parameter: key, which forces
168
- * the cache key to fetch.
169
- * In case the key is not provided, it defaults to <collection>/id
170
- * (e.g. users/12)
171
- *
172
- * @param {string} id - The id of the object to get
173
- * @param {object} [options] - Optional options.
174
- * @returns {Promise}
175
- */
176
- async load(id, options = {}) {
177
- if (this.cacheDb === cacheDbEnum.NONE) {
178
- return this.loadOneFromDatabase(id);
84
+ async loadMultiFromDatabase(ids) {
85
+ const { items } = await this.store.mGet(this.collection, ids);
86
+ if (items.length === 0) {
87
+ return [];
88
+ }
89
+ const promises = [];
90
+ for (const item of items) {
91
+ promises.push(this.fromDTO({
92
+ ...item._source,
93
+ _id: item._id,
94
+ }));
95
+ }
96
+ const objects = await Promise.all(promises);
97
+ return objects;
179
98
  }
180
-
181
- const object = await this.loadFromCache(id, options);
182
-
183
- if (object === null) {
184
- if (this.store === null) {
185
- return null;
186
- }
187
-
188
- const objectFromDatabase = await this.loadOneFromDatabase(id);
189
-
190
- if (objectFromDatabase !== null) {
191
- await this.persistToCache(objectFromDatabase);
192
- }
193
-
194
- return objectFromDatabase;
99
+ /**
100
+ * Search in database corresponding repository according to a query
101
+ *
102
+ * @param {object} searchBody
103
+ * @param {object} [options] - optional search arguments (from, size, scroll)
104
+ * @returns {Promise}
105
+ */
106
+ async search(searchBody, options = {}) {
107
+ const response = await this.store.search(this.collection, searchBody, options);
108
+ return this.formatSearchResults(response);
195
109
  }
196
-
197
- await this.refreshCacheTTL(object);
198
-
199
- return object;
200
- }
201
-
202
- /**
203
- * Persists the given object in the collection that is attached to the repository.
204
- *
205
- * @param {Profile|Role|User} object - The object to persist
206
- * @param {object} [options] - The persistence options
207
- * @returns {Promise}
208
- */
209
- persistToDatabase(object, options = {}) {
210
- const method = options.method || "createOrReplace";
211
-
212
- if (method === "create") {
213
- return this.store.create(
214
- this.collection,
215
- this.serializeToDatabase(object),
216
- { ...options, id: object._id }
217
- );
110
+ /**
111
+ * Scroll over a paginated search request
112
+ */
113
+ async scroll(scrollId, ttl) {
114
+ const response = await this.store.scroll(scrollId, ttl);
115
+ return this.formatSearchResults(response);
218
116
  }
219
-
220
- return this.store[method](
221
- this.collection,
222
- object._id,
223
- this.serializeToDatabase(object),
224
- options
225
- );
226
- }
227
-
228
- /**
229
- * Given an object with an id, delete it from the configured storage engines
230
- *
231
- * @param {object} object - The object to delete
232
- * The options optional parameters currently accepts only 1 option:
233
- * key: if provided, removes the given key instead of the default one (<collection>/<id>)
234
- * @param {object} [options] - optional options for the current operation
235
- * @returns {Promise}
236
- */
237
- delete(object, options = {}) {
238
- const promises = [];
239
-
240
- if (this.cacheDb !== cacheDbEnum.NONE) {
241
- promises.push(this.deleteFromCache(object._id, options));
117
+ /**
118
+ * Loads an object from Cache. Returns a promise that resolves either to the
119
+ * retrieved object of null in case it is not found.
120
+ *
121
+ * The opts object currently accepts one optional parameter: key, which forces
122
+ * the cache key to fetch.
123
+ * In case the key is not provided, it defaults to repos/<index>/<collection>/<id>, i.e.: repos/%kuzzle/users/12
124
+ *
125
+ * @param id - The id of the object to get
126
+ * @param options.key - Cache key.
127
+ */
128
+ async loadFromCache(id, options = {}) {
129
+ const key = options.key || this.getCacheKey(id);
130
+ let response;
131
+ try {
132
+ response = await global.kuzzle.ask(`core:cache:${this.cacheDb}:get`, key);
133
+ if (response === null) {
134
+ return null;
135
+ }
136
+ return await this.fromDTO(Object.assign({}, JSON.parse(response)));
137
+ }
138
+ catch (err) {
139
+ throw kerror.get("services", "cache", "read_failed", err.message);
140
+ }
242
141
  }
243
-
244
- if (this.store) {
245
- promises.push(this.deleteFromDatabase(object._id, options));
142
+ /**
143
+ * Loads an object from Cache or from the Database if not available in Cache.
144
+ * Returns a promise that resolves either to the
145
+ * retrieved object of null in case it is not found.
146
+ *
147
+ * If the object is not found in Cache and found in the Database,
148
+ * it will be written to cache also.
149
+ *
150
+ * The opts object currently accepts one optional parameter: key, which forces
151
+ * the cache key to fetch.
152
+ * In case the key is not provided, it defaults to <collection>/id
153
+ * (e.g. users/12)
154
+ *
155
+ * @param id - The id of the object to get
156
+ * @param options.key - Optional cache key
157
+ */
158
+ async load(id, options = {}) {
159
+ if (this.cacheDb === cacheDbEnum_1.default.NONE) {
160
+ return this.loadOneFromDatabase(id);
161
+ }
162
+ const object = await this.loadFromCache(id, options);
163
+ if (object === null) {
164
+ if (this.store === null) {
165
+ return null;
166
+ }
167
+ const objectFromDatabase = await this.loadOneFromDatabase(id);
168
+ if (objectFromDatabase !== null) {
169
+ await this.persistToCache(objectFromDatabase);
170
+ }
171
+ return objectFromDatabase;
172
+ }
173
+ await this.refreshCacheTTL(object);
174
+ return object;
246
175
  }
247
-
248
- return Bluebird.all(promises);
249
- }
250
-
251
- /**
252
- * Delete repository from database according to its id
253
- *
254
- * @param {string} id
255
- * @param {object} [options]
256
- */
257
- deleteFromDatabase(id, options = {}) {
258
- return this.store.delete(this.collection, id, options);
259
- }
260
-
261
- /**
262
- * Persists the given ObjectConstructor object in cache.
263
- * The opts optional parameters currently accept 2 options:
264
- * key: if provided, stores the object to the given key instead of the
265
- * default one (<collection>/<id>)
266
- * ttl: if provided, overrides the default ttl set on the repository for
267
- * the current operation.
268
- *
269
- * @param {object} object - The object to persist
270
- * @param {object} [options] - Optional options for the current operation
271
- * @returns {Promise}
272
- */
273
- async persistToCache(object, options = {}) {
274
- const key = options.key || this.getCacheKey(object._id);
275
- const value = JSON.stringify(this.serializeToCache(object));
276
- const ttl = options.ttl !== undefined ? options.ttl : this.ttl;
277
-
278
- await global.kuzzle.ask(`core:cache:${this.cacheDb}:store`, key, value, {
279
- ttl,
280
- });
281
-
282
- return object;
283
- }
284
-
285
- /**
286
- * Removes the object from the Cache Engine
287
- * The opts optional parameters currently accepts only 1 option:
288
- * key: if provided, removes the given key instead of the default one (<collection>/<id>)
289
- *
290
- * @param {string} id
291
- * @param {object} [options] - optional options for the current operation
292
- * @returns {Promise}
293
- */
294
- deleteFromCache(id, options = {}) {
295
- const key = options.key || this.getCacheKey(id);
296
-
297
- return global.kuzzle.ask(`core:cache:${this.cacheDb}:del`, key);
298
- }
299
-
300
- /**
301
- * @param {object} object
302
- * @param {object} [options] - optional options for the current operation
303
- * @returns {Promise}
304
- */
305
- refreshCacheTTL(object, options = {}) {
306
- const key = options.key || this.getCacheKey(object._id);
307
- let ttl;
308
-
309
- if (options.ttl !== undefined) {
310
- ttl = options.ttl;
311
- } else if (object.ttl !== undefined) {
312
- // if a TTL has been defined at the entry creation, we should
313
- // use it
314
- ttl = object.ttl;
315
- } else {
316
- ttl = this.ttl;
176
+ /**
177
+ * Persists the given object in the collection that is attached to the repository.
178
+ *
179
+ * @param object - The object to persist
180
+ * @param options.method -
181
+ * @returns {Promise}
182
+ */
183
+ persistToDatabase(object, options = {}) {
184
+ const method = options.method || "createOrReplace";
185
+ if (method === "create") {
186
+ return this.store.create(this.collection, this.serializeToDatabase(object), { ...options, id: object._id });
187
+ }
188
+ return this.store[method](this.collection, object._id, this.serializeToDatabase(object), options);
317
189
  }
318
-
319
- if (ttl > 0) {
320
- return global.kuzzle.ask(`core:cache:${this.cacheDb}:expire`, key, ttl);
190
+ /**
191
+ * Given an object with an id, delete it from the configured storage engines
192
+ *
193
+ * @param object - The object to delete
194
+ * @param options.key - if provided, removes the given key instead of the default one (<collection>/<id>)
195
+ */
196
+ async delete(object, options = {}) {
197
+ const promises = [];
198
+ if (this.cacheDb !== cacheDbEnum_1.default.NONE) {
199
+ promises.push(this.deleteFromCache(object._id, options));
200
+ }
201
+ if (this.store) {
202
+ promises.push(this.deleteFromDatabase(object._id, options));
203
+ }
204
+ await Promise.all(promises);
321
205
  }
322
-
323
- return global.kuzzle.ask(`core:cache:${this.cacheDb}:persist`, key);
324
- }
325
-
326
- /**
327
- * @param {object} object
328
- * @param {object} [options] - optional options for the current operation
329
- * @returns {*}
330
- */
331
- expireFromCache(object, options = {}) {
332
- const key = options.key || this.getCacheKey(object._id);
333
- return global.kuzzle.ask(`core:cache:${this.cacheDb}:expire`, key, -1);
334
- }
335
-
336
- /**
337
- * Serializes the object before being persisted to cache.
338
- *
339
- * @param {object} object - The object to serialize
340
- * @returns {object}
341
- */
342
- serializeToCache(object) {
343
- return this.toDTO(object);
344
- }
345
-
346
- /**
347
- * Serializes the object before being persisted to the database.
348
- *
349
- * @param {object} object - The object to serialize
350
- * @returns {object}
351
- */
352
- serializeToDatabase(object) {
353
- const dto = this.toDTO(object);
354
- delete dto._id;
355
- return dto;
356
- }
357
-
358
- /**
359
- * @param {string} id
360
- */
361
- getCacheKey(id) {
362
- return `repos/${this.index}/${this.collection}/${id}`;
363
- }
364
-
365
- /**
366
- * @param {object} dto
367
- * @returns {Promise<ObjectConstructor>}
368
- */
369
- async fromDTO(dto) {
370
- const o = new this.ObjectConstructor();
371
- Object.assign(o, dto);
372
-
373
- return o;
374
- }
375
-
376
- /**
377
- * @param {ObjectConstructor} o
378
- * @returns {object}
379
- */
380
- toDTO(o) {
381
- return Object.assign({}, o);
382
- }
383
-
384
- /**
385
- * Recursively delete all objects in repository with a scroll
386
- *
387
- * @param {object} options - ES options (refresh)
388
- * @param {object} part
389
- * @returns {Promise<integer>} total deleted objects
390
- */
391
- async truncate(options) {
392
- // Allows safe overrides, as _truncate is called recursively
393
- return this._truncate(options);
394
- }
395
-
396
- /**
397
- * Do not override this: this function calls itself.
398
- * @private
399
- */
400
- async _truncate(options, part = null) {
401
- if (part === null) {
402
- const objects = await this.search(
403
- {},
404
- { refresh: options.refresh, scroll: "5s", size: 100 }
405
- );
406
- const deleted = await this._truncatePart(objects, options);
407
-
408
- if (objects.hits.length < objects.total) {
409
- const total = await this._truncate(options, {
410
- fetched: objects.hits.length,
411
- scrollId: objects.scrollId,
412
- total: objects.total,
206
+ /**
207
+ * Delete repository from database according to its id
208
+ */
209
+ deleteFromDatabase(id, options = {}) {
210
+ return this.store.delete(this.collection, id, options);
211
+ }
212
+ /**
213
+ * Persists the given ObjectConstructor object in cache.
214
+ *
215
+ * @param object - The object to persist
216
+ * @param options.key - if provided, stores the object to the given key instead of the default one (<collection>/<id>)
217
+ * @param options.ttl - if provided, overrides the default ttl set on the repository for the current operation
218
+ */
219
+ async persistToCache(object, options = {}) {
220
+ const key = options.key || this.getCacheKey(object._id);
221
+ const value = JSON.stringify(this.serializeToCache(object));
222
+ const ttl = options.ttl !== undefined ? options.ttl : this.ttl;
223
+ await global.kuzzle.ask(`core:cache:${this.cacheDb}:store`, key, value, {
224
+ ttl,
413
225
  });
414
-
415
- return deleted + total;
416
- }
417
-
418
- return deleted;
226
+ return object;
419
227
  }
420
-
421
- const objects = await this.scroll(part.scrollId, "5s");
422
- const deleted = await this._truncatePart(objects, options);
423
-
424
- part.fetched += objects.hits.length;
425
-
426
- if (part.fetched < part.total) {
427
- part.scrollId = objects.scrollId;
428
-
429
- const total = await this._truncate(options, part);
430
- return deleted + total;
228
+ /**
229
+ * Removes the object from the Cache Engine
230
+ *
231
+ * @param id
232
+ * @param options.key - if provided, stores the object to the given key instead of the default one (<collection>/<id>)
233
+ */
234
+ async deleteFromCache(id, options = {}) {
235
+ const key = options.key || this.getCacheKey(id);
236
+ await global.kuzzle.ask(`core:cache:${this.cacheDb}:del`, key);
431
237
  }
432
-
433
- return deleted;
434
- }
435
-
436
- /**
437
- * @param {Array} objects
438
- * @param {object} options
439
- * @returns {Promise<integer>} count of deleted objects
440
- * @private
441
- */
442
- async _truncatePart(objects, options) {
443
- return Bluebird.map(objects.hits, async (object) => {
444
- // profile and role repositories have protected objects, we can't delete
445
- // them
446
- const protectedObjects =
447
- ["profiles", "roles"].indexOf(this.collection) !== -1
448
- ? ["admin", "default", "anonymous"]
449
- : [];
450
-
451
- if (protectedObjects.indexOf(object._id) !== -1) {
452
- return 0;
453
- }
454
-
455
- const loaded = await this.load(object._id);
456
- await this.delete(loaded, options);
457
-
458
- return 1;
459
- }).reduce((total, deleted) => total + deleted, 0);
460
- }
461
-
462
- /**
463
- * Given a raw search response from ES, returns a {total: int, hits: []} object
464
- * @param {object} raw
465
- * @returns {Promise<object>}
466
- * @private
467
- */
468
- async _formatSearchResults(raw) {
469
- const result = {
470
- aggregations: raw.aggregations,
471
- hits: [],
472
- scrollId: raw.scrollId,
473
- total: raw.total,
474
- };
475
-
476
- if (raw.hits && raw.hits.length > 0) {
477
- result.hits = await Bluebird.map(raw.hits, (doc) => {
478
- return this.fromDTO(Object.assign({}, doc._source, { _id: doc._id }));
479
- });
238
+ /**
239
+ * @param object
240
+ * @param options.key - if provided, stores the object to the given key instead of the default one (<collection>/<id>)
241
+ * @param options.ttl - if provided, overrides the default ttl set on the repository for the current operation
242
+ */
243
+ refreshCacheTTL(object, options = {}) {
244
+ const key = options.key || this.getCacheKey(object._id);
245
+ let ttl;
246
+ if (options.ttl !== undefined) {
247
+ ttl = options.ttl;
248
+ }
249
+ else if (object.ttl !== undefined) {
250
+ // if a TTL has been defined at the entry creation, we should
251
+ // use it
252
+ ttl = object.ttl;
253
+ }
254
+ else {
255
+ ttl = this.ttl;
256
+ }
257
+ if (ttl > 0) {
258
+ return global.kuzzle.ask(`core:cache:${this.cacheDb}:expire`, key, ttl);
259
+ }
260
+ return global.kuzzle.ask(`core:cache:${this.cacheDb}:persist`, key);
261
+ }
262
+ /**
263
+ * @param object
264
+ * @param options.key - if provided, stores the object to the given key instead of the default one (<collection>/<id>)
265
+ */
266
+ async expireFromCache(object, options = {}) {
267
+ const key = options.key || this.getCacheKey(object._id);
268
+ await global.kuzzle.ask(`core:cache:${this.cacheDb}:expire`, key, -1);
269
+ }
270
+ /**
271
+ * Serializes the object before being persisted to cache.
272
+ *
273
+ * @param object - The object to serialize
274
+ */
275
+ serializeToCache(object) {
276
+ return this.toDTO(object);
277
+ }
278
+ /**
279
+ * Serializes the object before being persisted to the database.
280
+ *
281
+ * @param object - The object to serialize
282
+ */
283
+ serializeToDatabase(object) {
284
+ const dto = this.toDTO(object);
285
+ delete dto._id;
286
+ return dto;
287
+ }
288
+ /**
289
+ * @param {string} id
290
+ */
291
+ getCacheKey(id) {
292
+ return `repos/${this.index}/${this.collection}/${id}`;
293
+ }
294
+ /**
295
+ * @param {object} dto
296
+ * @returns {Promise<ObjectConstructor>}
297
+ */
298
+ async fromDTO(dto) {
299
+ const o = new this.ObjectConstructor();
300
+ Object.assign(o, dto);
301
+ return o;
302
+ }
303
+ /**
304
+ * @param {ObjectConstructor} o
305
+ * @returns {object}
306
+ */
307
+ toDTO(o) {
308
+ return Object.assign({}, o);
309
+ }
310
+ /**
311
+ * Recursively delete all objects in repository with a scroll
312
+ *
313
+ * @param {object} options - ES options (refresh)
314
+ * @param {object} part
315
+ * @returns {Promise<integer>} total deleted objects
316
+ */
317
+ async truncate(options) {
318
+ // Allows safe overrides, as _truncate is called recursively
319
+ return this._truncate(options);
320
+ }
321
+ /**
322
+ * Do not override this: this function calls itself.
323
+ */
324
+ async _truncate(options, part = null) {
325
+ if (part === null) {
326
+ const objects = await this.search({}, { refresh: options.refresh, scroll: "5s", size: 100 });
327
+ const deleted = await this.truncatePart(objects, options);
328
+ if (objects.hits.length < objects.total) {
329
+ const total = await this._truncate(options, {
330
+ fetched: objects.hits.length,
331
+ scrollId: objects.scrollId,
332
+ total: objects.total,
333
+ });
334
+ return deleted + total;
335
+ }
336
+ return deleted;
337
+ }
338
+ const objects = await this.scroll(part.scrollId, "5s");
339
+ const deleted = await this.truncatePart(objects, options);
340
+ part.fetched += objects.hits.length;
341
+ if (part.fetched < part.total) {
342
+ part.scrollId = objects.scrollId;
343
+ const total = await this._truncate(options, part);
344
+ return deleted + total;
345
+ }
346
+ return deleted;
347
+ }
348
+ /**
349
+ * @param {Array} objects
350
+ * @param {object} options
351
+ * @returns {Promise<integer>} count of deleted objects
352
+ */
353
+ async truncatePart(objects, options) {
354
+ const promises = [];
355
+ const processObject = async (object) => {
356
+ // profile and role repositories have protected objects, we can't delete
357
+ // them
358
+ const protectedObjects = ["profiles", "roles"].indexOf(this.collection) !== -1
359
+ ? ["admin", "default", "anonymous"]
360
+ : [];
361
+ if (protectedObjects.indexOf(object._id) !== -1) {
362
+ return 0;
363
+ }
364
+ const loaded = await this.load(object._id);
365
+ await this.delete(loaded, options);
366
+ return 1;
367
+ };
368
+ for (const hit of objects.hits) {
369
+ promises.push(processObject(hit));
370
+ }
371
+ const results = await Promise.all(promises);
372
+ return results.reduce((total, deleted) => total + deleted, 0);
373
+ }
374
+ /**
375
+ * Given a raw search response from ES, returns a {total: int, hits: []} object
376
+ * @param {object} raw
377
+ * @returns {Promise<object>}
378
+ * @private
379
+ */
380
+ async formatSearchResults(raw) {
381
+ const result = {
382
+ aggregations: raw.aggregations,
383
+ hits: [],
384
+ scrollId: raw.scrollId,
385
+ total: raw.total,
386
+ };
387
+ if (raw.hits && raw.hits.length > 0) {
388
+ const promises = [];
389
+ for (const hit of raw.hits) {
390
+ promises.push(this.fromDTO({
391
+ ...hit._source,
392
+ _id: hit._id,
393
+ }));
394
+ }
395
+ result.hits = await Promise.all(promises);
396
+ }
397
+ return result;
480
398
  }
481
-
482
- return result;
483
- }
484
399
  }
485
-
486
- module.exports = Repository;
400
+ exports.Repository = Repository;
401
+ //# sourceMappingURL=repository.js.map