@webiny/api-headless-cms-ddb 0.0.0-unstable.2af142b57e → 0.0.0-unstable.3bc8100a7f

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 (161) hide show
  1. package/definitions/entry.d.ts +4 -3
  2. package/definitions/entry.js +109 -12
  3. package/definitions/entry.js.map +1 -1
  4. package/definitions/group.d.ts +4 -3
  5. package/definitions/group.js +9 -8
  6. package/definitions/group.js.map +1 -1
  7. package/definitions/model.d.ts +4 -3
  8. package/definitions/model.js +26 -8
  9. package/definitions/model.js.map +1 -1
  10. package/definitions/system.d.ts +4 -3
  11. package/definitions/system.js +9 -8
  12. package/definitions/system.js.map +1 -1
  13. package/definitions/table.d.ts +5 -5
  14. package/definitions/table.js +8 -4
  15. package/definitions/table.js.map +1 -1
  16. package/dynamoDb/index.js +5 -3
  17. package/dynamoDb/index.js.map +1 -1
  18. package/dynamoDb/path/locationFolderId.d.ts +2 -0
  19. package/dynamoDb/path/locationFolderId.js +43 -0
  20. package/dynamoDb/path/locationFolderId.js.map +1 -0
  21. package/dynamoDb/path/plainObject.js +3 -1
  22. package/dynamoDb/path/plainObject.js.map +1 -1
  23. package/dynamoDb/storage/longText.js +4 -1
  24. package/dynamoDb/storage/longText.js.map +1 -1
  25. package/dynamoDb/storage/richText.js +24 -58
  26. package/dynamoDb/storage/richText.js.map +1 -1
  27. package/dynamoDb/transformValue/datetime.d.ts +1 -1
  28. package/dynamoDb/transformValue/datetime.js +3 -1
  29. package/dynamoDb/transformValue/datetime.js.map +1 -1
  30. package/index.d.ts +1 -1
  31. package/index.js +16 -23
  32. package/index.js.map +1 -1
  33. package/operations/entry/dataLoader/DataLoaderCache.d.ts +17 -0
  34. package/operations/entry/dataLoader/DataLoaderCache.js +41 -0
  35. package/operations/entry/dataLoader/DataLoaderCache.js.map +1 -0
  36. package/operations/entry/dataLoader/constants.d.ts +1 -0
  37. package/operations/entry/dataLoader/constants.js +10 -0
  38. package/operations/entry/dataLoader/constants.js.map +1 -0
  39. package/operations/entry/dataLoader/createBatchScheduleFn.d.ts +8 -0
  40. package/operations/entry/dataLoader/createBatchScheduleFn.js +25 -0
  41. package/operations/entry/dataLoader/createBatchScheduleFn.js.map +1 -0
  42. package/operations/entry/dataLoader/getAllEntryRevisions.d.ts +4 -0
  43. package/operations/entry/dataLoader/getAllEntryRevisions.js +45 -0
  44. package/operations/entry/dataLoader/getAllEntryRevisions.js.map +1 -0
  45. package/operations/entry/dataLoader/getLatestRevisionByEntryId.d.ts +4 -0
  46. package/operations/entry/dataLoader/getLatestRevisionByEntryId.js +56 -0
  47. package/operations/entry/dataLoader/getLatestRevisionByEntryId.js.map +1 -0
  48. package/operations/entry/dataLoader/getPublishedRevisionByEntryId.d.ts +4 -0
  49. package/operations/entry/dataLoader/getPublishedRevisionByEntryId.js +56 -0
  50. package/operations/entry/dataLoader/getPublishedRevisionByEntryId.js.map +1 -0
  51. package/operations/entry/dataLoader/getRevisionById.d.ts +4 -0
  52. package/operations/entry/dataLoader/getRevisionById.js +62 -0
  53. package/operations/entry/dataLoader/getRevisionById.js.map +1 -0
  54. package/operations/entry/dataLoader/index.d.ts +8 -0
  55. package/operations/entry/dataLoader/index.js +40 -0
  56. package/operations/entry/dataLoader/index.js.map +1 -0
  57. package/operations/entry/dataLoader/types.d.ts +6 -0
  58. package/operations/entry/dataLoader/types.js +7 -0
  59. package/operations/entry/dataLoader/types.js.map +1 -0
  60. package/operations/entry/dataLoaders.d.ts +12 -27
  61. package/operations/entry/dataLoaders.js +55 -217
  62. package/operations/entry/dataLoaders.js.map +1 -1
  63. package/operations/entry/filtering/createExpressions.d.ts +4 -4
  64. package/operations/entry/filtering/createExpressions.js +3 -1
  65. package/operations/entry/filtering/createExpressions.js.map +1 -1
  66. package/operations/entry/filtering/createFields.d.ts +6 -4
  67. package/operations/entry/filtering/createFields.js +77 -74
  68. package/operations/entry/filtering/createFields.js.map +1 -1
  69. package/operations/entry/filtering/extractSort.d.ts +3 -3
  70. package/operations/entry/filtering/extractSort.js +3 -1
  71. package/operations/entry/filtering/extractSort.js.map +1 -1
  72. package/operations/entry/filtering/filter.d.ts +3 -3
  73. package/operations/entry/filtering/filter.js +24 -9
  74. package/operations/entry/filtering/filter.js.map +1 -1
  75. package/operations/entry/filtering/fullTextSearch.d.ts +3 -3
  76. package/operations/entry/filtering/fullTextSearch.js +3 -1
  77. package/operations/entry/filtering/fullTextSearch.js.map +1 -1
  78. package/operations/entry/filtering/getValue.js +6 -3
  79. package/operations/entry/filtering/getValue.js.map +1 -1
  80. package/operations/entry/filtering/index.js +3 -1
  81. package/operations/entry/filtering/index.js.map +1 -1
  82. package/operations/entry/filtering/mapPlugins.d.ts +2 -2
  83. package/operations/entry/filtering/mapPlugins.js +3 -1
  84. package/operations/entry/filtering/mapPlugins.js.map +1 -1
  85. package/operations/entry/filtering/plugins/defaultFilterCreate.d.ts +1 -1
  86. package/operations/entry/filtering/plugins/defaultFilterCreate.js +6 -2
  87. package/operations/entry/filtering/plugins/defaultFilterCreate.js.map +1 -1
  88. package/operations/entry/filtering/plugins/index.d.ts +1 -1
  89. package/operations/entry/filtering/plugins/index.js +5 -2
  90. package/operations/entry/filtering/plugins/index.js.map +1 -1
  91. package/operations/entry/filtering/plugins/objectFilterCreate.d.ts +1 -1
  92. package/operations/entry/filtering/plugins/objectFilterCreate.js +6 -2
  93. package/operations/entry/filtering/plugins/objectFilterCreate.js.map +1 -1
  94. package/operations/entry/filtering/plugins/refFilterCreate.d.ts +2 -1
  95. package/operations/entry/filtering/plugins/refFilterCreate.js +12 -3
  96. package/operations/entry/filtering/plugins/refFilterCreate.js.map +1 -1
  97. package/operations/entry/filtering/plugins/searchableJsonFilterCreate.d.ts +2 -0
  98. package/operations/entry/filtering/plugins/searchableJsonFilterCreate.js +65 -0
  99. package/operations/entry/filtering/plugins/searchableJsonFilterCreate.js.map +1 -0
  100. package/operations/entry/filtering/sort.d.ts +3 -3
  101. package/operations/entry/filtering/sort.js +5 -3
  102. package/operations/entry/filtering/sort.js.map +1 -1
  103. package/operations/entry/filtering/systemFields.d.ts +2 -2
  104. package/operations/entry/filtering/systemFields.js +49 -29
  105. package/operations/entry/filtering/systemFields.js.map +1 -1
  106. package/operations/entry/filtering/transform.d.ts +1 -1
  107. package/operations/entry/filtering/transform.js +3 -1
  108. package/operations/entry/filtering/transform.js.map +1 -1
  109. package/operations/entry/filtering/types.d.ts +2 -2
  110. package/operations/entry/filtering/types.js +3 -1
  111. package/operations/entry/filtering/types.js.map +1 -1
  112. package/operations/entry/filtering/values.d.ts +1 -1
  113. package/operations/entry/filtering/values.js +3 -1
  114. package/operations/entry/filtering/values.js.map +1 -1
  115. package/operations/entry/filtering/where.js +6 -3
  116. package/operations/entry/filtering/where.js.map +1 -1
  117. package/operations/entry/index.d.ts +3 -3
  118. package/operations/entry/index.js +712 -193
  119. package/operations/entry/index.js.map +1 -1
  120. package/operations/entry/keys.js +3 -1
  121. package/operations/entry/keys.js.map +1 -1
  122. package/operations/group/index.d.ts +3 -3
  123. package/operations/group/index.js +33 -21
  124. package/operations/group/index.js.map +1 -1
  125. package/operations/model/index.d.ts +2 -2
  126. package/operations/model/index.js +26 -13
  127. package/operations/model/index.js.map +1 -1
  128. package/operations/system/index.d.ts +2 -2
  129. package/operations/system/index.js +19 -7
  130. package/operations/system/index.js.map +1 -1
  131. package/package.json +21 -26
  132. package/plugins/CmsEntryFieldFilterPathPlugin.d.ts +3 -2
  133. package/plugins/CmsEntryFieldFilterPathPlugin.js +11 -4
  134. package/plugins/CmsEntryFieldFilterPathPlugin.js.map +1 -1
  135. package/plugins/CmsEntryFieldFilterPlugin.d.ts +10 -10
  136. package/plugins/CmsEntryFieldFilterPlugin.js +9 -6
  137. package/plugins/CmsEntryFieldFilterPlugin.js.map +1 -1
  138. package/plugins/CmsEntryFieldSortingPlugin.d.ts +2 -2
  139. package/plugins/CmsEntryFieldSortingPlugin.js +4 -5
  140. package/plugins/CmsEntryFieldSortingPlugin.js.map +1 -1
  141. package/plugins/CmsFieldFilterValueTransformPlugin.d.ts +11 -0
  142. package/plugins/CmsFieldFilterValueTransformPlugin.js +23 -0
  143. package/plugins/CmsFieldFilterValueTransformPlugin.js.map +1 -0
  144. package/plugins/index.d.ts +1 -0
  145. package/plugins/index.js +14 -1
  146. package/plugins/index.js.map +1 -1
  147. package/types.d.ts +20 -13
  148. package/types.js +5 -5
  149. package/types.js.map +1 -1
  150. package/definitions/settings.d.ts +0 -9
  151. package/definitions/settings.js +0 -53
  152. package/definitions/settings.js.map +0 -1
  153. package/dynamoDb/storage/date.d.ts +0 -3
  154. package/dynamoDb/storage/date.js +0 -91
  155. package/dynamoDb/storage/date.js.map +0 -1
  156. package/operations/entry/systemFields.d.ts +0 -2
  157. package/operations/entry/systemFields.js +0 -72
  158. package/operations/entry/systemFields.js.map +0 -1
  159. package/operations/settings/index.d.ts +0 -7
  160. package/operations/settings/index.js +0 -111
  161. package/operations/settings/index.js.map +0 -1
@@ -5,19 +5,17 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.createEntriesStorageOperations = void 0;
8
- var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
9
8
  var _error = _interopRequireDefault(require("@webiny/error"));
10
9
  var _dataLoaders = require("./dataLoaders");
11
10
  var _types = require("@webiny/api-headless-cms/types");
12
11
  var _keys = require("./keys");
13
- var _batchWrite = require("@webiny/db-dynamodb/utils/batchWrite");
14
- var _query = require("@webiny/db-dynamodb/utils/query");
15
- var _cleanup = require("@webiny/db-dynamodb/utils/cleanup");
12
+ var _dbDynamodb = require("@webiny/db-dynamodb");
16
13
  var _cursor = require("@webiny/utils/cursor");
17
14
  var _zeroPad = require("@webiny/utils/zeroPad");
18
15
  var _apiHeadlessCms = require("@webiny/api-headless-cms");
19
16
  var _createFields = require("./filtering/createFields");
20
17
  var _filtering = require("./filtering");
18
+ var _constants = require("@webiny/api-headless-cms/constants");
21
19
  const createType = () => {
22
20
  return "cms.entry";
23
21
  };
@@ -36,9 +34,10 @@ const convertToStorageEntry = params => {
36
34
  fields: model.fields,
37
35
  values: storageEntry.values
38
36
  });
39
- return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
37
+ return {
38
+ ...storageEntry,
40
39
  values
41
- });
40
+ };
42
41
  };
43
42
  const convertFromStorageEntry = params => {
44
43
  const {
@@ -49,23 +48,38 @@ const convertFromStorageEntry = params => {
49
48
  fields: model.fields,
50
49
  values: storageEntry.values
51
50
  });
52
- return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
51
+ return {
52
+ ...storageEntry,
53
53
  values
54
- });
54
+ };
55
55
  };
56
+ const MAX_LIST_LIMIT = 1000000;
56
57
  const createEntriesStorageOperations = params => {
57
58
  const {
58
59
  entity,
59
60
  plugins
60
61
  } = params;
62
+ let storageOperationsCmsModelPlugin;
63
+ const getStorageOperationsCmsModelPlugin = () => {
64
+ if (storageOperationsCmsModelPlugin) {
65
+ return storageOperationsCmsModelPlugin;
66
+ }
67
+ storageOperationsCmsModelPlugin = plugins.oneByType(_apiHeadlessCms.StorageOperationsCmsModelPlugin.type);
68
+ return storageOperationsCmsModelPlugin;
69
+ };
70
+ const getStorageOperationsModel = model => {
71
+ const plugin = getStorageOperationsCmsModelPlugin();
72
+ return plugin.getModel(model);
73
+ };
61
74
  const dataLoaders = new _dataLoaders.DataLoadersHandler({
62
75
  entity
63
76
  });
64
- const storageTransformPlugins = plugins.byType(_apiHeadlessCms.StorageTransformPlugin.type).reduce((collection, plugin) => {
65
- collection[plugin.fieldType] = plugin;
66
- return collection;
67
- }, {});
68
77
  const createStorageTransformCallable = model => {
78
+ // Cache StorageTransformPlugin to optimize execution.
79
+ const storageTransformPlugins = plugins.byType(_apiHeadlessCms.StorageTransformPlugin.type).reduce((collection, plugin) => {
80
+ collection[plugin.fieldType] = plugin;
81
+ return collection;
82
+ }, {});
69
83
  return (field, value) => {
70
84
  const plugin = storageTransformPlugins[field.type];
71
85
  if (!plugin) {
@@ -82,11 +96,12 @@ const createEntriesStorageOperations = params => {
82
96
  });
83
97
  };
84
98
  };
85
- const create = async (model, params) => {
99
+ const create = async (initialModel, params) => {
86
100
  const {
87
101
  entry,
88
102
  storageEntry: initialStorageEntry
89
103
  } = params;
104
+ const model = getStorageOperationsModel(initialModel);
90
105
  const partitionKey = (0, _keys.createPartitionKey)({
91
106
  id: entry.id,
92
107
  locale: model.locale,
@@ -101,42 +116,45 @@ const createEntriesStorageOperations = params => {
101
116
  /**
102
117
  * We need to:
103
118
  * - create new main entry item
104
- * - create new or update latest entry item
119
+ * - create new or update the latest entry item
105
120
  */
106
- const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
107
- locked,
108
- PK: partitionKey,
109
- SK: (0, _keys.createRevisionSortKey)(entry),
110
- TYPE: createType(),
111
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
112
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
113
- })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
114
- locked,
115
- PK: partitionKey,
116
- SK: (0, _keys.createLatestSortKey)(),
117
- TYPE: createLatestType(),
118
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
119
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
120
- }))];
121
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
122
+ entity,
123
+ put: [{
124
+ ...storageEntry,
125
+ locked,
126
+ PK: partitionKey,
127
+ SK: (0, _keys.createRevisionSortKey)(entry),
128
+ TYPE: createType(),
129
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
130
+ GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
131
+ }, {
132
+ ...storageEntry,
133
+ locked,
134
+ PK: partitionKey,
135
+ SK: (0, _keys.createLatestSortKey)(),
136
+ TYPE: createLatestType(),
137
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
138
+ GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
139
+ }]
140
+ });
121
141
 
122
142
  /**
123
143
  * We need to create published entry if
124
144
  */
125
145
  if (isPublished) {
126
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
146
+ entityBatch.put({
147
+ ...storageEntry,
127
148
  locked,
128
149
  PK: partitionKey,
129
150
  SK: (0, _keys.createPublishedSortKey)(),
130
151
  TYPE: createLatestType(),
131
152
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
132
153
  GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
133
- })));
154
+ });
134
155
  }
135
156
  try {
136
- await (0, _batchWrite.batchWriteAll)({
137
- table: entity.table,
138
- items
139
- });
157
+ await entityBatch.execute();
140
158
  dataLoaders.clearAll({
141
159
  model
142
160
  });
@@ -148,11 +166,12 @@ const createEntriesStorageOperations = params => {
148
166
  }
149
167
  return initialStorageEntry;
150
168
  };
151
- const createRevisionFrom = async (model, params) => {
169
+ const createRevisionFrom = async (initialModel, params) => {
152
170
  const {
153
171
  entry,
154
172
  storageEntry: initialStorageEntry
155
173
  } = params;
174
+ const model = getStorageOperationsModel(initialModel);
156
175
  const partitionKey = (0, _keys.createPartitionKey)({
157
176
  id: entry.id,
158
177
  locale: model.locale,
@@ -162,29 +181,63 @@ const createEntriesStorageOperations = params => {
162
181
  storageEntry: initialStorageEntry,
163
182
  model
164
183
  });
184
+
165
185
  /**
166
186
  * We need to:
167
187
  * - create the main entry item
168
- * - update the last entry item to a current one
188
+ * - update the latest entry item to the current one
189
+ * - if the entry's status was set to "published":
190
+ * - update the published entry item to the current one
191
+ * - unpublish previously published revision (if any)
169
192
  */
170
- const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
171
- PK: partitionKey,
172
- SK: (0, _keys.createRevisionSortKey)(storageEntry),
173
- TYPE: createType(),
174
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
175
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
176
- })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
177
- PK: partitionKey,
178
- SK: (0, _keys.createLatestSortKey)(),
179
- TYPE: createLatestType(),
180
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
181
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
182
- }))];
183
- try {
184
- await (0, _batchWrite.batchWriteAll)({
185
- table: entity.table,
186
- items
193
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
194
+ entity,
195
+ put: [{
196
+ ...storageEntry,
197
+ PK: partitionKey,
198
+ SK: (0, _keys.createRevisionSortKey)(storageEntry),
199
+ TYPE: createType(),
200
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
201
+ GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
202
+ }, {
203
+ ...storageEntry,
204
+ PK: partitionKey,
205
+ SK: (0, _keys.createLatestSortKey)(),
206
+ TYPE: createLatestType(),
207
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
208
+ GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
209
+ }]
210
+ });
211
+ const isPublished = entry.status === "published";
212
+ if (isPublished) {
213
+ entityBatch.put({
214
+ ...storageEntry,
215
+ PK: partitionKey,
216
+ SK: (0, _keys.createPublishedSortKey)(),
217
+ TYPE: createPublishedType(),
218
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
219
+ GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
220
+ });
221
+
222
+ // Unpublish previously published revision (if any).
223
+ const [publishedRevisionStorageEntry] = await dataLoaders.getPublishedRevisionByEntryId({
224
+ model,
225
+ ids: [entry.id]
187
226
  });
227
+ if (publishedRevisionStorageEntry) {
228
+ entityBatch.put({
229
+ ...publishedRevisionStorageEntry,
230
+ PK: partitionKey,
231
+ SK: (0, _keys.createRevisionSortKey)(publishedRevisionStorageEntry),
232
+ TYPE: createType(),
233
+ status: _types.CONTENT_ENTRY_STATUS.UNPUBLISHED,
234
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
235
+ GSI1_SK: (0, _keys.createGSISortKey)(publishedRevisionStorageEntry)
236
+ });
237
+ }
238
+ }
239
+ try {
240
+ await entityBatch.execute();
188
241
  dataLoaders.clearAll({
189
242
  model
190
243
  });
@@ -200,11 +253,12 @@ const createEntriesStorageOperations = params => {
200
253
  */
201
254
  return initialStorageEntry;
202
255
  };
203
- const update = async (model, params) => {
256
+ const update = async (initialModel, params) => {
204
257
  const {
205
258
  entry,
206
259
  storageEntry: initialStorageEntry
207
260
  } = params;
261
+ const model = getStorageOperationsModel(initialModel);
208
262
  const partitionKey = (0, _keys.createPartitionKey)({
209
263
  id: entry.id,
210
264
  locale: model.locale,
@@ -212,7 +266,6 @@ const createEntriesStorageOperations = params => {
212
266
  });
213
267
  const isPublished = entry.status === "published";
214
268
  const locked = isPublished ? true : entry.locked;
215
- const items = [];
216
269
  const storageEntry = convertToStorageEntry({
217
270
  model,
218
271
  storageEntry: initialStorageEntry
@@ -222,44 +275,81 @@ const createEntriesStorageOperations = params => {
222
275
  * - update the current entry
223
276
  * - update the latest entry if the current entry is the latest one
224
277
  */
225
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
226
- locked,
227
- PK: partitionKey,
228
- SK: (0, _keys.createRevisionSortKey)(storageEntry),
229
- TYPE: createType(),
230
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
231
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
232
- })));
278
+
279
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
280
+ entity,
281
+ put: [{
282
+ ...storageEntry,
283
+ locked,
284
+ PK: partitionKey,
285
+ SK: (0, _keys.createRevisionSortKey)(storageEntry),
286
+ TYPE: createType(),
287
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
288
+ GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
289
+ }]
290
+ });
233
291
  if (isPublished) {
234
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
292
+ entityBatch.put({
293
+ ...storageEntry,
235
294
  locked,
236
295
  PK: partitionKey,
237
296
  SK: (0, _keys.createPublishedSortKey)(),
238
297
  TYPE: createPublishedType(),
239
298
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
240
299
  GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
241
- })));
300
+ });
242
301
  }
243
302
 
244
303
  /**
245
- * We need the latest entry to update it as well if neccessary.
304
+ * We need the latest entry to update it as well if necessary.
246
305
  */
247
306
  const latestStorageEntry = await getLatestRevisionByEntryId(model, entry);
248
- if (latestStorageEntry && latestStorageEntry.id === entry.id) {
249
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
250
- locked,
251
- PK: partitionKey,
252
- SK: (0, _keys.createLatestSortKey)(),
253
- TYPE: createLatestType(),
254
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
255
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
256
- })));
307
+ if (latestStorageEntry) {
308
+ const updatingLatestRevision = latestStorageEntry.id === entry.id;
309
+ if (updatingLatestRevision) {
310
+ entityBatch.put({
311
+ ...storageEntry,
312
+ locked,
313
+ PK: partitionKey,
314
+ SK: (0, _keys.createLatestSortKey)(),
315
+ TYPE: createLatestType(),
316
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
317
+ GSI1_SK: (0, _keys.createGSISortKey)(entry)
318
+ });
319
+ } else {
320
+ /**
321
+ * If not updating latest revision, we still want to update the latest revision's
322
+ * entry-level meta fields to match the current revision's entry-level meta fields.
323
+ */
324
+ const updatedEntryLevelMetaFields = (0, _constants.pickEntryMetaFields)(entry, _constants.isEntryLevelEntryMetaField);
325
+
326
+ /**
327
+ * First we update the regular DynamoDB table. Two updates are needed:
328
+ * - one for the actual revision record
329
+ * - one for the latest record
330
+ */
331
+ entityBatch.put({
332
+ ...latestStorageEntry,
333
+ ...updatedEntryLevelMetaFields,
334
+ PK: partitionKey,
335
+ SK: (0, _keys.createRevisionSortKey)(latestStorageEntry),
336
+ TYPE: createType(),
337
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
338
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
339
+ });
340
+ entityBatch.put({
341
+ ...latestStorageEntry,
342
+ ...updatedEntryLevelMetaFields,
343
+ PK: partitionKey,
344
+ SK: (0, _keys.createLatestSortKey)(),
345
+ TYPE: createLatestType(),
346
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
347
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
348
+ });
349
+ }
257
350
  }
258
351
  try {
259
- await (0, _batchWrite.batchWriteAll)({
260
- table: entity.table,
261
- items
262
- });
352
+ await entityBatch.execute();
263
353
  dataLoaders.clearAll({
264
354
  model
265
355
  });
@@ -272,10 +362,69 @@ const createEntriesStorageOperations = params => {
272
362
  });
273
363
  }
274
364
  };
275
- const deleteEntry = async (model, params) => {
365
+ const move = async (initialModel, id, folderId) => {
366
+ /**
367
+ * We need to:
368
+ * - load all the revisions of the entry, including published and latest
369
+ * - update all the revisions (published and latest ) of the entry with new folderId
370
+ */
371
+ const model = getStorageOperationsModel(initialModel);
372
+ /**
373
+ * First we need to load all the revisions and published / latest entry.
374
+ */
375
+ const queryAllParams = {
376
+ entity,
377
+ partitionKey: (0, _keys.createPartitionKey)({
378
+ id,
379
+ locale: model.locale,
380
+ tenant: model.tenant
381
+ }),
382
+ options: {
383
+ gte: " "
384
+ }
385
+ };
386
+ const records = await (0, _dbDynamodb.queryAll)(queryAllParams);
387
+ /**
388
+ * Then create the batch writes for the DynamoDB, with the updated folderId.
389
+ */
390
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
391
+ entity,
392
+ put: records.map(item => {
393
+ return {
394
+ ...item,
395
+ location: {
396
+ ...item.location,
397
+ folderId
398
+ }
399
+ };
400
+ })
401
+ });
402
+
403
+ /**
404
+ * And finally write it...
405
+ */
406
+ try {
407
+ await entityBatch.execute();
408
+ } catch (ex) {
409
+ throw _error.default.from(ex, {
410
+ message: "Could not move records to a new folder.",
411
+ data: {
412
+ id,
413
+ folderId
414
+ }
415
+ });
416
+ }
417
+ };
418
+ const moveToBin = async (initialModel, params) => {
276
419
  const {
277
- entry
420
+ entry,
421
+ storageEntry: initialStorageEntry
278
422
  } = params;
423
+ const model = getStorageOperationsModel(initialModel);
424
+
425
+ /**
426
+ * First we need to load all the revisions and published / latest entries.
427
+ */
279
428
  const queryAllParams = {
280
429
  entity,
281
430
  partitionKey: (0, _keys.createPartitionKey)({
@@ -289,24 +438,91 @@ const createEntriesStorageOperations = params => {
289
438
  };
290
439
  let records = [];
291
440
  try {
292
- records = await (0, _query.queryAll)(queryAllParams);
441
+ records = await (0, _dbDynamodb.queryAll)(queryAllParams);
293
442
  } catch (ex) {
294
443
  throw new _error.default(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
295
444
  error: ex,
296
- entry
445
+ id: entry.id
297
446
  });
298
447
  }
299
- const items = records.map(item => {
300
- return entity.deleteBatch({
301
- PK: item.PK,
302
- SK: item.SK
303
- });
448
+ if (records.length === 0) {
449
+ return;
450
+ }
451
+ const storageEntry = convertToStorageEntry({
452
+ model,
453
+ storageEntry: initialStorageEntry
454
+ });
455
+
456
+ /**
457
+ * Let's pick the `deleted` meta fields from the storage entry.
458
+ */
459
+ const updatedDeletedMetaFields = (0, _constants.pickEntryMetaFields)(storageEntry, _constants.isDeletedEntryMetaField);
460
+
461
+ /**
462
+ * Then create the batch writes for the DynamoDB, with the updated data.
463
+ */
464
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
465
+ entity,
466
+ put: records.map(record => {
467
+ return {
468
+ ...record,
469
+ ...updatedDeletedMetaFields,
470
+ wbyDeleted: storageEntry.wbyDeleted,
471
+ location: storageEntry.location,
472
+ binOriginalFolderId: storageEntry.binOriginalFolderId
473
+ };
474
+ })
304
475
  });
476
+ /**
477
+ * And finally write it...
478
+ */
305
479
  try {
306
- await (0, _batchWrite.batchWriteAll)({
307
- table: entity.table,
308
- items
480
+ await entityBatch.execute();
481
+ } catch (ex) {
482
+ throw new _error.default(ex.message || "Could not move the entry to the bin.", ex.code || "MOVE_ENTRY_TO_BIN_ERROR", {
483
+ error: ex,
484
+ entry,
485
+ storageEntry
309
486
  });
487
+ }
488
+ };
489
+ const deleteEntry = async (initialModel, params) => {
490
+ const {
491
+ entry
492
+ } = params;
493
+ const id = entry.id || entry.entryId;
494
+ const model = getStorageOperationsModel(initialModel);
495
+ const queryAllParams = {
496
+ entity,
497
+ partitionKey: (0, _keys.createPartitionKey)({
498
+ id,
499
+ locale: model.locale,
500
+ tenant: model.tenant
501
+ }),
502
+ options: {
503
+ gte: " "
504
+ }
505
+ };
506
+ let records = [];
507
+ try {
508
+ records = await (0, _dbDynamodb.queryAll)(queryAllParams);
509
+ } catch (ex) {
510
+ throw new _error.default(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
511
+ error: ex,
512
+ id
513
+ });
514
+ }
515
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
516
+ entity,
517
+ delete: records.map(item => {
518
+ return {
519
+ PK: item.PK,
520
+ SK: item.SK
521
+ };
522
+ })
523
+ });
524
+ try {
525
+ await entityBatch.execute();
310
526
  dataLoaders.clearAll({
311
527
  model
312
528
  });
@@ -314,54 +530,139 @@ const createEntriesStorageOperations = params => {
314
530
  throw new _error.default(ex.message || "Could not delete the entry.", ex.code || "DELETE_ENTRY_ERROR", {
315
531
  error: ex,
316
532
  partitionKey: queryAllParams.partitionKey,
317
- entry
533
+ id
318
534
  });
319
535
  }
320
536
  };
321
- const deleteRevision = async (model, params) => {
537
+ const restoreFromBin = async (initialModel, params) => {
538
+ const {
539
+ entry,
540
+ storageEntry: initialStorageEntry
541
+ } = params;
542
+ const model = getStorageOperationsModel(initialModel);
543
+
544
+ /**
545
+ * First we need to load all the revisions and published / latest entries.
546
+ */
547
+ const queryAllParams = {
548
+ entity,
549
+ partitionKey: (0, _keys.createPartitionKey)({
550
+ id: entry.id,
551
+ locale: model.locale,
552
+ tenant: model.tenant
553
+ }),
554
+ options: {
555
+ gte: " "
556
+ }
557
+ };
558
+ let records = [];
559
+ try {
560
+ records = await (0, _dbDynamodb.queryAll)(queryAllParams);
561
+ } catch (ex) {
562
+ throw new _error.default(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
563
+ error: ex,
564
+ id: entry.id
565
+ });
566
+ }
567
+ if (records.length === 0) {
568
+ return initialStorageEntry;
569
+ }
570
+ const storageEntry = convertToStorageEntry({
571
+ model,
572
+ storageEntry: initialStorageEntry
573
+ });
574
+
575
+ /**
576
+ * Let's pick the `restored` meta fields from the storage entry.
577
+ */
578
+ const updatedRestoredMetaFields = (0, _constants.pickEntryMetaFields)(storageEntry, _constants.isRestoredEntryMetaField);
579
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
580
+ entity,
581
+ put: records.map(record => {
582
+ return {
583
+ ...record,
584
+ ...updatedRestoredMetaFields,
585
+ wbyDeleted: storageEntry.wbyDeleted,
586
+ location: storageEntry.location,
587
+ binOriginalFolderId: storageEntry.binOriginalFolderId
588
+ };
589
+ })
590
+ });
591
+
592
+ /**
593
+ * And finally write it...
594
+ */
595
+ try {
596
+ await entityBatch.execute();
597
+ dataLoaders.clearAll({
598
+ model
599
+ });
600
+ return initialStorageEntry;
601
+ } catch (ex) {
602
+ throw new _error.default(ex.message || "Could not restore the entry from the bin.", ex.code || "RESTORE_ENTRY_ERROR", {
603
+ error: ex,
604
+ entry,
605
+ storageEntry
606
+ });
607
+ }
608
+ };
609
+ const deleteRevision = async (initialModel, params) => {
322
610
  const {
323
611
  entry,
324
612
  latestEntry,
325
613
  latestStorageEntry: initialLatestStorageEntry
326
614
  } = params;
615
+ const model = getStorageOperationsModel(initialModel);
327
616
  const partitionKey = (0, _keys.createPartitionKey)({
328
617
  id: entry.id,
329
618
  locale: model.locale,
330
619
  tenant: model.tenant
331
620
  });
332
- const items = [entity.deleteBatch({
333
- PK: partitionKey,
334
- SK: (0, _keys.createRevisionSortKey)(entry)
335
- })];
621
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
622
+ entity,
623
+ delete: [{
624
+ PK: partitionKey,
625
+ SK: (0, _keys.createRevisionSortKey)(entry)
626
+ }]
627
+ });
336
628
  const publishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
337
629
 
338
630
  /**
339
631
  * If revision we are deleting is the published one as well, we need to delete those records as well.
340
632
  */
341
633
  if (publishedStorageEntry && entry.id === publishedStorageEntry.id) {
342
- items.push(entity.deleteBatch({
634
+ entityBatch.delete({
343
635
  PK: partitionKey,
344
636
  SK: (0, _keys.createPublishedSortKey)()
345
- }));
637
+ });
346
638
  }
347
639
  if (initialLatestStorageEntry) {
348
640
  const latestStorageEntry = convertToStorageEntry({
349
641
  storageEntry: initialLatestStorageEntry,
350
642
  model
351
643
  });
352
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, latestStorageEntry), {}, {
644
+ entityBatch.put({
645
+ ...latestStorageEntry,
353
646
  PK: partitionKey,
354
647
  SK: (0, _keys.createLatestSortKey)(),
355
648
  TYPE: createLatestType(),
356
649
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
357
650
  GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
358
- })));
651
+ });
652
+
653
+ // Do an update on the latest revision. We need to update the latest revision's
654
+ // entry-level meta fields to match the previous revision's entry-level meta fields.
655
+ entityBatch.put({
656
+ ...latestStorageEntry,
657
+ PK: partitionKey,
658
+ SK: (0, _keys.createRevisionSortKey)(initialLatestStorageEntry),
659
+ TYPE: createType(),
660
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
661
+ GSI1_SK: (0, _keys.createGSISortKey)(initialLatestStorageEntry)
662
+ });
359
663
  }
360
664
  try {
361
- await (0, _batchWrite.batchWriteAll)({
362
- table: entity.table,
363
- items
364
- });
665
+ entityBatch.execute();
365
666
  dataLoaders.clearAll({
366
667
  model
367
668
  });
@@ -373,7 +674,59 @@ const createEntriesStorageOperations = params => {
373
674
  });
374
675
  }
375
676
  };
376
- const getLatestRevisionByEntryId = async (model, params) => {
677
+ const deleteMultipleEntries = async (initialModel, params) => {
678
+ const {
679
+ entries
680
+ } = params;
681
+ const model = getStorageOperationsModel(initialModel);
682
+ /**
683
+ * First we need all the revisions of the entries we want to delete.
684
+ */
685
+ const revisions = await dataLoaders.getAllEntryRevisions({
686
+ model,
687
+ ids: entries
688
+ });
689
+ /**
690
+ * Then we need to construct the queries for all the revisions and entries.
691
+ */
692
+
693
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
694
+ entity
695
+ });
696
+ for (const id of entries) {
697
+ const partitionKey = (0, _keys.createPartitionKey)({
698
+ id,
699
+ locale: model.locale,
700
+ tenant: model.tenant
701
+ });
702
+ entityBatch.delete({
703
+ PK: partitionKey,
704
+ SK: "L"
705
+ });
706
+ entityBatch.delete({
707
+ PK: partitionKey,
708
+ SK: "P"
709
+ });
710
+ }
711
+ /**
712
+ * Exact revisions of all the entries
713
+ */
714
+ for (const revision of revisions) {
715
+ entityBatch.delete({
716
+ PK: (0, _keys.createPartitionKey)({
717
+ id: revision.id,
718
+ locale: model.locale,
719
+ tenant: model.tenant
720
+ }),
721
+ SK: (0, _keys.createRevisionSortKey)({
722
+ version: revision.version
723
+ })
724
+ });
725
+ }
726
+ await entityBatch.execute();
727
+ };
728
+ const getLatestRevisionByEntryId = async (initialModel, params) => {
729
+ const model = getStorageOperationsModel(initialModel);
377
730
  const items = await dataLoaders.getLatestRevisionByEntryId({
378
731
  model,
379
732
  ids: [params.id]
@@ -387,7 +740,8 @@ const createEntriesStorageOperations = params => {
387
740
  model
388
741
  });
389
742
  };
390
- const getPublishedRevisionByEntryId = async (model, params) => {
743
+ const getPublishedRevisionByEntryId = async (initialModel, params) => {
744
+ const model = getStorageOperationsModel(initialModel);
391
745
  const items = await dataLoaders.getPublishedRevisionByEntryId({
392
746
  model,
393
747
  ids: [params.id]
@@ -401,7 +755,8 @@ const createEntriesStorageOperations = params => {
401
755
  model
402
756
  });
403
757
  };
404
- const getRevisionById = async (model, params) => {
758
+ const getRevisionById = async (initialModel, params) => {
759
+ const model = getStorageOperationsModel(initialModel);
405
760
  const items = await dataLoaders.getRevisionById({
406
761
  model,
407
762
  ids: [params.id]
@@ -415,7 +770,8 @@ const createEntriesStorageOperations = params => {
415
770
  model
416
771
  });
417
772
  };
418
- const getRevisions = async (model, params) => {
773
+ const getRevisions = async (initialModel, params) => {
774
+ const model = getStorageOperationsModel(initialModel);
419
775
  const items = await dataLoaders.getAllEntryRevisions({
420
776
  model,
421
777
  ids: [params.id]
@@ -427,7 +783,8 @@ const createEntriesStorageOperations = params => {
427
783
  });
428
784
  });
429
785
  };
430
- const getByIds = async (model, params) => {
786
+ const getByIds = async (initialModel, params) => {
787
+ const model = getStorageOperationsModel(initialModel);
431
788
  const items = await dataLoaders.getRevisionById({
432
789
  model,
433
790
  ids: params.ids
@@ -439,7 +796,8 @@ const createEntriesStorageOperations = params => {
439
796
  });
440
797
  });
441
798
  };
442
- const getLatestByIds = async (model, params) => {
799
+ const getLatestByIds = async (initialModel, params) => {
800
+ const model = getStorageOperationsModel(initialModel);
443
801
  const items = await dataLoaders.getLatestRevisionByEntryId({
444
802
  model,
445
803
  ids: params.ids
@@ -451,7 +809,8 @@ const createEntriesStorageOperations = params => {
451
809
  });
452
810
  });
453
811
  };
454
- const getPublishedByIds = async (model, params) => {
812
+ const getPublishedByIds = async (initialModel, params) => {
813
+ const model = getStorageOperationsModel(initialModel);
455
814
  const items = await dataLoaders.getPublishedRevisionByEntryId({
456
815
  model,
457
816
  ids: params.ids
@@ -463,7 +822,8 @@ const createEntriesStorageOperations = params => {
463
822
  });
464
823
  });
465
824
  };
466
- const getPreviousRevision = async (model, params) => {
825
+ const getPreviousRevision = async (initialModel, params) => {
826
+ const model = getStorageOperationsModel(initialModel);
467
827
  const {
468
828
  entryId,
469
829
  version
@@ -491,8 +851,8 @@ const createEntriesStorageOperations = params => {
491
851
  }
492
852
  };
493
853
  try {
494
- const result = await (0, _query.queryOne)(queryParams);
495
- const storageEntry = (0, _cleanup.cleanupItem)(entity, result);
854
+ const result = await (0, _dbDynamodb.queryOne)(queryParams);
855
+ const storageEntry = (0, _dbDynamodb.cleanupItem)(entity, result);
496
856
  if (!storageEntry) {
497
857
  return null;
498
858
  }
@@ -501,15 +861,17 @@ const createEntriesStorageOperations = params => {
501
861
  model
502
862
  });
503
863
  } catch (ex) {
504
- throw new _error.default(ex.message || "Could not get previous version of given entry.", ex.code || "GET_PREVIOUS_VERSION_ERROR", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, params), {}, {
864
+ throw new _error.default(ex.message || "Could not get previous version of given entry.", ex.code || "GET_PREVIOUS_VERSION_ERROR", {
865
+ ...params,
505
866
  error: ex,
506
867
  partitionKey: queryParams.partitionKey,
507
868
  options: queryParams.options,
508
869
  model
509
- }));
870
+ });
510
871
  }
511
872
  };
512
- const list = async (model, params) => {
873
+ const list = async (initialModel, params) => {
874
+ const model = getStorageOperationsModel(initialModel);
513
875
  const {
514
876
  limit: initialLimit = 10,
515
877
  where: initialWhere,
@@ -518,7 +880,7 @@ const createEntriesStorageOperations = params => {
518
880
  fields,
519
881
  search
520
882
  } = params;
521
- const limit = initialLimit <= 0 || initialLimit >= 10000 ? 10000 : initialLimit;
883
+ const limit = initialLimit <= 0 || initialLimit >= MAX_LIST_LIMIT ? MAX_LIST_LIMIT : initialLimit;
522
884
  const type = initialWhere.published ? "P" : "L";
523
885
  const queryAllParams = {
524
886
  entity,
@@ -530,7 +892,7 @@ const createEntriesStorageOperations = params => {
530
892
  };
531
893
  let storageEntries = [];
532
894
  try {
533
- storageEntries = await (0, _query.queryAll)(queryAllParams);
895
+ storageEntries = await (0, _dbDynamodb.queryAll)(queryAllParams);
534
896
  } catch (ex) {
535
897
  throw new _error.default(ex.message, "QUERY_ENTRIES_ERROR", {
536
898
  error: ex,
@@ -546,7 +908,9 @@ const createEntriesStorageOperations = params => {
546
908
  items: []
547
909
  };
548
910
  }
549
- const where = (0, _objectSpread2.default)({}, initialWhere);
911
+ const where = {
912
+ ...initialWhere
913
+ };
550
914
  delete where["published"];
551
915
  delete where["latest"];
552
916
  /**
@@ -608,27 +972,30 @@ const createEntriesStorageOperations = params => {
608
972
  * Although we do not need a cursor here, we will use it as such to keep it standardized.
609
973
  * Number is simply encoded.
610
974
  */
611
- const cursor = totalCount > start + limit ? (0, _cursor.encodeCursor)(`${start + limit}`) : null;
975
+ const cursor = (0, _cursor.encodeCursor)(`${start + limit}`);
612
976
  return {
613
977
  hasMoreItems,
614
978
  totalCount,
615
979
  cursor,
616
- items: (0, _cleanup.cleanupItems)(entity, slicedItems)
980
+ items: (0, _dbDynamodb.cleanupItems)(entity, slicedItems)
617
981
  };
618
982
  };
619
- const get = async (model, params) => {
983
+ const get = async (initialModel, params) => {
984
+ const model = getStorageOperationsModel(initialModel);
620
985
  const {
621
986
  items
622
- } = await list(model, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, params), {}, {
987
+ } = await list(model, {
988
+ ...params,
623
989
  limit: 1
624
- }));
990
+ });
625
991
  return items.shift() || null;
626
992
  };
627
- const publish = async (model, params) => {
993
+ const publish = async (initialModel, params) => {
628
994
  const {
629
995
  entry,
630
996
  storageEntry: initialStorageEntry
631
997
  } = params;
998
+ const model = getStorageOperationsModel(initialModel);
632
999
  const partitionKey = (0, _keys.createPartitionKey)({
633
1000
  id: entry.id,
634
1001
  locale: model.locale,
@@ -636,62 +1003,132 @@ const createEntriesStorageOperations = params => {
636
1003
  });
637
1004
 
638
1005
  /**
639
- * We need the latest and published entries to see if something needs to be updated along side the publishing one.
1006
+ * We need the latest and published entries to see if something needs to be updated alongside the publishing one.
640
1007
  */
641
1008
  const initialLatestStorageEntry = await getLatestRevisionByEntryId(model, entry);
1009
+ if (!initialLatestStorageEntry) {
1010
+ throw new _error.default(`Could not publish entry. Could not load latest ("L") record.`, "PUBLISH_ERROR", {
1011
+ entry
1012
+ });
1013
+ }
642
1014
  const initialPublishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
643
1015
  const storageEntry = convertToStorageEntry({
644
1016
  model,
645
1017
  storageEntry: initialStorageEntry
646
1018
  });
647
- /**
648
- * We need to update:
649
- * - current entry revision sort key
650
- * - published sort key
651
- * - latest sort key - if entry updated is actually latest
652
- * - previous published entry to unpublished status - if any previously published entry
653
- */
654
- const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
655
- PK: partitionKey,
656
- SK: (0, _keys.createRevisionSortKey)(entry),
657
- TYPE: createType(),
658
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
659
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
660
- })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
661
- PK: partitionKey,
662
- SK: (0, _keys.createPublishedSortKey)(),
663
- TYPE: createPublishedType(),
664
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
665
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
666
- }))];
667
- if (initialLatestStorageEntry && entry.id === initialLatestStorageEntry.id) {
668
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
1019
+
1020
+ // 1. Update REV# and P records with new data.
1021
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
1022
+ entity,
1023
+ put: [{
1024
+ ...storageEntry,
1025
+ PK: partitionKey,
1026
+ SK: (0, _keys.createRevisionSortKey)(entry),
1027
+ TYPE: createType(),
1028
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
1029
+ GSI1_SK: (0, _keys.createGSISortKey)(entry)
1030
+ }, {
1031
+ ...storageEntry,
1032
+ PK: partitionKey,
1033
+ SK: (0, _keys.createPublishedSortKey)(),
1034
+ TYPE: createPublishedType(),
1035
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
1036
+ GSI1_SK: (0, _keys.createGSISortKey)(entry)
1037
+ }]
1038
+ });
1039
+
1040
+ // 2. When it comes to the latest record, we need to perform a couple of different
1041
+ // updates, based on whether the entry being published is the latest revision or not.
1042
+ const publishedRevisionId = initialPublishedStorageEntry?.id;
1043
+ const publishingLatestRevision = entry.id === initialLatestStorageEntry.id;
1044
+ if (publishingLatestRevision) {
1045
+ // 2.1 If we're publishing the latest revision, we first need to update the L record.
1046
+ entityBatch.put({
1047
+ ...storageEntry,
669
1048
  PK: partitionKey,
670
1049
  SK: (0, _keys.createLatestSortKey)(),
671
1050
  TYPE: createLatestType(),
672
1051
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
673
1052
  GSI1_SK: (0, _keys.createGSISortKey)(entry)
674
- })));
675
- }
676
- if (initialPublishedStorageEntry && initialPublishedStorageEntry.id !== entry.id) {
677
- const publishedStorageEntry = convertToStorageEntry({
678
- storageEntry: initialPublishedStorageEntry,
1053
+ });
1054
+
1055
+ // 2.2 Additionally, if we have a previously published entry, we need to mark it as unpublished.
1056
+ if (publishedRevisionId && publishedRevisionId !== entry.id) {
1057
+ const publishedStorageEntry = convertToStorageEntry({
1058
+ storageEntry: initialPublishedStorageEntry,
1059
+ model
1060
+ });
1061
+ entityBatch.put({
1062
+ ...publishedStorageEntry,
1063
+ PK: partitionKey,
1064
+ SK: (0, _keys.createRevisionSortKey)(publishedStorageEntry),
1065
+ TYPE: createType(),
1066
+ status: _types.CONTENT_ENTRY_STATUS.UNPUBLISHED,
1067
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
1068
+ GSI1_SK: (0, _keys.createGSISortKey)(publishedStorageEntry)
1069
+ });
1070
+ }
1071
+ } else {
1072
+ // 2.3 If the published revision is not the latest one, the situation is a bit
1073
+ // more complex. We first need to update the L and REV# records with the new
1074
+ // values of *only entry-level* meta fields.
1075
+ const updatedEntryLevelMetaFields = (0, _constants.pickEntryMetaFields)(entry, _constants.isEntryLevelEntryMetaField);
1076
+ const latestStorageEntry = convertToStorageEntry({
1077
+ storageEntry: initialLatestStorageEntry,
679
1078
  model
680
1079
  });
681
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, publishedStorageEntry), {}, {
1080
+
1081
+ // 2.3.1 Update L record. Apart from updating the entry-level meta fields, we also need
1082
+ // to change the status from "published" to "unpublished" (if the status is set to "published").
1083
+ let latestRevisionStatus = latestStorageEntry.status;
1084
+ if (latestRevisionStatus === _types.CONTENT_ENTRY_STATUS.PUBLISHED) {
1085
+ latestRevisionStatus = _types.CONTENT_ENTRY_STATUS.UNPUBLISHED;
1086
+ }
1087
+ const latestStorageEntryFields = {
1088
+ ...latestStorageEntry,
1089
+ ...updatedEntryLevelMetaFields,
1090
+ status: latestRevisionStatus
1091
+ };
1092
+ entityBatch.put({
1093
+ ...latestStorageEntryFields,
682
1094
  PK: partitionKey,
683
- SK: (0, _keys.createRevisionSortKey)(publishedStorageEntry),
1095
+ SK: (0, _keys.createLatestSortKey)(),
1096
+ TYPE: createLatestType(),
1097
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
1098
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
1099
+ });
1100
+
1101
+ // 2.3.2 Update REV# record.
1102
+ entityBatch.put({
1103
+ ...latestStorageEntryFields,
1104
+ PK: partitionKey,
1105
+ SK: (0, _keys.createRevisionSortKey)(latestStorageEntry),
684
1106
  TYPE: createType(),
685
- status: _types.CONTENT_ENTRY_STATUS.UNPUBLISHED,
686
1107
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
687
- GSI1_SK: (0, _keys.createGSISortKey)(publishedStorageEntry)
688
- })));
1108
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
1109
+ });
1110
+
1111
+ // 2.3.3 Finally, if we got a published entry, but it wasn't the latest one, we need to take
1112
+ // an extra step and mark it as unpublished.
1113
+ const publishedRevisionDifferentFromLatest = publishedRevisionId && publishedRevisionId !== latestStorageEntry.id;
1114
+ if (publishedRevisionDifferentFromLatest) {
1115
+ const publishedStorageEntry = convertToStorageEntry({
1116
+ storageEntry: initialPublishedStorageEntry,
1117
+ model
1118
+ });
1119
+ entityBatch.put({
1120
+ ...publishedStorageEntry,
1121
+ PK: partitionKey,
1122
+ SK: (0, _keys.createRevisionSortKey)(publishedStorageEntry),
1123
+ TYPE: createType(),
1124
+ status: _types.CONTENT_ENTRY_STATUS.UNPUBLISHED,
1125
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
1126
+ GSI1_SK: (0, _keys.createGSISortKey)(publishedStorageEntry)
1127
+ });
1128
+ }
689
1129
  }
690
1130
  try {
691
- await (0, _batchWrite.batchWriteAll)({
692
- table: entity.table,
693
- items
694
- });
1131
+ await entityBatch.execute();
695
1132
  dataLoaders.clearAll({
696
1133
  model
697
1134
  });
@@ -704,11 +1141,12 @@ const createEntriesStorageOperations = params => {
704
1141
  });
705
1142
  }
706
1143
  };
707
- const unpublish = async (model, params) => {
1144
+ const unpublish = async (initialModel, params) => {
708
1145
  const {
709
1146
  entry,
710
1147
  storageEntry: initialStorageEntry
711
1148
  } = params;
1149
+ const model = getStorageOperationsModel(initialModel);
712
1150
  const partitionKey = (0, _keys.createPartitionKey)({
713
1151
  id: entry.id,
714
1152
  locale: model.locale,
@@ -722,37 +1160,74 @@ const createEntriesStorageOperations = params => {
722
1160
  * We need to:
723
1161
  * - delete currently published entry
724
1162
  * - update current entry revision with new data
725
- * - update latest entry status - if entry being unpublished is latest
1163
+ * - update the latest entry status - if entry being unpublished is latest
726
1164
  */
727
- const items = [entity.deleteBatch({
728
- PK: partitionKey,
729
- SK: (0, _keys.createPublishedSortKey)()
730
- }), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
731
- PK: partitionKey,
732
- SK: (0, _keys.createRevisionSortKey)(entry),
733
- TYPE: createType(),
734
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
735
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
736
- }))];
1165
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
1166
+ entity,
1167
+ delete: [{
1168
+ PK: partitionKey,
1169
+ SK: (0, _keys.createPublishedSortKey)()
1170
+ }],
1171
+ put: [{
1172
+ ...storageEntry,
1173
+ PK: partitionKey,
1174
+ SK: (0, _keys.createRevisionSortKey)(entry),
1175
+ TYPE: createType(),
1176
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
1177
+ GSI1_SK: (0, _keys.createGSISortKey)(entry)
1178
+ }]
1179
+ });
737
1180
 
738
1181
  /**
739
- * We need the latest entry to see if something needs to be updated along side the unpublishing one.
1182
+ * We need the latest entry to see if something needs to be updated alongside the unpublishing one.
740
1183
  */
741
- const latestStorageEntry = await getLatestRevisionByEntryId(model, entry);
742
- if (latestStorageEntry && entry.id === latestStorageEntry.id) {
743
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
744
- PK: partitionKey,
745
- SK: (0, _keys.createLatestSortKey)(),
746
- TYPE: createLatestType(),
747
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
748
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
749
- })));
1184
+ const initialLatestStorageEntry = await getLatestRevisionByEntryId(model, entry);
1185
+ if (initialLatestStorageEntry) {
1186
+ const unpublishingLatestRevision = entry.id === initialLatestStorageEntry.id;
1187
+ if (unpublishingLatestRevision) {
1188
+ entityBatch.put({
1189
+ ...storageEntry,
1190
+ PK: partitionKey,
1191
+ SK: (0, _keys.createLatestSortKey)(),
1192
+ TYPE: createLatestType(),
1193
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
1194
+ GSI1_SK: (0, _keys.createGSISortKey)(entry)
1195
+ });
1196
+ } else {
1197
+ const latestStorageEntry = convertToStorageEntry({
1198
+ storageEntry: initialLatestStorageEntry,
1199
+ model
1200
+ });
1201
+
1202
+ // If the unpublished revision is not the latest one, we still need to
1203
+ // update the latest record with the new values of entry-level meta fields.
1204
+ const updatedEntryLevelMetaFields = (0, _constants.pickEntryMetaFields)(entry, _constants.isEntryLevelEntryMetaField);
1205
+
1206
+ // 1. Update actual revision record.
1207
+ entityBatch.put({
1208
+ ...latestStorageEntry,
1209
+ ...updatedEntryLevelMetaFields,
1210
+ PK: partitionKey,
1211
+ SK: (0, _keys.createRevisionSortKey)(latestStorageEntry),
1212
+ TYPE: createType(),
1213
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
1214
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
1215
+ });
1216
+
1217
+ // 2. Update latest record.
1218
+ entityBatch.put({
1219
+ ...latestStorageEntry,
1220
+ ...updatedEntryLevelMetaFields,
1221
+ PK: partitionKey,
1222
+ SK: (0, _keys.createLatestSortKey)(),
1223
+ TYPE: createLatestType(),
1224
+ GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
1225
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
1226
+ });
1227
+ }
750
1228
  }
751
1229
  try {
752
- await (0, _batchWrite.batchWriteAll)({
753
- table: entity.table,
754
- items
755
- });
1230
+ await entityBatch.execute();
756
1231
  dataLoaders.clearAll({
757
1232
  model
758
1233
  });
@@ -764,12 +1239,52 @@ const createEntriesStorageOperations = params => {
764
1239
  });
765
1240
  }
766
1241
  };
1242
+ const getUniqueFieldValues = async (model, params) => {
1243
+ const {
1244
+ where,
1245
+ fieldId
1246
+ } = params;
1247
+ const field = model.fields.find(f => f.fieldId === fieldId);
1248
+ if (!field) {
1249
+ throw new _error.default(`Could not find field with given "fieldId" value.`, "FIELD_NOT_FOUND", {
1250
+ fieldId
1251
+ });
1252
+ }
1253
+ const {
1254
+ items
1255
+ } = await list(model, {
1256
+ where,
1257
+ limit: MAX_LIST_LIMIT
1258
+ });
1259
+ const result = {};
1260
+ for (const item of items) {
1261
+ const fieldValue = item.values[field.fieldId];
1262
+ if (!fieldValue) {
1263
+ continue;
1264
+ }
1265
+ const values = Array.isArray(fieldValue) ? fieldValue : [fieldValue];
1266
+ if (values.length === 0) {
1267
+ continue;
1268
+ }
1269
+ for (const value of values) {
1270
+ result[value] = {
1271
+ value,
1272
+ count: (result[value]?.count || 0) + 1
1273
+ };
1274
+ }
1275
+ }
1276
+ return Object.values(result).sort((a, b) => a.value > b.value ? 1 : b.value > a.value ? -1 : 0).sort((a, b) => b.count - a.count);
1277
+ };
767
1278
  return {
768
1279
  create,
769
1280
  createRevisionFrom,
770
1281
  update,
1282
+ move,
771
1283
  delete: deleteEntry,
1284
+ moveToBin,
1285
+ restoreFromBin,
772
1286
  deleteRevision,
1287
+ deleteMultipleEntries,
773
1288
  getPreviousRevision,
774
1289
  getPublishedByIds,
775
1290
  getLatestByIds,
@@ -781,7 +1296,11 @@ const createEntriesStorageOperations = params => {
781
1296
  getRevisions,
782
1297
  publish,
783
1298
  list,
784
- unpublish
1299
+ unpublish,
1300
+ dataLoaders,
1301
+ getUniqueFieldValues
785
1302
  };
786
1303
  };
787
- exports.createEntriesStorageOperations = createEntriesStorageOperations;
1304
+ exports.createEntriesStorageOperations = createEntriesStorageOperations;
1305
+
1306
+ //# sourceMappingURL=index.js.map