@webiny/api-headless-cms-ddb 0.0.0-unstable.aa00eecd97 → 0.0.0-unstable.ac6ebf63c6
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/README.md +6 -20
- package/definitions/entry.d.ts +4 -5
- package/definitions/entry.js +7 -88
- package/definitions/entry.js.map +1 -1
- package/definitions/group.d.ts +4 -5
- package/definitions/group.js +7 -59
- package/definitions/group.js.map +1 -1
- package/definitions/model.d.ts +4 -5
- package/definitions/model.js +7 -103
- package/definitions/model.js.map +1 -1
- package/definitions/table.d.ts +4 -6
- package/definitions/table.js +8 -26
- package/definitions/table.js.map +1 -1
- package/definitions/types.d.ts +59 -0
- package/definitions/types.js +3 -0
- package/definitions/types.js.map +1 -0
- package/dynamoDb/index.d.ts +1 -1
- package/dynamoDb/index.js +7 -12
- package/dynamoDb/index.js.map +1 -1
- package/dynamoDb/path/locationFolderId.d.ts +2 -0
- package/dynamoDb/path/locationFolderId.js +34 -0
- package/dynamoDb/path/locationFolderId.js.map +1 -0
- package/dynamoDb/path/plainObject.d.ts +1 -1
- package/dynamoDb/path/plainObject.js +7 -14
- package/dynamoDb/path/plainObject.js.map +1 -1
- package/dynamoDb/storage/longText.js +13 -18
- package/dynamoDb/storage/longText.js.map +1 -1
- package/dynamoDb/storage/richText.js +28 -71
- package/dynamoDb/storage/richText.js.map +1 -1
- package/dynamoDb/transformValue/datetime.d.ts +1 -1
- package/dynamoDb/transformValue/datetime.js +7 -12
- package/dynamoDb/transformValue/datetime.js.map +1 -1
- package/index.d.ts +2 -2
- package/index.js +40 -82
- package/index.js.map +1 -1
- package/operations/entry/dataLoader/DataLoaderCache.d.ts +1 -3
- package/operations/entry/dataLoader/DataLoaderCache.js +8 -17
- package/operations/entry/dataLoader/DataLoaderCache.js.map +1 -1
- package/operations/entry/dataLoader/constants.js +3 -8
- package/operations/entry/dataLoader/constants.js.map +1 -1
- package/operations/entry/dataLoader/createBatchScheduleFn.js +6 -10
- package/operations/entry/dataLoader/createBatchScheduleFn.js.map +1 -1
- package/operations/entry/dataLoader/getAllEntryRevisions.d.ts +3 -3
- package/operations/entry/dataLoader/getAllEntryRevisions.js +13 -24
- package/operations/entry/dataLoader/getAllEntryRevisions.js.map +1 -1
- package/operations/entry/dataLoader/getLatestRevisionByEntryId.d.ts +3 -3
- package/operations/entry/dataLoader/getLatestRevisionByEntryId.js +24 -35
- package/operations/entry/dataLoader/getLatestRevisionByEntryId.js.map +1 -1
- package/operations/entry/dataLoader/getPublishedRevisionByEntryId.d.ts +3 -3
- package/operations/entry/dataLoader/getPublishedRevisionByEntryId.js +24 -35
- package/operations/entry/dataLoader/getPublishedRevisionByEntryId.js.map +1 -1
- package/operations/entry/dataLoader/getRevisionById.d.ts +3 -3
- package/operations/entry/dataLoader/getRevisionById.js +26 -37
- package/operations/entry/dataLoader/getRevisionById.js.map +1 -1
- package/operations/entry/dataLoader/index.d.ts +5 -5
- package/operations/entry/dataLoader/index.js +12 -31
- package/operations/entry/dataLoader/index.js.map +1 -1
- package/operations/entry/dataLoader/types.d.ts +3 -4
- package/operations/entry/dataLoader/types.js +2 -4
- package/operations/entry/dataLoader/types.js.map +1 -1
- package/operations/entry/dataLoaders.d.ts +11 -12
- package/operations/entry/dataLoaders.js +25 -34
- package/operations/entry/dataLoaders.js.map +1 -1
- package/operations/entry/filtering/createExpressions.d.ts +5 -5
- package/operations/entry/filtering/createExpressions.js +29 -30
- package/operations/entry/filtering/createExpressions.js.map +1 -1
- package/operations/entry/filtering/createFields.d.ts +6 -4
- package/operations/entry/filtering/createFields.js +87 -86
- package/operations/entry/filtering/createFields.js.map +1 -1
- package/operations/entry/filtering/extractSort.d.ts +6 -6
- package/operations/entry/filtering/extractSort.js +40 -23
- package/operations/entry/filtering/extractSort.js.map +1 -1
- package/operations/entry/filtering/filter.d.ts +6 -6
- package/operations/entry/filtering/filter.js +36 -29
- package/operations/entry/filtering/filter.js.map +1 -1
- package/operations/entry/filtering/fullTextSearch.d.ts +3 -3
- package/operations/entry/filtering/fullTextSearch.js +8 -14
- package/operations/entry/filtering/fullTextSearch.js.map +1 -1
- package/operations/entry/filtering/getValue.js +6 -10
- package/operations/entry/filtering/getValue.js.map +1 -1
- package/operations/entry/filtering/index.d.ts +2 -2
- package/operations/entry/filtering/index.js +3 -18
- package/operations/entry/filtering/index.js.map +1 -1
- package/operations/entry/filtering/mapPlugins.d.ts +2 -2
- package/operations/entry/filtering/mapPlugins.js +5 -11
- package/operations/entry/filtering/mapPlugins.js.map +1 -1
- package/operations/entry/filtering/plugins/defaultFilterCreate.d.ts +2 -2
- package/operations/entry/filtering/plugins/defaultFilterCreate.js +10 -14
- package/operations/entry/filtering/plugins/defaultFilterCreate.js.map +1 -1
- package/operations/entry/filtering/plugins/index.d.ts +1 -1
- package/operations/entry/filtering/plugins/index.js +8 -12
- package/operations/entry/filtering/plugins/index.js.map +1 -1
- package/operations/entry/filtering/plugins/objectFilterCreate.d.ts +2 -2
- package/operations/entry/filtering/plugins/objectFilterCreate.js +17 -19
- package/operations/entry/filtering/plugins/objectFilterCreate.js.map +1 -1
- package/operations/entry/filtering/plugins/refFilterCreate.d.ts +3 -2
- package/operations/entry/filtering/plugins/refFilterCreate.js +22 -19
- package/operations/entry/filtering/plugins/refFilterCreate.js.map +1 -1
- package/operations/entry/filtering/plugins/searchableJsonFilterCreate.d.ts +2 -0
- package/operations/entry/filtering/plugins/searchableJsonFilterCreate.js +57 -0
- package/operations/entry/filtering/plugins/searchableJsonFilterCreate.js.map +1 -0
- package/operations/entry/filtering/sort.d.ts +6 -6
- package/operations/entry/filtering/sort.js +18 -20
- package/operations/entry/filtering/sort.js.map +1 -1
- package/operations/entry/filtering/systemFields.d.ts +2 -4
- package/operations/entry/filtering/systemFields.js +88 -42
- package/operations/entry/filtering/systemFields.js.map +1 -1
- package/operations/entry/filtering/transform.d.ts +1 -1
- package/operations/entry/filtering/transform.js +3 -8
- package/operations/entry/filtering/transform.js.map +1 -1
- package/operations/entry/filtering/types.d.ts +3 -3
- package/operations/entry/filtering/types.js +2 -4
- package/operations/entry/filtering/types.js.map +1 -1
- package/operations/entry/filtering/values.d.ts +1 -1
- package/operations/entry/filtering/values.js +6 -12
- package/operations/entry/filtering/values.js.map +1 -1
- package/operations/entry/filtering/where.js +6 -10
- package/operations/entry/filtering/where.js.map +1 -1
- package/operations/entry/index.d.ts +3 -4
- package/operations/entry/index.js +635 -339
- package/operations/entry/index.js.map +1 -1
- package/operations/entry/keys.d.ts +40 -2
- package/operations/entry/keys.js +55 -30
- package/operations/entry/keys.js.map +1 -1
- package/operations/group/index.d.ts +4 -4
- package/operations/group/index.js +44 -61
- package/operations/group/index.js.map +1 -1
- package/operations/model/index.d.ts +3 -3
- package/operations/model/index.js +37 -46
- package/operations/model/index.js.map +1 -1
- package/package.json +21 -28
- package/plugins/CmsEntryFieldFilterPathPlugin.d.ts +4 -3
- package/plugins/CmsEntryFieldFilterPathPlugin.js +15 -16
- package/plugins/CmsEntryFieldFilterPathPlugin.js.map +1 -1
- package/plugins/CmsEntryFieldFilterPlugin.d.ts +10 -10
- package/plugins/CmsEntryFieldFilterPlugin.js +11 -14
- package/plugins/CmsEntryFieldFilterPlugin.js.map +1 -1
- package/plugins/CmsEntryFieldSortingPlugin.d.ts +2 -2
- package/plugins/CmsEntryFieldSortingPlugin.js +6 -15
- package/plugins/CmsEntryFieldSortingPlugin.js.map +1 -1
- package/plugins/CmsFieldFilterValueTransformPlugin.d.ts +2 -2
- package/plugins/CmsFieldFilterValueTransformPlugin.js +5 -13
- package/plugins/CmsFieldFilterValueTransformPlugin.js.map +1 -1
- package/plugins/index.d.ts +4 -4
- package/plugins/index.js +5 -48
- package/plugins/index.js.map +1 -1
- package/types.d.ts +18 -22
- package/types.js +5 -12
- package/types.js.map +1 -1
- package/definitions/settings.d.ts +0 -9
- package/definitions/settings.js +0 -53
- package/definitions/settings.js.map +0 -1
- package/definitions/system.d.ts +0 -9
- package/definitions/system.js +0 -41
- package/definitions/system.js.map +0 -1
- package/dynamoDb/storage/date.d.ts +0 -3
- package/dynamoDb/storage/date.js +0 -91
- package/dynamoDb/storage/date.js.map +0 -1
- package/operations/entry/systemFields.d.ts +0 -2
- package/operations/entry/systemFields.js +0 -72
- package/operations/entry/systemFields.js.map +0 -1
- package/operations/settings/index.d.ts +0 -7
- package/operations/settings/index.js +0 -111
- package/operations/settings/index.js.map +0 -1
- package/operations/system/index.d.ts +0 -7
- package/operations/system/index.js +0 -82
- package/operations/system/index.js.map +0 -1
|
@@ -1,32 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var _types = require("@webiny/api-headless-cms/types");
|
|
12
|
-
var _keys = require("./keys");
|
|
13
|
-
var _batchWrite = require("@webiny/db-dynamodb/utils/batchWrite");
|
|
14
|
-
var _query = require("@webiny/db-dynamodb/utils/query");
|
|
15
|
-
var _cleanup = require("@webiny/db-dynamodb/utils/cleanup");
|
|
16
|
-
var _cursor = require("@webiny/utils/cursor");
|
|
17
|
-
var _zeroPad = require("@webiny/utils/zeroPad");
|
|
18
|
-
var _apiHeadlessCms = require("@webiny/api-headless-cms");
|
|
19
|
-
var _createFields = require("./filtering/createFields");
|
|
20
|
-
var _filtering = require("./filtering");
|
|
21
|
-
const createType = () => {
|
|
22
|
-
return "cms.entry";
|
|
23
|
-
};
|
|
24
|
-
const createLatestType = () => {
|
|
25
|
-
return `${createType()}.l`;
|
|
26
|
-
};
|
|
27
|
-
const createPublishedType = () => {
|
|
28
|
-
return `${createType()}.p`;
|
|
29
|
-
};
|
|
1
|
+
import WebinyError from "@webiny/error";
|
|
2
|
+
import { DataLoadersHandler } from "./dataLoaders.js";
|
|
3
|
+
import { CONTENT_ENTRY_STATUS } from "@webiny/api-headless-cms/types/index.js";
|
|
4
|
+
import { createEntryLatestKeys, createEntryPublishedKeys, createEntryRevisionKeys, createGSIPartitionKey, createPartitionKey, createPublishedSortKey, createRevisionSortKey } from "./keys.js";
|
|
5
|
+
import { decodeCursor, encodeCursor } from "@webiny/utils";
|
|
6
|
+
import { StorageOperationsCmsModelPlugin, StorageTransformPlugin } from "@webiny/api-headless-cms";
|
|
7
|
+
import { createFields } from "./filtering/createFields.js";
|
|
8
|
+
import { filter, sort } from "./filtering/index.js";
|
|
9
|
+
import { isDeletedEntryMetaField, isEntryLevelEntryMetaField, isRestoredEntryMetaField, pickEntryMetaFields } from "@webiny/api-headless-cms/constants.js";
|
|
10
|
+
import { getBaseFieldType } from "@webiny/api-headless-cms/utils/getBaseFieldType.js";
|
|
30
11
|
const convertToStorageEntry = params => {
|
|
31
12
|
const {
|
|
32
13
|
model,
|
|
@@ -36,9 +17,10 @@ const convertToStorageEntry = params => {
|
|
|
36
17
|
fields: model.fields,
|
|
37
18
|
values: storageEntry.values
|
|
38
19
|
});
|
|
39
|
-
return
|
|
20
|
+
return {
|
|
21
|
+
...storageEntry,
|
|
40
22
|
values
|
|
41
|
-
}
|
|
23
|
+
};
|
|
42
24
|
};
|
|
43
25
|
const convertFromStorageEntry = params => {
|
|
44
26
|
const {
|
|
@@ -49,12 +31,13 @@ const convertFromStorageEntry = params => {
|
|
|
49
31
|
fields: model.fields,
|
|
50
32
|
values: storageEntry.values
|
|
51
33
|
});
|
|
52
|
-
return
|
|
34
|
+
return {
|
|
35
|
+
...storageEntry,
|
|
53
36
|
values
|
|
54
|
-
}
|
|
37
|
+
};
|
|
55
38
|
};
|
|
56
|
-
const MAX_LIST_LIMIT =
|
|
57
|
-
const createEntriesStorageOperations = params => {
|
|
39
|
+
const MAX_LIST_LIMIT = 1000000;
|
|
40
|
+
export const createEntriesStorageOperations = params => {
|
|
58
41
|
const {
|
|
59
42
|
entity,
|
|
60
43
|
plugins
|
|
@@ -64,23 +47,25 @@ const createEntriesStorageOperations = params => {
|
|
|
64
47
|
if (storageOperationsCmsModelPlugin) {
|
|
65
48
|
return storageOperationsCmsModelPlugin;
|
|
66
49
|
}
|
|
67
|
-
storageOperationsCmsModelPlugin = plugins.oneByType(
|
|
50
|
+
storageOperationsCmsModelPlugin = plugins.oneByType(StorageOperationsCmsModelPlugin.type);
|
|
68
51
|
return storageOperationsCmsModelPlugin;
|
|
69
52
|
};
|
|
70
53
|
const getStorageOperationsModel = model => {
|
|
71
54
|
const plugin = getStorageOperationsCmsModelPlugin();
|
|
72
55
|
return plugin.getModel(model);
|
|
73
56
|
};
|
|
74
|
-
const dataLoaders = new
|
|
57
|
+
const dataLoaders = new DataLoadersHandler({
|
|
75
58
|
entity
|
|
76
59
|
});
|
|
77
|
-
const storageTransformPlugins = plugins.byType(_apiHeadlessCms.StorageTransformPlugin.type).reduce((collection, plugin) => {
|
|
78
|
-
collection[plugin.fieldType] = plugin;
|
|
79
|
-
return collection;
|
|
80
|
-
}, {});
|
|
81
60
|
const createStorageTransformCallable = model => {
|
|
61
|
+
// Cache StorageTransformPlugin to optimize execution.
|
|
62
|
+
const storageTransformPlugins = plugins.byType(StorageTransformPlugin.type).reduce((collection, plugin) => {
|
|
63
|
+
collection[plugin.fieldType] = plugin;
|
|
64
|
+
return collection;
|
|
65
|
+
}, {});
|
|
82
66
|
return (field, value) => {
|
|
83
|
-
const
|
|
67
|
+
const fieldType = getBaseFieldType(field);
|
|
68
|
+
const plugin = storageTransformPlugins[fieldType];
|
|
84
69
|
if (!plugin) {
|
|
85
70
|
return value;
|
|
86
71
|
}
|
|
@@ -101,61 +86,55 @@ const createEntriesStorageOperations = params => {
|
|
|
101
86
|
storageEntry: initialStorageEntry
|
|
102
87
|
} = params;
|
|
103
88
|
const model = getStorageOperationsModel(initialModel);
|
|
104
|
-
const partitionKey = (0, _keys.createPartitionKey)({
|
|
105
|
-
id: entry.id,
|
|
106
|
-
locale: model.locale,
|
|
107
|
-
tenant: model.tenant
|
|
108
|
-
});
|
|
109
89
|
const isPublished = entry.status === "published";
|
|
110
90
|
const locked = isPublished ? true : entry.locked;
|
|
111
91
|
const storageEntry = convertToStorageEntry({
|
|
112
92
|
model,
|
|
113
93
|
storageEntry: initialStorageEntry
|
|
114
94
|
});
|
|
95
|
+
const storageEntryRevisionKeys = createEntryRevisionKeys(entry);
|
|
96
|
+
const storageEntryLatestKeys = createEntryLatestKeys(entry);
|
|
115
97
|
/**
|
|
116
98
|
* We need to:
|
|
117
99
|
* - create new main entry item
|
|
118
100
|
* - create new or update the latest entry item
|
|
119
101
|
*/
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
})
|
|
102
|
+
const entityBatch = entity.createEntityWriter({
|
|
103
|
+
put: [{
|
|
104
|
+
...storageEntryRevisionKeys,
|
|
105
|
+
data: {
|
|
106
|
+
...storageEntry,
|
|
107
|
+
locked
|
|
108
|
+
}
|
|
109
|
+
}, {
|
|
110
|
+
...storageEntryLatestKeys,
|
|
111
|
+
data: {
|
|
112
|
+
...storageEntry,
|
|
113
|
+
locked
|
|
114
|
+
}
|
|
115
|
+
}]
|
|
116
|
+
});
|
|
135
117
|
|
|
136
118
|
/**
|
|
137
119
|
* We need to create published entry if
|
|
138
120
|
*/
|
|
139
121
|
if (isPublished) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
})
|
|
122
|
+
const storageEntryPublishedKeys = createEntryPublishedKeys(storageEntry);
|
|
123
|
+
entityBatch.put({
|
|
124
|
+
...storageEntryPublishedKeys,
|
|
125
|
+
data: {
|
|
126
|
+
...storageEntry,
|
|
127
|
+
locked
|
|
128
|
+
}
|
|
129
|
+
});
|
|
148
130
|
}
|
|
149
131
|
try {
|
|
150
|
-
await (
|
|
151
|
-
table: entity.table,
|
|
152
|
-
items
|
|
153
|
-
});
|
|
132
|
+
await entityBatch.execute();
|
|
154
133
|
dataLoaders.clearAll({
|
|
155
134
|
model
|
|
156
135
|
});
|
|
157
136
|
} catch (ex) {
|
|
158
|
-
throw new
|
|
137
|
+
throw new WebinyError(ex.message || "Could not insert data into the DynamoDB.", ex.code || "CREATE_ENTRY_ERROR", {
|
|
159
138
|
error: ex,
|
|
160
139
|
entry
|
|
161
140
|
});
|
|
@@ -168,43 +147,63 @@ const createEntriesStorageOperations = params => {
|
|
|
168
147
|
storageEntry: initialStorageEntry
|
|
169
148
|
} = params;
|
|
170
149
|
const model = getStorageOperationsModel(initialModel);
|
|
171
|
-
const partitionKey = (0, _keys.createPartitionKey)({
|
|
172
|
-
id: entry.id,
|
|
173
|
-
locale: model.locale,
|
|
174
|
-
tenant: model.tenant
|
|
175
|
-
});
|
|
176
150
|
const storageEntry = convertToStorageEntry({
|
|
177
151
|
storageEntry: initialStorageEntry,
|
|
178
152
|
model
|
|
179
153
|
});
|
|
154
|
+
|
|
180
155
|
/**
|
|
181
156
|
* We need to:
|
|
182
157
|
* - create the main entry item
|
|
183
|
-
* - update the
|
|
158
|
+
* - update the latest entry item to the current one
|
|
159
|
+
* - if the entry's status was set to "published":
|
|
160
|
+
* - update the published entry item to the current one
|
|
161
|
+
* - unpublish previously published revision (if any)
|
|
184
162
|
*/
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
163
|
+
const entityBatch = entity.createEntityWriter({
|
|
164
|
+
put: [{
|
|
165
|
+
...createEntryRevisionKeys(storageEntry),
|
|
166
|
+
data: {
|
|
167
|
+
...storageEntry
|
|
168
|
+
}
|
|
169
|
+
}, {
|
|
170
|
+
...createEntryLatestKeys(storageEntry),
|
|
171
|
+
data: {
|
|
172
|
+
...storageEntry
|
|
173
|
+
}
|
|
174
|
+
}]
|
|
175
|
+
});
|
|
176
|
+
const isPublished = entry.status === "published";
|
|
177
|
+
if (isPublished) {
|
|
178
|
+
entityBatch.put({
|
|
179
|
+
...createEntryPublishedKeys(storageEntry),
|
|
180
|
+
data: {
|
|
181
|
+
...storageEntry
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Unpublish previously published revision (if any).
|
|
186
|
+
const [publishedRevisionStorageEntry] = await dataLoaders.getPublishedRevisionByEntryId({
|
|
187
|
+
model,
|
|
188
|
+
ids: [entry.id]
|
|
202
189
|
});
|
|
190
|
+
if (publishedRevisionStorageEntry) {
|
|
191
|
+
entityBatch.put({
|
|
192
|
+
...createEntryRevisionKeys(publishedRevisionStorageEntry),
|
|
193
|
+
data: {
|
|
194
|
+
...publishedRevisionStorageEntry,
|
|
195
|
+
status: CONTENT_ENTRY_STATUS.UNPUBLISHED
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
await entityBatch.execute();
|
|
203
202
|
dataLoaders.clearAll({
|
|
204
203
|
model
|
|
205
204
|
});
|
|
206
205
|
} catch (ex) {
|
|
207
|
-
throw new
|
|
206
|
+
throw new WebinyError(ex.message || "Could not create revision from given entry.", ex.code || "CREATE_REVISION_ERROR", {
|
|
208
207
|
error: ex,
|
|
209
208
|
entry,
|
|
210
209
|
storageEntry
|
|
@@ -221,14 +220,8 @@ const createEntriesStorageOperations = params => {
|
|
|
221
220
|
storageEntry: initialStorageEntry
|
|
222
221
|
} = params;
|
|
223
222
|
const model = getStorageOperationsModel(initialModel);
|
|
224
|
-
const partitionKey = (0, _keys.createPartitionKey)({
|
|
225
|
-
id: entry.id,
|
|
226
|
-
locale: model.locale,
|
|
227
|
-
tenant: model.tenant
|
|
228
|
-
});
|
|
229
223
|
const isPublished = entry.status === "published";
|
|
230
224
|
const locked = isPublished ? true : entry.locked;
|
|
231
|
-
const items = [];
|
|
232
225
|
const storageEntry = convertToStorageEntry({
|
|
233
226
|
model,
|
|
234
227
|
storageEntry: initialStorageEntry
|
|
@@ -238,104 +231,322 @@ const createEntriesStorageOperations = params => {
|
|
|
238
231
|
* - update the current entry
|
|
239
232
|
* - update the latest entry if the current entry is the latest one
|
|
240
233
|
*/
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
234
|
+
|
|
235
|
+
const entityBatch = entity.createEntityWriter({
|
|
236
|
+
put: [{
|
|
237
|
+
...createEntryRevisionKeys(storageEntry),
|
|
238
|
+
data: {
|
|
239
|
+
...storageEntry,
|
|
240
|
+
locked
|
|
241
|
+
}
|
|
242
|
+
}]
|
|
243
|
+
});
|
|
249
244
|
if (isPublished) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
})));
|
|
245
|
+
entityBatch.put({
|
|
246
|
+
...createEntryPublishedKeys(storageEntry),
|
|
247
|
+
data: {
|
|
248
|
+
...storageEntry,
|
|
249
|
+
locked
|
|
250
|
+
}
|
|
251
|
+
});
|
|
258
252
|
}
|
|
259
253
|
|
|
260
254
|
/**
|
|
261
255
|
* We need the latest entry to update it as well if necessary.
|
|
262
256
|
*/
|
|
263
257
|
const latestStorageEntry = await getLatestRevisionByEntryId(model, entry);
|
|
264
|
-
if (latestStorageEntry
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
258
|
+
if (latestStorageEntry) {
|
|
259
|
+
const updatingLatestRevision = latestStorageEntry.id === entry.id;
|
|
260
|
+
if (updatingLatestRevision) {
|
|
261
|
+
entityBatch.put({
|
|
262
|
+
...createEntryLatestKeys(storageEntry),
|
|
263
|
+
data: {
|
|
264
|
+
...storageEntry,
|
|
265
|
+
locked
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
} else {
|
|
269
|
+
/**
|
|
270
|
+
* If not updating latest revision, we still want to update the latest revision's
|
|
271
|
+
* entry-level meta fields to match the current revision's entry-level meta fields.
|
|
272
|
+
*/
|
|
273
|
+
const updatedEntryLevelMetaFields = pickEntryMetaFields(entry, isEntryLevelEntryMetaField);
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* First we update the regular DynamoDB table. Two updates are needed:
|
|
277
|
+
* - one for the actual revision record
|
|
278
|
+
* - one for the latest record
|
|
279
|
+
*/
|
|
280
|
+
entityBatch.put({
|
|
281
|
+
...createEntryRevisionKeys(latestStorageEntry),
|
|
282
|
+
data: {
|
|
283
|
+
...latestStorageEntry,
|
|
284
|
+
...updatedEntryLevelMetaFields
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
entityBatch.put({
|
|
288
|
+
...createEntryLatestKeys(latestStorageEntry),
|
|
289
|
+
data: {
|
|
290
|
+
...latestStorageEntry,
|
|
291
|
+
...updatedEntryLevelMetaFields
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
273
295
|
}
|
|
274
296
|
try {
|
|
275
|
-
await (
|
|
276
|
-
table: entity.table,
|
|
277
|
-
items
|
|
278
|
-
});
|
|
297
|
+
await entityBatch.execute();
|
|
279
298
|
dataLoaders.clearAll({
|
|
280
299
|
model
|
|
281
300
|
});
|
|
282
301
|
return initialStorageEntry;
|
|
283
302
|
} catch (ex) {
|
|
284
|
-
throw new
|
|
303
|
+
throw new WebinyError(ex.message || "Could not update entry.", ex.code || "UPDATE_ERROR", {
|
|
285
304
|
error: ex,
|
|
286
305
|
entry,
|
|
287
306
|
latestStorageEntry
|
|
288
307
|
});
|
|
289
308
|
}
|
|
290
309
|
};
|
|
310
|
+
const move = async (initialModel, id, folderId) => {
|
|
311
|
+
/**
|
|
312
|
+
* We need to:
|
|
313
|
+
* - load all the revisions of the entry, including published and latest
|
|
314
|
+
* - update all the revisions (published and latest ) of the entry with new folderId
|
|
315
|
+
*/
|
|
316
|
+
const model = getStorageOperationsModel(initialModel);
|
|
317
|
+
/**
|
|
318
|
+
* First we need to load all the revisions and published / latest entry.
|
|
319
|
+
*/
|
|
320
|
+
const partitionKey = createPartitionKey({
|
|
321
|
+
id,
|
|
322
|
+
tenant: model.tenant
|
|
323
|
+
});
|
|
324
|
+
const records = await entity.queryAll({
|
|
325
|
+
partitionKey,
|
|
326
|
+
options: {
|
|
327
|
+
gte: " "
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
/**
|
|
331
|
+
* Then create the batch writes for the DynamoDB, with the updated folderId.
|
|
332
|
+
*/
|
|
333
|
+
const entityBatch = entity.createEntityWriter({
|
|
334
|
+
put: records.map(item => {
|
|
335
|
+
return {
|
|
336
|
+
...item,
|
|
337
|
+
data: {
|
|
338
|
+
...item.data,
|
|
339
|
+
location: {
|
|
340
|
+
...item.data.location,
|
|
341
|
+
folderId
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* And finally write it...
|
|
350
|
+
*/
|
|
351
|
+
try {
|
|
352
|
+
await entityBatch.execute();
|
|
353
|
+
} catch (ex) {
|
|
354
|
+
throw WebinyError.from(ex, {
|
|
355
|
+
message: "Could not move records to a new folder.",
|
|
356
|
+
data: {
|
|
357
|
+
id,
|
|
358
|
+
folderId
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
const moveToBin = async (initialModel, params) => {
|
|
364
|
+
const {
|
|
365
|
+
entry,
|
|
366
|
+
storageEntry: initialStorageEntry
|
|
367
|
+
} = params;
|
|
368
|
+
const model = getStorageOperationsModel(initialModel);
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* First we need to load all the revisions and published / latest entries.
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
let records = [];
|
|
375
|
+
try {
|
|
376
|
+
records = await entity.queryAll({
|
|
377
|
+
partitionKey: createPartitionKey({
|
|
378
|
+
id: entry.id,
|
|
379
|
+
tenant: model.tenant
|
|
380
|
+
}),
|
|
381
|
+
options: {
|
|
382
|
+
gte: " "
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
} catch (ex) {
|
|
386
|
+
throw new WebinyError(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
|
|
387
|
+
error: ex,
|
|
388
|
+
id: entry.id
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
if (records.length === 0) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const storageEntry = convertToStorageEntry({
|
|
395
|
+
model,
|
|
396
|
+
storageEntry: initialStorageEntry
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Let's pick the `deleted` meta fields from the storage entry.
|
|
401
|
+
*/
|
|
402
|
+
const updatedDeletedMetaFields = pickEntryMetaFields(storageEntry, isDeletedEntryMetaField);
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Then create the batch writes for the DynamoDB, with the updated data.
|
|
406
|
+
*/
|
|
407
|
+
const entityBatch = entity.createEntityWriter({
|
|
408
|
+
put: records.map(record => {
|
|
409
|
+
return {
|
|
410
|
+
...record,
|
|
411
|
+
data: {
|
|
412
|
+
...record.data,
|
|
413
|
+
...updatedDeletedMetaFields,
|
|
414
|
+
wbyDeleted: storageEntry.wbyDeleted,
|
|
415
|
+
location: storageEntry.location,
|
|
416
|
+
binOriginalFolderId: storageEntry.binOriginalFolderId
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
})
|
|
420
|
+
});
|
|
421
|
+
/**
|
|
422
|
+
* And finally write it...
|
|
423
|
+
*/
|
|
424
|
+
try {
|
|
425
|
+
await entityBatch.execute();
|
|
426
|
+
} catch (ex) {
|
|
427
|
+
throw new WebinyError(ex.message || "Could not move the entry to the bin.", ex.code || "MOVE_ENTRY_TO_BIN_ERROR", {
|
|
428
|
+
error: ex,
|
|
429
|
+
entry,
|
|
430
|
+
storageEntry
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
};
|
|
291
434
|
const deleteEntry = async (initialModel, params) => {
|
|
292
435
|
const {
|
|
293
436
|
entry
|
|
294
437
|
} = params;
|
|
295
438
|
const id = entry.id || entry.entryId;
|
|
296
439
|
const model = getStorageOperationsModel(initialModel);
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
locale: model.locale,
|
|
302
|
-
tenant: model.tenant
|
|
303
|
-
}),
|
|
304
|
-
options: {
|
|
305
|
-
gte: " "
|
|
306
|
-
}
|
|
307
|
-
};
|
|
440
|
+
const partitionKey = createPartitionKey({
|
|
441
|
+
id,
|
|
442
|
+
tenant: model.tenant
|
|
443
|
+
});
|
|
308
444
|
let records = [];
|
|
309
445
|
try {
|
|
310
|
-
records = await
|
|
446
|
+
records = await entity.queryAll({
|
|
447
|
+
partitionKey,
|
|
448
|
+
options: {
|
|
449
|
+
gte: " "
|
|
450
|
+
}
|
|
451
|
+
});
|
|
311
452
|
} catch (ex) {
|
|
312
|
-
throw new
|
|
453
|
+
throw new WebinyError(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
|
|
313
454
|
error: ex,
|
|
314
455
|
id
|
|
315
456
|
});
|
|
316
457
|
}
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
458
|
+
const entityBatch = entity.createEntityWriter({
|
|
459
|
+
delete: records.map(item => {
|
|
460
|
+
return {
|
|
461
|
+
PK: item.PK,
|
|
462
|
+
SK: item.SK
|
|
463
|
+
};
|
|
464
|
+
})
|
|
322
465
|
});
|
|
323
466
|
try {
|
|
324
|
-
await (
|
|
325
|
-
table: entity.table,
|
|
326
|
-
items
|
|
327
|
-
});
|
|
467
|
+
await entityBatch.execute();
|
|
328
468
|
dataLoaders.clearAll({
|
|
329
469
|
model
|
|
330
470
|
});
|
|
331
471
|
} catch (ex) {
|
|
332
|
-
throw new
|
|
472
|
+
throw new WebinyError(ex.message || "Could not delete the entry.", ex.code || "DELETE_ENTRY_ERROR", {
|
|
333
473
|
error: ex,
|
|
334
|
-
partitionKey
|
|
474
|
+
partitionKey,
|
|
335
475
|
id
|
|
336
476
|
});
|
|
337
477
|
}
|
|
338
478
|
};
|
|
479
|
+
const restoreFromBin = async (initialModel, params) => {
|
|
480
|
+
const {
|
|
481
|
+
entry,
|
|
482
|
+
storageEntry: initialStorageEntry
|
|
483
|
+
} = params;
|
|
484
|
+
const model = getStorageOperationsModel(initialModel);
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* First we need to load all the revisions and published / latest entries.
|
|
488
|
+
*/
|
|
489
|
+
let records = [];
|
|
490
|
+
try {
|
|
491
|
+
records = await entity.queryAll({
|
|
492
|
+
partitionKey: createPartitionKey({
|
|
493
|
+
id: entry.id,
|
|
494
|
+
tenant: model.tenant
|
|
495
|
+
}),
|
|
496
|
+
options: {
|
|
497
|
+
gte: " "
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
} catch (ex) {
|
|
501
|
+
throw new WebinyError(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
|
|
502
|
+
error: ex,
|
|
503
|
+
id: entry.id
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
if (records.length === 0) {
|
|
507
|
+
return initialStorageEntry;
|
|
508
|
+
}
|
|
509
|
+
const storageEntry = convertToStorageEntry({
|
|
510
|
+
model,
|
|
511
|
+
storageEntry: initialStorageEntry
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Let's pick the `restored` meta fields from the storage entry.
|
|
516
|
+
*/
|
|
517
|
+
const updatedRestoredMetaFields = pickEntryMetaFields(storageEntry, isRestoredEntryMetaField);
|
|
518
|
+
const entityBatch = entity.createEntityWriter({
|
|
519
|
+
put: records.map(record => {
|
|
520
|
+
return {
|
|
521
|
+
...record,
|
|
522
|
+
data: {
|
|
523
|
+
...record.data,
|
|
524
|
+
...updatedRestoredMetaFields,
|
|
525
|
+
wbyDeleted: storageEntry.wbyDeleted,
|
|
526
|
+
location: storageEntry.location,
|
|
527
|
+
binOriginalFolderId: storageEntry.binOriginalFolderId
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
})
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* And finally write it...
|
|
535
|
+
*/
|
|
536
|
+
try {
|
|
537
|
+
await entityBatch.execute();
|
|
538
|
+
dataLoaders.clearAll({
|
|
539
|
+
model
|
|
540
|
+
});
|
|
541
|
+
return initialStorageEntry;
|
|
542
|
+
} catch (ex) {
|
|
543
|
+
throw new WebinyError(ex.message || "Could not restore the entry from the bin.", ex.code || "RESTORE_ENTRY_ERROR", {
|
|
544
|
+
error: ex,
|
|
545
|
+
entry,
|
|
546
|
+
storageEntry
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
};
|
|
339
550
|
const deleteRevision = async (initialModel, params) => {
|
|
340
551
|
const {
|
|
341
552
|
entry,
|
|
@@ -343,49 +554,55 @@ const createEntriesStorageOperations = params => {
|
|
|
343
554
|
latestStorageEntry: initialLatestStorageEntry
|
|
344
555
|
} = params;
|
|
345
556
|
const model = getStorageOperationsModel(initialModel);
|
|
346
|
-
const partitionKey =
|
|
557
|
+
const partitionKey = createPartitionKey({
|
|
347
558
|
id: entry.id,
|
|
348
|
-
locale: model.locale,
|
|
349
559
|
tenant: model.tenant
|
|
350
560
|
});
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
561
|
+
const entityBatch = entity.createEntityWriter({
|
|
562
|
+
delete: [{
|
|
563
|
+
PK: partitionKey,
|
|
564
|
+
SK: createRevisionSortKey(entry)
|
|
565
|
+
}]
|
|
566
|
+
});
|
|
355
567
|
const publishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
|
|
356
568
|
|
|
357
569
|
/**
|
|
358
570
|
* If revision we are deleting is the published one as well, we need to delete those records as well.
|
|
359
571
|
*/
|
|
360
572
|
if (publishedStorageEntry && entry.id === publishedStorageEntry.id) {
|
|
361
|
-
|
|
573
|
+
entityBatch.delete({
|
|
362
574
|
PK: partitionKey,
|
|
363
|
-
SK:
|
|
364
|
-
})
|
|
575
|
+
SK: createPublishedSortKey()
|
|
576
|
+
});
|
|
365
577
|
}
|
|
366
578
|
if (initialLatestStorageEntry) {
|
|
367
579
|
const latestStorageEntry = convertToStorageEntry({
|
|
368
580
|
storageEntry: initialLatestStorageEntry,
|
|
369
581
|
model
|
|
370
582
|
});
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
583
|
+
entityBatch.put({
|
|
584
|
+
...createEntryLatestKeys(latestStorageEntry),
|
|
585
|
+
data: {
|
|
586
|
+
...latestStorageEntry
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
// Do an update on the latest revision. We need to update the latest revision's
|
|
591
|
+
// entry-level meta fields to match the previous revision's entry-level meta fields.
|
|
592
|
+
entityBatch.put({
|
|
593
|
+
...createEntryRevisionKeys(latestStorageEntry),
|
|
594
|
+
data: {
|
|
595
|
+
...latestStorageEntry
|
|
596
|
+
}
|
|
597
|
+
});
|
|
378
598
|
}
|
|
379
599
|
try {
|
|
380
|
-
await (
|
|
381
|
-
table: entity.table,
|
|
382
|
-
items
|
|
383
|
-
});
|
|
600
|
+
await entityBatch.execute();
|
|
384
601
|
dataLoaders.clearAll({
|
|
385
602
|
model
|
|
386
603
|
});
|
|
387
604
|
} catch (ex) {
|
|
388
|
-
throw new
|
|
605
|
+
throw new WebinyError(ex.message, ex.code, {
|
|
389
606
|
error: ex,
|
|
390
607
|
entry,
|
|
391
608
|
latestEntry
|
|
@@ -407,50 +624,37 @@ const createEntriesStorageOperations = params => {
|
|
|
407
624
|
/**
|
|
408
625
|
* Then we need to construct the queries for all the revisions and entries.
|
|
409
626
|
*/
|
|
410
|
-
|
|
627
|
+
|
|
628
|
+
const entityBatch = entity.createEntityWriter();
|
|
411
629
|
for (const id of entries) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
locale: model.locale,
|
|
419
|
-
tenant: model.tenant
|
|
420
|
-
}),
|
|
630
|
+
const partitionKey = createPartitionKey({
|
|
631
|
+
id,
|
|
632
|
+
tenant: model.tenant
|
|
633
|
+
});
|
|
634
|
+
entityBatch.delete({
|
|
635
|
+
PK: partitionKey,
|
|
421
636
|
SK: "L"
|
|
422
|
-
})
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
*/
|
|
426
|
-
items.push(entity.deleteBatch({
|
|
427
|
-
PK: (0, _keys.createPartitionKey)({
|
|
428
|
-
id,
|
|
429
|
-
locale: model.locale,
|
|
430
|
-
tenant: model.tenant
|
|
431
|
-
}),
|
|
637
|
+
});
|
|
638
|
+
entityBatch.delete({
|
|
639
|
+
PK: partitionKey,
|
|
432
640
|
SK: "P"
|
|
433
|
-
})
|
|
641
|
+
});
|
|
434
642
|
}
|
|
435
643
|
/**
|
|
436
644
|
* Exact revisions of all the entries
|
|
437
645
|
*/
|
|
438
646
|
for (const revision of revisions) {
|
|
439
|
-
|
|
440
|
-
PK:
|
|
647
|
+
entityBatch.delete({
|
|
648
|
+
PK: createPartitionKey({
|
|
441
649
|
id: revision.id,
|
|
442
|
-
locale: model.locale,
|
|
443
650
|
tenant: model.tenant
|
|
444
651
|
}),
|
|
445
|
-
SK:
|
|
652
|
+
SK: createRevisionSortKey({
|
|
446
653
|
version: revision.version
|
|
447
654
|
})
|
|
448
|
-
})
|
|
655
|
+
});
|
|
449
656
|
}
|
|
450
|
-
await (
|
|
451
|
-
table: entity.table,
|
|
452
|
-
items
|
|
453
|
-
});
|
|
657
|
+
await entityBatch.execute();
|
|
454
658
|
};
|
|
455
659
|
const getLatestRevisionByEntryId = async (initialModel, params) => {
|
|
456
660
|
const model = getStorageOperationsModel(initialModel);
|
|
@@ -555,45 +759,36 @@ const createEntriesStorageOperations = params => {
|
|
|
555
759
|
entryId,
|
|
556
760
|
version
|
|
557
761
|
} = params;
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}),
|
|
762
|
+
const partitionKey = createPartitionKey({
|
|
763
|
+
tenant: model.tenant,
|
|
764
|
+
id: entryId
|
|
765
|
+
});
|
|
766
|
+
const unfilteredRevisions = await entity.queryAll({
|
|
767
|
+
partitionKey,
|
|
565
768
|
options: {
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* We need to have extra checks because DynamoDB will return published or latest record if there is no REV# record.
|
|
569
|
-
*/
|
|
570
|
-
filters: [{
|
|
571
|
-
attr: "TYPE",
|
|
572
|
-
eq: createType()
|
|
573
|
-
}, {
|
|
574
|
-
attr: "version",
|
|
575
|
-
lt: version
|
|
576
|
-
}],
|
|
769
|
+
beginsWith: `REV#`,
|
|
577
770
|
reverse: true
|
|
578
771
|
}
|
|
579
|
-
};
|
|
772
|
+
});
|
|
773
|
+
const filteredRevisions = unfilteredRevisions.filter(item => {
|
|
774
|
+
return item.data.version < version;
|
|
775
|
+
});
|
|
776
|
+
const storageEntry = filteredRevisions[0];
|
|
777
|
+
if (!storageEntry) {
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
580
780
|
try {
|
|
581
|
-
const result = await (0, _query.queryOne)(queryParams);
|
|
582
|
-
const storageEntry = (0, _cleanup.cleanupItem)(entity, result);
|
|
583
|
-
if (!storageEntry) {
|
|
584
|
-
return null;
|
|
585
|
-
}
|
|
586
781
|
return convertFromStorageEntry({
|
|
587
|
-
storageEntry,
|
|
782
|
+
storageEntry: storageEntry.data,
|
|
588
783
|
model
|
|
589
784
|
});
|
|
590
785
|
} catch (ex) {
|
|
591
|
-
throw new
|
|
786
|
+
throw new WebinyError(ex.message || "Could not get previous version of given entry.", ex.code || "GET_PREVIOUS_VERSION_ERROR", {
|
|
787
|
+
...params,
|
|
592
788
|
error: ex,
|
|
593
|
-
partitionKey
|
|
594
|
-
options: queryParams.options,
|
|
789
|
+
partitionKey,
|
|
595
790
|
model
|
|
596
|
-
})
|
|
791
|
+
});
|
|
597
792
|
}
|
|
598
793
|
};
|
|
599
794
|
const list = async (initialModel, params) => {
|
|
@@ -608,22 +803,22 @@ const createEntriesStorageOperations = params => {
|
|
|
608
803
|
} = params;
|
|
609
804
|
const limit = initialLimit <= 0 || initialLimit >= MAX_LIST_LIMIT ? MAX_LIST_LIMIT : initialLimit;
|
|
610
805
|
const type = initialWhere.published ? "P" : "L";
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
index: "GSI1",
|
|
616
|
-
gte: " "
|
|
617
|
-
}
|
|
806
|
+
const partitionKey = createGSIPartitionKey(model, type);
|
|
807
|
+
const options = {
|
|
808
|
+
index: "GSI1",
|
|
809
|
+
gte: " "
|
|
618
810
|
};
|
|
619
811
|
let storageEntries = [];
|
|
620
812
|
try {
|
|
621
|
-
storageEntries = await
|
|
813
|
+
storageEntries = await entity.queryAll({
|
|
814
|
+
partitionKey,
|
|
815
|
+
options
|
|
816
|
+
});
|
|
622
817
|
} catch (ex) {
|
|
623
|
-
throw new
|
|
818
|
+
throw new WebinyError(ex.message, "QUERY_ENTRIES_ERROR", {
|
|
624
819
|
error: ex,
|
|
625
|
-
partitionKey
|
|
626
|
-
options
|
|
820
|
+
partitionKey,
|
|
821
|
+
options
|
|
627
822
|
});
|
|
628
823
|
}
|
|
629
824
|
if (storageEntries.length === 0) {
|
|
@@ -634,14 +829,16 @@ const createEntriesStorageOperations = params => {
|
|
|
634
829
|
items: []
|
|
635
830
|
};
|
|
636
831
|
}
|
|
637
|
-
const where =
|
|
832
|
+
const where = {
|
|
833
|
+
...initialWhere
|
|
834
|
+
};
|
|
638
835
|
delete where["published"];
|
|
639
836
|
delete where["latest"];
|
|
640
837
|
/**
|
|
641
838
|
* We need an object containing field, transformers and paths.
|
|
642
839
|
* Just build it here and pass on into other methods that require it to avoid mapping multiple times.
|
|
643
840
|
*/
|
|
644
|
-
const modelFields =
|
|
841
|
+
const modelFields = createFields({
|
|
645
842
|
plugins,
|
|
646
843
|
fields: model.fields
|
|
647
844
|
});
|
|
@@ -653,7 +850,7 @@ const createEntriesStorageOperations = params => {
|
|
|
653
850
|
*/
|
|
654
851
|
const records = await Promise.all(storageEntries.map(async storageEntry => {
|
|
655
852
|
const entry = convertFromStorageEntry({
|
|
656
|
-
storageEntry,
|
|
853
|
+
storageEntry: storageEntry.data,
|
|
657
854
|
model
|
|
658
855
|
});
|
|
659
856
|
for (const field of model.fields) {
|
|
@@ -665,7 +862,7 @@ const createEntriesStorageOperations = params => {
|
|
|
665
862
|
* Filter the read items via the code.
|
|
666
863
|
* It will build the filters out of the where input and transform the values it is using.
|
|
667
864
|
*/
|
|
668
|
-
const filteredItems =
|
|
865
|
+
const filteredItems = filter({
|
|
669
866
|
items: records,
|
|
670
867
|
where,
|
|
671
868
|
plugins,
|
|
@@ -681,14 +878,14 @@ const createEntriesStorageOperations = params => {
|
|
|
681
878
|
* Sorting is also done via the code.
|
|
682
879
|
* It takes the sort input and sorts by it via the lodash sortBy method.
|
|
683
880
|
*/
|
|
684
|
-
const sortedItems =
|
|
881
|
+
const sortedItems = sort({
|
|
685
882
|
model,
|
|
686
883
|
plugins,
|
|
687
884
|
items: filteredItems,
|
|
688
885
|
sort: sortBy,
|
|
689
886
|
fields: modelFields
|
|
690
887
|
});
|
|
691
|
-
const start = parseInt(
|
|
888
|
+
const start = parseInt(decodeCursor(after) || "0") || 0;
|
|
692
889
|
const hasMoreItems = totalCount > start + limit;
|
|
693
890
|
const end = limit > totalCount + start + limit ? undefined : start + limit;
|
|
694
891
|
const slicedItems = sortedItems.slice(start, end);
|
|
@@ -696,21 +893,22 @@ const createEntriesStorageOperations = params => {
|
|
|
696
893
|
* Although we do not need a cursor here, we will use it as such to keep it standardized.
|
|
697
894
|
* Number is simply encoded.
|
|
698
895
|
*/
|
|
699
|
-
const cursor =
|
|
896
|
+
const cursor = encodeCursor(`${start + limit}`);
|
|
700
897
|
return {
|
|
701
898
|
hasMoreItems,
|
|
702
899
|
totalCount,
|
|
703
900
|
cursor,
|
|
704
|
-
items:
|
|
901
|
+
items: slicedItems
|
|
705
902
|
};
|
|
706
903
|
};
|
|
707
904
|
const get = async (initialModel, params) => {
|
|
708
905
|
const model = getStorageOperationsModel(initialModel);
|
|
709
906
|
const {
|
|
710
907
|
items
|
|
711
|
-
} = await list(model,
|
|
908
|
+
} = await list(model, {
|
|
909
|
+
...params,
|
|
712
910
|
limit: 1
|
|
713
|
-
})
|
|
911
|
+
});
|
|
714
912
|
return items.shift() || null;
|
|
715
913
|
};
|
|
716
914
|
const publish = async (initialModel, params) => {
|
|
@@ -719,75 +917,125 @@ const createEntriesStorageOperations = params => {
|
|
|
719
917
|
storageEntry: initialStorageEntry
|
|
720
918
|
} = params;
|
|
721
919
|
const model = getStorageOperationsModel(initialModel);
|
|
722
|
-
const partitionKey = (0, _keys.createPartitionKey)({
|
|
723
|
-
id: entry.id,
|
|
724
|
-
locale: model.locale,
|
|
725
|
-
tenant: model.tenant
|
|
726
|
-
});
|
|
727
920
|
|
|
728
921
|
/**
|
|
729
922
|
* We need the latest and published entries to see if something needs to be updated alongside the publishing one.
|
|
730
923
|
*/
|
|
731
924
|
const initialLatestStorageEntry = await getLatestRevisionByEntryId(model, entry);
|
|
925
|
+
if (!initialLatestStorageEntry) {
|
|
926
|
+
throw new WebinyError(`Could not publish entry. Could not load latest ("L") record.`, "PUBLISH_ERROR", {
|
|
927
|
+
entry
|
|
928
|
+
});
|
|
929
|
+
}
|
|
732
930
|
const initialPublishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
|
|
733
931
|
const storageEntry = convertToStorageEntry({
|
|
734
932
|
model,
|
|
735
933
|
storageEntry: initialStorageEntry
|
|
736
934
|
});
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
if (
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
})
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
935
|
+
|
|
936
|
+
// 1. Update REV# and P records with new data.
|
|
937
|
+
const entityBatch = entity.createEntityWriter({
|
|
938
|
+
put: [{
|
|
939
|
+
...createEntryRevisionKeys(storageEntry),
|
|
940
|
+
data: {
|
|
941
|
+
...storageEntry
|
|
942
|
+
}
|
|
943
|
+
}, {
|
|
944
|
+
...createEntryPublishedKeys(storageEntry),
|
|
945
|
+
data: {
|
|
946
|
+
...storageEntry
|
|
947
|
+
}
|
|
948
|
+
}]
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
// 2. When it comes to the latest record, we need to perform a couple of different
|
|
952
|
+
// updates, based on whether the entry being published is the latest revision or not.
|
|
953
|
+
const publishedRevisionId = initialPublishedStorageEntry?.id;
|
|
954
|
+
const publishingLatestRevision = entry.id === initialLatestStorageEntry.id;
|
|
955
|
+
if (publishingLatestRevision) {
|
|
956
|
+
// 2.1 If we're publishing the latest revision, we first need to update the L record.
|
|
957
|
+
entityBatch.put({
|
|
958
|
+
...createEntryLatestKeys(storageEntry),
|
|
959
|
+
data: {
|
|
960
|
+
...storageEntry
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
// 2.2 Additionally, if we have a previously published entry, we need to mark it as unpublished.
|
|
965
|
+
if (publishedRevisionId && publishedRevisionId !== entry.id) {
|
|
966
|
+
const publishedStorageEntry = convertToStorageEntry({
|
|
967
|
+
storageEntry: initialPublishedStorageEntry,
|
|
968
|
+
model
|
|
969
|
+
});
|
|
970
|
+
entityBatch.put({
|
|
971
|
+
...createEntryRevisionKeys(publishedStorageEntry),
|
|
972
|
+
data: {
|
|
973
|
+
...publishedStorageEntry,
|
|
974
|
+
status: CONTENT_ENTRY_STATUS.UNPUBLISHED
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
} else {
|
|
979
|
+
// 2.3 If the published revision is not the latest one, the situation is a bit
|
|
980
|
+
// more complex. We first need to update the L and REV# records with the new
|
|
981
|
+
// values of *only entry-level* meta fields.
|
|
982
|
+
const updatedEntryLevelMetaFields = pickEntryMetaFields(entry, isEntryLevelEntryMetaField);
|
|
983
|
+
const latestStorageEntry = convertToStorageEntry({
|
|
984
|
+
storageEntry: initialLatestStorageEntry,
|
|
769
985
|
model
|
|
770
986
|
});
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
987
|
+
|
|
988
|
+
// 2.3.1 Update L record. Apart from updating the entry-level meta fields, we also need
|
|
989
|
+
// to change the status from "published" to "unpublished" (if the status is set to "published").
|
|
990
|
+
let latestRevisionStatus = latestStorageEntry.status;
|
|
991
|
+
if (latestRevisionStatus === CONTENT_ENTRY_STATUS.PUBLISHED) {
|
|
992
|
+
latestRevisionStatus = CONTENT_ENTRY_STATUS.UNPUBLISHED;
|
|
993
|
+
}
|
|
994
|
+
const latestStorageEntryFields = {
|
|
995
|
+
...latestStorageEntry,
|
|
996
|
+
...updatedEntryLevelMetaFields,
|
|
997
|
+
status: latestRevisionStatus
|
|
998
|
+
};
|
|
999
|
+
entityBatch.put({
|
|
1000
|
+
...createEntryLatestKeys(latestStorageEntryFields),
|
|
1001
|
+
data: {
|
|
1002
|
+
...latestStorageEntryFields
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
// 2.3.2 Update REV# record.
|
|
1007
|
+
entityBatch.put({
|
|
1008
|
+
...createEntryRevisionKeys(latestStorageEntryFields),
|
|
1009
|
+
data: {
|
|
1010
|
+
...latestStorageEntryFields
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
|
|
1014
|
+
// 2.3.3 Finally, if we got a published entry, but it wasn't the latest one, we need to take
|
|
1015
|
+
// an extra step and mark it as unpublished.
|
|
1016
|
+
const publishedRevisionDifferentFromLatest = publishedRevisionId && publishedRevisionId !== latestStorageEntry.id;
|
|
1017
|
+
if (publishedRevisionDifferentFromLatest) {
|
|
1018
|
+
const publishedStorageEntry = convertToStorageEntry({
|
|
1019
|
+
storageEntry: initialPublishedStorageEntry,
|
|
1020
|
+
model
|
|
1021
|
+
});
|
|
1022
|
+
entityBatch.put({
|
|
1023
|
+
...createEntryRevisionKeys(publishedStorageEntry),
|
|
1024
|
+
data: {
|
|
1025
|
+
...publishedStorageEntry,
|
|
1026
|
+
status: CONTENT_ENTRY_STATUS.UNPUBLISHED
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
779
1030
|
}
|
|
780
1031
|
try {
|
|
781
|
-
await (
|
|
782
|
-
table: entity.table,
|
|
783
|
-
items
|
|
784
|
-
});
|
|
1032
|
+
await entityBatch.execute();
|
|
785
1033
|
dataLoaders.clearAll({
|
|
786
1034
|
model
|
|
787
1035
|
});
|
|
788
1036
|
return initialStorageEntry;
|
|
789
1037
|
} catch (ex) {
|
|
790
|
-
throw new
|
|
1038
|
+
throw new WebinyError(ex.message || "Could not execute the publishing batch.", ex.code || "PUBLISH_ERROR", {
|
|
791
1039
|
entry,
|
|
792
1040
|
latestStorageEntry: initialLatestStorageEntry,
|
|
793
1041
|
publishedStorageEntry: initialPublishedStorageEntry
|
|
@@ -800,9 +1048,8 @@ const createEntriesStorageOperations = params => {
|
|
|
800
1048
|
storageEntry: initialStorageEntry
|
|
801
1049
|
} = params;
|
|
802
1050
|
const model = getStorageOperationsModel(initialModel);
|
|
803
|
-
const partitionKey =
|
|
1051
|
+
const partitionKey = createPartitionKey({
|
|
804
1052
|
id: entry.id,
|
|
805
|
-
locale: model.locale,
|
|
806
1053
|
tenant: model.tenant
|
|
807
1054
|
});
|
|
808
1055
|
const storageEntry = convertToStorageEntry({
|
|
@@ -815,41 +1062,69 @@ const createEntriesStorageOperations = params => {
|
|
|
815
1062
|
* - update current entry revision with new data
|
|
816
1063
|
* - update the latest entry status - if entry being unpublished is latest
|
|
817
1064
|
*/
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1065
|
+
const entityBatch = entity.createEntityWriter({
|
|
1066
|
+
delete: [{
|
|
1067
|
+
PK: partitionKey,
|
|
1068
|
+
SK: createPublishedSortKey()
|
|
1069
|
+
}],
|
|
1070
|
+
put: [{
|
|
1071
|
+
...createEntryRevisionKeys(storageEntry),
|
|
1072
|
+
data: {
|
|
1073
|
+
...storageEntry
|
|
1074
|
+
}
|
|
1075
|
+
}]
|
|
1076
|
+
});
|
|
828
1077
|
|
|
829
1078
|
/**
|
|
830
1079
|
* We need the latest entry to see if something needs to be updated alongside the unpublishing one.
|
|
831
1080
|
*/
|
|
832
|
-
const
|
|
833
|
-
if (
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1081
|
+
const initialLatestStorageEntry = await getLatestRevisionByEntryId(model, entry);
|
|
1082
|
+
if (initialLatestStorageEntry) {
|
|
1083
|
+
const unpublishingLatestRevision = entry.id === initialLatestStorageEntry.id;
|
|
1084
|
+
if (unpublishingLatestRevision) {
|
|
1085
|
+
entityBatch.put({
|
|
1086
|
+
...createEntryLatestKeys(storageEntry),
|
|
1087
|
+
data: {
|
|
1088
|
+
...storageEntry
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
} else {
|
|
1092
|
+
const latestStorageEntry = convertToStorageEntry({
|
|
1093
|
+
storageEntry: initialLatestStorageEntry,
|
|
1094
|
+
model
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
// If the unpublished revision is not the latest one, we still need to
|
|
1098
|
+
// update the latest record with the new values of entry-level meta fields.
|
|
1099
|
+
const updatedEntryLevelMetaFields = pickEntryMetaFields(entry, isEntryLevelEntryMetaField);
|
|
1100
|
+
|
|
1101
|
+
// 1. Update actual revision record.
|
|
1102
|
+
entityBatch.put({
|
|
1103
|
+
...createEntryRevisionKeys(latestStorageEntry),
|
|
1104
|
+
data: {
|
|
1105
|
+
...latestStorageEntry,
|
|
1106
|
+
...updatedEntryLevelMetaFields
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
// 2. Update latest record.
|
|
1111
|
+
entityBatch.put({
|
|
1112
|
+
...createEntryLatestKeys(latestStorageEntry),
|
|
1113
|
+
data: {
|
|
1114
|
+
...latestStorageEntry,
|
|
1115
|
+
...updatedEntryLevelMetaFields
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
841
1119
|
}
|
|
842
1120
|
try {
|
|
843
|
-
await (
|
|
844
|
-
table: entity.table,
|
|
845
|
-
items
|
|
846
|
-
});
|
|
1121
|
+
await entityBatch.execute();
|
|
847
1122
|
dataLoaders.clearAll({
|
|
848
1123
|
model
|
|
849
1124
|
});
|
|
850
1125
|
return initialStorageEntry;
|
|
851
1126
|
} catch (ex) {
|
|
852
|
-
throw new
|
|
1127
|
+
throw new WebinyError(ex.message || "Could not execute unpublish batch.", ex.code || "UNPUBLISH_ERROR", {
|
|
853
1128
|
entry,
|
|
854
1129
|
storageEntry
|
|
855
1130
|
});
|
|
@@ -862,7 +1137,7 @@ const createEntriesStorageOperations = params => {
|
|
|
862
1137
|
} = params;
|
|
863
1138
|
const field = model.fields.find(f => f.fieldId === fieldId);
|
|
864
1139
|
if (!field) {
|
|
865
|
-
throw new
|
|
1140
|
+
throw new WebinyError(`Could not find field with given "fieldId" value.`, "FIELD_NOT_FOUND", {
|
|
866
1141
|
fieldId
|
|
867
1142
|
});
|
|
868
1143
|
}
|
|
@@ -872,13 +1147,33 @@ const createEntriesStorageOperations = params => {
|
|
|
872
1147
|
where,
|
|
873
1148
|
limit: MAX_LIST_LIMIT
|
|
874
1149
|
});
|
|
875
|
-
|
|
1150
|
+
const result = {};
|
|
1151
|
+
for (const item of items) {
|
|
1152
|
+
const fieldValue = item.values[field.fieldId];
|
|
1153
|
+
if (!fieldValue) {
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
const values = Array.isArray(fieldValue) ? fieldValue : [fieldValue];
|
|
1157
|
+
if (values.length === 0) {
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
for (const value of values) {
|
|
1161
|
+
result[value] = {
|
|
1162
|
+
value,
|
|
1163
|
+
count: (result[value]?.count || 0) + 1
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
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);
|
|
876
1168
|
};
|
|
877
1169
|
return {
|
|
878
1170
|
create,
|
|
879
1171
|
createRevisionFrom,
|
|
880
1172
|
update,
|
|
1173
|
+
move,
|
|
881
1174
|
delete: deleteEntry,
|
|
1175
|
+
moveToBin,
|
|
1176
|
+
restoreFromBin,
|
|
882
1177
|
deleteRevision,
|
|
883
1178
|
deleteMultipleEntries,
|
|
884
1179
|
getPreviousRevision,
|
|
@@ -897,4 +1192,5 @@ const createEntriesStorageOperations = params => {
|
|
|
897
1192
|
getUniqueFieldValues
|
|
898
1193
|
};
|
|
899
1194
|
};
|
|
900
|
-
|
|
1195
|
+
|
|
1196
|
+
//# sourceMappingURL=index.js.map
|