@adobe/spacecat-shared-data-access 1.59.2 → 1.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +2 -2
  3. package/src/models/site/config.js +1 -1
  4. package/src/service/audits/accessPatterns.js +7 -7
  5. package/src/service/experiments/accessPatterns.js +2 -2
  6. package/src/service/import-job/accessPatterns.js +1 -1
  7. package/src/service/import-url/accessPatterns.js +2 -2
  8. package/src/service/index.js +10 -18
  9. package/src/service/key-events/accessPatterns.js +3 -3
  10. package/src/service/organizations/accessPatterns.js +3 -3
  11. package/src/service/site-candidates/accessPatterns.js +1 -1
  12. package/src/service/sites/accessPatterns.js +11 -11
  13. package/src/v2/models/api-key/api-key.collection.js +26 -0
  14. package/src/v2/models/api-key/api-key.model.js +59 -0
  15. package/src/v2/models/api-key/api-key.schema.js +82 -0
  16. package/src/v2/models/api-key/index.d.ts +37 -0
  17. package/src/v2/models/api-key/index.js +19 -0
  18. package/src/v2/models/audit/audit.collection.js +26 -0
  19. package/src/v2/models/audit/audit.model.js +89 -0
  20. package/src/v2/models/audit/audit.schema.js +66 -0
  21. package/src/v2/models/audit/index.d.ts +40 -0
  22. package/src/v2/models/audit/index.js +19 -0
  23. package/src/v2/models/base/base.collection.js +450 -0
  24. package/src/v2/models/{base.model.js → base/base.model.js} +109 -89
  25. package/src/v2/models/base/constants.js +17 -0
  26. package/src/v2/models/base/entity.registry.js +137 -0
  27. package/src/v2/models/base/index.d.ts +83 -0
  28. package/src/v2/models/base/index.js +27 -0
  29. package/src/v2/models/base/reference.js +159 -0
  30. package/src/v2/models/base/schema.builder.js +420 -0
  31. package/src/v2/models/base/schema.js +283 -0
  32. package/src/v2/models/configuration/configuration.collection.js +39 -0
  33. package/src/v2/models/configuration/configuration.model.js +160 -0
  34. package/src/v2/models/configuration/configuration.schema.js +103 -0
  35. package/src/v2/models/configuration/index.d.ts +111 -0
  36. package/src/v2/models/configuration/index.js +19 -0
  37. package/src/v2/models/experiment/experiment.collection.js +26 -0
  38. package/src/v2/models/experiment/experiment.model.js +28 -0
  39. package/src/v2/models/experiment/experiment.schema.js +70 -0
  40. package/src/v2/models/experiment/index.d.ts +49 -0
  41. package/src/v2/models/experiment/index.js +19 -0
  42. package/src/v2/models/import-job/import-job.collection.js +45 -0
  43. package/src/v2/models/import-job/import-job.model.js +55 -0
  44. package/src/v2/models/import-job/import-job.schema.js +152 -0
  45. package/src/v2/models/import-job/index.d.ts +51 -0
  46. package/src/v2/models/import-job/index.js +19 -0
  47. package/src/v2/models/import-url/import-url.collection.js +26 -0
  48. package/src/v2/models/import-url/import-url.model.js +28 -0
  49. package/src/v2/models/import-url/import-url.schema.js +59 -0
  50. package/src/v2/models/import-url/index.d.ts +35 -0
  51. package/src/v2/models/import-url/index.js +19 -0
  52. package/src/v2/models/index.d.ts +11 -99
  53. package/src/v2/models/index.js +14 -15
  54. package/src/v2/models/key-event/index.d.ts +28 -0
  55. package/src/v2/models/key-event/index.js +19 -0
  56. package/src/v2/models/key-event/key-event.collection.js +26 -0
  57. package/src/v2/models/key-event/key-event.model.js +37 -0
  58. package/src/v2/models/key-event/key-event.schema.js +45 -0
  59. package/src/v2/models/opportunity/index.d.ts +46 -0
  60. package/src/v2/models/opportunity/index.js +19 -0
  61. package/src/v2/models/opportunity/opportunity.collection.js +26 -0
  62. package/src/v2/models/{opportunity.model.js → opportunity/opportunity.model.js} +15 -2
  63. package/src/v2/models/opportunity/opportunity.schema.js +69 -0
  64. package/src/v2/models/organization/index.d.ts +28 -0
  65. package/src/v2/models/organization/index.js +19 -0
  66. package/src/v2/models/organization/organization.collection.js +26 -0
  67. package/src/v2/models/organization/organization.model.js +31 -0
  68. package/src/v2/models/organization/organization.schema.js +51 -0
  69. package/src/v2/models/site/index.d.ts +43 -0
  70. package/src/v2/models/site/index.js +20 -0
  71. package/src/v2/models/site/site.collection.js +28 -0
  72. package/src/v2/models/site/site.model.js +47 -0
  73. package/src/v2/models/site/site.schema.js +91 -0
  74. package/src/v2/models/site-candidate/index.d.ts +38 -0
  75. package/src/v2/models/site-candidate/index.js +19 -0
  76. package/src/v2/models/site-candidate/site-candidate.collection.js +27 -0
  77. package/src/v2/models/site-candidate/site-candidate.model.js +41 -0
  78. package/src/v2/models/site-candidate/site-candidate.schema.js +59 -0
  79. package/src/v2/models/site-top-page/index.d.ts +35 -0
  80. package/src/v2/models/site-top-page/index.js +19 -0
  81. package/src/v2/models/site-top-page/site-top-page.collection.js +44 -0
  82. package/src/v2/models/site-top-page/site-top-page.model.js +28 -0
  83. package/src/v2/models/site-top-page/site-top-page.schema.js +65 -0
  84. package/src/v2/models/suggestion/index.d.ts +34 -0
  85. package/src/v2/models/suggestion/index.js +19 -0
  86. package/src/v2/models/suggestion/suggestion.collection.js +55 -0
  87. package/src/v2/models/{suggestion.model.js → suggestion/suggestion.model.js} +16 -1
  88. package/src/v2/models/suggestion/suggestion.schema.js +53 -0
  89. package/src/v2/readme.md +201 -256
  90. package/src/v2/util/accessor.utils.js +158 -0
  91. package/src/v2/util/guards.d.ts +7 -0
  92. package/src/v2/util/guards.js +21 -4
  93. package/src/v2/util/index.js +1 -0
  94. package/src/v2/util/patcher.js +54 -25
  95. package/src/v2/util/util.js +84 -0
  96. package/src/v2/models/base.collection.js +0 -275
  97. package/src/v2/models/model.factory.js +0 -74
  98. package/src/v2/models/opportunity.collection.js +0 -74
  99. package/src/v2/models/suggestion.collection.js +0 -104
  100. package/src/v2/schema/opportunity.schema.js +0 -159
  101. package/src/v2/schema/suggestion.schema.js +0 -132
  102. package/src/v2/util/reference.js +0 -41
@@ -1,275 +0,0 @@
1
- /*
2
- * Copyright 2024 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import { isNonEmptyObject } from '@adobe/spacecat-shared-utils';
14
-
15
- import { ElectroValidationError } from 'electrodb';
16
-
17
- import ValidationError from '../errors/validation.error.js';
18
- import { guardId } from '../util/guards.js';
19
- import { keyNamesToIndexName } from '../util/reference.js';
20
-
21
- /**
22
- * BaseCollection - A base class for managing collections of entities in the application.
23
- * This class uses ElectroDB to interact with entities and provides common functionality
24
- * for data operations.
25
- *
26
- * @class BaseCollection
27
- */
28
- class BaseCollection {
29
- /**
30
- * Constructs an instance of BaseCollection.
31
- * @constructor
32
- * @param {Object} electroService - The ElectroDB service used for managing entities.
33
- * @param {Object} modelFactory - A factory for creating model instances.
34
- * @param {BaseModel} clazz - The model class that represents the entity.
35
- * @param {Object} log - A logger for capturing logging information.
36
- */
37
- constructor(electroService, modelFactory, clazz, log) {
38
- this.electroService = electroService;
39
- this.modelFactory = modelFactory;
40
- this.clazz = clazz;
41
- this.entityName = this.clazz.name.toLowerCase();
42
- this.entity = electroService.entities[this.entityName];
43
- this.idName = `${this.entityName}Id`;
44
- this.log = log;
45
- }
46
-
47
- /**
48
- * Creates an instance of a model from a record.
49
- * @private
50
- * @param {Object} record - The record containing data to create the model instance.
51
- * @returns {BaseModel|null} - Returns an instance of the model class if the data is valid,
52
- * otherwise null.
53
- */
54
- #createInstance(record) {
55
- if (!isNonEmptyObject(record?.data)) {
56
- this.log.warn(`Failed to create instance of [${this.entityName}]: record is empty`);
57
- return null;
58
- }
59
- // eslint-disable-next-line new-cap
60
- return new this.clazz(
61
- this.electroService,
62
- this.modelFactory,
63
- record.data,
64
- this.log,
65
- );
66
- }
67
-
68
- /**
69
- * Creates instances of models from a set of records.
70
- * @private
71
- * @param {Object} records - The records containing data to create the model instances.
72
- * @returns {Array<BaseModel>} - An array of instances of the model class.
73
- */
74
- #createInstances(records) {
75
- if (!Array.isArray(records?.data)) {
76
- this.log.warn(`Failed to create instances of [${this.entityName}]: records are empty`);
77
- return [];
78
- }
79
- return records.data.map((record) => this.#createInstance({ data: record }));
80
- }
81
-
82
- /**
83
- * Retrieves the enum values for a field in the entity schema. Useful for validating
84
- * enum values prior to creating or updating an entity.
85
- * @param {string} fieldName - The name of the field to retrieve enum values for.
86
- * @return {string[]} - An array of enum values for the field.
87
- * @protected
88
- */
89
- _getEnumValues(fieldName) {
90
- return this.entity.model.schema.attributes[fieldName]?.enumArray;
91
- }
92
-
93
- /**
94
- * Finds an entity by its ID.
95
- * @async
96
- * @param {string} id - The unique identifier of the entity to be found.
97
- * @returns {Promise<BaseModel|null>} - A promise that resolves to an instance of
98
- * the model if found, otherwise null.
99
- * @throws {Error} - Throws an error if the ID is not provided.
100
- */
101
- async findById(id) {
102
- guardId(this.idName, id, this.entityName);
103
-
104
- const record = await this.entity.get({ [this.idName]: id }).go();
105
-
106
- return this.#createInstance(record);
107
- }
108
-
109
- /**
110
- * Finds entities by a set of index keys. Index keys are used to query entities by
111
- * a specific index defined in the entity schema. The index keys must match the
112
- * fields defined in the index.
113
- * @param {Object} keys - The index keys to use for the query.
114
- * @return {Promise<Array<BaseModel>>} - A promise that resolves to an array of model instances.
115
- * @throws {Error} - Throws an error if the index keys are not provided or if the index
116
- * is not found.
117
- * @async
118
- */
119
- async findByIndexKeys(keys) {
120
- if (!isNonEmptyObject(keys)) {
121
- const message = `Failed to find by index keys [${this.entityName}]: keys are required`;
122
- this.log.error(message);
123
- throw new Error(message);
124
- }
125
-
126
- const indexName = keyNamesToIndexName(Object.keys(keys));
127
- const index = this.entity.query[indexName];
128
-
129
- if (!index) {
130
- const message = `Failed to find by index keys [${this.entityName}]: index [${indexName}] not found`;
131
- this.log.error(message);
132
- throw new Error(message);
133
- }
134
-
135
- const records = await index(keys).go();
136
-
137
- return this.#createInstances(records);
138
- }
139
-
140
- /**
141
- * Creates a new entity in the collection and directly persists it to the database.
142
- * There is no need to call the save method (which is for updates only) after creating
143
- * the entity.
144
- * @async
145
- * @param {Object} item - The data for the entity to be created.
146
- * @returns {Promise<BaseModel>} - A promise that resolves to the created model instance.
147
- * @throws {Error} - Throws an error if the data is invalid or if the creation process fails.
148
- */
149
- async create(item) {
150
- if (!isNonEmptyObject(item)) {
151
- const message = `Failed to create [${this.entityName}]: data is required`;
152
- this.log.error(message);
153
- throw new Error(message);
154
- }
155
-
156
- try {
157
- // todo: catch ElectroDB validation errors and re-throws as ValidationError
158
- // todo: validate associations
159
- const record = await this.entity.create(item).go();
160
- return this.#createInstance(record);
161
- } catch (error) {
162
- this.log.error(`Failed to create [${this.entityName}]`, error);
163
- throw error;
164
- }
165
- }
166
-
167
- /**
168
- * Creates multiple entities in the collection and directly persists them to the database in
169
- * a batch write operation. Batches are written in parallel and are limited to 25 items per batch.
170
- *
171
- * @async
172
- * @param {Array<Object>} newItems - An array of data for the entities to be created.
173
- * @param {BaseModel} [parent] - Optional parent entity that these items are associated with.
174
- * @return {Promise<{ createdItems: BaseModel[],
175
- * errorItems: { item: Object, error: ElectroValidationError }[] }>} - A promise that resolves to
176
- * an object containing the created items and any items that failed validation.
177
- * @throws {ValidationError} - Throws a validation error if any of the items has validation
178
- * failures.
179
- */
180
- async createMany(newItems, parent = null) {
181
- if (!Array.isArray(newItems) || newItems.length === 0) {
182
- const message = `Failed to create many [${this.entityName}]: items must be a non-empty array`;
183
- this.log.error(message);
184
- throw new Error(message);
185
- }
186
-
187
- try {
188
- const validatedItems = [];
189
- const errorItems = [];
190
- const createdItems = [];
191
-
192
- newItems.forEach((item) => {
193
- try {
194
- this.entity.put(item).params();
195
- validatedItems.push(item);
196
- } catch (error) {
197
- if (error instanceof ElectroValidationError) {
198
- errorItems.push({ item, error: new ValidationError(error) });
199
- }
200
- }
201
- });
202
-
203
- /**
204
- * ElectroDB does not return the created items in the response for batch write operations.
205
- * This listener intercepts the batch write requests and extracts the items before they
206
- * are stored in the database.
207
- * @param {Object} result - The result of the operation.
208
- */
209
- const requestItemsListener = (result) => {
210
- if (result?.type !== 'query' || result?.method !== 'batchWrite') {
211
- return;
212
- }
213
-
214
- result.params?.RequestItems[this.entity.model.table].forEach((putRequest) => {
215
- createdItems.push(putRequest.PutRequest.Item);
216
- });
217
- };
218
-
219
- let records = [];
220
- if (validatedItems.length > 0) {
221
- const response = await this.entity.put(validatedItems).go(
222
- { listeners: [requestItemsListener] },
223
- );
224
- records = this.#createInstances({ data: createdItems });
225
-
226
- if (Array.isArray(response.unprocessed) && response.unprocessed.length > 0) {
227
- this.log.error(`Failed to process all items in batch write for [${this.entityName}]: ${JSON.stringify(response.unprocessed)}`);
228
- }
229
- }
230
-
231
- if (parent) {
232
- records.forEach((record) => {
233
- // eslint-disable-next-line no-underscore-dangle
234
- record._cacheReference(parent.entity.model.name, parent);
235
- });
236
- }
237
-
238
- return { createdItems: records, errorItems };
239
- } catch (error) {
240
- this.log.error(`Failed to create many [${this.entityName}]`, error);
241
- throw error;
242
- }
243
- }
244
-
245
- /**
246
- * Updates a collection of entities in the database using a batch write (put) operation.
247
- *
248
- * @async
249
- * @param {Array<BaseModel>} items - An array of model instances to be updated.
250
- * @return {Promise<void>} - A promise that resolves when the update operation is complete.
251
- * @throws {Error} - Throws an error if the update operation fails.
252
- * @protected
253
- */
254
- async _saveMany(items) {
255
- if (!Array.isArray(items) || items.length === 0) {
256
- const message = `Failed to save many [${this.entityName}]: items must be a non-empty array`;
257
- this.log.error(message);
258
- throw new Error(message);
259
- }
260
-
261
- try {
262
- const updates = items.map((item) => item.record);
263
- const response = await this.entity.put(updates).go();
264
-
265
- if (response.unprocessed) {
266
- this.log.error(`Failed to process all items in batch write for [${this.entityName}]: ${JSON.stringify(response.unprocessed)}`);
267
- }
268
- } catch (error) {
269
- this.log.error(`Failed to save many [${this.entityName}]`, error);
270
- throw error;
271
- }
272
- }
273
- }
274
-
275
- export default BaseCollection;
@@ -1,74 +0,0 @@
1
- /*
2
- * Copyright 2024 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import OpportunityCollection from './opportunity.collection.js';
14
- import SuggestionCollection from './suggestion.collection.js';
15
-
16
- /**
17
- * ModelFactory - A factory class responsible for creating and managing collections
18
- * of different models. This class serves as a centralized point for accessing and
19
- * instantiating model collections.
20
- *
21
- * @class ModelFactory
22
- */
23
- class ModelFactory {
24
- /**
25
- * Constructs an instance of ModelFactory.
26
- * @constructor
27
- * @param {Object} service - The ElectroDB service instance used to manage entities.
28
- * @param {Object} logger - A logger for capturing and logging information.
29
- */
30
- constructor(service, logger) {
31
- this.service = service;
32
- this.logger = logger;
33
- this.models = new Map();
34
-
35
- this.initialize();
36
- }
37
-
38
- /**
39
- * Initializes the collections managed by the ModelFactory.
40
- * This method creates instances of each collection and stores them in an internal map.
41
- * @private
42
- */
43
- initialize() {
44
- const opportunityCollection = new OpportunityCollection(
45
- this.service,
46
- this,
47
- this.logger,
48
- );
49
- const suggestionCollection = new SuggestionCollection(
50
- this.service,
51
- this,
52
- this.logger,
53
- );
54
-
55
- this.models.set(OpportunityCollection.name, opportunityCollection);
56
- this.models.set(SuggestionCollection.name, suggestionCollection);
57
- }
58
-
59
- /**
60
- * Gets a collection instance by its name.
61
- * @param {string} collectionName - The name of the collection to retrieve.
62
- * @returns {Object} - The requested collection instance.
63
- * @throws {Error} - Throws an error if the collection with the specified name is not found.
64
- */
65
- getCollection(collectionName) {
66
- const collection = this.models.get(collectionName);
67
- if (!collection) {
68
- throw new Error(`Collection ${collectionName} not found`);
69
- }
70
- return collection;
71
- }
72
- }
73
-
74
- export default ModelFactory;
@@ -1,74 +0,0 @@
1
- /*
2
- * Copyright 2024 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import { hasText } from '@adobe/spacecat-shared-utils';
14
-
15
- import BaseCollection from './base.collection.js';
16
- import Opportunity from './opportunity.model.js';
17
-
18
- /**
19
- * OpportunityCollection - A collection class responsible for managing Opportunity entities.
20
- * Extends the BaseCollection to provide specific methods for interacting with Opportunity records.
21
- *
22
- * @class OpportunityCollection
23
- * @extends BaseCollection
24
- */
25
- class OpportunityCollection extends BaseCollection {
26
- /**
27
- * Constructs an instance of OpportunityCollection. Tells the base class which model to use.
28
- * @constructor
29
- * @param {Object} service - The ElectroDB service instance used to manage Opportunity entities.
30
- * @param {Object} modelFactory - A factory for creating model instances.
31
- * @param {Object} log - A logger for capturing logging information.
32
- */
33
- constructor(service, modelFactory, log) {
34
- super(service, modelFactory, Opportunity, log);
35
- }
36
-
37
- /**
38
- * Retrieves all Opportunity entities by their associated site ID.
39
- * @async
40
- * @param {string} siteId - The unique identifier of the site.
41
- * @returns {Promise<Array<Opportunity>>} - A promise that resolves to an array of
42
- * Opportunity instances related to the given site ID.
43
- * @throws {Error} - Throws an error if the siteId is not provided or if the query fails.
44
- */
45
- async allBySiteId(siteId) {
46
- if (!hasText(siteId)) {
47
- throw new Error('SiteId is required');
48
- }
49
- return this.findByIndexKeys({ siteId });
50
- }
51
-
52
- /**
53
- * Retrieves all Opportunity entities by their associated site ID and status.
54
- * @param {string} siteId - The unique identifier of the site.
55
- * @param {string} status - The status of the Opportunity entities to retrieve.
56
- * @return {Promise<Array<BaseModel>>} - A promise that resolves to an array of
57
- * Opportunity instances.
58
- * @throws {Error} - Throws an error if the siteId or status is not provided or if the
59
- * query fails.
60
- */
61
- async allBySiteIdAndStatus(siteId, status) {
62
- if (!hasText(siteId)) {
63
- throw new Error('SiteId is required');
64
- }
65
-
66
- if (!hasText(status)) {
67
- throw new Error('Status is required');
68
- }
69
-
70
- return this.findByIndexKeys({ siteId, status });
71
- }
72
- }
73
-
74
- export default OpportunityCollection;
@@ -1,104 +0,0 @@
1
- /*
2
- * Copyright 2024 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- import { hasText } from '@adobe/spacecat-shared-utils';
14
-
15
- import BaseCollection from './base.collection.js';
16
- import Suggestion from './suggestion.model.js';
17
-
18
- /**
19
- * SuggestionCollection - A collection class responsible for managing Suggestion entities.
20
- * Extends the BaseCollection to provide specific methods for interacting with Suggestion records.
21
- *
22
- * @class SuggestionCollection
23
- * @extends BaseCollection
24
- */
25
- class SuggestionCollection extends BaseCollection {
26
- /**
27
- * Constructs an instance of SuggestionCollection. Tells the base class which model to use.
28
- * @constructor
29
- * @param {Object} service - The ElectroDB service instance used to manage Suggestion entities.
30
- * @param {Object} modelFactory - A factory for creating model instances.
31
- * @param {Object} log - A logger for capturing logging information.
32
- */
33
- constructor(service, modelFactory, log) {
34
- super(service, modelFactory, Suggestion, log);
35
- }
36
-
37
- /**
38
- * Retrieves all Suggestion entities by their associated Opportunity ID.
39
- * @async
40
- * @param {string} opportunityId - The unique identifier of the associated Opportunity.
41
- * @returns {Promise<Suggestion[]>} - A promise that resolves to an array of Suggestion
42
- * instances related to the given Opportunity ID.
43
- * @throws {Error} - Throws an error if the opportunityId is not provided or if the query fails.
44
- */
45
- async allByOpportunityId(opportunityId) {
46
- if (!hasText(opportunityId)) {
47
- throw new Error('OpportunityId is required');
48
- }
49
- return this.findByIndexKeys({ opportunityId });
50
- }
51
-
52
- /**
53
- * Retrieves all Suggestion entities by their associated Opportunity ID and status.
54
- * @param {string} opportunityId - The unique identifier of the associated Opportunity.
55
- * @param {string} status - The status of the Suggestion entities
56
- * @return {Promise<BaseModel[]>} - A promise that resolves to an array of
57
- * Suggestion instances.
58
- * @throws {Error} - Throws an error if the opportunityId or status is not provided.
59
- */
60
- async allByOpportunityIdAndStatus(opportunityId, status) {
61
- if (!hasText(opportunityId)) {
62
- throw new Error('OpportunityId is required');
63
- }
64
-
65
- if (!hasText(status)) {
66
- throw new Error('Status is required');
67
- }
68
-
69
- return this.findByIndexKeys({ opportunityId, status });
70
- }
71
-
72
- /**
73
- * Updates the status of multiple given suggestions. The given status must conform
74
- * to the status enum defined in the Suggestion schema.
75
- * Saves the updated suggestions to the database automatically.
76
- * You don't need to call save() on the suggestions after calling this method.
77
- * @async
78
- * @param {Suggestion[]} suggestions - An array of Suggestion instances to update.
79
- * @param {string} status - The new status to set for the suggestions.
80
- * @return {Promise<*>} - A promise that resolves to the updated suggestions.
81
- * @throws {Error} - Throws an error if the suggestions are not provided
82
- * or if the status is invalid.
83
- */
84
- async bulkUpdateStatus(suggestions, status) {
85
- if (!Array.isArray(suggestions)) {
86
- throw new Error('Suggestions must be an array');
87
- }
88
-
89
- const validStatuses = this._getEnumValues('status');
90
- if (!validStatuses?.includes(status)) {
91
- throw new Error(`Invalid status: ${status}. Must be one of: ${validStatuses.join(', ')}`);
92
- }
93
-
94
- suggestions.forEach((suggestion) => {
95
- suggestion.setStatus(status);
96
- });
97
-
98
- await this._saveMany(suggestions);
99
-
100
- return suggestions;
101
- }
102
- }
103
-
104
- export default SuggestionCollection;
@@ -1,159 +0,0 @@
1
- /*
2
- * Copyright 2024 Adobe. All rights reserved.
3
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License. You may obtain a copy
5
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- *
7
- * Unless required by applicable law or agreed to in writing, software distributed under
8
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- * OF ANY KIND, either express or implied. See the License for the specific language
10
- * governing permissions and limitations under the License.
11
- */
12
-
13
- /* c8 ignore start */
14
-
15
- import { isNonEmptyObject, isValidUrl } from '@adobe/spacecat-shared-utils';
16
-
17
- import { validate as uuidValidate, v4 as uuid } from 'uuid';
18
-
19
- /*
20
- Schema Doc: https://electrodb.dev/en/modeling/schema/
21
- Attribute Doc: https://electrodb.dev/en/modeling/attributes/
22
- Indexes Doc: https://electrodb.dev/en/modeling/indexes/
23
- */
24
-
25
- const OpportunitySchema = {
26
- model: {
27
- entity: 'Opportunity',
28
- version: '1',
29
- service: 'SpaceCat',
30
- },
31
- attributes: {
32
- opportunityId: {
33
- type: 'string',
34
- required: true,
35
- readOnly: true,
36
- // https://electrodb.dev/en/modeling/attributes/#default
37
- default: () => uuid(),
38
- // https://electrodb.dev/en/modeling/attributes/#attribute-validation
39
- validate: (value) => uuidValidate(value),
40
- },
41
- siteId: {
42
- type: 'string',
43
- required: true,
44
- validate: (value) => uuidValidate(value),
45
- },
46
- auditId: {
47
- type: 'string',
48
- required: true,
49
- validate: (value) => uuidValidate(value),
50
- },
51
- runbook: {
52
- type: 'string',
53
- validate: (value) => !value || isValidUrl(value),
54
- },
55
- type: {
56
- type: 'string',
57
- readOnly: true,
58
- required: true,
59
- },
60
- data: {
61
- type: 'any',
62
- required: false,
63
- validate: (value) => !value || isNonEmptyObject(value),
64
- },
65
- origin: {
66
- type: ['ESS_OPS', 'AI', 'AUTOMATION'],
67
- required: true,
68
- },
69
- title: {
70
- type: 'string',
71
- required: true,
72
- },
73
- description: {
74
- type: 'string',
75
- required: false,
76
- },
77
- status: {
78
- type: ['NEW', 'IN_PROGRESS', 'IGNORED', 'RESOLVED'],
79
- required: true,
80
- default: () => 'NEW',
81
- },
82
- guidance: {
83
- type: 'any',
84
- required: false,
85
- validate: (value) => !value || isNonEmptyObject(value),
86
- },
87
- tags: {
88
- type: 'set',
89
- items: 'string',
90
- required: false,
91
- },
92
- createdAt: {
93
- type: 'number',
94
- readOnly: true,
95
- required: true,
96
- default: () => Date.now(),
97
- set: () => Date.now(),
98
- },
99
- updatedAt: {
100
- type: 'number',
101
- watch: '*',
102
- required: true,
103
- default: () => Date.now(),
104
- set: () => Date.now(),
105
- },
106
- // todo: add createdBy, updatedBy and auto-set from auth context
107
- },
108
- indexes: {
109
- primary: { // operates on the main table, no 'index' property
110
- pk: {
111
- field: 'pk',
112
- composite: ['opportunityId'],
113
- },
114
- sk: {
115
- field: 'sk',
116
- composite: [],
117
- },
118
- },
119
- bySiteId: {
120
- index: 'spacecat-data-opportunity-by-site',
121
- pk: {
122
- field: 'gsi1pk',
123
- composite: ['siteId'],
124
- },
125
- sk: {
126
- field: 'gsi1sk',
127
- composite: ['opportunityId'],
128
- },
129
- },
130
- bySiteIdAndStatus: {
131
- index: 'spacecat-data-opportunity-by-site-and-status',
132
- pk: {
133
- field: 'gsi2pk',
134
- composite: ['siteId', 'status'],
135
- },
136
- sk: {
137
- field: 'gsi2sk',
138
- composite: ['updatedAt'],
139
- },
140
- },
141
- },
142
- };
143
-
144
- /**
145
- * References to other entities. This is not part of the standard ElectroDB schema, but is used
146
- * to define relationships between entities in our data layer API.
147
- * @type {{belongs_to: [{type: string, target: string}]}}
148
- */
149
- OpportunitySchema.references = {
150
- has_many: [
151
- { type: 'has_many', target: 'Suggestions' },
152
- ],
153
- belongs_to: [
154
- { type: 'belongs_to', target: 'Site' },
155
- { type: 'belongs_to', target: 'Audit' },
156
- ],
157
- };
158
-
159
- export default OpportunitySchema;