@webiny/api-form-builder-so-ddb-es 0.0.0-ee-vpcs.549378cf03

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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +12 -0
  3. package/configurations.d.ts +11 -0
  4. package/configurations.js +50 -0
  5. package/configurations.js.map +1 -0
  6. package/definitions/elasticsearch.d.ts +9 -0
  7. package/definitions/elasticsearch.js +43 -0
  8. package/definitions/elasticsearch.js.map +1 -0
  9. package/definitions/form.d.ts +9 -0
  10. package/definitions/form.js +100 -0
  11. package/definitions/form.js.map +1 -0
  12. package/definitions/settings.d.ts +9 -0
  13. package/definitions/settings.js +49 -0
  14. package/definitions/settings.js.map +1 -0
  15. package/definitions/submission.d.ts +9 -0
  16. package/definitions/submission.js +70 -0
  17. package/definitions/submission.js.map +1 -0
  18. package/definitions/system.d.ts +9 -0
  19. package/definitions/system.js +40 -0
  20. package/definitions/system.js.map +1 -0
  21. package/definitions/table.d.ts +8 -0
  22. package/definitions/table.js +23 -0
  23. package/definitions/table.js.map +1 -0
  24. package/definitions/tableElasticsearch.d.ts +8 -0
  25. package/definitions/tableElasticsearch.js +23 -0
  26. package/definitions/tableElasticsearch.js.map +1 -0
  27. package/elasticsearch/createElasticsearchIndex.d.ts +10 -0
  28. package/elasticsearch/createElasticsearchIndex.js +63 -0
  29. package/elasticsearch/createElasticsearchIndex.js.map +1 -0
  30. package/elasticsearch/indices/base.d.ts +2 -0
  31. package/elasticsearch/indices/base.js +15 -0
  32. package/elasticsearch/indices/base.js.map +1 -0
  33. package/elasticsearch/indices/index.d.ts +1 -0
  34. package/elasticsearch/indices/index.js +16 -0
  35. package/elasticsearch/indices/index.js.map +1 -0
  36. package/elasticsearch/indices/japanese.d.ts +2 -0
  37. package/elasticsearch/indices/japanese.js +16 -0
  38. package/elasticsearch/indices/japanese.js.map +1 -0
  39. package/index.d.ts +2 -0
  40. package/index.js +191 -0
  41. package/index.js.map +1 -0
  42. package/operations/form/elasticsearchBody.d.ts +13 -0
  43. package/operations/form/elasticsearchBody.js +170 -0
  44. package/operations/form/elasticsearchBody.js.map +1 -0
  45. package/operations/form/elasticsearchFields.d.ts +3 -0
  46. package/operations/form/elasticsearchFields.js +33 -0
  47. package/operations/form/elasticsearchFields.js.map +1 -0
  48. package/operations/form/fields.d.ts +3 -0
  49. package/operations/form/fields.js +15 -0
  50. package/operations/form/fields.js.map +1 -0
  51. package/operations/form/index.d.ts +17 -0
  52. package/operations/form/index.js +904 -0
  53. package/operations/form/index.js.map +1 -0
  54. package/operations/settings/index.d.ts +7 -0
  55. package/operations/settings/index.js +118 -0
  56. package/operations/settings/index.js.map +1 -0
  57. package/operations/submission/elasticsearchBody.d.ts +13 -0
  58. package/operations/submission/elasticsearchBody.js +187 -0
  59. package/operations/submission/elasticsearchBody.js.map +1 -0
  60. package/operations/submission/elasticsearchFields.d.ts +3 -0
  61. package/operations/submission/elasticsearchFields.js +30 -0
  62. package/operations/submission/elasticsearchFields.js.map +1 -0
  63. package/operations/submission/index.d.ts +12 -0
  64. package/operations/submission/index.js +335 -0
  65. package/operations/submission/index.js.map +1 -0
  66. package/operations/system/index.d.ts +7 -0
  67. package/operations/system/index.js +101 -0
  68. package/operations/system/index.js.map +1 -0
  69. package/package.json +63 -0
  70. package/plugins/FormDynamoDbFieldPlugin.d.ts +4 -0
  71. package/plugins/FormDynamoDbFieldPlugin.js +17 -0
  72. package/plugins/FormDynamoDbFieldPlugin.js.map +1 -0
  73. package/plugins/FormElasticsearchBodyModifierPlugin.d.ts +4 -0
  74. package/plugins/FormElasticsearchBodyModifierPlugin.js +17 -0
  75. package/plugins/FormElasticsearchBodyModifierPlugin.js.map +1 -0
  76. package/plugins/FormElasticsearchFieldPlugin.d.ts +4 -0
  77. package/plugins/FormElasticsearchFieldPlugin.js +17 -0
  78. package/plugins/FormElasticsearchFieldPlugin.js.map +1 -0
  79. package/plugins/FormElasticsearchIndexPlugin.d.ts +4 -0
  80. package/plugins/FormElasticsearchIndexPlugin.js +17 -0
  81. package/plugins/FormElasticsearchIndexPlugin.js.map +1 -0
  82. package/plugins/FormElasticsearchQueryModifierPlugin.d.ts +4 -0
  83. package/plugins/FormElasticsearchQueryModifierPlugin.js +17 -0
  84. package/plugins/FormElasticsearchQueryModifierPlugin.js.map +1 -0
  85. package/plugins/FormElasticsearchSortModifierPlugin.d.ts +4 -0
  86. package/plugins/FormElasticsearchSortModifierPlugin.js +17 -0
  87. package/plugins/FormElasticsearchSortModifierPlugin.js.map +1 -0
  88. package/plugins/SubmissionElasticsearchBodyModifierPlugin.d.ts +4 -0
  89. package/plugins/SubmissionElasticsearchBodyModifierPlugin.js +17 -0
  90. package/plugins/SubmissionElasticsearchBodyModifierPlugin.js.map +1 -0
  91. package/plugins/SubmissionElasticsearchFieldPlugin.d.ts +4 -0
  92. package/plugins/SubmissionElasticsearchFieldPlugin.js +17 -0
  93. package/plugins/SubmissionElasticsearchFieldPlugin.js.map +1 -0
  94. package/plugins/SubmissionElasticsearchQueryModifierPlugin.d.ts +4 -0
  95. package/plugins/SubmissionElasticsearchQueryModifierPlugin.js +17 -0
  96. package/plugins/SubmissionElasticsearchQueryModifierPlugin.js.map +1 -0
  97. package/plugins/SubmissionElasticsearchSortModifierPlugin.d.ts +4 -0
  98. package/plugins/SubmissionElasticsearchSortModifierPlugin.js +17 -0
  99. package/plugins/SubmissionElasticsearchSortModifierPlugin.js.map +1 -0
  100. package/types.d.ts +66 -0
  101. package/types.js +17 -0
  102. package/types.js.map +1 -0
@@ -0,0 +1,904 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.createFormStorageOperations = void 0;
9
+
10
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
11
+
12
+ var _query = require("@webiny/db-dynamodb/utils/query");
13
+
14
+ var _error = _interopRequireDefault(require("@webiny/error"));
15
+
16
+ var _cleanup = require("@webiny/db-dynamodb/utils/cleanup");
17
+
18
+ var _batchWrite = require("@webiny/db-dynamodb/utils/batchWrite");
19
+
20
+ var _configurations = require("../../configurations");
21
+
22
+ var _filter = require("@webiny/db-dynamodb/utils/filter");
23
+
24
+ var _fields = _interopRequireDefault(require("./fields"));
25
+
26
+ var _sort = require("@webiny/db-dynamodb/utils/sort");
27
+
28
+ var _utils = require("@webiny/utils");
29
+
30
+ var _elasticsearchBody = require("./elasticsearchBody");
31
+
32
+ var _apiElasticsearch = require("@webiny/api-elasticsearch");
33
+
34
+ const getESDataForLatestRevision = form => ({
35
+ __type: (0, _elasticsearchBody.createFormElasticType)(),
36
+ id: form.id,
37
+ createdOn: form.createdOn,
38
+ savedOn: form.savedOn,
39
+ name: form.name,
40
+ slug: form.slug,
41
+ published: form.published,
42
+ publishedOn: form.publishedOn,
43
+ version: form.version,
44
+ locked: form.locked,
45
+ status: form.status,
46
+ createdBy: form.createdBy,
47
+ ownedBy: form.ownedBy,
48
+ tenant: form.tenant,
49
+ locale: form.locale,
50
+ webinyVersion: form.webinyVersion,
51
+ formId: form.formId
52
+ });
53
+
54
+ const createFormStorageOperations = params => {
55
+ const {
56
+ entity,
57
+ esEntity,
58
+ table,
59
+ plugins,
60
+ elasticsearch
61
+ } = params;
62
+ const formDynamoDbFields = (0, _fields.default)();
63
+
64
+ const createFormPartitionKey = params => {
65
+ const {
66
+ tenant,
67
+ locale,
68
+ id: targetId
69
+ } = params;
70
+ const {
71
+ id
72
+ } = (0, _utils.parseIdentifier)(targetId);
73
+ return `T#${tenant}#L#${locale}#FB#F#${id}`;
74
+ };
75
+
76
+ const createRevisionSortKey = value => {
77
+ const version = typeof value === "number" ? Number(value) : (0, _utils.parseIdentifier)(value).version;
78
+ return `REV#${(0, _utils.zeroPad)(version)}`;
79
+ };
80
+
81
+ const createLatestSortKey = () => {
82
+ return "L";
83
+ };
84
+
85
+ const createLatestPublishedSortKey = () => {
86
+ return "LP";
87
+ };
88
+
89
+ const createFormType = () => {
90
+ return "fb.form";
91
+ };
92
+
93
+ const createFormLatestType = () => {
94
+ return "fb.form.latest";
95
+ };
96
+
97
+ const createFormLatestPublishedType = () => {
98
+ return "fb.form.latestPublished";
99
+ };
100
+
101
+ const createForm = async params => {
102
+ const {
103
+ form
104
+ } = params;
105
+ const revisionKeys = {
106
+ PK: createFormPartitionKey(form),
107
+ SK: createRevisionSortKey(form.id)
108
+ };
109
+ const latestKeys = {
110
+ PK: createFormPartitionKey(form),
111
+ SK: createLatestSortKey()
112
+ };
113
+ const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), {}, {
114
+ TYPE: createFormType()
115
+ }, revisionKeys)), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), {}, {
116
+ TYPE: createFormLatestType()
117
+ }, latestKeys))];
118
+
119
+ try {
120
+ await (0, _batchWrite.batchWriteAll)({
121
+ table,
122
+ items
123
+ });
124
+ } catch (ex) {
125
+ throw new _error.default(ex.message || "Could not insert form data into regular table.", ex.code || "CREATE_FORM_ERROR", {
126
+ revisionKeys,
127
+ latestKeys,
128
+ form
129
+ });
130
+ }
131
+
132
+ try {
133
+ const {
134
+ index
135
+ } = _configurations.configurations.es({
136
+ tenant: form.tenant,
137
+ locale: form.locale
138
+ });
139
+
140
+ await esEntity.put((0, _objectSpread2.default)({
141
+ index,
142
+ data: getESDataForLatestRevision(form),
143
+ TYPE: createFormType()
144
+ }, latestKeys));
145
+ } catch (ex) {
146
+ throw new _error.default(ex.message || "Could not insert form data into Elasticsearch table.", ex.code || "CREATE_FORM_ERROR", {
147
+ latestKeys,
148
+ form
149
+ });
150
+ }
151
+
152
+ return form;
153
+ };
154
+
155
+ const createFormFrom = async params => {
156
+ const {
157
+ form,
158
+ original,
159
+ latest
160
+ } = params;
161
+ const revisionKeys = {
162
+ PK: createFormPartitionKey(form),
163
+ SK: createRevisionSortKey(form.version)
164
+ };
165
+ const latestKeys = {
166
+ PK: createFormPartitionKey(form),
167
+ SK: createLatestSortKey()
168
+ };
169
+ const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), revisionKeys), {}, {
170
+ TYPE: createFormType()
171
+ })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), latestKeys), {}, {
172
+ TYPE: createFormLatestType()
173
+ }))];
174
+
175
+ try {
176
+ await (0, _batchWrite.batchWriteAll)({
177
+ table,
178
+ items
179
+ });
180
+ } catch (ex) {
181
+ throw new _error.default(ex.message || "Could not create form data in the regular table, from existing form.", ex.code || "CREATE_FORM_FROM_ERROR", {
182
+ revisionKeys,
183
+ latestKeys,
184
+ original,
185
+ form,
186
+ latest
187
+ });
188
+ }
189
+
190
+ try {
191
+ const {
192
+ index
193
+ } = _configurations.configurations.es({
194
+ tenant: form.tenant,
195
+ locale: form.locale
196
+ });
197
+
198
+ await esEntity.put((0, _objectSpread2.default)({
199
+ index,
200
+ data: getESDataForLatestRevision(form),
201
+ TYPE: createFormLatestType()
202
+ }, latestKeys));
203
+ } catch (ex) {
204
+ throw new _error.default(ex.message || "Could not create form in the Elasticsearch table, from existing form.", ex.code || "CREATE_FORM_FROM_ERROR", {
205
+ latestKeys,
206
+ form,
207
+ latest,
208
+ original
209
+ });
210
+ }
211
+
212
+ return form;
213
+ };
214
+
215
+ const updateForm = async params => {
216
+ const {
217
+ form,
218
+ original
219
+ } = params;
220
+ const revisionKeys = {
221
+ PK: createFormPartitionKey(form),
222
+ SK: createRevisionSortKey(form.id)
223
+ };
224
+ const latestKeys = {
225
+ PK: createFormPartitionKey(form),
226
+ SK: createLatestSortKey()
227
+ };
228
+ const {
229
+ formId,
230
+ tenant,
231
+ locale
232
+ } = form;
233
+ const latestForm = await getForm({
234
+ where: {
235
+ formId,
236
+ tenant,
237
+ locale,
238
+ latest: true
239
+ }
240
+ });
241
+ const isLatestForm = latestForm ? latestForm.id === form.id : false;
242
+ const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), {}, {
243
+ TYPE: createFormType()
244
+ }, revisionKeys))];
245
+
246
+ if (isLatestForm) {
247
+ items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), {}, {
248
+ TYPE: createFormLatestType()
249
+ }, latestKeys)));
250
+ }
251
+
252
+ try {
253
+ await (0, _batchWrite.batchWriteAll)({
254
+ table,
255
+ items
256
+ });
257
+ } catch (ex) {
258
+ throw new _error.default(ex.message || "Could not update form data in the regular table.", ex.code || "UPDATE_FORM_ERROR", {
259
+ revisionKeys,
260
+ latestKeys,
261
+ original,
262
+ form,
263
+ latestForm
264
+ });
265
+ }
266
+ /**
267
+ * No need to go further if its not latest form.
268
+ */
269
+
270
+
271
+ if (!isLatestForm) {
272
+ return form;
273
+ }
274
+
275
+ try {
276
+ const {
277
+ index
278
+ } = _configurations.configurations.es({
279
+ tenant: form.tenant,
280
+ locale: form.locale
281
+ });
282
+
283
+ await esEntity.put((0, _objectSpread2.default)({
284
+ index,
285
+ data: getESDataForLatestRevision(form),
286
+ TYPE: createFormLatestType()
287
+ }, latestKeys));
288
+ } catch (ex) {
289
+ throw new _error.default(ex.message || "Could not update form data in the Elasticsearch table.", ex.code || "UPDATE_FORM_ERROR", {
290
+ latestKeys,
291
+ form,
292
+ latestForm,
293
+ original
294
+ });
295
+ }
296
+
297
+ return form;
298
+ };
299
+
300
+ const getForm = async params => {
301
+ const {
302
+ where
303
+ } = params;
304
+ const {
305
+ id,
306
+ formId,
307
+ latest,
308
+ published,
309
+ version,
310
+ tenant,
311
+ locale
312
+ } = where;
313
+
314
+ if (latest && published) {
315
+ throw new _error.default("Cannot have both latest and published params.");
316
+ }
317
+
318
+ let sortKey;
319
+
320
+ if (latest) {
321
+ sortKey = createLatestSortKey();
322
+ } else if (published && !version) {
323
+ /**
324
+ * Because of the specifics how DynamoDB works, we must not load the published record if version is sent.
325
+ */
326
+ sortKey = createLatestPublishedSortKey();
327
+ } else if (id || version) {
328
+ sortKey = createRevisionSortKey(version || id);
329
+ } else {
330
+ throw new _error.default("Missing parameter to create a sort key.", "MISSING_WHERE_PARAMETER", {
331
+ where
332
+ });
333
+ }
334
+
335
+ const keys = {
336
+ PK: createFormPartitionKey({
337
+ tenant,
338
+ locale,
339
+ id: formId || id
340
+ }),
341
+ SK: sortKey
342
+ };
343
+
344
+ try {
345
+ const result = await entity.get(keys);
346
+
347
+ if (!result || !result.Item) {
348
+ return null;
349
+ }
350
+
351
+ return (0, _cleanup.cleanupItem)(entity, result.Item);
352
+ } catch (ex) {
353
+ throw new _error.default(ex.message || "Could not get form by keys.", ex.code || "GET_FORM_ERROR", {
354
+ keys
355
+ });
356
+ }
357
+ };
358
+
359
+ const listForms = async params => {
360
+ const {
361
+ sort,
362
+ limit,
363
+ where,
364
+ after
365
+ } = params;
366
+ const body = (0, _elasticsearchBody.createElasticsearchBody)({
367
+ plugins,
368
+ sort,
369
+ limit: limit + 1,
370
+ where,
371
+ after: (0, _apiElasticsearch.decodeCursor)(after)
372
+ });
373
+
374
+ const esConfig = _configurations.configurations.es({
375
+ tenant: where.tenant,
376
+ locale: where.locale
377
+ });
378
+
379
+ const query = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, esConfig), {}, {
380
+ body
381
+ });
382
+ let response;
383
+
384
+ try {
385
+ response = await elasticsearch.search(query);
386
+ } catch (ex) {
387
+ throw new _error.default(ex.message || "Could list forms.", ex.code || "LIST_FORMS_ERROR", {
388
+ where,
389
+ query
390
+ });
391
+ }
392
+
393
+ const {
394
+ hits,
395
+ total
396
+ } = response.body.hits;
397
+ const items = hits.map(item => item._source);
398
+ const hasMoreItems = items.length > limit;
399
+
400
+ if (hasMoreItems) {
401
+ /**
402
+ * Remove the last item from results, we don't want to include it.
403
+ */
404
+ items.pop();
405
+ }
406
+ /**
407
+ * Cursor is the `sort` value of the last item in the array.
408
+ * https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html#search-after
409
+ */
410
+
411
+
412
+ const meta = {
413
+ hasMoreItems,
414
+ totalCount: total.value,
415
+ cursor: items.length > 0 ? (0, _apiElasticsearch.encodeCursor)(hits[items.length - 1].sort) || null : null
416
+ };
417
+ return {
418
+ items,
419
+ meta
420
+ };
421
+ };
422
+
423
+ const listFormRevisions = async params => {
424
+ const {
425
+ where: initialWhere,
426
+ sort
427
+ } = params;
428
+ const {
429
+ id,
430
+ formId,
431
+ tenant,
432
+ locale
433
+ } = initialWhere;
434
+ const queryAllParams = {
435
+ entity,
436
+ partitionKey: createFormPartitionKey({
437
+ tenant,
438
+ locale,
439
+ id: id || formId
440
+ }),
441
+ options: {
442
+ beginsWith: "REV#"
443
+ }
444
+ };
445
+ let items = [];
446
+
447
+ try {
448
+ items = await (0, _query.queryAll)(queryAllParams);
449
+ } catch (ex) {
450
+ throw new _error.default(ex.message || "Could not query forms by given params.", ex.code || "QUERY_FORMS_ERROR", {
451
+ partitionKey: queryAllParams.partitionKey,
452
+ options: queryAllParams.options
453
+ });
454
+ }
455
+
456
+ const where = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, initialWhere), {}, {
457
+ id: undefined,
458
+ formId: undefined
459
+ });
460
+ const filteredItems = (0, _filter.filterItems)({
461
+ plugins,
462
+ items,
463
+ where,
464
+ fields: formDynamoDbFields
465
+ });
466
+
467
+ if (!sort || sort.length === 0) {
468
+ return filteredItems;
469
+ }
470
+
471
+ return (0, _sort.sortItems)({
472
+ items: filteredItems,
473
+ sort,
474
+ fields: formDynamoDbFields
475
+ });
476
+ };
477
+
478
+ const deleteForm = async params => {
479
+ const {
480
+ form
481
+ } = params;
482
+ let items;
483
+ /**
484
+ * This will find all form and submission records.
485
+ */
486
+
487
+ const queryAllParams = {
488
+ entity,
489
+ partitionKey: createFormPartitionKey(form),
490
+ options: {
491
+ gte: " "
492
+ }
493
+ };
494
+
495
+ try {
496
+ items = await (0, _query.queryAll)(queryAllParams);
497
+ } catch (ex) {
498
+ throw new _error.default(ex.message || "Could not query forms and submissions by given params.", ex.code || "QUERY_FORM_AND_SUBMISSIONS_ERROR", {
499
+ partitionKey: queryAllParams.partitionKey,
500
+ options: queryAllParams.options
501
+ });
502
+ }
503
+
504
+ const deleteItems = items.map(item => {
505
+ return entity.deleteBatch({
506
+ PK: item.PK,
507
+ SK: item.SK
508
+ });
509
+ });
510
+
511
+ try {
512
+ await (0, _batchWrite.batchWriteAll)({
513
+ table,
514
+ items: deleteItems
515
+ });
516
+ } catch (ex) {
517
+ throw new _error.default(ex.message || "Could not delete form and it's submissions.", ex.code || "DELETE_FORM_AND_SUBMISSIONS_ERROR");
518
+ }
519
+
520
+ const latestKeys = {
521
+ PK: createFormPartitionKey(form),
522
+ SK: createLatestSortKey()
523
+ };
524
+
525
+ try {
526
+ await esEntity.delete(latestKeys);
527
+ } catch (ex) {
528
+ throw new _error.default(ex.message || "Could not delete latest form record from Elasticsearch.", ex.code || "DELETE_FORM_ERROR", {
529
+ latestKeys
530
+ });
531
+ }
532
+
533
+ return form;
534
+ };
535
+ /**
536
+ * We need to:
537
+ * - delete current revision
538
+ * - get previously published revision and update the record if it exists or delete if it does not
539
+ * - update latest record if current one is the latest
540
+ */
541
+
542
+
543
+ const deleteFormRevision = async params => {
544
+ const {
545
+ form,
546
+ revisions,
547
+ previous
548
+ } = params;
549
+ const revisionKeys = {
550
+ PK: createFormPartitionKey(form),
551
+ SK: createRevisionSortKey(form.id)
552
+ };
553
+ const latestKeys = {
554
+ PK: createFormPartitionKey(form),
555
+ SK: createLatestSortKey()
556
+ };
557
+ const latestForm = revisions[0];
558
+ const latestPublishedForm = revisions.find(rev => rev.published === true);
559
+ const isLatest = latestForm ? latestForm.id === form.id : false;
560
+ const isLatestPublished = latestPublishedForm ? latestPublishedForm.id === form.id : false;
561
+ const items = [entity.deleteBatch(revisionKeys)];
562
+ let esDataItem = undefined;
563
+
564
+ if (isLatest || isLatestPublished) {
565
+ /**
566
+ * Sort out the latest published record.
567
+ */
568
+ if (isLatestPublished) {
569
+ const previouslyPublishedForm = revisions.filter(f => !!f.publishedOn && f.version !== form.version).sort((a, b) => {
570
+ return new Date(b.publishedOn).getTime() - new Date(a.publishedOn).getTime();
571
+ }).shift();
572
+
573
+ if (previouslyPublishedForm) {
574
+ items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, previouslyPublishedForm), {}, {
575
+ PK: createFormPartitionKey(previouslyPublishedForm),
576
+ SK: createLatestPublishedSortKey(),
577
+ TYPE: createFormLatestPublishedType()
578
+ })));
579
+ } else {
580
+ items.push(entity.deleteBatch({
581
+ PK: createFormPartitionKey(form),
582
+ SK: createLatestPublishedSortKey()
583
+ }));
584
+ }
585
+ }
586
+ /**
587
+ * Sort out the latest record.
588
+ */
589
+
590
+
591
+ if (isLatest && previous) {
592
+ items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, previous), latestKeys), {}, {
593
+ TYPE: createFormLatestType()
594
+ })));
595
+
596
+ const {
597
+ index
598
+ } = _configurations.configurations.es({
599
+ tenant: previous.tenant,
600
+ locale: previous.locale
601
+ });
602
+
603
+ esDataItem = (0, _objectSpread2.default)((0, _objectSpread2.default)({
604
+ index
605
+ }, latestKeys), {}, {
606
+ data: getESDataForLatestRevision(previous)
607
+ });
608
+ }
609
+ }
610
+ /**
611
+ * Now save the batch data.
612
+ */
613
+
614
+
615
+ try {
616
+ await (0, _batchWrite.batchWriteAll)({
617
+ table,
618
+ items
619
+ });
620
+ } catch (ex) {
621
+ throw new _error.default(ex.message || "Could not delete form revision from regular table.", ex.code || "DELETE_FORM_REVISION_ERROR", {
622
+ form,
623
+ latestForm,
624
+ revisionKeys,
625
+ latestKeys
626
+ });
627
+ }
628
+ /**
629
+ * And then the Elasticsearch data, if any.
630
+ */
631
+
632
+
633
+ if (!esDataItem) {
634
+ return form;
635
+ }
636
+
637
+ try {
638
+ await esEntity.put(esDataItem);
639
+ return form;
640
+ } catch (ex) {
641
+ throw new _error.default(ex.message || "Could not delete form from to the Elasticsearch table.", ex.code || "DELETE_FORM_REVISION_ERROR", {
642
+ form,
643
+ latestForm,
644
+ revisionKeys,
645
+ latestKeys
646
+ });
647
+ }
648
+ };
649
+ /**
650
+ * We need to save form in:
651
+ * - regular form record
652
+ * - latest published form record
653
+ * - latest form record - if form is latest one
654
+ * - elasticsearch latest form record
655
+ */
656
+
657
+
658
+ const publishForm = async params => {
659
+ const {
660
+ form,
661
+ original
662
+ } = params;
663
+ const revisionKeys = {
664
+ PK: createFormPartitionKey(form),
665
+ SK: createRevisionSortKey(form.version)
666
+ };
667
+ const latestKeys = {
668
+ PK: createFormPartitionKey(form),
669
+ SK: createLatestSortKey()
670
+ };
671
+ const latestPublishedKeys = {
672
+ PK: createFormPartitionKey(form),
673
+ SK: createLatestPublishedSortKey()
674
+ };
675
+ const {
676
+ locale,
677
+ tenant,
678
+ formId
679
+ } = form;
680
+ const latestForm = await getForm({
681
+ where: {
682
+ formId,
683
+ tenant,
684
+ locale,
685
+ latest: true
686
+ }
687
+ });
688
+ const isLatestForm = latestForm ? latestForm.id === form.id : false;
689
+ /**
690
+ * Update revision and latest published records
691
+ */
692
+
693
+ const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), revisionKeys), {}, {
694
+ TYPE: createFormType()
695
+ })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), latestPublishedKeys), {}, {
696
+ TYPE: createFormLatestPublishedType()
697
+ }))];
698
+ /**
699
+ * Update the latest form as well
700
+ */
701
+
702
+ if (isLatestForm) {
703
+ items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), latestKeys), {}, {
704
+ TYPE: createFormLatestType()
705
+ })));
706
+ }
707
+
708
+ try {
709
+ await (0, _batchWrite.batchWriteAll)({
710
+ table,
711
+ items
712
+ });
713
+ } catch (ex) {
714
+ throw new _error.default(ex.message || "Could not publish form.", ex.code || "PUBLISH_FORM_ERROR", {
715
+ form,
716
+ original,
717
+ latestForm,
718
+ revisionKeys,
719
+ latestKeys,
720
+ latestPublishedKeys
721
+ });
722
+ }
723
+
724
+ if (!isLatestForm) {
725
+ return form;
726
+ }
727
+
728
+ const {
729
+ index
730
+ } = _configurations.configurations.es({
731
+ tenant: form.tenant,
732
+ locale: form.locale
733
+ });
734
+
735
+ const esData = getESDataForLatestRevision(form);
736
+
737
+ try {
738
+ await esEntity.put((0, _objectSpread2.default)((0, _objectSpread2.default)({}, latestKeys), {}, {
739
+ index,
740
+ TYPE: createFormLatestType(),
741
+ data: esData
742
+ }));
743
+ return form;
744
+ } catch (ex) {
745
+ throw new _error.default(ex.message || "Could not publish form to the Elasticsearch.", ex.code || "PUBLISH_FORM_ERROR", {
746
+ form,
747
+ original,
748
+ latestForm,
749
+ revisionKeys,
750
+ latestKeys,
751
+ latestPublishedKeys
752
+ });
753
+ }
754
+ };
755
+ /**
756
+ * We need to:
757
+ * - update form revision record
758
+ * - if latest published (LP) is current form, find the previously published record and update LP if there is some previously published, delete otherwise
759
+ * - if is latest update the Elasticsearch record
760
+ */
761
+
762
+
763
+ const unpublishForm = async params => {
764
+ const {
765
+ form,
766
+ original
767
+ } = params;
768
+ const revisionKeys = {
769
+ PK: createFormPartitionKey(form),
770
+ SK: createRevisionSortKey(form.version)
771
+ };
772
+ const latestKeys = {
773
+ PK: createFormPartitionKey(form),
774
+ SK: createLatestSortKey()
775
+ };
776
+ const latestPublishedKeys = {
777
+ PK: createFormPartitionKey(form),
778
+ SK: createLatestPublishedSortKey()
779
+ };
780
+ const {
781
+ formId,
782
+ tenant,
783
+ locale
784
+ } = form;
785
+ const latestForm = await getForm({
786
+ where: {
787
+ formId,
788
+ tenant,
789
+ locale,
790
+ latest: true
791
+ }
792
+ });
793
+ const latestPublishedForm = await getForm({
794
+ where: {
795
+ formId,
796
+ tenant,
797
+ locale,
798
+ published: true
799
+ }
800
+ });
801
+ const isLatest = latestForm ? latestForm.id === form.id : false;
802
+ const isLatestPublished = latestPublishedForm ? latestPublishedForm.id === form.id : false;
803
+ const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, form), revisionKeys), {}, {
804
+ TYPE: createFormType()
805
+ }))];
806
+ let esData = undefined;
807
+
808
+ if (isLatest) {
809
+ esData = getESDataForLatestRevision(form);
810
+ }
811
+ /**
812
+ * In case previously published revision exists, replace current one with that one.
813
+ * And if it does not, delete the record.
814
+ */
815
+
816
+
817
+ if (isLatestPublished) {
818
+ const revisions = await listFormRevisions({
819
+ where: {
820
+ formId,
821
+ tenant,
822
+ locale,
823
+ version_not: form.version,
824
+ publishedOn_not: null
825
+ },
826
+ sort: ["savedOn_DESC"]
827
+ });
828
+ const previouslyPublishedRevision = revisions.shift();
829
+
830
+ if (previouslyPublishedRevision) {
831
+ items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, previouslyPublishedRevision), latestPublishedKeys), {}, {
832
+ TYPE: createFormLatestPublishedType()
833
+ })));
834
+ } else {
835
+ items.push(entity.deleteBatch(latestPublishedKeys));
836
+ }
837
+ }
838
+
839
+ try {
840
+ await (0, _batchWrite.batchWriteAll)({
841
+ table,
842
+ items
843
+ });
844
+ } catch (ex) {
845
+ throw new _error.default(ex.message || "Could not unpublish form.", ex.code || "UNPUBLISH_FORM_ERROR", {
846
+ form,
847
+ original,
848
+ latestForm,
849
+ revisionKeys,
850
+ latestKeys,
851
+ latestPublishedKeys
852
+ });
853
+ }
854
+ /**
855
+ * No need to go further in case of non-existing Elasticsearch data.
856
+ */
857
+
858
+
859
+ if (!esData) {
860
+ return form;
861
+ }
862
+
863
+ const {
864
+ index
865
+ } = _configurations.configurations.es({
866
+ tenant: form.tenant,
867
+ locale: form.locale
868
+ });
869
+
870
+ try {
871
+ await esEntity.put((0, _objectSpread2.default)((0, _objectSpread2.default)({}, latestKeys), {}, {
872
+ index,
873
+ TYPE: createFormLatestType(),
874
+ data: esData
875
+ }));
876
+ return form;
877
+ } catch (ex) {
878
+ throw new _error.default(ex.message || "Could not unpublish form from the Elasticsearch.", ex.code || "UNPUBLISH_FORM_ERROR", {
879
+ form,
880
+ original,
881
+ latestForm,
882
+ revisionKeys,
883
+ latestKeys,
884
+ latestPublishedKeys
885
+ });
886
+ }
887
+ };
888
+
889
+ return {
890
+ createForm,
891
+ createFormFrom,
892
+ updateForm,
893
+ listForms,
894
+ listFormRevisions,
895
+ getForm,
896
+ deleteForm,
897
+ deleteFormRevision,
898
+ publishForm,
899
+ unpublishForm,
900
+ createFormPartitionKey
901
+ };
902
+ };
903
+
904
+ exports.createFormStorageOperations = createFormStorageOperations;