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