@webda/core 1.6.0-beta.2 → 2.0.0-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.
Files changed (253) hide show
  1. package/lib/application.d.ts +351 -195
  2. package/lib/application.js +188 -682
  3. package/lib/application.js.map +1 -1
  4. package/lib/application.spec.js +109 -289
  5. package/lib/application.spec.js.map +1 -1
  6. package/lib/core.d.ts +108 -214
  7. package/lib/core.js +169 -71
  8. package/lib/core.js.map +1 -1
  9. package/lib/core.spec.js +103 -42
  10. package/lib/core.spec.js.map +1 -1
  11. package/lib/index.d.ts +4 -0
  12. package/lib/index.js +9 -1
  13. package/lib/index.js.map +1 -1
  14. package/lib/models/aclmodel.d.ts +3 -1
  15. package/lib/models/aclmodel.js +6 -3
  16. package/lib/models/aclmodel.js.map +1 -1
  17. package/lib/models/aclmodel.spec.js +10 -5
  18. package/lib/models/aclmodel.spec.js.map +1 -1
  19. package/lib/models/coremodel.d.ts +11 -18
  20. package/lib/models/coremodel.js +36 -36
  21. package/lib/models/coremodel.js.map +1 -1
  22. package/lib/models/coremodel.spec.js +2 -2
  23. package/lib/models/coremodel.spec.js.map +1 -1
  24. package/lib/models/ident.d.ts +3 -3
  25. package/lib/models/ident.js +2 -1
  26. package/lib/models/ident.js.map +1 -1
  27. package/lib/models/ident.spec.js +1 -1
  28. package/lib/models/ident.spec.js.map +1 -1
  29. package/lib/models/ownermodel.d.ts +8 -4
  30. package/lib/models/ownermodel.js +9 -4
  31. package/lib/models/ownermodel.js.map +1 -1
  32. package/lib/models/ownermodel.spec.js +1 -1
  33. package/lib/models/ownermodel.spec.js.map +1 -1
  34. package/lib/models/rolemodel.js.map +1 -1
  35. package/lib/models/rolemodel.spec.js +5 -2
  36. package/lib/models/rolemodel.spec.js.map +1 -1
  37. package/lib/models/user.d.ts +4 -3
  38. package/lib/models/user.js +2 -1
  39. package/lib/models/user.js.map +1 -1
  40. package/lib/models/user.spec.js +1 -1
  41. package/lib/models/user.spec.js.map +1 -1
  42. package/lib/queues/filequeue.d.ts +2 -7
  43. package/lib/queues/filequeue.js +4 -13
  44. package/lib/queues/filequeue.js.map +1 -1
  45. package/lib/queues/filequeue.spec.js +2 -3
  46. package/lib/queues/filequeue.spec.js.map +1 -1
  47. package/lib/queues/memoryqueue.d.ts +2 -7
  48. package/lib/queues/memoryqueue.js +1 -11
  49. package/lib/queues/memoryqueue.js.map +1 -1
  50. package/lib/queues/memoryqueue.spec.js +1 -1
  51. package/lib/queues/memoryqueue.spec.js.map +1 -1
  52. package/lib/queues/queue.spec.d.ts +1 -1
  53. package/lib/queues/queue.spec.js +12 -10
  54. package/lib/queues/queue.spec.js.map +1 -1
  55. package/lib/queues/queueservice.d.ts +1 -1
  56. package/lib/queues/queueservice.js +1 -1
  57. package/lib/queues/queueservice.js.map +1 -1
  58. package/lib/router.d.ts +48 -2
  59. package/lib/router.js +78 -51
  60. package/lib/router.js.map +1 -1
  61. package/lib/router.spec.js +23 -6
  62. package/lib/router.spec.js.map +1 -1
  63. package/lib/services/asyncevents.d.ts +1 -0
  64. package/lib/services/asyncevents.js +4 -3
  65. package/lib/services/asyncevents.js.map +1 -1
  66. package/lib/services/asyncevents.spec.js +2 -2
  67. package/lib/services/asyncevents.spec.js.map +1 -1
  68. package/lib/services/authentication.d.ts +39 -11
  69. package/lib/services/authentication.js +60 -55
  70. package/lib/services/authentication.js.map +1 -1
  71. package/lib/services/authentication.spec.js +2 -1
  72. package/lib/services/authentication.spec.js.map +1 -1
  73. package/lib/services/binary.d.ts +127 -65
  74. package/lib/services/binary.js +255 -98
  75. package/lib/services/binary.js.map +1 -1
  76. package/lib/services/binary.spec.d.ts +2 -1
  77. package/lib/services/binary.spec.js +101 -30
  78. package/lib/services/binary.spec.js.map +1 -1
  79. package/lib/services/cloudbinary.d.ts +67 -0
  80. package/lib/services/cloudbinary.js +178 -0
  81. package/lib/services/cloudbinary.js.map +1 -0
  82. package/lib/services/cloudbinary.spec.d.ts +13 -0
  83. package/lib/services/cloudbinary.spec.js +212 -0
  84. package/lib/services/cloudbinary.spec.js.map +1 -0
  85. package/lib/services/configuration.d.ts +7 -2
  86. package/lib/services/configuration.js +6 -5
  87. package/lib/services/configuration.js.map +1 -1
  88. package/lib/services/configuration.spec.js +3 -2
  89. package/lib/services/configuration.spec.js.map +1 -1
  90. package/lib/services/cron.d.ts +5 -6
  91. package/lib/services/cron.js +5 -12
  92. package/lib/services/cron.js.map +1 -1
  93. package/lib/services/cron.spec.js +3 -4
  94. package/lib/services/cron.spec.js.map +1 -1
  95. package/lib/services/debugmailer.d.ts +3 -5
  96. package/lib/services/debugmailer.js +3 -11
  97. package/lib/services/debugmailer.js.map +1 -1
  98. package/lib/services/debugmailer.spec.js +1 -1
  99. package/lib/services/debugmailer.spec.js.map +1 -1
  100. package/lib/services/echo.d.ts +3 -7
  101. package/lib/services/echo.js +1 -11
  102. package/lib/services/echo.js.map +1 -1
  103. package/lib/services/echo.spec.js +4 -3
  104. package/lib/services/echo.spec.js.map +1 -1
  105. package/lib/services/filebinary.d.ts +40 -16
  106. package/lib/services/filebinary.js +142 -50
  107. package/lib/services/filebinary.js.map +1 -1
  108. package/lib/services/filebinary.spec.d.ts +4 -2
  109. package/lib/services/filebinary.spec.js +50 -12
  110. package/lib/services/filebinary.spec.js.map +1 -1
  111. package/lib/services/fileconfiguration.d.ts +1 -5
  112. package/lib/services/fileconfiguration.js +3 -12
  113. package/lib/services/fileconfiguration.js.map +1 -1
  114. package/lib/services/fileconfiguration.spec.js +2 -2
  115. package/lib/services/fileconfiguration.spec.js.map +1 -1
  116. package/lib/services/invitationservice.d.ts +28 -4
  117. package/lib/services/invitationservice.js +9 -6
  118. package/lib/services/invitationservice.js.map +1 -1
  119. package/lib/services/invitationservice.spec.js +4 -3
  120. package/lib/services/invitationservice.spec.js.map +1 -1
  121. package/lib/services/kubernetesconfiguration.d.ts +3 -5
  122. package/lib/services/kubernetesconfiguration.js +7 -14
  123. package/lib/services/kubernetesconfiguration.js.map +1 -1
  124. package/lib/services/kubernetesconfiguration.spec.js +5 -5
  125. package/lib/services/kubernetesconfiguration.spec.js.map +1 -1
  126. package/lib/services/mailer.d.ts +1 -5
  127. package/lib/services/mailer.js +1 -10
  128. package/lib/services/mailer.js.map +1 -1
  129. package/lib/services/mailer.spec.js +3 -3
  130. package/lib/services/mailer.spec.js.map +1 -1
  131. package/lib/services/notificationservice.d.ts +2 -0
  132. package/lib/services/notificationservice.js +2 -0
  133. package/lib/services/notificationservice.js.map +1 -1
  134. package/lib/services/notificationservice.spec.js +2 -2
  135. package/lib/services/notificationservice.spec.js.map +1 -1
  136. package/lib/services/oauth.d.ts +8 -6
  137. package/lib/services/oauth.js +30 -14
  138. package/lib/services/oauth.js.map +1 -1
  139. package/lib/services/oauth.spec.js +10 -10
  140. package/lib/services/oauth.spec.js.map +1 -1
  141. package/lib/services/resource.d.ts +18 -5
  142. package/lib/services/resource.js +42 -23
  143. package/lib/services/resource.js.map +1 -1
  144. package/lib/services/resource.spec.js +4 -4
  145. package/lib/services/resource.spec.js.map +1 -1
  146. package/lib/services/service.d.ts +22 -25
  147. package/lib/services/service.js +16 -22
  148. package/lib/services/service.js.map +1 -1
  149. package/lib/services/service.spec.js +2 -2
  150. package/lib/services/service.spec.js.map +1 -1
  151. package/lib/services/version.d.ts +2 -5
  152. package/lib/services/version.js +1 -10
  153. package/lib/services/version.js.map +1 -1
  154. package/lib/services/version.spec.js +1 -1
  155. package/lib/services/version.spec.js.map +1 -1
  156. package/lib/stores/aggregator.d.ts +3 -5
  157. package/lib/stores/aggregator.js +3 -10
  158. package/lib/stores/aggregator.js.map +1 -1
  159. package/lib/stores/file.d.ts +15 -8
  160. package/lib/stores/file.js +21 -18
  161. package/lib/stores/file.js.map +1 -1
  162. package/lib/stores/file.spec.d.ts +3 -1
  163. package/lib/stores/file.spec.js +32 -8
  164. package/lib/stores/file.spec.js.map +1 -1
  165. package/lib/stores/mapper.d.ts +1 -5
  166. package/lib/stores/mapper.js +4 -13
  167. package/lib/stores/mapper.js.map +1 -1
  168. package/lib/stores/mapper.spec.js +2 -2
  169. package/lib/stores/mapper.spec.js.map +1 -1
  170. package/lib/stores/memory.d.ts +5 -9
  171. package/lib/stores/memory.js +5 -17
  172. package/lib/stores/memory.js.map +1 -1
  173. package/lib/stores/memory.spec.d.ts +2 -1
  174. package/lib/stores/memory.spec.js +36 -4
  175. package/lib/stores/memory.spec.js.map +1 -1
  176. package/lib/stores/store.d.ts +137 -26
  177. package/lib/stores/store.js +431 -75
  178. package/lib/stores/store.js.map +1 -1
  179. package/lib/stores/store.spec.d.ts +31 -4
  180. package/lib/stores/store.spec.js +206 -35
  181. package/lib/stores/store.spec.js.map +1 -1
  182. package/lib/stores/webdaql/WebdaQLLexer.d.ts +53 -0
  183. package/lib/stores/webdaql/WebdaQLLexer.js +290 -0
  184. package/lib/stores/webdaql/WebdaQLLexer.js.map +1 -0
  185. package/lib/stores/webdaql/WebdaQLParserLexer.d.ts +53 -0
  186. package/lib/stores/webdaql/WebdaQLParserLexer.js +290 -0
  187. package/lib/stores/webdaql/WebdaQLParserLexer.js.map +1 -0
  188. package/lib/stores/webdaql/WebdaQLParserListener.d.ts +284 -0
  189. package/lib/stores/webdaql/WebdaQLParserListener.js +4 -0
  190. package/lib/stores/webdaql/WebdaQLParserListener.js.map +1 -0
  191. package/lib/stores/webdaql/WebdaQLParserParser.d.ts +301 -0
  192. package/lib/stores/webdaql/WebdaQLParserParser.js +1781 -0
  193. package/lib/stores/webdaql/WebdaQLParserParser.js.map +1 -0
  194. package/lib/stores/webdaql/WebdaQLParserVisitor.d.ts +174 -0
  195. package/lib/stores/webdaql/WebdaQLParserVisitor.js +4 -0
  196. package/lib/stores/webdaql/WebdaQLParserVisitor.js.map +1 -0
  197. package/lib/stores/webdaql/query.d.ts +300 -0
  198. package/lib/stores/webdaql/query.js +471 -0
  199. package/lib/stores/webdaql/query.js.map +1 -0
  200. package/lib/stores/webdaql/query.spec.d.ts +1 -0
  201. package/lib/stores/webdaql/query.spec.js +136 -0
  202. package/lib/stores/webdaql/query.spec.js.map +1 -0
  203. package/lib/test.d.ts +54 -9
  204. package/lib/test.js +139 -25
  205. package/lib/test.js.map +1 -1
  206. package/lib/unpackedapplication.d.ts +66 -0
  207. package/lib/unpackedapplication.js +219 -0
  208. package/lib/unpackedapplication.js.map +1 -0
  209. package/lib/utils/abstractdeployer.spec.js +1 -1
  210. package/lib/utils/abstractdeployer.spec.js.map +1 -1
  211. package/lib/utils/context.d.ts +17 -58
  212. package/lib/utils/context.js +33 -124
  213. package/lib/utils/context.js.map +1 -1
  214. package/lib/utils/context.spec.js +49 -28
  215. package/lib/utils/context.spec.js.map +1 -1
  216. package/lib/utils/cookie.d.ts +6 -3
  217. package/lib/utils/cookie.js +9 -5
  218. package/lib/utils/cookie.js.map +1 -1
  219. package/lib/utils/cookie.spec.js +5 -5
  220. package/lib/utils/cookie.spec.js.map +1 -1
  221. package/lib/utils/httpcontext.d.ts +157 -0
  222. package/lib/utils/httpcontext.js +279 -0
  223. package/lib/utils/httpcontext.js.map +1 -0
  224. package/lib/utils/httpcontext.spec.d.ts +5 -0
  225. package/lib/utils/httpcontext.spec.js +82 -0
  226. package/lib/utils/httpcontext.spec.js.map +1 -0
  227. package/lib/utils/logger.d.ts +18 -5
  228. package/lib/utils/logger.js +17 -4
  229. package/lib/utils/logger.js.map +1 -1
  230. package/lib/utils/logger.spec.js.map +1 -1
  231. package/lib/utils/serializers.js +5 -1
  232. package/lib/utils/serializers.js.map +1 -1
  233. package/lib/utils/serializers.spec.js +3 -3
  234. package/lib/utils/serializers.spec.js.map +1 -1
  235. package/lib/utils/waiter.d.ts +1 -1
  236. package/lib/utils/waiter.js.map +1 -1
  237. package/lib/utils/waiter.spec.js +2 -2
  238. package/lib/utils/waiter.spec.js.map +1 -1
  239. package/package.json +25 -18
  240. package/test/config-file-no-reload.json +2 -1
  241. package/test/config-file-reload.json +2 -1
  242. package/test/config-kube-reload.json +2 -1
  243. package/test/config-reload.json +1 -1
  244. package/test/config.json +8 -11
  245. package/test/config.old.json +1 -1
  246. package/test/moddas/annotatedservice.js +1 -3
  247. package/test/moddas/debugmailer.js +2 -7
  248. package/test/moddas/fakeservice.js +1 -1
  249. package/test/moddas/voidstore.js +2 -4
  250. package/test/models/ident.js +1 -1
  251. package/test/models/task.js +1 -6
  252. package/webda.module.json +1124 -0
  253. package/test/config.old-default.json +0 -151
@@ -13,6 +13,7 @@ exports.Store = exports.StoreParameters = exports.UpdateConditionFailError = exp
13
13
  const core_1 = require("../core");
14
14
  const coremodel_1 = require("../models/coremodel");
15
15
  const service_1 = require("../services/service");
16
+ const query_1 = require("./webdaql/query");
16
17
  class StoreNotFoundError extends core_1.WebdaError {
17
18
  constructor(uuid, storeName) {
18
19
  super("STORE_NOTFOUND", `Item not found ${uuid} Store(${storeName})`);
@@ -30,7 +31,8 @@ exports.UpdateConditionFailError = UpdateConditionFailError;
30
31
  */
31
32
  class StoreParameters extends service_1.ServiceParameters {
32
33
  constructor(params, service) {
33
- var _a, _b;
34
+ var _a, _b, _c, _d;
35
+ var _e;
34
36
  super(params);
35
37
  (_a = this.model) !== null && _a !== void 0 ? _a : (this.model = "Webda/CoreModel");
36
38
  let expose = params.expose;
@@ -49,6 +51,7 @@ class StoreParameters extends service_1.ServiceParameters {
49
51
  if (expose) {
50
52
  expose.restrict = expose.restrict || {};
51
53
  this.expose = expose;
54
+ (_b = (_e = this.expose).queryMethod) !== null && _b !== void 0 ? _b : (_e.queryMethod = "GET");
52
55
  }
53
56
  if (params.map) {
54
57
  throw new Error("Deprecated map usage, use a MapperService");
@@ -56,7 +59,8 @@ class StoreParameters extends service_1.ServiceParameters {
56
59
  if (params.index) {
57
60
  throw new Error("Deprecated index usage, use an AggregatorService");
58
61
  }
59
- (_b = this.strict) !== null && _b !== void 0 ? _b : (this.strict = true);
62
+ (_c = this.strict) !== null && _c !== void 0 ? _c : (this.strict = true);
63
+ (_d = this.slowQueryThreshold) !== null && _d !== void 0 ? _d : (this.slowQueryThreshold = 30000);
60
64
  }
61
65
  }
62
66
  exports.StoreParameters = StoreParameters;
@@ -105,6 +109,23 @@ class Store extends service_1.Service {
105
109
  * Contain the model uuid field
106
110
  */
107
111
  this._uuidField = "uuid";
112
+ /**
113
+ * Add metrics counter
114
+ */
115
+ this.metrics = {
116
+ save: 0,
117
+ update: 0,
118
+ partialUpdate: 0,
119
+ get: 0,
120
+ increment: 0,
121
+ delete: 0,
122
+ collectionUpsert: 0,
123
+ collectionDelete: 0,
124
+ attributeDelete: 0,
125
+ query: 0,
126
+ queryDuration: 0,
127
+ slowQueries: 0
128
+ };
108
129
  }
109
130
  /**
110
131
  * Load the parameters for a service
@@ -118,12 +139,18 @@ class Store extends service_1.Service {
118
139
  * @throws Error if model is not found
119
140
  */
120
141
  computeParameters() {
142
+ var _a;
121
143
  super.computeParameters();
122
144
  const p = this.parameters;
123
145
  this._model = this._webda.getModel(p.model);
124
146
  this._uuidField = this._model.getUuidField();
125
147
  this._lastUpdateField = this._model.getLastUpdateField();
126
148
  this._creationDateField = this._model.getCreationField();
149
+ (_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a.computeParameters();
150
+ this.cacheStorePatchException();
151
+ }
152
+ logSlowQuery(_query, _reason, _time) {
153
+ // TODO Need to implement: https://github.com/loopingz/webda.io/issues/202
127
154
  }
128
155
  /**
129
156
  * Return Store current model
@@ -135,8 +162,35 @@ class Store extends service_1.Service {
135
162
  getLastUpdateField() {
136
163
  return this._model.getLastUpdateField();
137
164
  }
165
+ /**
166
+ * Get From Cache or main
167
+ * @param uid
168
+ * @param raiseIfNotFound
169
+ * @returns
170
+ */
171
+ _getFromCache(uid, raiseIfNotFound = false) {
172
+ var _a;
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ let res = yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._get(uid));
175
+ if (!res) {
176
+ res = yield this._get(uid, raiseIfNotFound);
177
+ }
178
+ else {
179
+ res.__store = this;
180
+ }
181
+ return res;
182
+ });
183
+ }
184
+ /**
185
+ * Get object from store
186
+ * @param uid
187
+ * @returns
188
+ */
138
189
  getObject(uid) {
139
- return this._get(uid);
190
+ return __awaiter(this, void 0, void 0, function* () {
191
+ this.metrics.get++;
192
+ return this._getFromCache(uid);
193
+ });
140
194
  }
141
195
  /**
142
196
  * @inheritdoc
@@ -153,15 +207,25 @@ class Store extends service_1.Service {
153
207
  post: {
154
208
  description: `The way to create a new ${this._model.name} model`,
155
209
  summary: "Create a new " + this._model.name,
156
- model: this._model.name,
157
210
  operationId: `create${this._model.name}`,
158
211
  responses: {
159
212
  "200": {
160
- model: this._model.name
213
+ description: "Retrieve model",
214
+ content: {
215
+ "application/json": {
216
+ // schema: this._model.name
217
+ }
218
+ }
219
+ },
220
+ "400": {
221
+ description: "Object is invalid"
161
222
  },
162
- "400": "Object is invalid",
163
- "403": "You don't have permissions",
164
- "409": "Object already exists"
223
+ "403": {
224
+ description: "You don't have permissions"
225
+ },
226
+ "409": {
227
+ description: "Object already exists"
228
+ }
165
229
  }
166
230
  }
167
231
  });
@@ -175,6 +239,33 @@ class Store extends service_1.Service {
175
239
  if (!expose.restrict.get) {
176
240
  methods.push("GET");
177
241
  }
242
+ // Query endpoint
243
+ if (!expose.restrict.query) {
244
+ this.addRoute(expose.queryMethod === "GET" ? `${expose.url}{?q}` : expose.url, [expose.queryMethod], this.httpQuery, {
245
+ model: this._model.name,
246
+ [expose.queryMethod.toLowerCase()]: {
247
+ description: `Query on ${this._model.name} model with WebdaQL`,
248
+ summary: "Query " + this._model.name,
249
+ operationId: `create${this._model.name}`,
250
+ responses: {
251
+ "200": {
252
+ description: "Retrieve models",
253
+ content: {
254
+ "application/json": {
255
+ // schema: this._model.name
256
+ }
257
+ }
258
+ },
259
+ "400": {
260
+ description: "Query is invalid"
261
+ },
262
+ "403": {
263
+ description: "You don't have permissions"
264
+ }
265
+ }
266
+ }
267
+ });
268
+ }
178
269
  if (!expose.restrict.delete) {
179
270
  methods.push("DELETE");
180
271
  }
@@ -187,48 +278,71 @@ class Store extends service_1.Service {
187
278
  operationId: `get${this._model.name}`,
188
279
  responses: {
189
280
  "200": {
190
- model: this._model.name
281
+ //model: this._model.name
282
+ },
283
+ "400": {
284
+ description: "Object is invalid"
285
+ },
286
+ "403": {
287
+ description: "You don't have permissions"
191
288
  },
192
- "400": "Object is invalid",
193
- "403": "You don't have permissions",
194
- "404": "Unknown object"
289
+ "404": {
290
+ description: "Unknown object"
291
+ }
195
292
  }
196
293
  },
197
294
  put: {
198
295
  description: `Update a ${this._model.name} if the permissions allow`,
199
296
  summary: "Update a " + this._model.name,
200
- model: this._model.name,
201
297
  operationId: `updatet${this._model.name}`,
202
298
  responses: {
203
299
  "200": {
204
- model: this._model.name
300
+ // model: this._model.name
205
301
  },
206
- "400": "Object is invalid",
207
- "403": "You don't have permissions",
208
- "404": "Unknown object"
302
+ "400": {
303
+ description: "Object is invalid"
304
+ },
305
+ "403": {
306
+ description: "You don't have permissions"
307
+ },
308
+ "404": {
309
+ description: "Unknown object"
310
+ }
209
311
  }
210
312
  },
211
313
  patch: {
212
314
  description: `Patch a ${this._model.name} if the permissions allow`,
213
315
  summary: "Patch a " + this._model.name,
214
- model: this._model.name,
215
316
  operationId: `updatet${this._model.name}`,
216
317
  responses: {
217
- "204": "",
218
- "400": "Object is invalid",
219
- "403": "You don't have permissions",
220
- "404": "Unknown object"
318
+ "204": {
319
+ description: ""
320
+ },
321
+ "400": {
322
+ description: "Object is invalid"
323
+ },
324
+ "403": {
325
+ description: "You don't have permissions"
326
+ },
327
+ "404": {
328
+ description: "Unknown object"
329
+ }
221
330
  }
222
331
  },
223
332
  delete: {
224
333
  operationId: `delete${this._model.name}`,
225
334
  description: `Delete ${this._model.name} if the permissions allow`,
226
335
  summary: "Delete a " + this._model.name,
227
- model: this._model.name,
228
336
  responses: {
229
- "204": "",
230
- "403": "You don't have permissions",
231
- "404": "Unknown object"
337
+ "204": {
338
+ description: ""
339
+ },
340
+ "403": {
341
+ description: "You don't have permissions"
342
+ },
343
+ "404": {
344
+ description: "Unknown object"
345
+ }
232
346
  }
233
347
  }
234
348
  });
@@ -260,12 +374,51 @@ class Store extends service_1.Service {
260
374
  });
261
375
  }
262
376
  }
377
+ /**
378
+ * OVerwrite the model
379
+ * Used mainly in test
380
+ */
381
+ setModel(model) {
382
+ var _a;
383
+ this._model = model;
384
+ (_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a.setModel(model);
385
+ this.parameters.strict = false;
386
+ }
263
387
  /**
264
388
  * Get the url where the store is exposed
265
389
  */
266
390
  getUrl() {
267
391
  return this.parameters.expose.url;
268
392
  }
393
+ /**
394
+ * We should ignore exception from the store
395
+ */
396
+ cacheStorePatchException() {
397
+ if (!this._cacheStore) {
398
+ return;
399
+ }
400
+ const replacer = original => {
401
+ return (...args) => {
402
+ return original
403
+ .bind(this._cacheStore, ...args)()
404
+ .catch(err => {
405
+ this.log("TRACE", `Ignoring cache exception ${this._name}: ${err.message}`);
406
+ });
407
+ };
408
+ };
409
+ for (let i of [
410
+ "_get",
411
+ "_patch",
412
+ "_update",
413
+ "_delete",
414
+ "_incrementAttribute",
415
+ "_upsertItemToCollection",
416
+ "_deleteItemFromCollection",
417
+ "_removeAttribute"
418
+ ]) {
419
+ this._cacheStore[i] = replacer(this._cacheStore[i]);
420
+ }
421
+ }
269
422
  /**
270
423
  * Init a model from the current stored data
271
424
  *
@@ -311,13 +464,16 @@ class Store extends service_1.Service {
311
464
  });
312
465
  }
313
466
  incrementAttribute(uid, prop, value) {
467
+ var _a;
314
468
  return __awaiter(this, void 0, void 0, function* () {
315
469
  // If value === 0 no need to update anything
316
470
  if (value === 0) {
317
471
  return Promise.resolve();
318
472
  }
319
473
  let updateDate = new Date();
474
+ this.metrics.increment++;
320
475
  yield this._incrementAttribute(uid, prop, value, updateDate);
476
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._incrementAttribute(uid, prop, value, updateDate));
321
477
  return this.emitSync("Store.PartialUpdated", {
322
478
  object_id: uid,
323
479
  store: this,
@@ -332,12 +488,15 @@ class Store extends service_1.Service {
332
488
  });
333
489
  }
334
490
  upsertItemToCollection(uid, prop, item, index = undefined, itemWriteCondition = undefined, itemWriteConditionField = undefined) {
491
+ var _a;
335
492
  return __awaiter(this, void 0, void 0, function* () {
336
493
  if (itemWriteConditionField === undefined) {
337
494
  itemWriteConditionField = this._uuidField;
338
495
  }
339
496
  let updateDate = new Date();
497
+ this.metrics.collectionUpsert++;
340
498
  yield this._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate);
499
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate));
341
500
  yield this.emitSync("Store.PartialUpdated", {
342
501
  object_id: uid,
343
502
  store: this,
@@ -353,9 +512,12 @@ class Store extends service_1.Service {
353
512
  });
354
513
  }
355
514
  deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField = this._uuidField) {
515
+ var _a;
356
516
  return __awaiter(this, void 0, void 0, function* () {
357
517
  let updateDate = new Date();
518
+ this.metrics.collectionDelete++;
358
519
  yield this._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate);
520
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate));
359
521
  yield this.emitSync("Store.PartialUpdated", {
360
522
  object_id: uid,
361
523
  store: this,
@@ -369,6 +531,127 @@ class Store extends service_1.Service {
369
531
  });
370
532
  });
371
533
  }
534
+ /**
535
+ * Query store with WebdaQL
536
+ * @param query
537
+ * @param context to apply permission
538
+ */
539
+ query(query, context) {
540
+ return __awaiter(this, void 0, void 0, function* () {
541
+ let queryValidator = new query_1.WebdaQL.QueryValidator(query);
542
+ let offset = queryValidator.getOffset();
543
+ const limit = queryValidator.getLimit();
544
+ const parsedQuery = queryValidator.getQuery();
545
+ // Emit the default event
546
+ yield this.emitSync("Store.Query", {
547
+ query,
548
+ parsedQuery,
549
+ store: this,
550
+ context
551
+ });
552
+ const result = {
553
+ results: [],
554
+ continuationToken: undefined
555
+ };
556
+ /*
557
+ Offset are split in two with _
558
+
559
+ MainOffset is the database offset, retrieving a page from the database
560
+ SubOffset is the offset within the page
561
+
562
+ As we filter through the page, for additional filters or permissions, the page cut
563
+ by database does not endup being our final page cut, so we need a page offset to
564
+ abstract this completely
565
+ */
566
+ let [mainOffset, subOffset] = offset.split("_");
567
+ let secondOffset = parseInt(subOffset || "0");
568
+ let duration = Date.now();
569
+ this.metrics.query++;
570
+ while (result.results.length < limit) {
571
+ let tmpResults = yield this.find(Object.assign(Object.assign({}, parsedQuery), { continuationToken: mainOffset }));
572
+ // If no filter is returned assume it is by mistake and apply filtering
573
+ if (tmpResults.filter === undefined) {
574
+ tmpResults.filter = queryValidator.getExpression();
575
+ this.log("WARN", `Store '${this.getName()}' postquery full filtering`);
576
+ }
577
+ let subOffsetCount = 0;
578
+ for (let item of tmpResults.results) {
579
+ // Because of dynamic filter and permission we need to suboffset the pagination
580
+ subOffsetCount++;
581
+ if (subOffsetCount <= secondOffset) {
582
+ continue;
583
+ }
584
+ if (tmpResults.filter !== true && !tmpResults.filter.eval(item)) {
585
+ continue;
586
+ }
587
+ if (context) {
588
+ try {
589
+ yield item.canAct(context, "get");
590
+ }
591
+ catch (err) {
592
+ continue;
593
+ }
594
+ }
595
+ result.results.push(item);
596
+ if (result.results.length >= limit) {
597
+ if (subOffsetCount === tmpResults.results.length) {
598
+ result.continuationToken = tmpResults.continuationToken;
599
+ }
600
+ else {
601
+ result.continuationToken = `${mainOffset}_${subOffsetCount}`;
602
+ }
603
+ break;
604
+ }
605
+ }
606
+ // Update both offset
607
+ mainOffset = tmpResults.continuationToken;
608
+ // Fresh new query so we do not need to skip
609
+ secondOffset = 0;
610
+ if (mainOffset === undefined || result.results.length >= limit) {
611
+ break;
612
+ }
613
+ }
614
+ duration = Date.now() - duration;
615
+ this.metrics.queryDuration =
616
+ (this.metrics.queryDuration * (this.metrics.query - 1) + duration) / this.metrics.query;
617
+ if (duration > this.parameters.slowQueryThreshold) {
618
+ this.logSlowQuery(query, "", duration);
619
+ }
620
+ yield this.emitSync("Store.Queried", {
621
+ query,
622
+ parsedQuery: parsedQuery,
623
+ store: this,
624
+ continuationToken: result.continuationToken,
625
+ results: result.results,
626
+ context
627
+ });
628
+ return result;
629
+ });
630
+ }
631
+ /**
632
+ * Expose query to http
633
+ */
634
+ httpQuery(ctx) {
635
+ return __awaiter(this, void 0, void 0, function* () {
636
+ let query;
637
+ if (ctx.getHttpContext().getMethod() === "GET") {
638
+ query = ctx.getParameters().q;
639
+ }
640
+ else {
641
+ query = (yield ctx.getRequestBody()).q;
642
+ }
643
+ try {
644
+ ctx.write(yield this.query(query, ctx));
645
+ }
646
+ catch (err) {
647
+ if (err instanceof SyntaxError) {
648
+ this.log("INFO", "Query syntax error");
649
+ throw 400;
650
+ }
651
+ throw err;
652
+ }
653
+ });
654
+ }
372
655
  /**
373
656
  * Save an object
374
657
  *
@@ -379,27 +662,31 @@ class Store extends service_1.Service {
379
662
  * Might want to rename to create
380
663
  */
381
664
  save(object, ctx = undefined) {
382
- var _a;
383
- var _b;
665
+ var _a, _b;
666
+ var _c;
384
667
  return __awaiter(this, void 0, void 0, function* () {
385
668
  object = this.initModel(object);
386
669
  // Dates should be store by the Store
387
- (_a = object[_b = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_b] = new Date());
670
+ (_a = object[_c = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_c] = new Date());
388
671
  object[this._lastUpdateField] = new Date();
389
672
  if (ctx) {
390
673
  object.setContext(ctx);
391
674
  }
392
675
  yield this.emitSync("Store.Save", {
393
676
  object: object,
394
- store: this
677
+ store: this,
678
+ context: ctx
395
679
  });
396
680
  // Handle object auto listener
397
681
  yield object._onSave();
682
+ this.metrics.save++;
398
683
  let res = yield this._save(object);
684
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._save(object));
399
685
  object = this.initModel(res);
400
686
  yield this.emitSync("Store.Saved", {
401
687
  object: object,
402
- store: this
688
+ store: this,
689
+ context: ctx
403
690
  });
404
691
  yield object._onSaved();
405
692
  return object;
@@ -489,6 +776,7 @@ class Store extends service_1.Service {
489
776
  * @return {Promise} with saved object
490
777
  */
491
778
  update(object, reverseMap = true, partial = false) {
779
+ var _a, _b;
492
780
  return __awaiter(this, void 0, void 0, function* () {
493
781
  /** @ignore */
494
782
  var saved;
@@ -501,12 +789,12 @@ class Store extends service_1.Service {
501
789
  }
502
790
  }
503
791
  }
504
- let partialEvent = partial ? "Patch" : "";
505
792
  if (Object.keys(object).length < 2) {
506
793
  return {};
507
794
  }
508
795
  object[this._lastUpdateField] = new Date();
509
- let load = yield this._get(object[this._uuidField], true);
796
+ this.metrics.get++;
797
+ let load = yield this._getFromCache(object[this._uuidField], true);
510
798
  if (load.__type !== this._model.name && this.parameters.strict) {
511
799
  this.log("WARN", `Object '${object[this._uuidField]}' was not created by this store`);
512
800
  throw new StoreNotFoundError(object[this._uuidField], this.getName());
@@ -515,15 +803,26 @@ class Store extends service_1.Service {
515
803
  if (object instanceof coremodel_1.CoreModel) {
516
804
  loaded.setContext(object.getContext());
517
805
  }
518
- yield this.emitSync(`Store.${partialEvent}Update`, {
519
- object: loaded,
520
- store: this,
521
- update: object
522
- });
806
+ if (partial) {
807
+ yield this.emitSync(`Store.PatchUpdate`, {
808
+ object: loaded,
809
+ store: this,
810
+ update: object
811
+ });
812
+ }
813
+ else {
814
+ yield this.emitSync(`Store.Update`, {
815
+ object: loaded,
816
+ store: this,
817
+ update: object
818
+ });
819
+ }
523
820
  yield loaded._onUpdate(object);
524
821
  let res;
525
822
  if (partial) {
823
+ this.metrics.partialUpdate++;
526
824
  yield this._patch(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField);
825
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._patch(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField));
527
826
  res = object;
528
827
  }
529
828
  else {
@@ -531,7 +830,9 @@ class Store extends service_1.Service {
531
830
  for (let i in this._reverseMap) {
532
831
  object[this._reverseMap[i].property] = loaded[this._reverseMap[i].property];
533
832
  }
833
+ this.metrics.update++;
534
834
  res = yield this._update(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField);
835
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._update(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField));
535
836
  }
536
837
  // Return updated
537
838
  for (let i in res) {
@@ -541,10 +842,18 @@ class Store extends service_1.Service {
541
842
  loaded[i] = object[i];
542
843
  }
543
844
  saved = this.initModel(loaded);
544
- yield this.emitSync(`Store.${partialEvent}Updated`, {
545
- object: saved,
546
- store: this
547
- });
845
+ if (partial) {
846
+ yield this.emitSync(`Store.PatchUpdated`, {
847
+ object: saved,
848
+ store: this
849
+ });
850
+ }
851
+ else {
852
+ yield this.emitSync(`Store.Updated`, {
853
+ object: saved,
854
+ store: this
855
+ });
856
+ }
548
857
  yield saved._onUpdated();
549
858
  return saved;
550
859
  });
@@ -557,8 +866,11 @@ class Store extends service_1.Service {
557
866
  * @returns
558
867
  */
559
868
  removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField) {
869
+ var _a;
560
870
  return __awaiter(this, void 0, void 0, function* () {
871
+ this.metrics.attributeDelete++;
561
872
  yield this._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField);
873
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField));
562
874
  yield this.emitSync("Store.PartialUpdated", {
563
875
  object_id: uuid,
564
876
  partial_update: {
@@ -574,7 +886,7 @@ class Store extends service_1.Service {
574
886
  * @param uuid
575
887
  * @returns
576
888
  */
577
- cascadeDelete(obj, uuid) {
889
+ cascadeDelete(obj, _uuid) {
578
890
  return __awaiter(this, void 0, void 0, function* () {
579
891
  // We dont need uuid but Binary store will need it
580
892
  return this.delete(obj.getUuid());
@@ -598,6 +910,7 @@ class Store extends service_1.Service {
598
910
  * @return {Promise} the deletion promise
599
911
  */
600
912
  delete(uid, writeCondition, writeConditionField, sync = false) {
913
+ var _a, _b;
601
914
  return __awaiter(this, void 0, void 0, function* () {
602
915
  /** @ignore */
603
916
  let to_delete;
@@ -606,7 +919,8 @@ class Store extends service_1.Service {
606
919
  to_delete = uid;
607
920
  }
608
921
  else {
609
- to_delete = yield this._get(uid);
922
+ this.metrics.get++;
923
+ to_delete = yield this._getFromCache(uid);
610
924
  if (to_delete === undefined) {
611
925
  return;
612
926
  }
@@ -630,13 +944,19 @@ class Store extends service_1.Service {
630
944
  yield to_delete._onDelete();
631
945
  // If async we just tag the object as deleted
632
946
  if (this.parameters.asyncDelete && !sync) {
947
+ this.metrics.partialUpdate++;
633
948
  yield this._patch({
634
949
  __deleted: true
635
950
  }, to_delete.getUuid());
951
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._patch({
952
+ __deleted: true
953
+ }, to_delete.getUuid()));
636
954
  }
637
955
  else {
956
+ this.metrics.delete++;
638
957
  // Delete from the DB for real
639
958
  yield this._delete(to_delete.getUuid(), writeCondition, writeConditionField);
959
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._delete(to_delete.getUuid(), writeCondition, writeConditionField));
640
960
  }
641
961
  // Send post event
642
962
  yield this.emitSync("Store.Deleted", {
@@ -652,7 +972,7 @@ class Store extends service_1.Service {
652
972
  * @param id
653
973
  * @param callback
654
974
  */
655
- canTriggerConfiguration(id, callback) {
975
+ canTriggerConfiguration(_id, _callback) {
656
976
  return false;
657
977
  }
658
978
  /**
@@ -662,7 +982,8 @@ class Store extends service_1.Service {
662
982
  */
663
983
  getConfiguration(id) {
664
984
  return __awaiter(this, void 0, void 0, function* () {
665
- let object = yield this._get(id);
985
+ this.metrics.get++;
986
+ let object = yield this._getFromCache(id);
666
987
  if (!object) {
667
988
  return undefined;
668
989
  }
@@ -688,7 +1009,8 @@ class Store extends service_1.Service {
688
1009
  if (!uid) {
689
1010
  return undefined;
690
1011
  }
691
- let object = yield this._get(uid);
1012
+ this.metrics.get++;
1013
+ let object = yield this._getFromCache(uid);
692
1014
  if (!object) {
693
1015
  return undefined;
694
1016
  }
@@ -700,7 +1022,8 @@ class Store extends service_1.Service {
700
1022
  object.setContext(ctx);
701
1023
  yield this.emitSync("Store.Get", {
702
1024
  object: object,
703
- store: this
1025
+ store: this,
1026
+ context: ctx
704
1027
  });
705
1028
  yield object._onGet();
706
1029
  return object;
@@ -725,31 +1048,64 @@ class Store extends service_1.Service {
725
1048
  });
726
1049
  }
727
1050
  /**
728
- * Search inside the store
729
- *
730
- * Still need to define a good abstraction for it
731
- *
732
- * @param request
733
- * @param offset
734
- * @param limit
735
- * @returns
1051
+ * @override
736
1052
  */
737
- find(request = undefined, offset = 0, limit = undefined) {
1053
+ simulateFind(query, uuids) {
738
1054
  return __awaiter(this, void 0, void 0, function* () {
739
- yield this.emitSync("Store.Find", {
740
- request: request,
741
- store: this,
742
- offset: offset,
743
- limit: limit
744
- });
745
- let result = yield this._find(request, offset, limit);
746
- yield this.emitSync("Store.Found", {
747
- request: request,
748
- store: this,
749
- offset: offset,
750
- limit: limit,
751
- results: result
752
- });
1055
+ let result = {
1056
+ results: [],
1057
+ continuationToken: undefined,
1058
+ filter: true
1059
+ };
1060
+ let count = 0;
1061
+ let limit = query.limit;
1062
+ let offset = parseInt(query.continuationToken || "0");
1063
+ let originalOffset = offset;
1064
+ if (query.orderBy && query.orderBy.length) {
1065
+ offset = 0;
1066
+ // We need to retrieve everything to orderBy after
1067
+ limit = Number.MAX_SAFE_INTEGER;
1068
+ }
1069
+ // Need to transfert to Array
1070
+ for (let uuid of uuids) {
1071
+ count++;
1072
+ // Offset start
1073
+ if (offset >= count) {
1074
+ continue;
1075
+ }
1076
+ let obj = yield this._getFromCache(uuid);
1077
+ if (obj && query.filter.eval(obj)) {
1078
+ result.results.push(obj);
1079
+ if (result.results.length >= limit) {
1080
+ result.continuationToken = count.toString();
1081
+ return result;
1082
+ }
1083
+ }
1084
+ }
1085
+ // Order by
1086
+ if (query.orderBy && query.orderBy.length) {
1087
+ // Sorting the results
1088
+ result.results.sort((a, b) => {
1089
+ let valA, valB;
1090
+ for (let orderBy of query.orderBy) {
1091
+ let invert = orderBy.direction === "ASC" ? 1 : -1;
1092
+ valA = query_1.WebdaQL.ComparisonExpression.getAttributeValue(a, orderBy.field.split("."));
1093
+ valB = query_1.WebdaQL.ComparisonExpression.getAttributeValue(b, orderBy.field.split("."));
1094
+ if (valA === valB) {
1095
+ continue;
1096
+ }
1097
+ if (typeof valA === "string") {
1098
+ return valA.localeCompare(valB) * invert;
1099
+ }
1100
+ return (valA < valB ? -1 : 1) * invert;
1101
+ }
1102
+ return -1;
1103
+ });
1104
+ result.results = result.results.slice(originalOffset, query.limit + originalOffset);
1105
+ if (result.results.length >= query.limit) {
1106
+ result.continuationToken = (query.limit + originalOffset).toString();
1107
+ }
1108
+ }
753
1109
  return result;
754
1110
  });
755
1111
  }
@@ -759,14 +1115,14 @@ class Store extends service_1.Service {
759
1115
  */
760
1116
  httpCreate(ctx) {
761
1117
  return __awaiter(this, void 0, void 0, function* () {
762
- let body = ctx.getRequestBody();
1118
+ let body = yield ctx.getRequestBody();
763
1119
  var object = new this._model();
764
1120
  object.setContext(ctx);
765
1121
  object.load(body);
766
1122
  object[this._creationDateField] = new Date();
767
1123
  yield object.canAct(ctx, "create");
768
1124
  try {
769
- yield object.validate(ctx);
1125
+ yield object.validate(ctx, body);
770
1126
  }
771
1127
  catch (err) {
772
1128
  this.log("INFO", "Object is not valid", err);
@@ -847,7 +1203,7 @@ class Store extends service_1.Service {
847
1203
  */
848
1204
  httpUpdate(ctx) {
849
1205
  return __awaiter(this, void 0, void 0, function* () {
850
- let body = ctx.getRequestBody();
1206
+ let body = yield ctx.getRequestBody();
851
1207
  let uuid = ctx.parameter("uuid");
852
1208
  body[this._uuidField] = uuid;
853
1209
  let object = yield this.get(uuid, ctx);
@@ -884,7 +1240,7 @@ class Store extends service_1.Service {
884
1240
  updateObject[i] = object[i];
885
1241
  });
886
1242
  try {
887
- yield updateObject.validate(ctx);
1243
+ yield updateObject.validate(ctx, body);
888
1244
  }
889
1245
  catch (err) {
890
1246
  this.log("INFO", "Object invalid", err);