@webiny/api-headless-cms-ddb 0.0.0-unstable.fcdad0bc61 → 0.0.0-unstable.fdd9228b5d

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 (170) hide show
  1. package/definitions/entry.d.ts +4 -3
  2. package/definitions/entry.js +108 -16
  3. package/definitions/entry.js.map +1 -1
  4. package/definitions/group.d.ts +4 -3
  5. package/definitions/group.js +8 -12
  6. package/definitions/group.js.map +1 -1
  7. package/definitions/model.d.ts +4 -3
  8. package/definitions/model.js +30 -12
  9. package/definitions/model.js.map +1 -1
  10. package/definitions/system.d.ts +4 -3
  11. package/definitions/system.js +8 -12
  12. package/definitions/system.js.map +1 -1
  13. package/definitions/table.d.ts +5 -5
  14. package/definitions/table.js +7 -6
  15. package/definitions/table.js.map +1 -1
  16. package/dynamoDb/index.d.ts +1 -1
  17. package/dynamoDb/index.js +4 -9
  18. package/dynamoDb/index.js.map +1 -1
  19. package/dynamoDb/path/locationFolderId.d.ts +2 -0
  20. package/dynamoDb/path/locationFolderId.js +43 -0
  21. package/dynamoDb/path/locationFolderId.js.map +1 -0
  22. package/dynamoDb/path/plainObject.js +3 -8
  23. package/dynamoDb/path/plainObject.js.map +1 -1
  24. package/dynamoDb/storage/longText.d.ts +1 -1
  25. package/dynamoDb/storage/longText.js +10 -17
  26. package/dynamoDb/storage/longText.js.map +1 -1
  27. package/dynamoDb/storage/richText.d.ts +1 -1
  28. package/dynamoDb/storage/richText.js +23 -75
  29. package/dynamoDb/storage/richText.js.map +1 -1
  30. package/dynamoDb/transformValue/datetime.d.ts +1 -1
  31. package/dynamoDb/transformValue/datetime.js +3 -8
  32. package/dynamoDb/transformValue/datetime.js.map +1 -1
  33. package/index.d.ts +1 -1
  34. package/index.js +25 -41
  35. package/index.js.map +1 -1
  36. package/operations/entry/dataLoader/DataLoaderCache.d.ts +17 -0
  37. package/operations/entry/dataLoader/DataLoaderCache.js +41 -0
  38. package/operations/entry/dataLoader/DataLoaderCache.js.map +1 -0
  39. package/operations/entry/dataLoader/constants.d.ts +1 -0
  40. package/operations/entry/dataLoader/constants.js +10 -0
  41. package/operations/entry/dataLoader/constants.js.map +1 -0
  42. package/operations/entry/dataLoader/createBatchScheduleFn.d.ts +8 -0
  43. package/operations/entry/dataLoader/createBatchScheduleFn.js +25 -0
  44. package/operations/entry/dataLoader/createBatchScheduleFn.js.map +1 -0
  45. package/operations/entry/dataLoader/getAllEntryRevisions.d.ts +4 -0
  46. package/operations/entry/dataLoader/getAllEntryRevisions.js +45 -0
  47. package/operations/entry/dataLoader/getAllEntryRevisions.js.map +1 -0
  48. package/operations/entry/dataLoader/getLatestRevisionByEntryId.d.ts +4 -0
  49. package/operations/entry/dataLoader/getLatestRevisionByEntryId.js +56 -0
  50. package/operations/entry/dataLoader/getLatestRevisionByEntryId.js.map +1 -0
  51. package/operations/entry/dataLoader/getPublishedRevisionByEntryId.d.ts +4 -0
  52. package/operations/entry/dataLoader/getPublishedRevisionByEntryId.js +56 -0
  53. package/operations/entry/dataLoader/getPublishedRevisionByEntryId.js.map +1 -0
  54. package/operations/entry/dataLoader/getRevisionById.d.ts +4 -0
  55. package/operations/entry/dataLoader/getRevisionById.js +62 -0
  56. package/operations/entry/dataLoader/getRevisionById.js.map +1 -0
  57. package/operations/entry/dataLoader/index.d.ts +8 -0
  58. package/operations/entry/dataLoader/index.js +40 -0
  59. package/operations/entry/dataLoader/index.js.map +1 -0
  60. package/operations/entry/dataLoader/types.d.ts +6 -0
  61. package/operations/entry/dataLoader/types.js +7 -0
  62. package/operations/entry/dataLoader/types.js.map +1 -0
  63. package/operations/entry/dataLoaders.d.ts +12 -27
  64. package/operations/entry/dataLoaders.js +55 -260
  65. package/operations/entry/dataLoaders.js.map +1 -1
  66. package/operations/entry/filtering/createExpressions.d.ts +26 -0
  67. package/operations/entry/filtering/createExpressions.js +178 -0
  68. package/operations/entry/filtering/createExpressions.js.map +1 -0
  69. package/operations/entry/filtering/createFields.d.ts +16 -0
  70. package/operations/entry/filtering/createFields.js +108 -0
  71. package/operations/entry/filtering/createFields.js.map +1 -0
  72. package/operations/entry/filtering/extractSort.d.ts +17 -0
  73. package/operations/entry/filtering/extractSort.js +69 -0
  74. package/operations/entry/filtering/extractSort.js.map +1 -0
  75. package/operations/entry/filtering/filter.d.ts +15 -0
  76. package/operations/entry/filtering/filter.js +158 -0
  77. package/operations/entry/filtering/filter.js.map +1 -0
  78. package/operations/entry/filtering/fullTextSearch.d.ts +14 -0
  79. package/operations/entry/filtering/fullTextSearch.js +50 -0
  80. package/operations/entry/filtering/fullTextSearch.js.map +1 -0
  81. package/operations/entry/filtering/getValue.d.ts +5 -0
  82. package/operations/entry/filtering/getValue.js +66 -0
  83. package/operations/entry/filtering/getValue.js.map +1 -0
  84. package/operations/entry/filtering/index.d.ts +2 -0
  85. package/operations/entry/filtering/index.js +21 -0
  86. package/operations/entry/filtering/index.js.map +1 -0
  87. package/operations/entry/filtering/mapPlugins.d.ts +8 -0
  88. package/operations/entry/filtering/mapPlugins.js +33 -0
  89. package/operations/entry/filtering/mapPlugins.js.map +1 -0
  90. package/operations/entry/filtering/plugins/defaultFilterCreate.d.ts +2 -0
  91. package/operations/entry/filtering/plugins/defaultFilterCreate.js +45 -0
  92. package/operations/entry/filtering/plugins/defaultFilterCreate.js.map +1 -0
  93. package/operations/entry/filtering/plugins/index.d.ts +1 -0
  94. package/operations/entry/filtering/plugins/index.js +16 -0
  95. package/operations/entry/filtering/plugins/index.js.map +1 -0
  96. package/operations/entry/filtering/plugins/objectFilterCreate.d.ts +2 -0
  97. package/operations/entry/filtering/plugins/objectFilterCreate.js +90 -0
  98. package/operations/entry/filtering/plugins/objectFilterCreate.js.map +1 -0
  99. package/operations/entry/filtering/plugins/refFilterCreate.d.ts +3 -0
  100. package/operations/entry/filtering/plugins/refFilterCreate.js +80 -0
  101. package/operations/entry/filtering/plugins/refFilterCreate.js.map +1 -0
  102. package/operations/entry/filtering/plugins/searchableJsonFilterCreate.d.ts +2 -0
  103. package/operations/entry/filtering/plugins/searchableJsonFilterCreate.js +65 -0
  104. package/operations/entry/filtering/plugins/searchableJsonFilterCreate.js.map +1 -0
  105. package/operations/entry/filtering/sort.d.ts +12 -0
  106. package/operations/entry/filtering/sort.js +71 -0
  107. package/operations/entry/filtering/sort.js.map +1 -0
  108. package/operations/entry/filtering/systemFields.d.ts +4 -0
  109. package/operations/entry/filtering/systemFields.js +90 -0
  110. package/operations/entry/filtering/systemFields.js.map +1 -0
  111. package/operations/entry/filtering/transform.d.ts +6 -0
  112. package/operations/entry/filtering/transform.js +18 -0
  113. package/operations/entry/filtering/transform.js.map +1 -0
  114. package/operations/entry/filtering/types.d.ts +40 -0
  115. package/operations/entry/filtering/types.js +7 -0
  116. package/operations/entry/filtering/types.js.map +1 -0
  117. package/operations/entry/filtering/values.d.ts +2 -0
  118. package/operations/entry/filtering/values.js +24 -0
  119. package/operations/entry/filtering/values.js.map +1 -0
  120. package/operations/entry/filtering/where.d.ts +5 -0
  121. package/operations/entry/filtering/where.js +35 -0
  122. package/operations/entry/filtering/where.js.map +1 -0
  123. package/operations/entry/index.d.ts +3 -3
  124. package/operations/entry/index.js +733 -284
  125. package/operations/entry/index.js.map +1 -1
  126. package/operations/entry/keys.js +2 -18
  127. package/operations/entry/keys.js.map +1 -1
  128. package/operations/group/index.d.ts +3 -3
  129. package/operations/group/index.js +33 -51
  130. package/operations/group/index.js.map +1 -1
  131. package/operations/model/index.d.ts +2 -2
  132. package/operations/model/index.js +25 -37
  133. package/operations/model/index.js.map +1 -1
  134. package/operations/system/index.d.ts +2 -2
  135. package/operations/system/index.js +18 -23
  136. package/operations/system/index.js.map +1 -1
  137. package/package.json +21 -26
  138. package/plugins/CmsEntryFieldFilterPathPlugin.d.ts +4 -3
  139. package/plugins/CmsEntryFieldFilterPathPlugin.js +11 -18
  140. package/plugins/CmsEntryFieldFilterPathPlugin.js.map +1 -1
  141. package/plugins/CmsEntryFieldFilterPlugin.d.ts +43 -0
  142. package/plugins/CmsEntryFieldFilterPlugin.js +27 -0
  143. package/plugins/CmsEntryFieldFilterPlugin.js.map +1 -0
  144. package/plugins/CmsEntryFieldSortingPlugin.d.ts +42 -0
  145. package/plugins/CmsEntryFieldSortingPlugin.js +27 -0
  146. package/plugins/CmsEntryFieldSortingPlugin.js.map +1 -0
  147. package/plugins/CmsFieldFilterValueTransformPlugin.d.ts +11 -0
  148. package/plugins/CmsFieldFilterValueTransformPlugin.js +23 -0
  149. package/plugins/CmsFieldFilterValueTransformPlugin.js.map +1 -0
  150. package/plugins/index.d.ts +3 -0
  151. package/plugins/index.js +36 -3
  152. package/plugins/index.js.map +1 -1
  153. package/types.d.ts +21 -14
  154. package/types.js +5 -6
  155. package/types.js.map +1 -1
  156. package/definitions/settings.d.ts +0 -9
  157. package/definitions/settings.js +0 -58
  158. package/definitions/settings.js.map +0 -1
  159. package/dynamoDb/storage/date.d.ts +0 -2
  160. package/dynamoDb/storage/date.js +0 -99
  161. package/dynamoDb/storage/date.js.map +0 -1
  162. package/operations/entry/systemFields.d.ts +0 -2
  163. package/operations/entry/systemFields.js +0 -74
  164. package/operations/entry/systemFields.js.map +0 -1
  165. package/operations/entry/utils.d.ts +0 -36
  166. package/operations/entry/utils.js +0 -680
  167. package/operations/entry/utils.js.map +0 -1
  168. package/operations/settings/index.d.ts +0 -7
  169. package/operations/settings/index.js +0 -135
  170. package/operations/settings/index.js.map +0 -1
@@ -1,48 +1,30 @@
1
1
  "use strict";
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
-
5
4
  Object.defineProperty(exports, "__esModule", {
6
5
  value: true
7
6
  });
8
7
  exports.createEntriesStorageOperations = void 0;
9
-
10
- var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
11
-
12
8
  var _error = _interopRequireDefault(require("@webiny/error"));
13
-
14
9
  var _dataLoaders = require("./dataLoaders");
15
-
16
10
  var _types = require("@webiny/api-headless-cms/types");
17
-
18
- var _utils = require("./utils");
19
-
20
11
  var _keys = require("./keys");
21
-
22
- var _batchWrite = require("@webiny/db-dynamodb/utils/batchWrite");
23
-
24
- var _query = require("@webiny/db-dynamodb/utils/query");
25
-
26
- var _cleanup = require("@webiny/db-dynamodb/utils/cleanup");
27
-
12
+ var _dbDynamodb = require("@webiny/db-dynamodb");
28
13
  var _cursor = require("@webiny/utils/cursor");
29
-
30
14
  var _zeroPad = require("@webiny/utils/zeroPad");
31
-
32
15
  var _apiHeadlessCms = require("@webiny/api-headless-cms");
33
-
16
+ var _createFields = require("./filtering/createFields");
17
+ var _filtering = require("./filtering");
18
+ var _constants = require("@webiny/api-headless-cms/constants");
34
19
  const createType = () => {
35
20
  return "cms.entry";
36
21
  };
37
-
38
22
  const createLatestType = () => {
39
23
  return `${createType()}.l`;
40
24
  };
41
-
42
25
  const createPublishedType = () => {
43
26
  return `${createType()}.p`;
44
27
  };
45
-
46
28
  const convertToStorageEntry = params => {
47
29
  const {
48
30
  model,
@@ -52,11 +34,11 @@ const convertToStorageEntry = params => {
52
34
  fields: model.fields,
53
35
  values: storageEntry.values
54
36
  });
55
- return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
37
+ return {
38
+ ...storageEntry,
56
39
  values
57
- });
40
+ };
58
41
  };
59
-
60
42
  const convertFromStorageEntry = params => {
61
43
  const {
62
44
  model,
@@ -66,51 +48,60 @@ const convertFromStorageEntry = params => {
66
48
  fields: model.fields,
67
49
  values: storageEntry.values
68
50
  });
69
- return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
51
+ return {
52
+ ...storageEntry,
70
53
  values
71
- });
54
+ };
72
55
  };
73
-
56
+ const MAX_LIST_LIMIT = 1000000;
74
57
  const createEntriesStorageOperations = params => {
75
58
  const {
76
59
  entity,
77
60
  plugins
78
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
+ };
79
74
  const dataLoaders = new _dataLoaders.DataLoadersHandler({
80
75
  entity
81
76
  });
82
- const storageTransformPlugins = plugins.byType(_apiHeadlessCms.StorageTransformPlugin.type).reduce((collection, plugin) => {
83
- collection[plugin.fieldType] = plugin;
84
- return collection;
85
- }, {});
86
-
87
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
+ }, {});
88
83
  return (field, value) => {
89
84
  const plugin = storageTransformPlugins[field.type];
90
-
91
85
  if (!plugin) {
92
86
  return value;
93
87
  }
94
-
95
88
  return plugin.fromStorage({
96
89
  model,
97
90
  field,
98
91
  value,
99
-
100
92
  getStoragePlugin(fieldType) {
101
93
  return storageTransformPlugins[fieldType] || storageTransformPlugins["*"];
102
94
  },
103
-
104
95
  plugins
105
96
  });
106
97
  };
107
98
  };
108
-
109
- const create = async (model, params) => {
99
+ const create = async (initialModel, params) => {
110
100
  const {
111
101
  entry,
112
102
  storageEntry: initialStorageEntry
113
103
  } = params;
104
+ const model = getStorageOperationsModel(initialModel);
114
105
  const partitionKey = (0, _keys.createPartitionKey)({
115
106
  id: entry.id,
116
107
  locale: model.locale,
@@ -125,44 +116,45 @@ const createEntriesStorageOperations = params => {
125
116
  /**
126
117
  * We need to:
127
118
  * - create new main entry item
128
- * - create new or update latest entry item
119
+ * - create new or update the latest entry item
129
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
+ });
130
141
 
131
- const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
132
- locked,
133
- PK: partitionKey,
134
- SK: (0, _keys.createRevisionSortKey)(entry),
135
- TYPE: createType(),
136
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
137
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
138
- })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
139
- locked,
140
- PK: partitionKey,
141
- SK: (0, _keys.createLatestSortKey)(),
142
- TYPE: createLatestType(),
143
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
144
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
145
- }))];
146
142
  /**
147
143
  * We need to create published entry if
148
144
  */
149
-
150
145
  if (isPublished) {
151
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
146
+ entityBatch.put({
147
+ ...storageEntry,
152
148
  locked,
153
149
  PK: partitionKey,
154
150
  SK: (0, _keys.createPublishedSortKey)(),
155
151
  TYPE: createLatestType(),
156
152
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
157
153
  GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
158
- })));
154
+ });
159
155
  }
160
-
161
156
  try {
162
- await (0, _batchWrite.batchWriteAll)({
163
- table: entity.table,
164
- items
165
- });
157
+ await entityBatch.execute();
166
158
  dataLoaders.clearAll({
167
159
  model
168
160
  });
@@ -172,15 +164,14 @@ const createEntriesStorageOperations = params => {
172
164
  entry
173
165
  });
174
166
  }
175
-
176
167
  return initialStorageEntry;
177
168
  };
178
-
179
- const createRevisionFrom = async (model, params) => {
169
+ const createRevisionFrom = async (initialModel, params) => {
180
170
  const {
181
171
  entry,
182
172
  storageEntry: initialStorageEntry
183
173
  } = params;
174
+ const model = getStorageOperationsModel(initialModel);
184
175
  const partitionKey = (0, _keys.createPartitionKey)({
185
176
  id: entry.id,
186
177
  locale: model.locale,
@@ -190,31 +181,63 @@ const createEntriesStorageOperations = params => {
190
181
  storageEntry: initialStorageEntry,
191
182
  model
192
183
  });
184
+
193
185
  /**
194
186
  * We need to:
195
187
  * - create the main entry item
196
- * - 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)
197
192
  */
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
+ });
198
221
 
199
- const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
200
- PK: partitionKey,
201
- SK: (0, _keys.createRevisionSortKey)(storageEntry),
202
- TYPE: createType(),
203
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
204
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
205
- })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
206
- PK: partitionKey,
207
- SK: (0, _keys.createLatestSortKey)(),
208
- TYPE: createLatestType(),
209
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
210
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
211
- }))];
212
-
213
- try {
214
- await (0, _batchWrite.batchWriteAll)({
215
- table: entity.table,
216
- items
222
+ // Unpublish previously published revision (if any).
223
+ const [publishedRevisionStorageEntry] = await dataLoaders.getPublishedRevisionByEntryId({
224
+ model,
225
+ ids: [entry.id]
217
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();
218
241
  dataLoaders.clearAll({
219
242
  model
220
243
  });
@@ -228,16 +251,14 @@ const createEntriesStorageOperations = params => {
228
251
  /**
229
252
  * There are no modifications on the entry created so just return the data.
230
253
  */
231
-
232
-
233
254
  return initialStorageEntry;
234
255
  };
235
-
236
- const update = async (model, params) => {
256
+ const update = async (initialModel, params) => {
237
257
  const {
238
258
  entry,
239
259
  storageEntry: initialStorageEntry
240
260
  } = params;
261
+ const model = getStorageOperationsModel(initialModel);
241
262
  const partitionKey = (0, _keys.createPartitionKey)({
242
263
  id: entry.id,
243
264
  locale: model.locale,
@@ -245,7 +266,6 @@ const createEntriesStorageOperations = params => {
245
266
  });
246
267
  const isPublished = entry.status === "published";
247
268
  const locked = isPublished ? true : entry.locked;
248
- const items = [];
249
269
  const storageEntry = convertToStorageEntry({
250
270
  model,
251
271
  storageEntry: initialStorageEntry
@@ -256,48 +276,80 @@ const createEntriesStorageOperations = params => {
256
276
  * - update the latest entry if the current entry is the latest one
257
277
  */
258
278
 
259
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
260
- locked,
261
- PK: partitionKey,
262
- SK: (0, _keys.createRevisionSortKey)(storageEntry),
263
- TYPE: createType(),
264
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
265
- GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
266
- })));
267
-
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
+ });
268
291
  if (isPublished) {
269
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
292
+ entityBatch.put({
293
+ ...storageEntry,
270
294
  locked,
271
295
  PK: partitionKey,
272
296
  SK: (0, _keys.createPublishedSortKey)(),
273
297
  TYPE: createPublishedType(),
274
298
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
275
299
  GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
276
- })));
300
+ });
277
301
  }
302
+
278
303
  /**
279
- * 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.
280
305
  */
281
-
282
-
283
306
  const latestStorageEntry = await getLatestRevisionByEntryId(model, entry);
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);
284
325
 
285
- if (latestStorageEntry && latestStorageEntry.id === entry.id) {
286
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
287
- locked,
288
- PK: partitionKey,
289
- SK: (0, _keys.createLatestSortKey)(),
290
- TYPE: createLatestType(),
291
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
292
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
293
- })));
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
+ }
294
350
  }
295
-
296
351
  try {
297
- await (0, _batchWrite.batchWriteAll)({
298
- table: entity.table,
299
- items
300
- });
352
+ await entityBatch.execute();
301
353
  dataLoaders.clearAll({
302
354
  model
303
355
  });
@@ -310,11 +362,69 @@ const createEntriesStorageOperations = params => {
310
362
  });
311
363
  }
312
364
  };
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
+ });
313
402
 
314
- const deleteEntry = async (model, params) => {
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) => {
315
419
  const {
316
- entry
420
+ entry,
421
+ storageEntry: initialStorageEntry
317
422
  } = params;
423
+ const model = getStorageOperationsModel(initialModel);
424
+
425
+ /**
426
+ * First we need to load all the revisions and published / latest entries.
427
+ */
318
428
  const queryAllParams = {
319
429
  entity,
320
430
  partitionKey: (0, _keys.createPartitionKey)({
@@ -327,28 +437,92 @@ const createEntriesStorageOperations = params => {
327
437
  }
328
438
  };
329
439
  let records = [];
330
-
331
440
  try {
332
- records = await (0, _query.queryAll)(queryAllParams);
441
+ records = await (0, _dbDynamodb.queryAll)(queryAllParams);
333
442
  } catch (ex) {
334
443
  throw new _error.default(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
335
444
  error: ex,
336
- entry
445
+ id: entry.id
337
446
  });
338
447
  }
339
-
340
- const items = records.map(item => {
341
- return entity.deleteBatch({
342
- PK: item.PK,
343
- SK: item.SK
344
- });
448
+ if (records.length === 0) {
449
+ return;
450
+ }
451
+ const storageEntry = convertToStorageEntry({
452
+ model,
453
+ storageEntry: initialStorageEntry
345
454
  });
346
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
+ })
475
+ });
476
+ /**
477
+ * And finally write it...
478
+ */
347
479
  try {
348
- await (0, _batchWrite.batchWriteAll)({
349
- table: entity.table,
350
- 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
351
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();
352
526
  dataLoaders.clearAll({
353
527
  model
354
528
  });
@@ -356,57 +530,139 @@ const createEntriesStorageOperations = params => {
356
530
  throw new _error.default(ex.message || "Could not delete the entry.", ex.code || "DELETE_ENTRY_ERROR", {
357
531
  error: ex,
358
532
  partitionKey: queryAllParams.partitionKey,
359
- entry
533
+ id
360
534
  });
361
535
  }
362
536
  };
537
+ const restoreFromBin = async (initialModel, params) => {
538
+ const {
539
+ entry,
540
+ storageEntry: initialStorageEntry
541
+ } = params;
542
+ const model = getStorageOperationsModel(initialModel);
363
543
 
364
- const deleteRevision = async (model, params) => {
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) => {
365
610
  const {
366
611
  entry,
367
612
  latestEntry,
368
613
  latestStorageEntry: initialLatestStorageEntry
369
614
  } = params;
615
+ const model = getStorageOperationsModel(initialModel);
370
616
  const partitionKey = (0, _keys.createPartitionKey)({
371
617
  id: entry.id,
372
618
  locale: model.locale,
373
619
  tenant: model.tenant
374
620
  });
375
- const items = [entity.deleteBatch({
376
- PK: partitionKey,
377
- SK: (0, _keys.createRevisionSortKey)(entry)
378
- })];
621
+ const entityBatch = (0, _dbDynamodb.createEntityWriteBatch)({
622
+ entity,
623
+ delete: [{
624
+ PK: partitionKey,
625
+ SK: (0, _keys.createRevisionSortKey)(entry)
626
+ }]
627
+ });
379
628
  const publishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
629
+
380
630
  /**
381
631
  * If revision we are deleting is the published one as well, we need to delete those records as well.
382
632
  */
383
-
384
633
  if (publishedStorageEntry && entry.id === publishedStorageEntry.id) {
385
- items.push(entity.deleteBatch({
634
+ entityBatch.delete({
386
635
  PK: partitionKey,
387
636
  SK: (0, _keys.createPublishedSortKey)()
388
- }));
637
+ });
389
638
  }
390
-
391
639
  if (initialLatestStorageEntry) {
392
640
  const latestStorageEntry = convertToStorageEntry({
393
641
  storageEntry: initialLatestStorageEntry,
394
642
  model
395
643
  });
396
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, latestStorageEntry), {}, {
644
+ entityBatch.put({
645
+ ...latestStorageEntry,
397
646
  PK: partitionKey,
398
647
  SK: (0, _keys.createLatestSortKey)(),
399
648
  TYPE: createLatestType(),
400
649
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
401
650
  GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
402
- })));
403
- }
651
+ });
404
652
 
405
- try {
406
- await (0, _batchWrite.batchWriteAll)({
407
- table: entity.table,
408
- items
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)
409
662
  });
663
+ }
664
+ try {
665
+ entityBatch.execute();
410
666
  dataLoaders.clearAll({
411
667
  model
412
668
  });
@@ -418,59 +674,104 @@ const createEntriesStorageOperations = params => {
418
674
  });
419
675
  }
420
676
  };
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
+ */
421
692
 
422
- const getLatestRevisionByEntryId = async (model, params) => {
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);
423
730
  const items = await dataLoaders.getLatestRevisionByEntryId({
424
731
  model,
425
732
  ids: [params.id]
426
733
  });
427
734
  const item = items.shift() || null;
428
-
429
735
  if (!item) {
430
736
  return null;
431
737
  }
432
-
433
738
  return convertFromStorageEntry({
434
739
  storageEntry: item,
435
740
  model
436
741
  });
437
742
  };
438
-
439
- const getPublishedRevisionByEntryId = async (model, params) => {
743
+ const getPublishedRevisionByEntryId = async (initialModel, params) => {
744
+ const model = getStorageOperationsModel(initialModel);
440
745
  const items = await dataLoaders.getPublishedRevisionByEntryId({
441
746
  model,
442
747
  ids: [params.id]
443
748
  });
444
749
  const item = items.shift() || null;
445
-
446
750
  if (!item) {
447
751
  return null;
448
752
  }
449
-
450
753
  return convertFromStorageEntry({
451
754
  storageEntry: item,
452
755
  model
453
756
  });
454
757
  };
455
-
456
- const getRevisionById = async (model, params) => {
758
+ const getRevisionById = async (initialModel, params) => {
759
+ const model = getStorageOperationsModel(initialModel);
457
760
  const items = await dataLoaders.getRevisionById({
458
761
  model,
459
762
  ids: [params.id]
460
763
  });
461
764
  const item = items.shift() || null;
462
-
463
765
  if (!item) {
464
766
  return null;
465
767
  }
466
-
467
768
  return convertFromStorageEntry({
468
769
  storageEntry: item,
469
770
  model
470
771
  });
471
772
  };
472
-
473
- const getRevisions = async (model, params) => {
773
+ const getRevisions = async (initialModel, params) => {
774
+ const model = getStorageOperationsModel(initialModel);
474
775
  const items = await dataLoaders.getAllEntryRevisions({
475
776
  model,
476
777
  ids: [params.id]
@@ -482,8 +783,8 @@ const createEntriesStorageOperations = params => {
482
783
  });
483
784
  });
484
785
  };
485
-
486
- const getByIds = async (model, params) => {
786
+ const getByIds = async (initialModel, params) => {
787
+ const model = getStorageOperationsModel(initialModel);
487
788
  const items = await dataLoaders.getRevisionById({
488
789
  model,
489
790
  ids: params.ids
@@ -495,8 +796,8 @@ const createEntriesStorageOperations = params => {
495
796
  });
496
797
  });
497
798
  };
498
-
499
- const getLatestByIds = async (model, params) => {
799
+ const getLatestByIds = async (initialModel, params) => {
800
+ const model = getStorageOperationsModel(initialModel);
500
801
  const items = await dataLoaders.getLatestRevisionByEntryId({
501
802
  model,
502
803
  ids: params.ids
@@ -508,8 +809,8 @@ const createEntriesStorageOperations = params => {
508
809
  });
509
810
  });
510
811
  };
511
-
512
- const getPublishedByIds = async (model, params) => {
812
+ const getPublishedByIds = async (initialModel, params) => {
813
+ const model = getStorageOperationsModel(initialModel);
513
814
  const items = await dataLoaders.getPublishedRevisionByEntryId({
514
815
  model,
515
816
  ids: params.ids
@@ -521,8 +822,8 @@ const createEntriesStorageOperations = params => {
521
822
  });
522
823
  });
523
824
  };
524
-
525
- const getPreviousRevision = async (model, params) => {
825
+ const getPreviousRevision = async (initialModel, params) => {
826
+ const model = getStorageOperationsModel(initialModel);
526
827
  const {
527
828
  entryId,
528
829
  version
@@ -536,7 +837,6 @@ const createEntriesStorageOperations = params => {
536
837
  }),
537
838
  options: {
538
839
  lt: `REV#${(0, _zeroPad.zeroPad)(version)}`,
539
-
540
840
  /**
541
841
  * We need to have extra checks because DynamoDB will return published or latest record if there is no REV# record.
542
842
  */
@@ -550,39 +850,37 @@ const createEntriesStorageOperations = params => {
550
850
  reverse: true
551
851
  }
552
852
  };
553
-
554
853
  try {
555
- const result = await (0, _query.queryOne)(queryParams);
556
- const storageEntry = (0, _cleanup.cleanupItem)(entity, result);
557
-
854
+ const result = await (0, _dbDynamodb.queryOne)(queryParams);
855
+ const storageEntry = (0, _dbDynamodb.cleanupItem)(entity, result);
558
856
  if (!storageEntry) {
559
857
  return null;
560
858
  }
561
-
562
859
  return convertFromStorageEntry({
563
860
  storageEntry,
564
861
  model
565
862
  });
566
863
  } catch (ex) {
567
- 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,
568
866
  error: ex,
569
867
  partitionKey: queryParams.partitionKey,
570
868
  options: queryParams.options,
571
869
  model
572
- }));
870
+ });
573
871
  }
574
872
  };
575
-
576
- const list = async (model, params) => {
873
+ const list = async (initialModel, params) => {
874
+ const model = getStorageOperationsModel(initialModel);
577
875
  const {
578
876
  limit: initialLimit = 10,
579
877
  where: initialWhere,
580
878
  after,
581
- sort,
879
+ sort: sortBy,
582
880
  fields,
583
881
  search
584
882
  } = params;
585
- const limit = initialLimit <= 0 || initialLimit >= 10000 ? 10000 : initialLimit;
883
+ const limit = initialLimit <= 0 || initialLimit >= MAX_LIST_LIMIT ? MAX_LIST_LIMIT : initialLimit;
586
884
  const type = initialWhere.published ? "P" : "L";
587
885
  const queryAllParams = {
588
886
  entity,
@@ -592,10 +890,9 @@ const createEntriesStorageOperations = params => {
592
890
  gte: " "
593
891
  }
594
892
  };
595
- let records = [];
596
-
893
+ let storageEntries = [];
597
894
  try {
598
- records = await (0, _query.queryAll)(queryAllParams);
895
+ storageEntries = await (0, _dbDynamodb.queryAll)(queryAllParams);
599
896
  } catch (ex) {
600
897
  throw new _error.default(ex.message, "QUERY_ENTRIES_ERROR", {
601
898
  error: ex,
@@ -603,8 +900,7 @@ const createEntriesStorageOperations = params => {
603
900
  options: queryAllParams.options
604
901
  });
605
902
  }
606
-
607
- if (records.length === 0) {
903
+ if (storageEntries.length === 0) {
608
904
  return {
609
905
  hasMoreItems: false,
610
906
  totalCount: 0,
@@ -612,49 +908,60 @@ const createEntriesStorageOperations = params => {
612
908
  items: []
613
909
  };
614
910
  }
615
-
616
- const where = (0, _objectSpread2.default)({}, initialWhere);
911
+ const where = {
912
+ ...initialWhere
913
+ };
617
914
  delete where["published"];
618
915
  delete where["latest"];
619
916
  /**
620
- * We need a object containing field, transformers and paths.
917
+ * We need an object containing field, transformers and paths.
621
918
  * Just build it here and pass on into other methods that require it to avoid mapping multiple times.
622
919
  */
623
-
624
- const modelFields = (0, _utils.buildModelFields)({
920
+ const modelFields = (0, _createFields.createFields)({
625
921
  plugins,
626
- model
922
+ fields: model.fields
627
923
  });
924
+ const fromStorage = createStorageTransformCallable(model);
925
+ /**
926
+ * Let's transform records from storage ones to regular ones, so we do not need to do it later.
927
+ *
928
+ * This is always being done, but at least its in parallel.
929
+ */
930
+ const records = await Promise.all(storageEntries.map(async storageEntry => {
931
+ const entry = convertFromStorageEntry({
932
+ storageEntry,
933
+ model
934
+ });
935
+ for (const field of model.fields) {
936
+ entry.values[field.fieldId] = await fromStorage(field, entry.values[field.fieldId]);
937
+ }
938
+ return entry;
939
+ }));
628
940
  /**
629
941
  * Filter the read items via the code.
630
942
  * It will build the filters out of the where input and transform the values it is using.
631
943
  */
632
-
633
- const filteredItems = await (0, _utils.filterItems)({
634
- items: records.map(record => {
635
- return convertFromStorageEntry({
636
- storageEntry: record,
637
- model
638
- });
639
- }),
944
+ const filteredItems = (0, _filtering.filter)({
945
+ items: records,
640
946
  where,
641
947
  plugins,
642
948
  fields: modelFields,
643
- fromStorage: createStorageTransformCallable(model),
644
949
  fullTextSearch: {
645
950
  term: search,
646
951
  fields: fields || []
647
952
  }
648
953
  });
649
954
  const totalCount = filteredItems.length;
955
+
650
956
  /**
651
957
  * Sorting is also done via the code.
652
958
  * It takes the sort input and sorts by it via the lodash sortBy method.
653
959
  */
654
-
655
- const sortedItems = (0, _utils.sortEntryItems)({
960
+ const sortedItems = (0, _filtering.sort)({
961
+ model,
962
+ plugins,
656
963
  items: filteredItems,
657
- sort,
964
+ sort: sortBy,
658
965
  fields: modelFields
659
966
  });
660
967
  const start = parseInt((0, _cursor.decodeCursor)(after) || "0") || 0;
@@ -665,97 +972,163 @@ const createEntriesStorageOperations = params => {
665
972
  * Although we do not need a cursor here, we will use it as such to keep it standardized.
666
973
  * Number is simply encoded.
667
974
  */
668
-
669
- const cursor = totalCount > start + limit ? (0, _cursor.encodeCursor)(`${start + limit}`) : null;
975
+ const cursor = (0, _cursor.encodeCursor)(`${start + limit}`);
670
976
  return {
671
977
  hasMoreItems,
672
978
  totalCount,
673
979
  cursor,
674
- items: (0, _cleanup.cleanupItems)(entity, slicedItems)
980
+ items: (0, _dbDynamodb.cleanupItems)(entity, slicedItems)
675
981
  };
676
982
  };
677
-
678
- const get = async (model, params) => {
983
+ const get = async (initialModel, params) => {
984
+ const model = getStorageOperationsModel(initialModel);
679
985
  const {
680
986
  items
681
- } = await list(model, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, params), {}, {
987
+ } = await list(model, {
988
+ ...params,
682
989
  limit: 1
683
- }));
990
+ });
684
991
  return items.shift() || null;
685
992
  };
686
-
687
- const publish = async (model, params) => {
993
+ const publish = async (initialModel, params) => {
688
994
  const {
689
995
  entry,
690
996
  storageEntry: initialStorageEntry
691
997
  } = params;
998
+ const model = getStorageOperationsModel(initialModel);
692
999
  const partitionKey = (0, _keys.createPartitionKey)({
693
1000
  id: entry.id,
694
1001
  locale: model.locale,
695
1002
  tenant: model.tenant
696
1003
  });
1004
+
697
1005
  /**
698
- * 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.
699
1007
  */
700
-
701
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
+ }
702
1014
  const initialPublishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
703
1015
  const storageEntry = convertToStorageEntry({
704
1016
  model,
705
1017
  storageEntry: initialStorageEntry
706
1018
  });
707
- /**
708
- * We need to update:
709
- * - current entry revision sort key
710
- * - published sort key
711
- * - latest sort key - if entry updated is actually latest
712
- * - previous published entry to unpublished status - if any previously published entry
713
- */
714
1019
 
715
- const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
716
- PK: partitionKey,
717
- SK: (0, _keys.createRevisionSortKey)(entry),
718
- TYPE: createType(),
719
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
720
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
721
- })), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
722
- PK: partitionKey,
723
- SK: (0, _keys.createPublishedSortKey)(),
724
- TYPE: createPublishedType(),
725
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "P"),
726
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
727
- }))];
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
+ });
728
1039
 
729
- if (initialLatestStorageEntry && entry.id === initialLatestStorageEntry.id) {
730
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
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,
731
1048
  PK: partitionKey,
732
1049
  SK: (0, _keys.createLatestSortKey)(),
733
1050
  TYPE: createLatestType(),
734
1051
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
735
1052
  GSI1_SK: (0, _keys.createGSISortKey)(entry)
736
- })));
737
- }
1053
+ });
738
1054
 
739
- if (initialPublishedStorageEntry && initialPublishedStorageEntry.id !== entry.id) {
740
- const publishedStorageEntry = convertToStorageEntry({
741
- storageEntry: initialPublishedStorageEntry,
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,
742
1078
  model
743
1079
  });
744
- 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,
1094
+ PK: partitionKey,
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,
745
1104
  PK: partitionKey,
746
- SK: (0, _keys.createRevisionSortKey)(publishedStorageEntry),
1105
+ SK: (0, _keys.createRevisionSortKey)(latestStorageEntry),
747
1106
  TYPE: createType(),
748
- status: _types.CONTENT_ENTRY_STATUS.UNPUBLISHED,
749
1107
  GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
750
- GSI1_SK: (0, _keys.createGSISortKey)(publishedStorageEntry)
751
- })));
752
- }
1108
+ GSI1_SK: (0, _keys.createGSISortKey)(latestStorageEntry)
1109
+ });
753
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
+ }
1129
+ }
754
1130
  try {
755
- await (0, _batchWrite.batchWriteAll)({
756
- table: entity.table,
757
- items
758
- });
1131
+ await entityBatch.execute();
759
1132
  dataLoaders.clearAll({
760
1133
  model
761
1134
  });
@@ -768,12 +1141,12 @@ const createEntriesStorageOperations = params => {
768
1141
  });
769
1142
  }
770
1143
  };
771
-
772
- const unpublish = async (model, params) => {
1144
+ const unpublish = async (initialModel, params) => {
773
1145
  const {
774
1146
  entry,
775
1147
  storageEntry: initialStorageEntry
776
1148
  } = params;
1149
+ const model = getStorageOperationsModel(initialModel);
777
1150
  const partitionKey = (0, _keys.createPartitionKey)({
778
1151
  id: entry.id,
779
1152
  locale: model.locale,
@@ -787,40 +1160,74 @@ const createEntriesStorageOperations = params => {
787
1160
  * We need to:
788
1161
  * - delete currently published entry
789
1162
  * - update current entry revision with new data
790
- * - update latest entry status - if entry being unpublished is latest
1163
+ * - update the latest entry status - if entry being unpublished is latest
791
1164
  */
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
+ });
792
1180
 
793
- const items = [entity.deleteBatch({
794
- PK: partitionKey,
795
- SK: (0, _keys.createPublishedSortKey)()
796
- }), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
797
- PK: partitionKey,
798
- SK: (0, _keys.createRevisionSortKey)(entry),
799
- TYPE: createType(),
800
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
801
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
802
- }))];
803
1181
  /**
804
- * 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.
805
1183
  */
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
+ });
806
1201
 
807
- const latestStorageEntry = await getLatestRevisionByEntryId(model, entry);
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
+ });
808
1216
 
809
- if (latestStorageEntry && entry.id === latestStorageEntry.id) {
810
- items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
811
- PK: partitionKey,
812
- SK: (0, _keys.createLatestSortKey)(),
813
- TYPE: createLatestType(),
814
- GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
815
- GSI1_SK: (0, _keys.createGSISortKey)(entry)
816
- })));
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
+ }
817
1228
  }
818
-
819
1229
  try {
820
- await (0, _batchWrite.batchWriteAll)({
821
- table: entity.table,
822
- items
823
- });
1230
+ await entityBatch.execute();
824
1231
  dataLoaders.clearAll({
825
1232
  model
826
1233
  });
@@ -832,13 +1239,52 @@ const createEntriesStorageOperations = params => {
832
1239
  });
833
1240
  }
834
1241
  };
835
-
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
+ };
836
1278
  return {
837
1279
  create,
838
1280
  createRevisionFrom,
839
1281
  update,
1282
+ move,
840
1283
  delete: deleteEntry,
1284
+ moveToBin,
1285
+ restoreFromBin,
841
1286
  deleteRevision,
1287
+ deleteMultipleEntries,
842
1288
  getPreviousRevision,
843
1289
  getPublishedByIds,
844
1290
  getLatestByIds,
@@ -850,8 +1296,11 @@ const createEntriesStorageOperations = params => {
850
1296
  getRevisions,
851
1297
  publish,
852
1298
  list,
853
- unpublish
1299
+ unpublish,
1300
+ dataLoaders,
1301
+ getUniqueFieldValues
854
1302
  };
855
1303
  };
1304
+ exports.createEntriesStorageOperations = createEntriesStorageOperations;
856
1305
 
857
- exports.createEntriesStorageOperations = createEntriesStorageOperations;
1306
+ //# sourceMappingURL=index.js.map