@webda/core 1.6.0-beta.3 → 2.0.0-beta.2

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 +355 -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 +150 -215
  7. package/lib/core.js +188 -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 +86 -24
  20. package/lib/models/coremodel.js +85 -36
  21. package/lib/models/coremodel.js.map +1 -1
  22. package/lib/models/coremodel.spec.js +21 -2
  23. package/lib/models/coremodel.spec.js.map +1 -1
  24. package/lib/models/ident.d.ts +7 -5
  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 +18 -4
  30. package/lib/models/ownermodel.js +24 -4
  31. package/lib/models/ownermodel.js.map +1 -1
  32. package/lib/models/ownermodel.spec.js +18 -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 +7 -6
  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 +52 -2
  59. package/lib/router.js +80 -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 +45 -16
  106. package/lib/services/filebinary.js +147 -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 +11 -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 +25 -25
  147. package/lib/services/service.js +21 -25
  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 +5 -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 +142 -29
  177. package/lib/stores/store.js +451 -82
  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 +52 -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 +182 -0
  222. package/lib/utils/httpcontext.js +325 -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 +90 -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"
191
285
  },
192
- "400": "Object is invalid",
193
- "403": "You don't have permissions",
194
- "404": "Unknown object"
286
+ "403": {
287
+ description: "You don't have permissions"
288
+ },
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
301
+ },
302
+ "400": {
303
+ description: "Object is invalid"
205
304
  },
206
- "400": "Object is invalid",
207
- "403": "You don't have permissions",
208
- "404": "Unknown object"
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
  *
@@ -279,9 +432,7 @@ class Store extends service_1.Service {
279
432
  var _b;
280
433
  // Make sure to send a model object
281
434
  if (!(object instanceof this._model)) {
282
- let model = new this._model();
283
- model.load(object, true);
284
- object = model;
435
+ object = this._model.factory(this._model, object);
285
436
  }
286
437
  if (!object.getUuid()) {
287
438
  object.setUuid(object.generateUid(object));
@@ -311,13 +462,16 @@ class Store extends service_1.Service {
311
462
  });
312
463
  }
313
464
  incrementAttribute(uid, prop, value) {
465
+ var _a;
314
466
  return __awaiter(this, void 0, void 0, function* () {
315
467
  // If value === 0 no need to update anything
316
468
  if (value === 0) {
317
469
  return Promise.resolve();
318
470
  }
319
471
  let updateDate = new Date();
472
+ this.metrics.increment++;
320
473
  yield this._incrementAttribute(uid, prop, value, updateDate);
474
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._incrementAttribute(uid, prop, value, updateDate));
321
475
  return this.emitSync("Store.PartialUpdated", {
322
476
  object_id: uid,
323
477
  store: this,
@@ -332,12 +486,15 @@ class Store extends service_1.Service {
332
486
  });
333
487
  }
334
488
  upsertItemToCollection(uid, prop, item, index = undefined, itemWriteCondition = undefined, itemWriteConditionField = undefined) {
489
+ var _a;
335
490
  return __awaiter(this, void 0, void 0, function* () {
336
491
  if (itemWriteConditionField === undefined) {
337
492
  itemWriteConditionField = this._uuidField;
338
493
  }
339
494
  let updateDate = new Date();
495
+ this.metrics.collectionUpsert++;
340
496
  yield this._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate);
497
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._upsertItemToCollection(uid, prop, item, index, itemWriteCondition, itemWriteConditionField, updateDate));
341
498
  yield this.emitSync("Store.PartialUpdated", {
342
499
  object_id: uid,
343
500
  store: this,
@@ -353,9 +510,12 @@ class Store extends service_1.Service {
353
510
  });
354
511
  }
355
512
  deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField = this._uuidField) {
513
+ var _a;
356
514
  return __awaiter(this, void 0, void 0, function* () {
357
515
  let updateDate = new Date();
516
+ this.metrics.collectionDelete++;
358
517
  yield this._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate);
518
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._deleteItemFromCollection(uid, prop, index, itemWriteCondition, itemWriteConditionField, updateDate));
359
519
  yield this.emitSync("Store.PartialUpdated", {
360
520
  object_id: uid,
361
521
  store: this,
@@ -369,6 +529,142 @@ class Store extends service_1.Service {
369
529
  });
370
530
  });
371
531
  }
532
+ /**
533
+ * Query store with WebdaQL
534
+ * @param query
535
+ * @param context to apply permission
536
+ */
537
+ query(query, context) {
538
+ return __awaiter(this, void 0, void 0, function* () {
539
+ let permissionQuery = this._model.getPermissionQuery(context);
540
+ let partialPermission = true;
541
+ let fullQuery;
542
+ if (permissionQuery) {
543
+ partialPermission = permissionQuery.partial;
544
+ if (query.trim() !== "") {
545
+ fullQuery = `(${permissionQuery.query}) AND ${query}`;
546
+ }
547
+ else {
548
+ fullQuery = permissionQuery.query;
549
+ }
550
+ }
551
+ else {
552
+ fullQuery = query;
553
+ }
554
+ let queryValidator = new query_1.WebdaQL.QueryValidator(fullQuery);
555
+ let offset = queryValidator.getOffset();
556
+ const limit = queryValidator.getLimit();
557
+ const parsedQuery = queryValidator.getQuery();
558
+ // Emit the default event
559
+ yield this.emitSync("Store.Query", {
560
+ query,
561
+ parsedQuery,
562
+ store: this,
563
+ context
564
+ });
565
+ const result = {
566
+ results: [],
567
+ continuationToken: undefined
568
+ };
569
+ /*
570
+ Offset are split in two with _
571
+
572
+ MainOffset is the database offset, retrieving a page from the database
573
+ SubOffset is the offset within the page
574
+
575
+ As we filter through the page, for additional filters or permissions, the page cut
576
+ by database does not endup being our final page cut, so we need a page offset to
577
+ abstract this completely
578
+ */
579
+ let [mainOffset, subOffset] = offset.split("_");
580
+ let secondOffset = parseInt(subOffset || "0");
581
+ let duration = Date.now();
582
+ this.metrics.query++;
583
+ while (result.results.length < limit) {
584
+ let tmpResults = yield this.find(Object.assign(Object.assign({}, parsedQuery), { continuationToken: mainOffset }));
585
+ // If no filter is returned assume it is by mistake and apply filtering
586
+ if (tmpResults.filter === undefined) {
587
+ tmpResults.filter = queryValidator.getExpression();
588
+ this.log("WARN", `Store '${this.getName()}' postquery full filtering`);
589
+ }
590
+ let subOffsetCount = 0;
591
+ for (let item of tmpResults.results) {
592
+ // Because of dynamic filter and permission we need to suboffset the pagination
593
+ subOffsetCount++;
594
+ if (subOffsetCount <= secondOffset) {
595
+ continue;
596
+ }
597
+ if (tmpResults.filter !== true && !tmpResults.filter.eval(item)) {
598
+ continue;
599
+ }
600
+ if (context && partialPermission) {
601
+ try {
602
+ yield item.canAct(context, "get");
603
+ }
604
+ catch (err) {
605
+ continue;
606
+ }
607
+ }
608
+ result.results.push(item);
609
+ if (result.results.length >= limit) {
610
+ if (subOffsetCount === tmpResults.results.length) {
611
+ result.continuationToken = tmpResults.continuationToken;
612
+ }
613
+ else {
614
+ result.continuationToken = `${mainOffset}_${subOffsetCount}`;
615
+ }
616
+ break;
617
+ }
618
+ }
619
+ // Update both offset
620
+ mainOffset = tmpResults.continuationToken;
621
+ // Fresh new query so we do not need to skip
622
+ secondOffset = 0;
623
+ if (mainOffset === undefined || result.results.length >= limit) {
624
+ break;
625
+ }
626
+ }
627
+ duration = Date.now() - duration;
628
+ this.metrics.queryDuration =
629
+ (this.metrics.queryDuration * (this.metrics.query - 1) + duration) / this.metrics.query;
630
+ if (duration > this.parameters.slowQueryThreshold) {
631
+ this.logSlowQuery(query, "", duration);
632
+ }
633
+ yield this.emitSync("Store.Queried", {
634
+ query,
635
+ parsedQuery: parsedQuery,
636
+ store: this,
637
+ continuationToken: result.continuationToken,
638
+ results: result.results,
639
+ context
640
+ });
641
+ return result;
642
+ });
643
+ }
644
+ /**
645
+ * Expose query to http
646
+ */
647
+ httpQuery(ctx) {
648
+ return __awaiter(this, void 0, void 0, function* () {
649
+ let query;
650
+ if (ctx.getHttpContext().getMethod() === "GET") {
651
+ query = ctx.getParameters().q;
652
+ }
653
+ else {
654
+ query = (yield ctx.getRequestBody()).q;
655
+ }
656
+ try {
657
+ ctx.write(yield this.query(query, ctx));
658
+ }
659
+ catch (err) {
660
+ if (err instanceof SyntaxError) {
661
+ this.log("INFO", "Query syntax error");
662
+ throw 400;
663
+ }
664
+ throw err;
665
+ }
666
+ });
667
+ }
372
668
  /**
373
669
  * Save an object
374
670
  *
@@ -379,27 +675,31 @@ class Store extends service_1.Service {
379
675
  * Might want to rename to create
380
676
  */
381
677
  save(object, ctx = undefined) {
382
- var _a;
383
- var _b;
678
+ var _a, _b;
679
+ var _c;
384
680
  return __awaiter(this, void 0, void 0, function* () {
385
681
  object = this.initModel(object);
386
682
  // Dates should be store by the Store
387
- (_a = object[_b = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_b] = new Date());
683
+ (_a = object[_c = this._creationDateField]) !== null && _a !== void 0 ? _a : (object[_c] = new Date());
388
684
  object[this._lastUpdateField] = new Date();
389
685
  if (ctx) {
390
686
  object.setContext(ctx);
391
687
  }
392
688
  yield this.emitSync("Store.Save", {
393
689
  object: object,
394
- store: this
690
+ store: this,
691
+ context: ctx
395
692
  });
396
693
  // Handle object auto listener
397
694
  yield object._onSave();
695
+ this.metrics.save++;
398
696
  let res = yield this._save(object);
697
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._save(object));
399
698
  object = this.initModel(res);
400
699
  yield this.emitSync("Store.Saved", {
401
700
  object: object,
402
- store: this
701
+ store: this,
702
+ context: ctx
403
703
  });
404
704
  yield object._onSaved();
405
705
  return object;
@@ -484,11 +784,14 @@ class Store extends service_1.Service {
484
784
  /**
485
785
  * Update an object
486
786
  *
787
+ * If no attribute can be updated then return undefined
788
+ *
487
789
  * @param {Object} Object to save
488
790
  * @param {Boolean} reverseMap internal use only, for disable map resolution
489
791
  * @return {Promise} with saved object
490
792
  */
491
793
  update(object, reverseMap = true, partial = false) {
794
+ var _a, _b;
492
795
  return __awaiter(this, void 0, void 0, function* () {
493
796
  /** @ignore */
494
797
  var saved;
@@ -501,12 +804,12 @@ class Store extends service_1.Service {
501
804
  }
502
805
  }
503
806
  }
504
- let partialEvent = partial ? "Patch" : "";
505
807
  if (Object.keys(object).length < 2) {
506
- return {};
808
+ return undefined;
507
809
  }
508
810
  object[this._lastUpdateField] = new Date();
509
- let load = yield this._get(object[this._uuidField], true);
811
+ this.metrics.get++;
812
+ let load = yield this._getFromCache(object[this._uuidField], true);
510
813
  if (load.__type !== this._model.name && this.parameters.strict) {
511
814
  this.log("WARN", `Object '${object[this._uuidField]}' was not created by this store`);
512
815
  throw new StoreNotFoundError(object[this._uuidField], this.getName());
@@ -515,15 +818,26 @@ class Store extends service_1.Service {
515
818
  if (object instanceof coremodel_1.CoreModel) {
516
819
  loaded.setContext(object.getContext());
517
820
  }
518
- yield this.emitSync(`Store.${partialEvent}Update`, {
519
- object: loaded,
520
- store: this,
521
- update: object
522
- });
821
+ if (partial) {
822
+ yield this.emitSync(`Store.PatchUpdate`, {
823
+ object: loaded,
824
+ store: this,
825
+ update: object
826
+ });
827
+ }
828
+ else {
829
+ yield this.emitSync(`Store.Update`, {
830
+ object: loaded,
831
+ store: this,
832
+ update: object
833
+ });
834
+ }
523
835
  yield loaded._onUpdate(object);
524
836
  let res;
525
837
  if (partial) {
838
+ this.metrics.partialUpdate++;
526
839
  yield this._patch(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField);
840
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._patch(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField));
527
841
  res = object;
528
842
  }
529
843
  else {
@@ -531,7 +845,9 @@ class Store extends service_1.Service {
531
845
  for (let i in this._reverseMap) {
532
846
  object[this._reverseMap[i].property] = loaded[this._reverseMap[i].property];
533
847
  }
848
+ this.metrics.update++;
534
849
  res = yield this._update(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField);
850
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._update(object, object[this._uuidField], load[this._lastUpdateField], this._lastUpdateField));
535
851
  }
536
852
  // Return updated
537
853
  for (let i in res) {
@@ -541,10 +857,18 @@ class Store extends service_1.Service {
541
857
  loaded[i] = object[i];
542
858
  }
543
859
  saved = this.initModel(loaded);
544
- yield this.emitSync(`Store.${partialEvent}Updated`, {
545
- object: saved,
546
- store: this
547
- });
860
+ if (partial) {
861
+ yield this.emitSync(`Store.PatchUpdated`, {
862
+ object: saved,
863
+ store: this
864
+ });
865
+ }
866
+ else {
867
+ yield this.emitSync(`Store.Updated`, {
868
+ object: saved,
869
+ store: this
870
+ });
871
+ }
548
872
  yield saved._onUpdated();
549
873
  return saved;
550
874
  });
@@ -557,8 +881,11 @@ class Store extends service_1.Service {
557
881
  * @returns
558
882
  */
559
883
  removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField) {
884
+ var _a;
560
885
  return __awaiter(this, void 0, void 0, function* () {
886
+ this.metrics.attributeDelete++;
561
887
  yield this._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField);
888
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._removeAttribute(uuid, attribute, itemWriteCondition, itemWriteConditionField));
562
889
  yield this.emitSync("Store.PartialUpdated", {
563
890
  object_id: uuid,
564
891
  partial_update: {
@@ -574,7 +901,7 @@ class Store extends service_1.Service {
574
901
  * @param uuid
575
902
  * @returns
576
903
  */
577
- cascadeDelete(obj, uuid) {
904
+ cascadeDelete(obj, _uuid) {
578
905
  return __awaiter(this, void 0, void 0, function* () {
579
906
  // We dont need uuid but Binary store will need it
580
907
  return this.delete(obj.getUuid());
@@ -598,6 +925,7 @@ class Store extends service_1.Service {
598
925
  * @return {Promise} the deletion promise
599
926
  */
600
927
  delete(uid, writeCondition, writeConditionField, sync = false) {
928
+ var _a, _b;
601
929
  return __awaiter(this, void 0, void 0, function* () {
602
930
  /** @ignore */
603
931
  let to_delete;
@@ -606,7 +934,8 @@ class Store extends service_1.Service {
606
934
  to_delete = uid;
607
935
  }
608
936
  else {
609
- to_delete = yield this._get(uid);
937
+ this.metrics.get++;
938
+ to_delete = yield this._getFromCache(uid);
610
939
  if (to_delete === undefined) {
611
940
  return;
612
941
  }
@@ -630,13 +959,19 @@ class Store extends service_1.Service {
630
959
  yield to_delete._onDelete();
631
960
  // If async we just tag the object as deleted
632
961
  if (this.parameters.asyncDelete && !sync) {
962
+ this.metrics.partialUpdate++;
633
963
  yield this._patch({
634
964
  __deleted: true
635
965
  }, to_delete.getUuid());
966
+ yield ((_a = this._cacheStore) === null || _a === void 0 ? void 0 : _a._patch({
967
+ __deleted: true
968
+ }, to_delete.getUuid()));
636
969
  }
637
970
  else {
971
+ this.metrics.delete++;
638
972
  // Delete from the DB for real
639
973
  yield this._delete(to_delete.getUuid(), writeCondition, writeConditionField);
974
+ yield ((_b = this._cacheStore) === null || _b === void 0 ? void 0 : _b._delete(to_delete.getUuid(), writeCondition, writeConditionField));
640
975
  }
641
976
  // Send post event
642
977
  yield this.emitSync("Store.Deleted", {
@@ -652,7 +987,7 @@ class Store extends service_1.Service {
652
987
  * @param id
653
988
  * @param callback
654
989
  */
655
- canTriggerConfiguration(id, callback) {
990
+ canTriggerConfiguration(_id, _callback) {
656
991
  return false;
657
992
  }
658
993
  /**
@@ -662,7 +997,8 @@ class Store extends service_1.Service {
662
997
  */
663
998
  getConfiguration(id) {
664
999
  return __awaiter(this, void 0, void 0, function* () {
665
- let object = yield this._get(id);
1000
+ this.metrics.get++;
1001
+ let object = yield this._getFromCache(id);
666
1002
  if (!object) {
667
1003
  return undefined;
668
1004
  }
@@ -688,7 +1024,8 @@ class Store extends service_1.Service {
688
1024
  if (!uid) {
689
1025
  return undefined;
690
1026
  }
691
- let object = yield this._get(uid);
1027
+ this.metrics.get++;
1028
+ let object = yield this._getFromCache(uid);
692
1029
  if (!object) {
693
1030
  return undefined;
694
1031
  }
@@ -700,7 +1037,8 @@ class Store extends service_1.Service {
700
1037
  object.setContext(ctx);
701
1038
  yield this.emitSync("Store.Get", {
702
1039
  object: object,
703
- store: this
1040
+ store: this,
1041
+ context: ctx
704
1042
  });
705
1043
  yield object._onGet();
706
1044
  return object;
@@ -725,31 +1063,64 @@ class Store extends service_1.Service {
725
1063
  });
726
1064
  }
727
1065
  /**
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
1066
+ * @override
736
1067
  */
737
- find(request = undefined, offset = 0, limit = undefined) {
1068
+ simulateFind(query, uuids) {
738
1069
  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
- });
1070
+ let result = {
1071
+ results: [],
1072
+ continuationToken: undefined,
1073
+ filter: true
1074
+ };
1075
+ let count = 0;
1076
+ let limit = query.limit;
1077
+ let offset = parseInt(query.continuationToken || "0");
1078
+ let originalOffset = offset;
1079
+ if (query.orderBy && query.orderBy.length) {
1080
+ offset = 0;
1081
+ // We need to retrieve everything to orderBy after
1082
+ limit = Number.MAX_SAFE_INTEGER;
1083
+ }
1084
+ // Need to transfert to Array
1085
+ for (let uuid of uuids) {
1086
+ count++;
1087
+ // Offset start
1088
+ if (offset >= count) {
1089
+ continue;
1090
+ }
1091
+ let obj = yield this._getFromCache(uuid);
1092
+ if (obj && query.filter.eval(obj)) {
1093
+ result.results.push(obj);
1094
+ if (result.results.length >= limit) {
1095
+ result.continuationToken = count.toString();
1096
+ return result;
1097
+ }
1098
+ }
1099
+ }
1100
+ // Order by
1101
+ if (query.orderBy && query.orderBy.length) {
1102
+ // Sorting the results
1103
+ result.results.sort((a, b) => {
1104
+ let valA, valB;
1105
+ for (let orderBy of query.orderBy) {
1106
+ let invert = orderBy.direction === "ASC" ? 1 : -1;
1107
+ valA = query_1.WebdaQL.ComparisonExpression.getAttributeValue(a, orderBy.field.split("."));
1108
+ valB = query_1.WebdaQL.ComparisonExpression.getAttributeValue(b, orderBy.field.split("."));
1109
+ if (valA === valB) {
1110
+ continue;
1111
+ }
1112
+ if (typeof valA === "string") {
1113
+ return valA.localeCompare(valB) * invert;
1114
+ }
1115
+ return (valA < valB ? -1 : 1) * invert;
1116
+ }
1117
+ return -1;
1118
+ });
1119
+ result.results = result.results.slice(originalOffset, query.limit + originalOffset);
1120
+ if (result.results.length >= query.limit) {
1121
+ result.continuationToken = (query.limit + originalOffset).toString();
1122
+ }
1123
+ }
753
1124
  return result;
754
1125
  });
755
1126
  }
@@ -759,14 +1130,12 @@ class Store extends service_1.Service {
759
1130
  */
760
1131
  httpCreate(ctx) {
761
1132
  return __awaiter(this, void 0, void 0, function* () {
762
- let body = ctx.getRequestBody();
763
- var object = new this._model();
764
- object.setContext(ctx);
765
- object.load(body);
1133
+ let body = yield ctx.getRequestBody();
1134
+ let object = this._model.factory(this._model, body, ctx);
766
1135
  object[this._creationDateField] = new Date();
767
1136
  yield object.canAct(ctx, "create");
768
1137
  try {
769
- yield object.validate(ctx);
1138
+ yield object.validate(ctx, body);
770
1139
  }
771
1140
  catch (err) {
772
1141
  this.log("INFO", "Object is not valid", err);
@@ -847,7 +1216,7 @@ class Store extends service_1.Service {
847
1216
  */
848
1217
  httpUpdate(ctx) {
849
1218
  return __awaiter(this, void 0, void 0, function* () {
850
- let body = ctx.getRequestBody();
1219
+ let body = yield ctx.getRequestBody();
851
1220
  let uuid = ctx.parameter("uuid");
852
1221
  body[this._uuidField] = uuid;
853
1222
  let object = yield this.get(uuid, ctx);
@@ -884,7 +1253,7 @@ class Store extends service_1.Service {
884
1253
  updateObject[i] = object[i];
885
1254
  });
886
1255
  try {
887
- yield updateObject.validate(ctx);
1256
+ yield updateObject.validate(ctx, body);
888
1257
  }
889
1258
  catch (err) {
890
1259
  this.log("INFO", "Object invalid", err);