1 | ;
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | return new (P || (P = Promise))(function (resolve, reject) {
|
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8 | });
|
9 | };
|
10 | var __generator = (this && this.__generator) || function (thisArg, body) {
|
11 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
|
12 | return { next: verb(0), "throw": verb(1), "return": verb(2) };
|
13 | function verb(n) { return function (v) { return step([n, v]); }; }
|
14 | function step(op) {
|
15 | if (f) throw new TypeError("Generator is already executing.");
|
16 | while (_) try {
|
17 | if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
|
18 | if (y = 0, t) op = [0, t.value];
|
19 | switch (op[0]) {
|
20 | case 0: case 1: t = op; break;
|
21 | case 4: _.label++; return { value: op[1], done: false };
|
22 | case 5: _.label++; y = op[1]; op = [0]; continue;
|
23 | case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
24 | default:
|
25 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
26 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
27 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
28 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
29 | if (t[2]) _.ops.pop();
|
30 | _.trys.pop(); continue;
|
31 | }
|
32 | op = body.call(thisArg, _);
|
33 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
34 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
35 | }
|
36 | };
|
37 | var Constants_1 = require("./Constants");
|
38 | var Types_1 = require("./Types");
|
39 | var Errors_1 = require("./Errors");
|
40 | var Log = require("./log");
|
41 | var Util_1 = require("./Util");
|
42 | var ModelMapper_1 = require("./ModelMapper");
|
43 | var MetadataManager_1 = require("./MetadataManager");
|
44 | var typeguard_1 = require("typeguard");
|
45 | // Logger
|
46 | var log = Log.create(__filename);
|
47 | /**
|
48 | * The core Repo implementation
|
49 | *
|
50 | * When requested from the coordinator,
|
51 | * it offers itself to all configured plugins for
|
52 | * them to attach to the model pipeline
|
53 | *
|
54 | *
|
55 | */
|
56 | var Repo = (function () {
|
57 | /**
|
58 | * Core repo is instantiated by providing the implementing/extending
|
59 | * class and the model that will be supported
|
60 | *
|
61 | * @param repoClazz
|
62 | * @param modelClazz
|
63 | */
|
64 | function Repo(repoClazz, modelClazz) {
|
65 | var _this = this;
|
66 | this.repoClazz = repoClazz;
|
67 | this.modelClazz = modelClazz;
|
68 | this.plugins = Array();
|
69 | this.getPlugins = function (predicate) { return _this.plugins.filter(predicate); };
|
70 | }
|
71 | Repo.prototype.getRepoPlugins = function () {
|
72 | return Util_1.PluginFilter(this.plugins, Types_1.PluginType.Repo);
|
73 | // return this.plugins
|
74 | // .filter((plugin) => isRepoPlugin(plugin)) as IRepoPlugin<M>[]
|
75 | };
|
76 | Repo.prototype.getFinderPlugins = function () {
|
77 | return Util_1.PluginFilter(this.plugins, Types_1.PluginType.Finder);
|
78 | };
|
79 | Repo.prototype.attr = function (name) {
|
80 | return this.modelType.options.attrs.find(function (attr) { return attr.name === name; });
|
81 | };
|
82 | Repo.prototype.init = function (coordinator) {
|
83 | this.coordinator = coordinator;
|
84 | this.modelType = coordinator.getModel(this.modelClazz);
|
85 | this.modelOpts = this.modelType.options;
|
86 | this.repoOpts = Reflect.getMetadata(Constants_1.TypeStoreRepoKey, this.repoClazz) || {};
|
87 | };
|
88 | Repo.prototype.start = function () {
|
89 | // Grab a mapper
|
90 | this.mapper = this.getMapper(this.modelClazz);
|
91 | // Decorate all the finders
|
92 | this.decorateFinders();
|
93 | };
|
94 | Repo.prototype.getMapper = function (clazz) {
|
95 | return ModelMapper_1.getDefaultMapper(clazz);
|
96 | };
|
97 | /**
|
98 | * Attach a plugin to the repo - could be a store,
|
99 | * indexer, etc, etc
|
100 | *
|
101 | * @param plugin
|
102 | * @returns {Repo}
|
103 | */
|
104 | Repo.prototype.attach = function (plugin) {
|
105 | if (this.plugins.includes(plugin)) {
|
106 | log.warn("Trying to register repo plugin a second time");
|
107 | }
|
108 | else {
|
109 | this.plugins.push(plugin);
|
110 | }
|
111 | return this;
|
112 | };
|
113 | Repo.prototype.getFinderOptions = function (finderKey) {
|
114 | return MetadataManager_1.getMetadata(Constants_1.TypeStoreFinderKey, this, finderKey);
|
115 | };
|
116 | /**
|
117 | * Decorate finder by iterating all finder plugins
|
118 | * and trying until resolved
|
119 | *
|
120 | * @param finderKey
|
121 | */
|
122 | Repo.prototype.decorateFinder = function (finderKey) {
|
123 | var finder;
|
124 | // Iterate all finder plugins
|
125 | for (var _i = 0, _a = this.getPlugins(Util_1.isFinderPlugin); _i < _a.length; _i++) {
|
126 | var plugin = _a[_i];
|
127 | if (!typeguard_1.isFunction(plugin.decorateFinder))
|
128 | continue;
|
129 | var finderPlugin = plugin;
|
130 | //let finderResult
|
131 | if (finder = finderPlugin.decorateFinder(this, finderKey)) {
|
132 | /**
|
133 | * If we got a promise back then we need to wait
|
134 | *
|
135 | * IE. pouch db creating an index
|
136 | */
|
137 | // if (isFunction(finderResult.then)) {
|
138 | // finder = (...args) => {
|
139 | // return (finderResult as Promise<any>).then(finderFn => {
|
140 | // if (!finderFn)
|
141 | // NotImplemented(`Promised finder is not available ${finderKey}`)
|
142 | //
|
143 | // return finderFn(...args)
|
144 | // })
|
145 | // }
|
146 | // } else {
|
147 | //
|
148 | // }
|
149 | //finder = finderResult
|
150 | break;
|
151 | }
|
152 | }
|
153 | if (!finder && this.getFinderOptions(finderKey).optional !== true)
|
154 | Errors_1.NotImplemented("No plugin supports this finder " + finderKey);
|
155 | this.setFinder(finderKey, finder);
|
156 | };
|
157 | /**
|
158 | * Decorate all finders on Repo
|
159 | */
|
160 | Repo.prototype.decorateFinders = function () {
|
161 | var _this = this;
|
162 | (Reflect.getMetadata(Constants_1.TypeStoreFindersKey, this) || [])
|
163 | .forEach(function (finderKey) { return _this.decorateFinder(finderKey); });
|
164 | };
|
165 | /**
|
166 | * Create a generic finder, in order
|
167 | * to do this search options must have been
|
168 | * annotated on the model
|
169 | *
|
170 | * @param finderKey
|
171 | * @param searchProvider
|
172 | * @param searchOpts
|
173 | * @returns {any}
|
174 | */
|
175 | Repo.prototype.makeGenericFinder = function (finderKey, searchProvider, searchOpts) {
|
176 | var _this = this;
|
177 | /**
|
178 | * Get the finder options
|
179 | * @type {any}
|
180 | */
|
181 | var opts = this.getFinderOptions(finderKey);
|
182 | return function () {
|
183 | var args = [];
|
184 | for (var _i = 0; _i < arguments.length; _i++) {
|
185 | args[_i] = arguments[_i];
|
186 | }
|
187 | return __awaiter(_this, void 0, void 0, function () {
|
188 | var _this = this;
|
189 | var results, keys;
|
190 | return __generator(this, function (_a) {
|
191 | switch (_a.label) {
|
192 | case 0: return [4 /*yield*/, searchProvider.search(this.modelType, searchOpts, args)];
|
193 | case 1:
|
194 | results = _a.sent();
|
195 | keys = results.map(function (result) {
|
196 | return searchOpts.resultKeyMapper(_this, searchOpts.resultType, result);
|
197 | });
|
198 | return [2 /*return*/, keys.map(function (key) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
199 | switch (_a.label) {
|
200 | case 0: return [4 /*yield*/, this.get(key)];
|
201 | case 1: return [2 /*return*/, _a.sent()];
|
202 | }
|
203 | }); }); })];
|
204 | }
|
205 | });
|
206 | });
|
207 | };
|
208 | };
|
209 | /**
|
210 | * Set a finder function on the repo
|
211 | *
|
212 | * @param finderKey
|
213 | * @param finderFn
|
214 | */
|
215 | Repo.prototype.setFinder = function (finderKey, finderFn) {
|
216 | this[finderKey] = finderFn;
|
217 | };
|
218 | /**
|
219 | * Triggers manually attached persistence callbacks
|
220 | * - works for internal indexing solutions, etc
|
221 | *
|
222 | * @param type
|
223 | * @param models
|
224 | */
|
225 | Repo.prototype.triggerPersistenceEvent = function (type) {
|
226 | var models = [];
|
227 | for (var _i = 1; _i < arguments.length; _i++) {
|
228 | models[_i - 1] = arguments[_i];
|
229 | }
|
230 | if (models.length < 1)
|
231 | return;
|
232 | var onPersistenceEvent = this.modelType.options.onPersistenceEvent;
|
233 | onPersistenceEvent && onPersistenceEvent.apply(void 0, [type].concat(models));
|
234 | };
|
235 | Repo.prototype.supportPersistenceEvents = function () {
|
236 | var onPersistenceEvent = this.modelType.options.onPersistenceEvent;
|
237 | return typeof onPersistenceEvent !== 'undefined' && onPersistenceEvent !== null;
|
238 | };
|
239 | /**
|
240 | * Call out to the indexers
|
241 | *
|
242 | * @param type
|
243 | * @param models
|
244 | * @returns {Bluebird<boolean>}
|
245 | */
|
246 | Repo.prototype.index = function (type) {
|
247 | var models = [];
|
248 | for (var _i = 1; _i < arguments.length; _i++) {
|
249 | models[_i - 1] = arguments[_i];
|
250 | }
|
251 | return __awaiter(this, void 0, void 0, function () {
|
252 | var _this = this;
|
253 | var indexPlugins, doIndex;
|
254 | return __generator(this, function (_a) {
|
255 | switch (_a.label) {
|
256 | case 0:
|
257 | indexPlugins = Util_1.PluginFilter(this.plugins, Types_1.PluginType.Indexer);
|
258 | doIndex = function (indexConfig) {
|
259 | return indexPlugins.map(function (plugin) { return plugin.index.apply(plugin, [type,
|
260 | indexConfig,
|
261 | _this.modelType,
|
262 | _this].concat(models)); });
|
263 | };
|
264 | if (!(this.repoOpts && this.repoOpts.indexes)) return [3 /*break*/, 2];
|
265 | return [4 /*yield*/, Promise.all(this.repoOpts.indexes.reduce(function (promises, indexConfig) {
|
266 | return promises.concat(doIndex(indexConfig));
|
267 | }, []))];
|
268 | case 1:
|
269 | _a.sent();
|
270 | _a.label = 2;
|
271 | case 2: return [2 /*return*/, Promise.resolve(true)];
|
272 | }
|
273 | });
|
274 | });
|
275 | };
|
276 | Repo.prototype.indexPromise = function (action) {
|
277 | var _this = this;
|
278 | return function (models) { return __awaiter(_this, void 0, void 0, function () {
|
279 | var indexPromise;
|
280 | return __generator(this, function (_a) {
|
281 | switch (_a.label) {
|
282 | case 0:
|
283 | indexPromise = this.index.apply(this, [action].concat(models.filter(function (model) { return !!model; })));
|
284 | return [4 /*yield*/, Promise.resolve(indexPromise)];
|
285 | case 1:
|
286 | _a.sent();
|
287 | return [2 /*return*/, models];
|
288 | }
|
289 | });
|
290 | }); };
|
291 | };
|
292 | /**
|
293 | * Not implemented
|
294 | *
|
295 | * @param args
|
296 | * @returns {null}
|
297 | */
|
298 | Repo.prototype.key = function () {
|
299 | var args = [];
|
300 | for (var _i = 0; _i < arguments.length; _i++) {
|
301 | args[_i] = arguments[_i];
|
302 | }
|
303 | for (var _a = 0, _b = this.getRepoPlugins(); _a < _b.length; _a++) {
|
304 | var plugin = _b[_a];
|
305 | var key = plugin.key.apply(plugin, args);
|
306 | if (key)
|
307 | return key;
|
308 | }
|
309 | return Errors_1.NotImplemented('key');
|
310 | };
|
311 | /**
|
312 | * Get one or more models with keys
|
313 | *
|
314 | * @param key
|
315 | * @returns {null}
|
316 | */
|
317 | Repo.prototype.get = function (key) {
|
318 | return __awaiter(this, void 0, void 0, function () {
|
319 | var _this = this;
|
320 | var results, _i, results_1, result;
|
321 | return __generator(this, function (_a) {
|
322 | results = this.getRepoPlugins().map(function (plugin) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
323 | switch (_a.label) {
|
324 | case 0: return [4 /*yield*/, plugin.get(key)];
|
325 | case 1: return [2 /*return*/, _a.sent()];
|
326 | }
|
327 | }); }); });
|
328 | for (_i = 0, results_1 = results; _i < results_1.length; _i++) {
|
329 | result = results_1[_i];
|
330 | if (result)
|
331 | return [2 /*return*/, result];
|
332 | }
|
333 | return [2 /*return*/, null];
|
334 | });
|
335 | });
|
336 | };
|
337 | /**
|
338 | * Save model
|
339 | *
|
340 | * @param o
|
341 | * @returns {null}
|
342 | */
|
343 | Repo.prototype.save = function (o) {
|
344 | return __awaiter(this, void 0, void 0, function () {
|
345 | var results, _i, results_2, result;
|
346 | return __generator(this, function (_a) {
|
347 | switch (_a.label) {
|
348 | case 0: return [4 /*yield*/, Util_1.PromiseMap(this.getRepoPlugins(), function (plugin) { return plugin.save(o); })];
|
349 | case 1:
|
350 | results = _a.sent();
|
351 | return [4 /*yield*/, this.indexPromise(Types_1.IndexAction.Add)(results)];
|
352 | case 2:
|
353 | _a.sent();
|
354 | for (_i = 0, results_2 = results; _i < results_2.length; _i++) {
|
355 | result = results_2[_i];
|
356 | if (result)
|
357 | return [2 /*return*/, result];
|
358 | }
|
359 | return [2 /*return*/, null];
|
360 | }
|
361 | });
|
362 | });
|
363 | };
|
364 | /**
|
365 | * Remove a model
|
366 | *
|
367 | * @param key
|
368 | * @returns {null}
|
369 | */
|
370 | Repo.prototype.remove = function (key) {
|
371 | return __awaiter(this, void 0, void 0, function () {
|
372 | var model;
|
373 | return __generator(this, function (_a) {
|
374 | switch (_a.label) {
|
375 | case 0: return [4 /*yield*/, this.get(key)];
|
376 | case 1:
|
377 | model = _a.sent();
|
378 | if (!model) {
|
379 | log.warn("No model found to remove with key", key);
|
380 | return [2 /*return*/, null];
|
381 | }
|
382 | return [4 /*yield*/, Util_1.PromiseMap(this.getRepoPlugins(), function (plugin) { return plugin.remove(key); })];
|
383 | case 2:
|
384 | _a.sent();
|
385 | return [2 /*return*/, this.indexPromise(Types_1.IndexAction.Remove)([model])];
|
386 | }
|
387 | });
|
388 | });
|
389 | };
|
390 | /**
|
391 | * Count models
|
392 | *
|
393 | * @returns {null}
|
394 | */
|
395 | Repo.prototype.count = function () {
|
396 | return __awaiter(this, void 0, void 0, function () {
|
397 | var _this = this;
|
398 | var results;
|
399 | return __generator(this, function (_a) {
|
400 | switch (_a.label) {
|
401 | case 0: return [4 /*yield*/, Promise.all(this.getRepoPlugins().map(function (plugin) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
402 | switch (_a.label) {
|
403 | case 0: return [4 /*yield*/, plugin.count()];
|
404 | case 1: return [2 /*return*/, _a.sent()];
|
405 | }
|
406 | }); }); }))];
|
407 | case 1:
|
408 | results = _a.sent();
|
409 | return [2 /*return*/, results.reduce(function (prev, current) { return prev + current; })];
|
410 | }
|
411 | });
|
412 | });
|
413 | };
|
414 | Repo.prototype.bulkGet = function () {
|
415 | var keys = [];
|
416 | for (var _i = 0; _i < arguments.length; _i++) {
|
417 | keys[_i] = arguments[_i];
|
418 | }
|
419 | return __awaiter(this, void 0, void 0, function () {
|
420 | var results;
|
421 | return __generator(this, function (_a) {
|
422 | switch (_a.label) {
|
423 | case 0: return [4 /*yield*/, Util_1.PromiseMap(this.getRepoPlugins(), function (plugin) { return plugin.bulkGet.apply(plugin, keys); })];
|
424 | case 1:
|
425 | results = _a.sent();
|
426 | return [2 /*return*/, results.reduce(function (allResults, result) {
|
427 | return allResults.concat(result);
|
428 | }, [])];
|
429 | }
|
430 | });
|
431 | });
|
432 | };
|
433 | Repo.prototype.bulkSave = function () {
|
434 | var models = [];
|
435 | for (var _i = 0; _i < arguments.length; _i++) {
|
436 | models[_i] = arguments[_i];
|
437 | }
|
438 | return __awaiter(this, void 0, void 0, function () {
|
439 | var results;
|
440 | return __generator(this, function (_a) {
|
441 | switch (_a.label) {
|
442 | case 0: return [4 /*yield*/, Util_1.PromiseMap(this.getRepoPlugins(), function (plugin) { return plugin.bulkSave.apply(plugin, models); })];
|
443 | case 1:
|
444 | results = _a.sent();
|
445 | results = results.reduce(function (allResults, result) {
|
446 | return allResults.concat(result);
|
447 | }, []);
|
448 | return [2 /*return*/, this.indexPromise(Types_1.IndexAction.Add)(results)];
|
449 | }
|
450 | });
|
451 | });
|
452 | };
|
453 | Repo.prototype.bulkRemove = function () {
|
454 | var keys = [];
|
455 | for (var _i = 0; _i < arguments.length; _i++) {
|
456 | keys[_i] = arguments[_i];
|
457 | }
|
458 | return __awaiter(this, void 0, void 0, function () {
|
459 | var models;
|
460 | return __generator(this, function (_a) {
|
461 | switch (_a.label) {
|
462 | case 0: return [4 /*yield*/, this.bulkGet.apply(this, keys)];
|
463 | case 1:
|
464 | models = _a.sent();
|
465 | if (models.length != keys.length)
|
466 | throw new Error('Not all keys exist');
|
467 | return [4 /*yield*/, Util_1.PromiseMap(this.getRepoPlugins(), function (plugin) { return plugin.bulkRemove.apply(plugin, keys); })];
|
468 | case 2:
|
469 | _a.sent();
|
470 | // results = results.reduce((allResults,result) => {
|
471 | // return allResults.concat(result)
|
472 | // },[])
|
473 | return [2 /*return*/, this.indexPromise(Types_1.IndexAction.Remove)(models)];
|
474 | }
|
475 | });
|
476 | });
|
477 | };
|
478 | return Repo;
|
479 | }());
|
480 | exports.Repo = Repo;
|
481 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVwby5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9SZXBvLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHlDQUlvQjtBQUVwQixpQ0FnQmdCO0FBR2hCLG1DQUF1QztBQUN2QywyQkFBNEI7QUFFNUIsK0JBSWU7QUFFZiw2Q0FBMEQ7QUFHMUQscURBQThDO0FBQzlDLHVDQUFzQztBQUV0QyxTQUFTO0FBQ1QsSUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQTtBQUdsQzs7Ozs7Ozs7R0FRRztBQUNIO0lBU0M7Ozs7OztPQU1HO0lBQ0gsY0FBbUIsU0FBYSxFQUFRLFVBQXNCO1FBQTlELGlCQUNDO1FBRGtCLGNBQVMsR0FBVCxTQUFTLENBQUk7UUFBUSxlQUFVLEdBQVYsVUFBVSxDQUFZO1FBVHBELFlBQU8sR0FBRyxLQUFLLEVBQVcsQ0FBQTtRQTBFcEMsZUFBVSxHQUFHLFVBQUMsU0FBb0IsSUFBSyxPQUFBLEtBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUE5QixDQUE4QixDQUFBO0lBaEVyRSxDQUFDO0lBRVMsNkJBQWMsR0FBeEI7UUFDQyxNQUFNLENBQUMsbUJBQVksQ0FBaUIsSUFBSSxDQUFDLE9BQU8sRUFBQyxrQkFBVSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ2pFLHNCQUFzQjtRQUN0QixpRUFBaUU7SUFDbEUsQ0FBQztJQUVTLCtCQUFnQixHQUExQjtRQUNDLE1BQU0sQ0FBQyxtQkFBWSxDQUFnQixJQUFJLENBQUMsT0FBTyxFQUFDLGtCQUFVLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDbkUsQ0FBQztJQUVELG1CQUFJLEdBQUosVUFBSyxJQUFXO1FBQ2YsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBQSxJQUFJLElB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 |
\ | No newline at end of file |