@webiny/api-headless-cms-ddb 0.0.0-unstable.bca7b3e350 → 0.0.0-unstable.c27f4d8a31
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 +6 -89
- package/definitions/entry.js.map +1 -1
- package/definitions/group.d.ts +4 -5
- package/definitions/group.js +6 -63
- package/definitions/group.js.map +1 -1
- package/definitions/model.d.ts +4 -5
- package/definitions/model.js +6 -90
- package/definitions/model.js.map +1 -1
- package/definitions/table.d.ts +4 -6
- package/definitions/table.js +7 -28
- package/definitions/table.js.map +1 -1
- package/definitions/types.d.ts +60 -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 +8 -20
- 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 +6 -20
- package/dynamoDb/path/plainObject.js.map +1 -1
- package/dynamoDb/storage/longText.js +13 -35
- package/dynamoDb/storage/longText.js.map +1 -1
- package/dynamoDb/storage/richText.js +27 -88
- package/dynamoDb/storage/richText.js.map +1 -1
- package/dynamoDb/transformValue/datetime.d.ts +1 -1
- package/dynamoDb/transformValue/datetime.js +7 -19
- package/dynamoDb/transformValue/datetime.js.map +1 -1
- package/index.d.ts +2 -2
- package/index.js +47 -111
- package/index.js.map +1 -1
- package/operations/entry/dataLoader/DataLoaderCache.d.ts +16 -0
- package/operations/entry/dataLoader/DataLoaderCache.js +31 -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 +4 -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 +19 -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 +35 -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 +50 -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 +50 -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 +56 -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 +19 -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 +3 -0
- package/operations/entry/dataLoader/types.js.map +1 -0
- package/operations/entry/dataLoaders.d.ts +14 -30
- package/operations/entry/dataLoaders.js +58 -271
- package/operations/entry/dataLoaders.js.map +1 -1
- package/operations/entry/filtering/createExpressions.d.ts +5 -5
- package/operations/entry/filtering/createExpressions.js +30 -68
- package/operations/entry/filtering/createExpressions.js.map +1 -1
- package/operations/entry/filtering/createFields.d.ts +6 -4
- package/operations/entry/filtering/createFields.js +86 -103
- package/operations/entry/filtering/createFields.js.map +1 -1
- package/operations/entry/filtering/extractSort.d.ts +6 -6
- package/operations/entry/filtering/extractSort.js +39 -32
- 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 -64
- package/operations/entry/filtering/filter.js.map +1 -1
- package/operations/entry/filtering/fullTextSearch.d.ts +3 -3
- package/operations/entry/filtering/fullTextSearch.js +6 -24
- package/operations/entry/filtering/fullTextSearch.js.map +1 -1
- package/operations/entry/filtering/getValue.js +5 -27
- 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 -20
- package/operations/entry/filtering/index.js.map +1 -1
- package/operations/entry/filtering/mapPlugins.d.ts +2 -2
- package/operations/entry/filtering/mapPlugins.js +4 -18
- 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 +9 -20
- 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 +7 -16
- 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 +16 -39
- 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 +21 -36
- 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 +17 -34
- package/operations/entry/filtering/sort.js.map +1 -1
- package/operations/entry/filtering/systemFields.d.ts +2 -4
- package/operations/entry/filtering/systemFields.js +102 -43
- package/operations/entry/filtering/systemFields.js.map +1 -1
- package/operations/entry/filtering/transform.d.ts +1 -1
- package/operations/entry/filtering/transform.js +2 -10
- 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 +5 -17
- package/operations/entry/filtering/values.js.map +1 -1
- package/operations/entry/filtering/where.js +5 -15
- package/operations/entry/filtering/where.js.map +1 -1
- package/operations/entry/index.d.ts +3 -4
- package/operations/entry/index.js +732 -410
- package/operations/entry/index.js.map +1 -1
- package/operations/entry/keys.d.ts +40 -2
- package/operations/entry/keys.js +54 -47
- package/operations/entry/keys.js.map +1 -1
- package/operations/group/index.d.ts +4 -4
- package/operations/group/index.js +44 -91
- package/operations/group/index.js.map +1 -1
- package/operations/model/index.d.ts +3 -3
- package/operations/model/index.js +36 -70
- package/operations/model/index.js.map +1 -1
- package/package.json +22 -29
- package/plugins/CmsEntryFieldFilterPathPlugin.d.ts +4 -3
- package/plugins/CmsEntryFieldFilterPathPlugin.js +14 -29
- package/plugins/CmsEntryFieldFilterPathPlugin.js.map +1 -1
- package/plugins/CmsEntryFieldFilterPlugin.d.ts +10 -10
- package/plugins/CmsEntryFieldFilterPlugin.js +9 -19
- package/plugins/CmsEntryFieldFilterPlugin.js.map +1 -1
- package/plugins/CmsEntryFieldSortingPlugin.d.ts +2 -2
- package/plugins/CmsEntryFieldSortingPlugin.js +5 -24
- package/plugins/CmsEntryFieldSortingPlugin.js.map +1 -1
- package/plugins/CmsFieldFilterValueTransformPlugin.d.ts +11 -0
- package/plugins/CmsFieldFilterValueTransformPlugin.js +16 -0
- package/plugins/CmsFieldFilterValueTransformPlugin.js.map +1 -0
- package/plugins/index.d.ts +4 -3
- package/plugins/index.js +5 -43
- package/plugins/index.js.map +1 -1
- package/types.d.ts +24 -19
- package/types.js +5 -13
- package/types.js.map +1 -1
- package/definitions/settings.d.ts +0 -9
- package/definitions/settings.js +0 -58
- package/definitions/settings.js.map +0 -1
- package/definitions/system.d.ts +0 -9
- package/definitions/system.js +0 -46
- package/definitions/system.js.map +0 -1
- package/dynamoDb/storage/date.d.ts +0 -3
- package/dynamoDb/storage/date.js +0 -109
- package/dynamoDb/storage/date.js.map +0 -1
- package/operations/entry/systemFields.d.ts +0 -2
- package/operations/entry/systemFields.js +0 -74
- package/operations/entry/systemFields.js.map +0 -1
- package/operations/settings/index.d.ts +0 -7
- package/operations/settings/index.js +0 -135
- package/operations/settings/index.js.map +0 -1
- package/operations/system/index.d.ts +0 -7
- package/operations/system/index.js +0 -99
- package/operations/system/index.js.map +0 -1
|
@@ -1,50 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var _error = _interopRequireDefault(require("@webiny/error"));
|
|
13
|
-
|
|
14
|
-
var _dataLoaders = require("./dataLoaders");
|
|
15
|
-
|
|
16
|
-
var _types = require("@webiny/api-headless-cms/types");
|
|
17
|
-
|
|
18
|
-
var _keys = require("./keys");
|
|
19
|
-
|
|
20
|
-
var _batchWrite = require("@webiny/db-dynamodb/utils/batchWrite");
|
|
21
|
-
|
|
22
|
-
var _query = require("@webiny/db-dynamodb/utils/query");
|
|
23
|
-
|
|
24
|
-
var _cleanup = require("@webiny/db-dynamodb/utils/cleanup");
|
|
25
|
-
|
|
26
|
-
var _cursor = require("@webiny/utils/cursor");
|
|
27
|
-
|
|
28
|
-
var _zeroPad = require("@webiny/utils/zeroPad");
|
|
29
|
-
|
|
30
|
-
var _apiHeadlessCms = require("@webiny/api-headless-cms");
|
|
31
|
-
|
|
32
|
-
var _createFields = require("./filtering/createFields");
|
|
33
|
-
|
|
34
|
-
var _filtering = require("./filtering");
|
|
35
|
-
|
|
36
|
-
const createType = () => {
|
|
37
|
-
return "cms.entry";
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const createLatestType = () => {
|
|
41
|
-
return `${createType()}.l`;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const createPublishedType = () => {
|
|
45
|
-
return `${createType()}.p`;
|
|
46
|
-
};
|
|
47
|
-
|
|
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";
|
|
48
11
|
const convertToStorageEntry = params => {
|
|
49
12
|
const {
|
|
50
13
|
model,
|
|
@@ -54,11 +17,11 @@ const convertToStorageEntry = params => {
|
|
|
54
17
|
fields: model.fields,
|
|
55
18
|
values: storageEntry.values
|
|
56
19
|
});
|
|
57
|
-
return
|
|
20
|
+
return {
|
|
21
|
+
...storageEntry,
|
|
58
22
|
values
|
|
59
|
-
}
|
|
23
|
+
};
|
|
60
24
|
};
|
|
61
|
-
|
|
62
25
|
const convertFromStorageEntry = params => {
|
|
63
26
|
const {
|
|
64
27
|
model,
|
|
@@ -68,160 +31,179 @@ const convertFromStorageEntry = params => {
|
|
|
68
31
|
fields: model.fields,
|
|
69
32
|
values: storageEntry.values
|
|
70
33
|
});
|
|
71
|
-
return
|
|
34
|
+
return {
|
|
35
|
+
...storageEntry,
|
|
72
36
|
values
|
|
73
|
-
}
|
|
37
|
+
};
|
|
74
38
|
};
|
|
75
|
-
|
|
76
|
-
const createEntriesStorageOperations = params => {
|
|
39
|
+
const MAX_LIST_LIMIT = 1000000;
|
|
40
|
+
export const createEntriesStorageOperations = params => {
|
|
77
41
|
const {
|
|
78
42
|
entity,
|
|
79
43
|
plugins
|
|
80
44
|
} = params;
|
|
81
|
-
|
|
45
|
+
let storageOperationsCmsModelPlugin;
|
|
46
|
+
const getStorageOperationsCmsModelPlugin = () => {
|
|
47
|
+
if (storageOperationsCmsModelPlugin) {
|
|
48
|
+
return storageOperationsCmsModelPlugin;
|
|
49
|
+
}
|
|
50
|
+
storageOperationsCmsModelPlugin = plugins.oneByType(StorageOperationsCmsModelPlugin.type);
|
|
51
|
+
return storageOperationsCmsModelPlugin;
|
|
52
|
+
};
|
|
53
|
+
const getStorageOperationsModel = model => {
|
|
54
|
+
const plugin = getStorageOperationsCmsModelPlugin();
|
|
55
|
+
return plugin.getModel(model);
|
|
56
|
+
};
|
|
57
|
+
const dataLoaders = new DataLoadersHandler({
|
|
82
58
|
entity
|
|
83
59
|
});
|
|
84
|
-
const storageTransformPlugins = plugins.byType(_apiHeadlessCms.StorageTransformPlugin.type).reduce((collection, plugin) => {
|
|
85
|
-
collection[plugin.fieldType] = plugin;
|
|
86
|
-
return collection;
|
|
87
|
-
}, {});
|
|
88
|
-
|
|
89
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
|
+
}, {});
|
|
90
66
|
return (field, value) => {
|
|
91
|
-
const
|
|
92
|
-
|
|
67
|
+
const fieldType = getBaseFieldType(field);
|
|
68
|
+
const plugin = storageTransformPlugins[fieldType];
|
|
93
69
|
if (!plugin) {
|
|
94
70
|
return value;
|
|
95
71
|
}
|
|
96
|
-
|
|
97
72
|
return plugin.fromStorage({
|
|
98
73
|
model,
|
|
99
74
|
field,
|
|
100
75
|
value,
|
|
101
|
-
|
|
102
76
|
getStoragePlugin(fieldType) {
|
|
103
77
|
return storageTransformPlugins[fieldType] || storageTransformPlugins["*"];
|
|
104
78
|
},
|
|
105
|
-
|
|
106
79
|
plugins
|
|
107
80
|
});
|
|
108
81
|
};
|
|
109
82
|
};
|
|
110
|
-
|
|
111
|
-
const create = async (model, params) => {
|
|
83
|
+
const create = async (initialModel, params) => {
|
|
112
84
|
const {
|
|
113
85
|
entry,
|
|
114
86
|
storageEntry: initialStorageEntry
|
|
115
87
|
} = params;
|
|
116
|
-
const
|
|
117
|
-
id: entry.id,
|
|
118
|
-
locale: model.locale,
|
|
119
|
-
tenant: model.tenant
|
|
120
|
-
});
|
|
88
|
+
const model = getStorageOperationsModel(initialModel);
|
|
121
89
|
const isPublished = entry.status === "published";
|
|
122
90
|
const locked = isPublished ? true : entry.locked;
|
|
123
91
|
const storageEntry = convertToStorageEntry({
|
|
124
92
|
model,
|
|
125
93
|
storageEntry: initialStorageEntry
|
|
126
94
|
});
|
|
95
|
+
const storageEntryRevisionKeys = createEntryRevisionKeys(entry);
|
|
96
|
+
const storageEntryLatestKeys = createEntryLatestKeys(entry);
|
|
127
97
|
/**
|
|
128
98
|
* We need to:
|
|
129
99
|
* - create new main entry item
|
|
130
|
-
* - create new or update latest entry item
|
|
100
|
+
* - create new or update the latest entry item
|
|
131
101
|
*/
|
|
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
|
+
});
|
|
132
117
|
|
|
133
|
-
const items = [entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
|
|
134
|
-
locked,
|
|
135
|
-
PK: partitionKey,
|
|
136
|
-
SK: (0, _keys.createRevisionSortKey)(entry),
|
|
137
|
-
TYPE: createType(),
|
|
138
|
-
GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
|
|
139
|
-
GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
|
|
140
|
-
})), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
|
|
141
|
-
locked,
|
|
142
|
-
PK: partitionKey,
|
|
143
|
-
SK: (0, _keys.createLatestSortKey)(),
|
|
144
|
-
TYPE: createLatestType(),
|
|
145
|
-
GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
|
|
146
|
-
GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
|
|
147
|
-
}))];
|
|
148
118
|
/**
|
|
149
119
|
* We need to create published entry if
|
|
150
120
|
*/
|
|
151
|
-
|
|
152
121
|
if (isPublished) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
})
|
|
122
|
+
const storageEntryPublishedKeys = createEntryPublishedKeys(storageEntry);
|
|
123
|
+
entityBatch.put({
|
|
124
|
+
...storageEntryPublishedKeys,
|
|
125
|
+
data: {
|
|
126
|
+
...storageEntry,
|
|
127
|
+
locked
|
|
128
|
+
}
|
|
129
|
+
});
|
|
161
130
|
}
|
|
162
|
-
|
|
163
131
|
try {
|
|
164
|
-
await (
|
|
165
|
-
table: entity.table,
|
|
166
|
-
items
|
|
167
|
-
});
|
|
132
|
+
await entityBatch.execute();
|
|
168
133
|
dataLoaders.clearAll({
|
|
169
134
|
model
|
|
170
135
|
});
|
|
171
136
|
} catch (ex) {
|
|
172
|
-
throw new
|
|
137
|
+
throw new WebinyError(ex.message || "Could not insert data into the DynamoDB.", ex.code || "CREATE_ENTRY_ERROR", {
|
|
173
138
|
error: ex,
|
|
174
139
|
entry
|
|
175
140
|
});
|
|
176
141
|
}
|
|
177
|
-
|
|
178
142
|
return initialStorageEntry;
|
|
179
143
|
};
|
|
180
|
-
|
|
181
|
-
const createRevisionFrom = async (model, params) => {
|
|
144
|
+
const createRevisionFrom = async (initialModel, params) => {
|
|
182
145
|
const {
|
|
183
146
|
entry,
|
|
184
147
|
storageEntry: initialStorageEntry
|
|
185
148
|
} = params;
|
|
186
|
-
const
|
|
187
|
-
id: entry.id,
|
|
188
|
-
locale: model.locale,
|
|
189
|
-
tenant: model.tenant
|
|
190
|
-
});
|
|
149
|
+
const model = getStorageOperationsModel(initialModel);
|
|
191
150
|
const storageEntry = convertToStorageEntry({
|
|
192
151
|
storageEntry: initialStorageEntry,
|
|
193
152
|
model
|
|
194
153
|
});
|
|
154
|
+
|
|
195
155
|
/**
|
|
196
156
|
* We need to:
|
|
197
157
|
* - create the main entry item
|
|
198
|
-
* - 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)
|
|
199
162
|
*/
|
|
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
|
+
});
|
|
200
184
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
|
|
206
|
-
GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
|
|
207
|
-
})), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
|
|
208
|
-
PK: partitionKey,
|
|
209
|
-
SK: (0, _keys.createLatestSortKey)(),
|
|
210
|
-
TYPE: createLatestType(),
|
|
211
|
-
GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "L"),
|
|
212
|
-
GSI1_SK: (0, _keys.createGSISortKey)(storageEntry)
|
|
213
|
-
}))];
|
|
214
|
-
|
|
215
|
-
try {
|
|
216
|
-
await (0, _batchWrite.batchWriteAll)({
|
|
217
|
-
table: entity.table,
|
|
218
|
-
items
|
|
185
|
+
// Unpublish previously published revision (if any).
|
|
186
|
+
const [publishedRevisionStorageEntry] = await dataLoaders.getPublishedRevisionByEntryId({
|
|
187
|
+
model,
|
|
188
|
+
ids: [entry.id]
|
|
219
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();
|
|
220
202
|
dataLoaders.clearAll({
|
|
221
203
|
model
|
|
222
204
|
});
|
|
223
205
|
} catch (ex) {
|
|
224
|
-
throw new
|
|
206
|
+
throw new WebinyError(ex.message || "Could not create revision from given entry.", ex.code || "CREATE_REVISION_ERROR", {
|
|
225
207
|
error: ex,
|
|
226
208
|
entry,
|
|
227
209
|
storageEntry
|
|
@@ -230,24 +212,16 @@ const createEntriesStorageOperations = params => {
|
|
|
230
212
|
/**
|
|
231
213
|
* There are no modifications on the entry created so just return the data.
|
|
232
214
|
*/
|
|
233
|
-
|
|
234
|
-
|
|
235
215
|
return initialStorageEntry;
|
|
236
216
|
};
|
|
237
|
-
|
|
238
|
-
const update = async (model, params) => {
|
|
217
|
+
const update = async (initialModel, params) => {
|
|
239
218
|
const {
|
|
240
219
|
entry,
|
|
241
220
|
storageEntry: initialStorageEntry
|
|
242
221
|
} = params;
|
|
243
|
-
const
|
|
244
|
-
id: entry.id,
|
|
245
|
-
locale: model.locale,
|
|
246
|
-
tenant: model.tenant
|
|
247
|
-
});
|
|
222
|
+
const model = getStorageOperationsModel(initialModel);
|
|
248
223
|
const isPublished = entry.status === "published";
|
|
249
224
|
const locked = isPublished ? true : entry.locked;
|
|
250
|
-
const items = [];
|
|
251
225
|
const storageEntry = convertToStorageEntry({
|
|
252
226
|
model,
|
|
253
227
|
storageEntry: initialStorageEntry
|
|
@@ -258,221 +232,477 @@ const createEntriesStorageOperations = params => {
|
|
|
258
232
|
* - update the latest entry if the current entry is the latest one
|
|
259
233
|
*/
|
|
260
234
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
235
|
+
const entityBatch = entity.createEntityWriter({
|
|
236
|
+
put: [{
|
|
237
|
+
...createEntryRevisionKeys(storageEntry),
|
|
238
|
+
data: {
|
|
239
|
+
...storageEntry,
|
|
240
|
+
locked
|
|
241
|
+
}
|
|
242
|
+
}]
|
|
243
|
+
});
|
|
270
244
|
if (isPublished) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
})));
|
|
245
|
+
entityBatch.put({
|
|
246
|
+
...createEntryPublishedKeys(storageEntry),
|
|
247
|
+
data: {
|
|
248
|
+
...storageEntry,
|
|
249
|
+
locked
|
|
250
|
+
}
|
|
251
|
+
});
|
|
279
252
|
}
|
|
253
|
+
|
|
280
254
|
/**
|
|
281
|
-
* We need the latest entry to update it as well if
|
|
255
|
+
* We need the latest entry to update it as well if necessary.
|
|
282
256
|
*/
|
|
283
|
-
|
|
284
|
-
|
|
285
257
|
const latestStorageEntry = await getLatestRevisionByEntryId(model, entry);
|
|
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);
|
|
286
274
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
+
}
|
|
296
295
|
}
|
|
297
|
-
|
|
298
296
|
try {
|
|
299
|
-
await (
|
|
300
|
-
table: entity.table,
|
|
301
|
-
items
|
|
302
|
-
});
|
|
297
|
+
await entityBatch.execute();
|
|
303
298
|
dataLoaders.clearAll({
|
|
304
299
|
model
|
|
305
300
|
});
|
|
306
301
|
return initialStorageEntry;
|
|
307
302
|
} catch (ex) {
|
|
308
|
-
throw new
|
|
303
|
+
throw new WebinyError(ex.message || "Could not update entry.", ex.code || "UPDATE_ERROR", {
|
|
309
304
|
error: ex,
|
|
310
305
|
entry,
|
|
311
306
|
latestStorageEntry
|
|
312
307
|
});
|
|
313
308
|
}
|
|
314
309
|
};
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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,
|
|
327
326
|
options: {
|
|
328
327
|
gte: " "
|
|
329
328
|
}
|
|
330
|
-
};
|
|
331
|
-
|
|
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
|
+
});
|
|
332
347
|
|
|
348
|
+
/**
|
|
349
|
+
* And finally write it...
|
|
350
|
+
*/
|
|
333
351
|
try {
|
|
334
|
-
|
|
352
|
+
await entityBatch.execute();
|
|
335
353
|
} catch (ex) {
|
|
336
|
-
throw
|
|
337
|
-
|
|
338
|
-
|
|
354
|
+
throw WebinyError.from(ex, {
|
|
355
|
+
message: "Could not move records to a new folder.",
|
|
356
|
+
data: {
|
|
357
|
+
id,
|
|
358
|
+
folderId
|
|
359
|
+
}
|
|
339
360
|
});
|
|
340
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
|
+
*/
|
|
341
373
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
|
346
389
|
});
|
|
390
|
+
}
|
|
391
|
+
if (records.length === 0) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const storageEntry = convertToStorageEntry({
|
|
395
|
+
model,
|
|
396
|
+
storageEntry: initialStorageEntry
|
|
347
397
|
});
|
|
348
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
|
+
*/
|
|
349
424
|
try {
|
|
350
|
-
await (
|
|
351
|
-
|
|
352
|
-
|
|
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
|
|
353
431
|
});
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const deleteEntry = async (initialModel, params) => {
|
|
435
|
+
const {
|
|
436
|
+
entry
|
|
437
|
+
} = params;
|
|
438
|
+
const id = entry.id || entry.entryId;
|
|
439
|
+
const model = getStorageOperationsModel(initialModel);
|
|
440
|
+
const partitionKey = createPartitionKey({
|
|
441
|
+
id,
|
|
442
|
+
tenant: model.tenant
|
|
443
|
+
});
|
|
444
|
+
let records = [];
|
|
445
|
+
try {
|
|
446
|
+
records = await entity.queryAll({
|
|
447
|
+
partitionKey,
|
|
448
|
+
options: {
|
|
449
|
+
gte: " "
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
} catch (ex) {
|
|
453
|
+
throw new WebinyError(ex.message || "Could not load all records.", ex.code || "LOAD_ALL_RECORDS_ERROR", {
|
|
454
|
+
error: ex,
|
|
455
|
+
id
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
const entityBatch = entity.createEntityWriter({
|
|
459
|
+
delete: records.map(item => {
|
|
460
|
+
return {
|
|
461
|
+
PK: item.PK,
|
|
462
|
+
SK: item.SK
|
|
463
|
+
};
|
|
464
|
+
})
|
|
465
|
+
});
|
|
466
|
+
try {
|
|
467
|
+
await entityBatch.execute();
|
|
354
468
|
dataLoaders.clearAll({
|
|
355
469
|
model
|
|
356
470
|
});
|
|
357
471
|
} catch (ex) {
|
|
358
|
-
throw new
|
|
472
|
+
throw new WebinyError(ex.message || "Could not delete the entry.", ex.code || "DELETE_ENTRY_ERROR", {
|
|
359
473
|
error: ex,
|
|
360
|
-
partitionKey
|
|
361
|
-
|
|
474
|
+
partitionKey,
|
|
475
|
+
id
|
|
362
476
|
});
|
|
363
477
|
}
|
|
364
478
|
};
|
|
479
|
+
const restoreFromBin = async (initialModel, params) => {
|
|
480
|
+
const {
|
|
481
|
+
entry,
|
|
482
|
+
storageEntry: initialStorageEntry
|
|
483
|
+
} = params;
|
|
484
|
+
const model = getStorageOperationsModel(initialModel);
|
|
365
485
|
|
|
366
|
-
|
|
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
|
+
};
|
|
550
|
+
const deleteRevision = async (initialModel, params) => {
|
|
367
551
|
const {
|
|
368
552
|
entry,
|
|
369
553
|
latestEntry,
|
|
370
554
|
latestStorageEntry: initialLatestStorageEntry
|
|
371
555
|
} = params;
|
|
372
|
-
const
|
|
556
|
+
const model = getStorageOperationsModel(initialModel);
|
|
557
|
+
const partitionKey = createPartitionKey({
|
|
373
558
|
id: entry.id,
|
|
374
|
-
locale: model.locale,
|
|
375
559
|
tenant: model.tenant
|
|
376
560
|
});
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
561
|
+
const entityBatch = entity.createEntityWriter({
|
|
562
|
+
delete: [{
|
|
563
|
+
PK: partitionKey,
|
|
564
|
+
SK: createRevisionSortKey(entry)
|
|
565
|
+
}]
|
|
566
|
+
});
|
|
381
567
|
const publishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
|
|
568
|
+
|
|
382
569
|
/**
|
|
383
570
|
* If revision we are deleting is the published one as well, we need to delete those records as well.
|
|
384
571
|
*/
|
|
385
|
-
|
|
386
572
|
if (publishedStorageEntry && entry.id === publishedStorageEntry.id) {
|
|
387
|
-
|
|
573
|
+
entityBatch.delete({
|
|
388
574
|
PK: partitionKey,
|
|
389
|
-
SK:
|
|
390
|
-
})
|
|
575
|
+
SK: createPublishedSortKey()
|
|
576
|
+
});
|
|
391
577
|
}
|
|
392
|
-
|
|
393
578
|
if (initialLatestStorageEntry) {
|
|
394
579
|
const latestStorageEntry = convertToStorageEntry({
|
|
395
580
|
storageEntry: initialLatestStorageEntry,
|
|
396
581
|
model
|
|
397
582
|
});
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
})));
|
|
405
|
-
}
|
|
583
|
+
entityBatch.put({
|
|
584
|
+
...createEntryLatestKeys(latestStorageEntry),
|
|
585
|
+
data: {
|
|
586
|
+
...latestStorageEntry
|
|
587
|
+
}
|
|
588
|
+
});
|
|
406
589
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
+
}
|
|
411
597
|
});
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
await entityBatch.execute();
|
|
412
601
|
dataLoaders.clearAll({
|
|
413
602
|
model
|
|
414
603
|
});
|
|
415
604
|
} catch (ex) {
|
|
416
|
-
throw new
|
|
605
|
+
throw new WebinyError(ex.message, ex.code, {
|
|
417
606
|
error: ex,
|
|
418
607
|
entry,
|
|
419
608
|
latestEntry
|
|
420
609
|
});
|
|
421
610
|
}
|
|
422
611
|
};
|
|
612
|
+
const deleteMultipleEntries = async (initialModel, params) => {
|
|
613
|
+
const {
|
|
614
|
+
entries
|
|
615
|
+
} = params;
|
|
616
|
+
const model = getStorageOperationsModel(initialModel);
|
|
617
|
+
/**
|
|
618
|
+
* First we need all the revisions of the entries we want to delete.
|
|
619
|
+
*/
|
|
620
|
+
const revisions = await dataLoaders.getAllEntryRevisions({
|
|
621
|
+
model,
|
|
622
|
+
ids: entries
|
|
623
|
+
});
|
|
624
|
+
/**
|
|
625
|
+
* Then we need to construct the queries for all the revisions and entries.
|
|
626
|
+
*/
|
|
423
627
|
|
|
424
|
-
|
|
628
|
+
const entityBatch = entity.createEntityWriter();
|
|
629
|
+
for (const id of entries) {
|
|
630
|
+
const partitionKey = createPartitionKey({
|
|
631
|
+
id,
|
|
632
|
+
tenant: model.tenant
|
|
633
|
+
});
|
|
634
|
+
entityBatch.delete({
|
|
635
|
+
PK: partitionKey,
|
|
636
|
+
SK: "L"
|
|
637
|
+
});
|
|
638
|
+
entityBatch.delete({
|
|
639
|
+
PK: partitionKey,
|
|
640
|
+
SK: "P"
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Exact revisions of all the entries
|
|
645
|
+
*/
|
|
646
|
+
for (const revision of revisions) {
|
|
647
|
+
entityBatch.delete({
|
|
648
|
+
PK: createPartitionKey({
|
|
649
|
+
id: revision.id,
|
|
650
|
+
tenant: model.tenant
|
|
651
|
+
}),
|
|
652
|
+
SK: createRevisionSortKey({
|
|
653
|
+
version: revision.version
|
|
654
|
+
})
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
await entityBatch.execute();
|
|
658
|
+
};
|
|
659
|
+
const getLatestRevisionByEntryId = async (initialModel, params) => {
|
|
660
|
+
const model = getStorageOperationsModel(initialModel);
|
|
425
661
|
const items = await dataLoaders.getLatestRevisionByEntryId({
|
|
426
662
|
model,
|
|
427
663
|
ids: [params.id]
|
|
428
664
|
});
|
|
429
665
|
const item = items.shift() || null;
|
|
430
|
-
|
|
431
666
|
if (!item) {
|
|
432
667
|
return null;
|
|
433
668
|
}
|
|
434
|
-
|
|
435
669
|
return convertFromStorageEntry({
|
|
436
670
|
storageEntry: item,
|
|
437
671
|
model
|
|
438
672
|
});
|
|
439
673
|
};
|
|
440
|
-
|
|
441
|
-
|
|
674
|
+
const getPublishedRevisionByEntryId = async (initialModel, params) => {
|
|
675
|
+
const model = getStorageOperationsModel(initialModel);
|
|
442
676
|
const items = await dataLoaders.getPublishedRevisionByEntryId({
|
|
443
677
|
model,
|
|
444
678
|
ids: [params.id]
|
|
445
679
|
});
|
|
446
680
|
const item = items.shift() || null;
|
|
447
|
-
|
|
448
681
|
if (!item) {
|
|
449
682
|
return null;
|
|
450
683
|
}
|
|
451
|
-
|
|
452
684
|
return convertFromStorageEntry({
|
|
453
685
|
storageEntry: item,
|
|
454
686
|
model
|
|
455
687
|
});
|
|
456
688
|
};
|
|
457
|
-
|
|
458
|
-
|
|
689
|
+
const getRevisionById = async (initialModel, params) => {
|
|
690
|
+
const model = getStorageOperationsModel(initialModel);
|
|
459
691
|
const items = await dataLoaders.getRevisionById({
|
|
460
692
|
model,
|
|
461
693
|
ids: [params.id]
|
|
462
694
|
});
|
|
463
695
|
const item = items.shift() || null;
|
|
464
|
-
|
|
465
696
|
if (!item) {
|
|
466
697
|
return null;
|
|
467
698
|
}
|
|
468
|
-
|
|
469
699
|
return convertFromStorageEntry({
|
|
470
700
|
storageEntry: item,
|
|
471
701
|
model
|
|
472
702
|
});
|
|
473
703
|
};
|
|
474
|
-
|
|
475
|
-
|
|
704
|
+
const getRevisions = async (initialModel, params) => {
|
|
705
|
+
const model = getStorageOperationsModel(initialModel);
|
|
476
706
|
const items = await dataLoaders.getAllEntryRevisions({
|
|
477
707
|
model,
|
|
478
708
|
ids: [params.id]
|
|
@@ -484,8 +714,8 @@ const createEntriesStorageOperations = params => {
|
|
|
484
714
|
});
|
|
485
715
|
});
|
|
486
716
|
};
|
|
487
|
-
|
|
488
|
-
|
|
717
|
+
const getByIds = async (initialModel, params) => {
|
|
718
|
+
const model = getStorageOperationsModel(initialModel);
|
|
489
719
|
const items = await dataLoaders.getRevisionById({
|
|
490
720
|
model,
|
|
491
721
|
ids: params.ids
|
|
@@ -497,8 +727,8 @@ const createEntriesStorageOperations = params => {
|
|
|
497
727
|
});
|
|
498
728
|
});
|
|
499
729
|
};
|
|
500
|
-
|
|
501
|
-
|
|
730
|
+
const getLatestByIds = async (initialModel, params) => {
|
|
731
|
+
const model = getStorageOperationsModel(initialModel);
|
|
502
732
|
const items = await dataLoaders.getLatestRevisionByEntryId({
|
|
503
733
|
model,
|
|
504
734
|
ids: params.ids
|
|
@@ -510,8 +740,8 @@ const createEntriesStorageOperations = params => {
|
|
|
510
740
|
});
|
|
511
741
|
});
|
|
512
742
|
};
|
|
513
|
-
|
|
514
|
-
|
|
743
|
+
const getPublishedByIds = async (initialModel, params) => {
|
|
744
|
+
const model = getStorageOperationsModel(initialModel);
|
|
515
745
|
const items = await dataLoaders.getPublishedRevisionByEntryId({
|
|
516
746
|
model,
|
|
517
747
|
ids: params.ids
|
|
@@ -523,59 +753,46 @@ const createEntriesStorageOperations = params => {
|
|
|
523
753
|
});
|
|
524
754
|
});
|
|
525
755
|
};
|
|
526
|
-
|
|
527
|
-
|
|
756
|
+
const getPreviousRevision = async (initialModel, params) => {
|
|
757
|
+
const model = getStorageOperationsModel(initialModel);
|
|
528
758
|
const {
|
|
529
759
|
entryId,
|
|
530
760
|
version
|
|
531
761
|
} = params;
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
}),
|
|
762
|
+
const partitionKey = createPartitionKey({
|
|
763
|
+
tenant: model.tenant,
|
|
764
|
+
id: entryId
|
|
765
|
+
});
|
|
766
|
+
const unfilteredRevisions = await entity.queryAll({
|
|
767
|
+
partitionKey,
|
|
539
768
|
options: {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* We need to have extra checks because DynamoDB will return published or latest record if there is no REV# record.
|
|
544
|
-
*/
|
|
545
|
-
filters: [{
|
|
546
|
-
attr: "TYPE",
|
|
547
|
-
eq: createType()
|
|
548
|
-
}, {
|
|
549
|
-
attr: "version",
|
|
550
|
-
lt: version
|
|
551
|
-
}],
|
|
769
|
+
beginsWith: `REV#`,
|
|
552
770
|
reverse: true
|
|
553
771
|
}
|
|
554
|
-
};
|
|
555
|
-
|
|
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
|
+
}
|
|
556
780
|
try {
|
|
557
|
-
const result = await (0, _query.queryOne)(queryParams);
|
|
558
|
-
const storageEntry = (0, _cleanup.cleanupItem)(entity, result);
|
|
559
|
-
|
|
560
|
-
if (!storageEntry) {
|
|
561
|
-
return null;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
781
|
return convertFromStorageEntry({
|
|
565
|
-
storageEntry,
|
|
782
|
+
storageEntry: storageEntry.data,
|
|
566
783
|
model
|
|
567
784
|
});
|
|
568
785
|
} catch (ex) {
|
|
569
|
-
throw new
|
|
786
|
+
throw new WebinyError(ex.message || "Could not get previous version of given entry.", ex.code || "GET_PREVIOUS_VERSION_ERROR", {
|
|
787
|
+
...params,
|
|
570
788
|
error: ex,
|
|
571
|
-
partitionKey
|
|
572
|
-
options: queryParams.options,
|
|
789
|
+
partitionKey,
|
|
573
790
|
model
|
|
574
|
-
})
|
|
791
|
+
});
|
|
575
792
|
}
|
|
576
793
|
};
|
|
577
|
-
|
|
578
|
-
|
|
794
|
+
const list = async (initialModel, params) => {
|
|
795
|
+
const model = getStorageOperationsModel(initialModel);
|
|
579
796
|
const {
|
|
580
797
|
limit: initialLimit = 10,
|
|
581
798
|
where: initialWhere,
|
|
@@ -584,28 +801,26 @@ const createEntriesStorageOperations = params => {
|
|
|
584
801
|
fields,
|
|
585
802
|
search
|
|
586
803
|
} = params;
|
|
587
|
-
const limit = initialLimit <= 0 || initialLimit >=
|
|
804
|
+
const limit = initialLimit <= 0 || initialLimit >= MAX_LIST_LIMIT ? MAX_LIST_LIMIT : initialLimit;
|
|
588
805
|
const type = initialWhere.published ? "P" : "L";
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
index: "GSI1",
|
|
594
|
-
gte: " "
|
|
595
|
-
}
|
|
806
|
+
const partitionKey = createGSIPartitionKey(model, type);
|
|
807
|
+
const options = {
|
|
808
|
+
index: "GSI1",
|
|
809
|
+
gte: " "
|
|
596
810
|
};
|
|
597
811
|
let storageEntries = [];
|
|
598
|
-
|
|
599
812
|
try {
|
|
600
|
-
storageEntries = await
|
|
813
|
+
storageEntries = await entity.queryAll({
|
|
814
|
+
partitionKey,
|
|
815
|
+
options
|
|
816
|
+
});
|
|
601
817
|
} catch (ex) {
|
|
602
|
-
throw new
|
|
818
|
+
throw new WebinyError(ex.message, "QUERY_ENTRIES_ERROR", {
|
|
603
819
|
error: ex,
|
|
604
|
-
partitionKey
|
|
605
|
-
options
|
|
820
|
+
partitionKey,
|
|
821
|
+
options
|
|
606
822
|
});
|
|
607
823
|
}
|
|
608
|
-
|
|
609
824
|
if (storageEntries.length === 0) {
|
|
610
825
|
return {
|
|
611
826
|
hasMoreItems: false,
|
|
@@ -614,16 +829,16 @@ const createEntriesStorageOperations = params => {
|
|
|
614
829
|
items: []
|
|
615
830
|
};
|
|
616
831
|
}
|
|
617
|
-
|
|
618
|
-
|
|
832
|
+
const where = {
|
|
833
|
+
...initialWhere
|
|
834
|
+
};
|
|
619
835
|
delete where["published"];
|
|
620
836
|
delete where["latest"];
|
|
621
837
|
/**
|
|
622
838
|
* We need an object containing field, transformers and paths.
|
|
623
839
|
* Just build it here and pass on into other methods that require it to avoid mapping multiple times.
|
|
624
840
|
*/
|
|
625
|
-
|
|
626
|
-
const modelFields = (0, _createFields.createFields)({
|
|
841
|
+
const modelFields = createFields({
|
|
627
842
|
plugins,
|
|
628
843
|
fields: model.fields
|
|
629
844
|
});
|
|
@@ -633,25 +848,21 @@ const createEntriesStorageOperations = params => {
|
|
|
633
848
|
*
|
|
634
849
|
* This is always being done, but at least its in parallel.
|
|
635
850
|
*/
|
|
636
|
-
|
|
637
851
|
const records = await Promise.all(storageEntries.map(async storageEntry => {
|
|
638
852
|
const entry = convertFromStorageEntry({
|
|
639
|
-
storageEntry,
|
|
853
|
+
storageEntry: storageEntry.data,
|
|
640
854
|
model
|
|
641
855
|
});
|
|
642
|
-
|
|
643
856
|
for (const field of model.fields) {
|
|
644
857
|
entry.values[field.fieldId] = await fromStorage(field, entry.values[field.fieldId]);
|
|
645
858
|
}
|
|
646
|
-
|
|
647
859
|
return entry;
|
|
648
860
|
}));
|
|
649
861
|
/**
|
|
650
862
|
* Filter the read items via the code.
|
|
651
863
|
* It will build the filters out of the where input and transform the values it is using.
|
|
652
864
|
*/
|
|
653
|
-
|
|
654
|
-
const filteredItems = (0, _filtering.filter)({
|
|
865
|
+
const filteredItems = filter({
|
|
655
866
|
items: records,
|
|
656
867
|
where,
|
|
657
868
|
plugins,
|
|
@@ -662,19 +873,19 @@ const createEntriesStorageOperations = params => {
|
|
|
662
873
|
}
|
|
663
874
|
});
|
|
664
875
|
const totalCount = filteredItems.length;
|
|
876
|
+
|
|
665
877
|
/**
|
|
666
878
|
* Sorting is also done via the code.
|
|
667
879
|
* It takes the sort input and sorts by it via the lodash sortBy method.
|
|
668
880
|
*/
|
|
669
|
-
|
|
670
|
-
const sortedItems = (0, _filtering.sort)({
|
|
881
|
+
const sortedItems = sort({
|
|
671
882
|
model,
|
|
672
883
|
plugins,
|
|
673
884
|
items: filteredItems,
|
|
674
885
|
sort: sortBy,
|
|
675
886
|
fields: modelFields
|
|
676
887
|
});
|
|
677
|
-
const start = parseInt(
|
|
888
|
+
const start = parseInt(decodeCursor(after) || "0") || 0;
|
|
678
889
|
const hasMoreItems = totalCount > start + limit;
|
|
679
890
|
const end = limit > totalCount + start + limit ? undefined : start + limit;
|
|
680
891
|
const slicedItems = sortedItems.slice(start, end);
|
|
@@ -682,118 +893,163 @@ const createEntriesStorageOperations = params => {
|
|
|
682
893
|
* Although we do not need a cursor here, we will use it as such to keep it standardized.
|
|
683
894
|
* Number is simply encoded.
|
|
684
895
|
*/
|
|
685
|
-
|
|
686
|
-
const cursor = totalCount > start + limit ? (0, _cursor.encodeCursor)(`${start + limit}`) : null;
|
|
896
|
+
const cursor = encodeCursor(`${start + limit}`);
|
|
687
897
|
return {
|
|
688
898
|
hasMoreItems,
|
|
689
899
|
totalCount,
|
|
690
900
|
cursor,
|
|
691
|
-
items:
|
|
901
|
+
items: slicedItems
|
|
692
902
|
};
|
|
693
903
|
};
|
|
694
|
-
|
|
695
|
-
|
|
904
|
+
const get = async (initialModel, params) => {
|
|
905
|
+
const model = getStorageOperationsModel(initialModel);
|
|
696
906
|
const {
|
|
697
907
|
items
|
|
698
|
-
} = await list(model,
|
|
908
|
+
} = await list(model, {
|
|
909
|
+
...params,
|
|
699
910
|
limit: 1
|
|
700
|
-
})
|
|
911
|
+
});
|
|
701
912
|
return items.shift() || null;
|
|
702
913
|
};
|
|
703
|
-
|
|
704
|
-
const publish = async (model, params) => {
|
|
914
|
+
const publish = async (initialModel, params) => {
|
|
705
915
|
const {
|
|
706
916
|
entry,
|
|
707
917
|
storageEntry: initialStorageEntry
|
|
708
918
|
} = params;
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
locale: model.locale,
|
|
712
|
-
tenant: model.tenant
|
|
713
|
-
});
|
|
919
|
+
const model = getStorageOperationsModel(initialModel);
|
|
920
|
+
|
|
714
921
|
/**
|
|
715
|
-
* We need the latest and published entries to see if something needs to be updated
|
|
922
|
+
* We need the latest and published entries to see if something needs to be updated alongside the publishing one.
|
|
716
923
|
*/
|
|
717
|
-
|
|
718
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
|
+
}
|
|
719
930
|
const initialPublishedStorageEntry = await getPublishedRevisionByEntryId(model, entry);
|
|
720
931
|
const storageEntry = convertToStorageEntry({
|
|
721
932
|
model,
|
|
722
933
|
storageEntry: initialStorageEntry
|
|
723
934
|
});
|
|
724
|
-
/**
|
|
725
|
-
* We need to update:
|
|
726
|
-
* - current entry revision sort key
|
|
727
|
-
* - published sort key
|
|
728
|
-
* - latest sort key - if entry updated is actually latest
|
|
729
|
-
* - previous published entry to unpublished status - if any previously published entry
|
|
730
|
-
*/
|
|
731
935
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
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
|
+
});
|
|
745
950
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
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
|
+
});
|
|
755
963
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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,
|
|
759
985
|
model
|
|
760
986
|
});
|
|
761
|
-
items.push(entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, publishedStorageEntry), {}, {
|
|
762
|
-
PK: partitionKey,
|
|
763
|
-
SK: (0, _keys.createRevisionSortKey)(publishedStorageEntry),
|
|
764
|
-
TYPE: createType(),
|
|
765
|
-
status: _types.CONTENT_ENTRY_STATUS.UNPUBLISHED,
|
|
766
|
-
GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
|
|
767
|
-
GSI1_SK: (0, _keys.createGSISortKey)(publishedStorageEntry)
|
|
768
|
-
})));
|
|
769
|
-
}
|
|
770
987
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
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
|
+
}
|
|
775
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
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
try {
|
|
1032
|
+
await entityBatch.execute();
|
|
776
1033
|
dataLoaders.clearAll({
|
|
777
1034
|
model
|
|
778
1035
|
});
|
|
779
1036
|
return initialStorageEntry;
|
|
780
1037
|
} catch (ex) {
|
|
781
|
-
throw new
|
|
1038
|
+
throw new WebinyError(ex.message || "Could not execute the publishing batch.", ex.code || "PUBLISH_ERROR", {
|
|
782
1039
|
entry,
|
|
783
1040
|
latestStorageEntry: initialLatestStorageEntry,
|
|
784
1041
|
publishedStorageEntry: initialPublishedStorageEntry
|
|
785
1042
|
});
|
|
786
1043
|
}
|
|
787
1044
|
};
|
|
788
|
-
|
|
789
|
-
const unpublish = async (model, params) => {
|
|
1045
|
+
const unpublish = async (initialModel, params) => {
|
|
790
1046
|
const {
|
|
791
1047
|
entry,
|
|
792
1048
|
storageEntry: initialStorageEntry
|
|
793
1049
|
} = params;
|
|
794
|
-
const
|
|
1050
|
+
const model = getStorageOperationsModel(initialModel);
|
|
1051
|
+
const partitionKey = createPartitionKey({
|
|
795
1052
|
id: entry.id,
|
|
796
|
-
locale: model.locale,
|
|
797
1053
|
tenant: model.tenant
|
|
798
1054
|
});
|
|
799
1055
|
const storageEntry = convertToStorageEntry({
|
|
@@ -804,58 +1060,122 @@ const createEntriesStorageOperations = params => {
|
|
|
804
1060
|
* We need to:
|
|
805
1061
|
* - delete currently published entry
|
|
806
1062
|
* - update current entry revision with new data
|
|
807
|
-
* - update latest entry status - if entry being unpublished is latest
|
|
1063
|
+
* - update the latest entry status - if entry being unpublished is latest
|
|
808
1064
|
*/
|
|
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
|
+
});
|
|
809
1077
|
|
|
810
|
-
const items = [entity.deleteBatch({
|
|
811
|
-
PK: partitionKey,
|
|
812
|
-
SK: (0, _keys.createPublishedSortKey)()
|
|
813
|
-
}), entity.putBatch((0, _objectSpread2.default)((0, _objectSpread2.default)({}, storageEntry), {}, {
|
|
814
|
-
PK: partitionKey,
|
|
815
|
-
SK: (0, _keys.createRevisionSortKey)(entry),
|
|
816
|
-
TYPE: createType(),
|
|
817
|
-
GSI1_PK: (0, _keys.createGSIPartitionKey)(model, "A"),
|
|
818
|
-
GSI1_SK: (0, _keys.createGSISortKey)(entry)
|
|
819
|
-
}))];
|
|
820
1078
|
/**
|
|
821
|
-
* We need the latest entry to see if something needs to be updated
|
|
1079
|
+
* We need the latest entry to see if something needs to be updated alongside the unpublishing one.
|
|
822
1080
|
*/
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
}
|
|
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
|
+
}
|
|
834
1119
|
}
|
|
835
|
-
|
|
836
1120
|
try {
|
|
837
|
-
await (
|
|
838
|
-
table: entity.table,
|
|
839
|
-
items
|
|
840
|
-
});
|
|
1121
|
+
await entityBatch.execute();
|
|
841
1122
|
dataLoaders.clearAll({
|
|
842
1123
|
model
|
|
843
1124
|
});
|
|
844
1125
|
return initialStorageEntry;
|
|
845
1126
|
} catch (ex) {
|
|
846
|
-
throw new
|
|
1127
|
+
throw new WebinyError(ex.message || "Could not execute unpublish batch.", ex.code || "UNPUBLISH_ERROR", {
|
|
847
1128
|
entry,
|
|
848
1129
|
storageEntry
|
|
849
1130
|
});
|
|
850
1131
|
}
|
|
851
1132
|
};
|
|
852
|
-
|
|
1133
|
+
const getUniqueFieldValues = async (model, params) => {
|
|
1134
|
+
const {
|
|
1135
|
+
where,
|
|
1136
|
+
fieldId
|
|
1137
|
+
} = params;
|
|
1138
|
+
const field = model.fields.find(f => f.fieldId === fieldId);
|
|
1139
|
+
if (!field) {
|
|
1140
|
+
throw new WebinyError(`Could not find field with given "fieldId" value.`, "FIELD_NOT_FOUND", {
|
|
1141
|
+
fieldId
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
const {
|
|
1145
|
+
items
|
|
1146
|
+
} = await list(model, {
|
|
1147
|
+
where,
|
|
1148
|
+
limit: MAX_LIST_LIMIT
|
|
1149
|
+
});
|
|
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);
|
|
1168
|
+
};
|
|
853
1169
|
return {
|
|
854
1170
|
create,
|
|
855
1171
|
createRevisionFrom,
|
|
856
1172
|
update,
|
|
1173
|
+
move,
|
|
857
1174
|
delete: deleteEntry,
|
|
1175
|
+
moveToBin,
|
|
1176
|
+
restoreFromBin,
|
|
858
1177
|
deleteRevision,
|
|
1178
|
+
deleteMultipleEntries,
|
|
859
1179
|
getPreviousRevision,
|
|
860
1180
|
getPublishedByIds,
|
|
861
1181
|
getLatestByIds,
|
|
@@ -867,8 +1187,10 @@ const createEntriesStorageOperations = params => {
|
|
|
867
1187
|
getRevisions,
|
|
868
1188
|
publish,
|
|
869
1189
|
list,
|
|
870
|
-
unpublish
|
|
1190
|
+
unpublish,
|
|
1191
|
+
dataLoaders,
|
|
1192
|
+
getUniqueFieldValues
|
|
871
1193
|
};
|
|
872
1194
|
};
|
|
873
1195
|
|
|
874
|
-
|
|
1196
|
+
//# sourceMappingURL=index.js.map
|