@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.
- package/CHANGELOG.md +7 -0
- package/package.json +2 -2
- package/src/models/site/config.js +1 -1
- package/src/service/audits/accessPatterns.js +7 -7
- package/src/service/experiments/accessPatterns.js +2 -2
- package/src/service/import-job/accessPatterns.js +1 -1
- package/src/service/import-url/accessPatterns.js +2 -2
- package/src/service/index.js +10 -18
- package/src/service/key-events/accessPatterns.js +3 -3
- package/src/service/organizations/accessPatterns.js +3 -3
- package/src/service/site-candidates/accessPatterns.js +1 -1
- package/src/service/sites/accessPatterns.js +11 -11
- package/src/v2/models/api-key/api-key.collection.js +26 -0
- package/src/v2/models/api-key/api-key.model.js +59 -0
- package/src/v2/models/api-key/api-key.schema.js +82 -0
- package/src/v2/models/api-key/index.d.ts +37 -0
- package/src/v2/models/api-key/index.js +19 -0
- package/src/v2/models/audit/audit.collection.js +26 -0
- package/src/v2/models/audit/audit.model.js +89 -0
- package/src/v2/models/audit/audit.schema.js +66 -0
- package/src/v2/models/audit/index.d.ts +40 -0
- package/src/v2/models/audit/index.js +19 -0
- package/src/v2/models/base/base.collection.js +450 -0
- package/src/v2/models/{base.model.js → base/base.model.js} +109 -89
- package/src/v2/models/base/constants.js +17 -0
- package/src/v2/models/base/entity.registry.js +137 -0
- package/src/v2/models/base/index.d.ts +83 -0
- package/src/v2/models/base/index.js +27 -0
- package/src/v2/models/base/reference.js +159 -0
- package/src/v2/models/base/schema.builder.js +420 -0
- package/src/v2/models/base/schema.js +283 -0
- package/src/v2/models/configuration/configuration.collection.js +39 -0
- package/src/v2/models/configuration/configuration.model.js +160 -0
- package/src/v2/models/configuration/configuration.schema.js +103 -0
- package/src/v2/models/configuration/index.d.ts +111 -0
- package/src/v2/models/configuration/index.js +19 -0
- package/src/v2/models/experiment/experiment.collection.js +26 -0
- package/src/v2/models/experiment/experiment.model.js +28 -0
- package/src/v2/models/experiment/experiment.schema.js +70 -0
- package/src/v2/models/experiment/index.d.ts +49 -0
- package/src/v2/models/experiment/index.js +19 -0
- package/src/v2/models/import-job/import-job.collection.js +45 -0
- package/src/v2/models/import-job/import-job.model.js +55 -0
- package/src/v2/models/import-job/import-job.schema.js +152 -0
- package/src/v2/models/import-job/index.d.ts +51 -0
- package/src/v2/models/import-job/index.js +19 -0
- package/src/v2/models/import-url/import-url.collection.js +26 -0
- package/src/v2/models/import-url/import-url.model.js +28 -0
- package/src/v2/models/import-url/import-url.schema.js +59 -0
- package/src/v2/models/import-url/index.d.ts +35 -0
- package/src/v2/models/import-url/index.js +19 -0
- package/src/v2/models/index.d.ts +11 -99
- package/src/v2/models/index.js +14 -15
- package/src/v2/models/key-event/index.d.ts +28 -0
- package/src/v2/models/key-event/index.js +19 -0
- package/src/v2/models/key-event/key-event.collection.js +26 -0
- package/src/v2/models/key-event/key-event.model.js +37 -0
- package/src/v2/models/key-event/key-event.schema.js +45 -0
- package/src/v2/models/opportunity/index.d.ts +46 -0
- package/src/v2/models/opportunity/index.js +19 -0
- package/src/v2/models/opportunity/opportunity.collection.js +26 -0
- package/src/v2/models/{opportunity.model.js → opportunity/opportunity.model.js} +15 -2
- package/src/v2/models/opportunity/opportunity.schema.js +69 -0
- package/src/v2/models/organization/index.d.ts +28 -0
- package/src/v2/models/organization/index.js +19 -0
- package/src/v2/models/organization/organization.collection.js +26 -0
- package/src/v2/models/organization/organization.model.js +31 -0
- package/src/v2/models/organization/organization.schema.js +51 -0
- package/src/v2/models/site/index.d.ts +43 -0
- package/src/v2/models/site/index.js +20 -0
- package/src/v2/models/site/site.collection.js +28 -0
- package/src/v2/models/site/site.model.js +47 -0
- package/src/v2/models/site/site.schema.js +91 -0
- package/src/v2/models/site-candidate/index.d.ts +38 -0
- package/src/v2/models/site-candidate/index.js +19 -0
- package/src/v2/models/site-candidate/site-candidate.collection.js +27 -0
- package/src/v2/models/site-candidate/site-candidate.model.js +41 -0
- package/src/v2/models/site-candidate/site-candidate.schema.js +59 -0
- package/src/v2/models/site-top-page/index.d.ts +35 -0
- package/src/v2/models/site-top-page/index.js +19 -0
- package/src/v2/models/site-top-page/site-top-page.collection.js +44 -0
- package/src/v2/models/site-top-page/site-top-page.model.js +28 -0
- package/src/v2/models/site-top-page/site-top-page.schema.js +65 -0
- package/src/v2/models/suggestion/index.d.ts +34 -0
- package/src/v2/models/suggestion/index.js +19 -0
- package/src/v2/models/suggestion/suggestion.collection.js +55 -0
- package/src/v2/models/{suggestion.model.js → suggestion/suggestion.model.js} +16 -1
- package/src/v2/models/suggestion/suggestion.schema.js +53 -0
- package/src/v2/readme.md +201 -256
- package/src/v2/util/accessor.utils.js +158 -0
- package/src/v2/util/guards.d.ts +7 -0
- package/src/v2/util/guards.js +21 -4
- package/src/v2/util/index.js +1 -0
- package/src/v2/util/patcher.js +54 -25
- package/src/v2/util/util.js +84 -0
- package/src/v2/models/base.collection.js +0 -275
- package/src/v2/models/model.factory.js +0 -74
- package/src/v2/models/opportunity.collection.js +0 -74
- package/src/v2/models/suggestion.collection.js +0 -104
- package/src/v2/schema/opportunity.schema.js +0 -159
- package/src/v2/schema/suggestion.schema.js +0 -132
- package/src/v2/util/reference.js +0 -41
|
@@ -12,13 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
import { isNonEmptyObject } from '@adobe/spacecat-shared-utils';
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import { createAccessors } from '../../util/accessor.utils.js';
|
|
16
|
+
import Patcher from '../../util/patcher.js';
|
|
16
17
|
import {
|
|
17
18
|
capitalize,
|
|
18
|
-
entityNameToCollectionName,
|
|
19
19
|
entityNameToIdName,
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
idNameToEntityName,
|
|
21
|
+
isNonEmptyArray,
|
|
22
|
+
} from '../../util/util.js';
|
|
23
|
+
|
|
24
|
+
import Reference from './reference.js';
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* Base - A base class for representing individual entities in the application.
|
|
@@ -40,20 +43,28 @@ class BaseModel {
|
|
|
40
43
|
* Constructs an instance of BaseModel.
|
|
41
44
|
* @constructor
|
|
42
45
|
* @param {Object} electroService - The ElectroDB service used for managing entities.
|
|
43
|
-
* @param {
|
|
46
|
+
* @param {EntityRegistry} entityRegistry - The registry holding entities, their schema
|
|
47
|
+
* and collection.
|
|
48
|
+
* @param {Schema} schema - The schema for the entity.
|
|
44
49
|
* @param {Object} record - The initial data for the entity instance.
|
|
45
|
-
* @param {Object} log - A
|
|
50
|
+
* @param {Object} log - A log for capturing logging information.
|
|
46
51
|
*/
|
|
47
|
-
constructor(electroService,
|
|
48
|
-
this.
|
|
52
|
+
constructor(electroService, entityRegistry, schema, record, log) {
|
|
53
|
+
this.electroService = electroService;
|
|
54
|
+
this.entityRegistry = entityRegistry;
|
|
55
|
+
this.schema = schema;
|
|
49
56
|
this.record = record;
|
|
50
|
-
this.entityName = this.constructor.name.toLowerCase();
|
|
51
|
-
this.entity = electroService.entities[this.entityName];
|
|
52
|
-
this.idName = `${this.entityName}Id`;
|
|
53
57
|
this.log = log;
|
|
54
|
-
this.referencesCache = {};
|
|
55
58
|
|
|
56
|
-
this.
|
|
59
|
+
this.entityName = schema.getEntityName();
|
|
60
|
+
this.idName = entityNameToIdName(this.entityName);
|
|
61
|
+
|
|
62
|
+
this.collection = entityRegistry.getCollection(schema.getCollectionName());
|
|
63
|
+
this.entity = electroService.entities[this.entityName];
|
|
64
|
+
|
|
65
|
+
this.patcher = new Patcher(this.entity, this.schema, this.record);
|
|
66
|
+
|
|
67
|
+
this._accessorCache = {};
|
|
57
68
|
|
|
58
69
|
this.#initializeReferences();
|
|
59
70
|
this.#initializeAttributes();
|
|
@@ -66,23 +77,16 @@ class BaseModel {
|
|
|
66
77
|
* @private
|
|
67
78
|
*/
|
|
68
79
|
#initializeReferences() {
|
|
69
|
-
const
|
|
70
|
-
if (!isNonEmptyObject(references)) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
for (const [type, refs] of Object.entries(references)) {
|
|
75
|
-
refs.forEach((ref) => {
|
|
76
|
-
const { target } = ref;
|
|
77
|
-
const methodName = entityNameToReferenceMethodName(target, type);
|
|
80
|
+
const references = this.schema.getReferences();
|
|
78
81
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
references.forEach((reference) => {
|
|
83
|
+
const accessorConfigs = reference.toAccessorConfigs(this.entityRegistry, this);
|
|
84
|
+
createAccessors(accessorConfigs, this.log);
|
|
85
|
+
});
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
#initializeAttributes() {
|
|
85
|
-
const
|
|
89
|
+
const attributes = this.schema.getAttributes();
|
|
86
90
|
|
|
87
91
|
if (!isNonEmptyObject(attributes)) {
|
|
88
92
|
return;
|
|
@@ -92,8 +96,9 @@ class BaseModel {
|
|
|
92
96
|
const capitalized = capitalize(name);
|
|
93
97
|
const getterMethodName = `get${capitalized}`;
|
|
94
98
|
const setterMethodName = `set${capitalized}`;
|
|
95
|
-
const isReference = this.
|
|
96
|
-
.
|
|
99
|
+
const isReference = this.schema
|
|
100
|
+
.getReferencesByType(Reference.TYPES.BELONGS_TO)
|
|
101
|
+
.some((ref) => ref.getTarget() === idNameToEntityName(name));
|
|
97
102
|
|
|
98
103
|
if (!this[getterMethodName] || name === this.idName) {
|
|
99
104
|
this[getterMethodName] = () => this.record[name];
|
|
@@ -108,64 +113,43 @@ class BaseModel {
|
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* @param {string} targetName - The name of the entity to fetch.
|
|
114
|
-
* @return {*}
|
|
115
|
-
*/
|
|
116
|
-
#getCachedReference(targetName) {
|
|
117
|
-
return this.referencesCache[targetName];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Caches a reference for the specified entity. This method is used to store
|
|
122
|
-
* fetched references to avoid redundant database queries.
|
|
123
|
-
* @param {string} targetName - The name of the entity to cache.
|
|
124
|
-
* @param {*} reference - The reference to cache.
|
|
125
|
-
* @private
|
|
126
|
-
*/
|
|
127
|
-
_cacheReference(targetName, reference) {
|
|
128
|
-
this.referencesCache[targetName] = reference;
|
|
116
|
+
#invalidateCache() {
|
|
117
|
+
this._accessorCache = {};
|
|
129
118
|
}
|
|
130
119
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
const foreignKey = entityNameToIdName(this.entityName);
|
|
161
|
-
result = await targetCollection.findByIndexKeys({ [foreignKey]: this.getId() });
|
|
162
|
-
}
|
|
120
|
+
async #fetchDependents() {
|
|
121
|
+
const promises = [];
|
|
122
|
+
|
|
123
|
+
const relationshipTypes = [
|
|
124
|
+
Reference.TYPES.HAS_MANY,
|
|
125
|
+
Reference.TYPES.HAS_ONE,
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
relationshipTypes.forEach((type) => {
|
|
129
|
+
const references = this.schema.getReferencesByType(type);
|
|
130
|
+
const targets = references.filter((reference) => reference.isRemoveDependents());
|
|
131
|
+
|
|
132
|
+
targets.forEach((reference) => {
|
|
133
|
+
const accessors = reference.toAccessorConfigs(this.entityRegistry, this);
|
|
134
|
+
const methodName = accessors[0].name;
|
|
135
|
+
promises.push(
|
|
136
|
+
this[methodName]()
|
|
137
|
+
.then((dependent) => {
|
|
138
|
+
if (isNonEmptyArray(dependent)) {
|
|
139
|
+
return dependent;
|
|
140
|
+
} else if (isNonEmptyObject(dependent)) {
|
|
141
|
+
return [dependent];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
163
149
|
|
|
164
|
-
|
|
165
|
-
await this._cacheReference(targetName, result);
|
|
166
|
-
}
|
|
150
|
+
const results = await Promise.all(promises);
|
|
167
151
|
|
|
168
|
-
return
|
|
152
|
+
return results.flat().filter((dependent) => dependent !== null);
|
|
169
153
|
}
|
|
170
154
|
|
|
171
155
|
/**
|
|
@@ -181,7 +165,7 @@ class BaseModel {
|
|
|
181
165
|
* @returns {string} - The ISO string representing when the entity was created.
|
|
182
166
|
*/
|
|
183
167
|
getCreatedAt() {
|
|
184
|
-
return
|
|
168
|
+
return this.record.createdAt;
|
|
185
169
|
}
|
|
186
170
|
|
|
187
171
|
/**
|
|
@@ -189,20 +173,37 @@ class BaseModel {
|
|
|
189
173
|
* @returns {string} - The ISO string representing when the entity was last updated.
|
|
190
174
|
*/
|
|
191
175
|
getUpdatedAt() {
|
|
192
|
-
return
|
|
176
|
+
return this.record.updatedAt;
|
|
193
177
|
}
|
|
194
178
|
|
|
195
179
|
/**
|
|
196
|
-
* Removes the current entity from the database.
|
|
180
|
+
* Removes the current entity from the database. This method also removes any dependent
|
|
181
|
+
* entities associated with the current entity. For example, if the current entity has
|
|
182
|
+
* a has_many relationship with another entity, the dependent entity will be removed.
|
|
183
|
+
* When adding a reference to an entity, the dependent entity will be removed if the
|
|
184
|
+
* removeDependentss flag is set to true in the reference definition.
|
|
185
|
+
*
|
|
186
|
+
* Dependents are removed by calling the remove method on each dependent entity, which in turn
|
|
187
|
+
* will also remove any dependent entities associated with the dependent entity. This may result
|
|
188
|
+
* in a cascade effect where multiple entities are removed. Consider the destructive
|
|
189
|
+
* and performance implications before using this method.
|
|
197
190
|
* @async
|
|
198
191
|
* @returns {Promise<BaseModel>} - A promise that resolves to the current instance of the entity
|
|
199
|
-
* after it
|
|
192
|
+
* after it and its dependents have been removed.
|
|
200
193
|
* @throws {Error} - Throws an error if the removal fails.
|
|
201
194
|
*/
|
|
202
195
|
async remove() {
|
|
203
196
|
try {
|
|
204
|
-
|
|
205
|
-
|
|
197
|
+
const dependents = await this.#fetchDependents();
|
|
198
|
+
const removePromises = dependents.map((dependent) => dependent.remove());
|
|
199
|
+
removePromises.push(this.entity.remove({ [this.idName]: this.getId() }).go());
|
|
200
|
+
|
|
201
|
+
this.log.info(`Removing entity ${this.entityName} with ID ${this.getId()} and ${dependents.length} dependents`);
|
|
202
|
+
|
|
203
|
+
await Promise.all(removePromises);
|
|
204
|
+
|
|
205
|
+
this.#invalidateCache();
|
|
206
|
+
|
|
206
207
|
return this;
|
|
207
208
|
} catch (error) {
|
|
208
209
|
this.log.error('Failed to remove record', error);
|
|
@@ -221,14 +222,33 @@ class BaseModel {
|
|
|
221
222
|
async save() {
|
|
222
223
|
// todo: validate associations
|
|
223
224
|
try {
|
|
225
|
+
this.log.info(`Saving entity ${this.entityName} with ID ${this.getId()}`);
|
|
226
|
+
|
|
224
227
|
await this.patcher.save();
|
|
225
|
-
|
|
228
|
+
this.#invalidateCache();
|
|
229
|
+
|
|
226
230
|
return this;
|
|
227
231
|
} catch (error) {
|
|
228
232
|
this.log.error('Failed to save record', error);
|
|
229
233
|
throw error;
|
|
230
234
|
}
|
|
231
235
|
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Converts the entity attributes to a JSON object.
|
|
239
|
+
* @returns {Object} - A JSON representation of the entity attributes.
|
|
240
|
+
*/
|
|
241
|
+
toJSON() {
|
|
242
|
+
const attributes = this.schema.getAttributes();
|
|
243
|
+
|
|
244
|
+
return Object.keys(attributes).reduce((json, key) => {
|
|
245
|
+
if (this.record[key] !== undefined) {
|
|
246
|
+
// eslint-disable-next-line no-param-reassign
|
|
247
|
+
json[key] = this.record[key];
|
|
248
|
+
}
|
|
249
|
+
return json;
|
|
250
|
+
}, {});
|
|
251
|
+
}
|
|
232
252
|
}
|
|
233
253
|
|
|
234
254
|
export default BaseModel;
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
export const INDEX_TYPES = {
|
|
13
|
+
PRIMARY: 'primary',
|
|
14
|
+
ALL: 'all',
|
|
15
|
+
BELONGS_TO: 'belongs_to',
|
|
16
|
+
OTHER: 'other',
|
|
17
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
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 { collectionNameToEntityName, decapitalize } from '../../util/util.js';
|
|
14
|
+
|
|
15
|
+
import ApiKeyCollection from '../api-key/api-key.collection.js';
|
|
16
|
+
import AuditCollection from '../audit/audit.collection.js';
|
|
17
|
+
import ConfigurationCollection from '../configuration/configuration.collection.js';
|
|
18
|
+
import ExperimentCollection from '../experiment/experiment.collection.js';
|
|
19
|
+
import ImportJobCollection from '../import-job/import-job.collection.js';
|
|
20
|
+
import ImportUrlCollection from '../import-url/import-url.collection.js';
|
|
21
|
+
import KeyEventCollection from '../key-event/key-event.collection.js';
|
|
22
|
+
import OpportunityCollection from '../opportunity/opportunity.collection.js';
|
|
23
|
+
import OrganizationCollection from '../organization/organization.collection.js';
|
|
24
|
+
import SiteCandidateCollection from '../site-candidate/site-candidate.collection.js';
|
|
25
|
+
import SiteCollection from '../site/site.collection.js';
|
|
26
|
+
import SiteTopPageCollection from '../site-top-page/site-top-page.collection.js';
|
|
27
|
+
import SuggestionCollection from '../suggestion/suggestion.collection.js';
|
|
28
|
+
|
|
29
|
+
import ApiKeySchema from '../api-key/api-key.schema.js';
|
|
30
|
+
import AuditSchema from '../audit/audit.schema.js';
|
|
31
|
+
import ConfigurationSchema from '../configuration/configuration.schema.js';
|
|
32
|
+
import ExperimentSchema from '../experiment/experiment.schema.js';
|
|
33
|
+
import ImportJobSchema from '../import-job/import-job.schema.js';
|
|
34
|
+
import ImportUrlSchema from '../import-url/import-url.schema.js';
|
|
35
|
+
import KeyEventSchema from '../key-event/key-event.schema.js';
|
|
36
|
+
import OpportunitySchema from '../opportunity/opportunity.schema.js';
|
|
37
|
+
import OrganizationSchema from '../organization/organization.schema.js';
|
|
38
|
+
import SiteSchema from '../site/site.schema.js';
|
|
39
|
+
import SiteCandidateSchema from '../site-candidate/site-candidate.schema.js';
|
|
40
|
+
import SiteTopPageSchema from '../site-top-page/site-top-page.schema.js';
|
|
41
|
+
import SuggestionSchema from '../suggestion/suggestion.schema.js';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* EntityRegistry - A registry class responsible for managing entities, their schema and collection.
|
|
45
|
+
*
|
|
46
|
+
* @class EntityRegistry
|
|
47
|
+
*/
|
|
48
|
+
class EntityRegistry {
|
|
49
|
+
static entities = {};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Constructs an instance of EntityRegistry.
|
|
53
|
+
* @constructor
|
|
54
|
+
* @param {Object} service - The ElectroDB service instance used to manage entities.
|
|
55
|
+
* @param {Object} log - A logger for capturing and logging information.
|
|
56
|
+
*/
|
|
57
|
+
constructor(service, log) {
|
|
58
|
+
this.service = service;
|
|
59
|
+
this.log = log;
|
|
60
|
+
this.collections = new Map();
|
|
61
|
+
|
|
62
|
+
this.#initialize();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Initializes the collections managed by the EntityRegistry.
|
|
67
|
+
* This method creates instances of each collection and stores them in an internal map.
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
#initialize() {
|
|
71
|
+
Object.values(EntityRegistry.entities).forEach(({ collection: Collection, schema }) => {
|
|
72
|
+
const collection = new Collection(this.service, this, schema, this.log);
|
|
73
|
+
this.collections.set(Collection.name, collection);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.#logIndexes();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#logIndexes() {
|
|
80
|
+
// reduce collection schema indexes into object
|
|
81
|
+
const indexes = Object.values(EntityRegistry.entities).reduce((acc, { schema }) => {
|
|
82
|
+
acc[schema.getEntityName()] = schema.indexes;
|
|
83
|
+
return acc;
|
|
84
|
+
}, {});
|
|
85
|
+
|
|
86
|
+
this.log.debug('Indexes:', JSON.stringify(indexes, null, 2));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Gets a collection instance by its name.
|
|
91
|
+
* @param {string} collectionName - The name of the collection to retrieve.
|
|
92
|
+
* @returns {Object} - The requested collection instance.
|
|
93
|
+
* @throws {Error} - Throws an error if the collection with the specified name is not found.
|
|
94
|
+
*/
|
|
95
|
+
getCollection(collectionName) {
|
|
96
|
+
const collection = this.collections.get(collectionName);
|
|
97
|
+
if (!collection) {
|
|
98
|
+
throw new Error(`Collection ${collectionName} not found`);
|
|
99
|
+
}
|
|
100
|
+
return collection;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getCollections() {
|
|
104
|
+
const collections = {};
|
|
105
|
+
for (const [key, value] of this.collections) {
|
|
106
|
+
collections[collectionNameToEntityName(key)] = value;
|
|
107
|
+
}
|
|
108
|
+
return collections;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static getEntities() {
|
|
112
|
+
return Object.keys(this.entities).reduce((acc, key) => {
|
|
113
|
+
acc[key] = this.entities[key].schema.toElectroDBSchema();
|
|
114
|
+
return acc;
|
|
115
|
+
}, {});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static registerEntity(schema, collection) {
|
|
119
|
+
this.entities[decapitalize(schema.getEntityName())] = { schema, collection };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
EntityRegistry.registerEntity(ApiKeySchema, ApiKeyCollection);
|
|
124
|
+
EntityRegistry.registerEntity(AuditSchema, AuditCollection);
|
|
125
|
+
EntityRegistry.registerEntity(ConfigurationSchema, ConfigurationCollection);
|
|
126
|
+
EntityRegistry.registerEntity(ExperimentSchema, ExperimentCollection);
|
|
127
|
+
EntityRegistry.registerEntity(ImportJobSchema, ImportJobCollection);
|
|
128
|
+
EntityRegistry.registerEntity(ImportUrlSchema, ImportUrlCollection);
|
|
129
|
+
EntityRegistry.registerEntity(KeyEventSchema, KeyEventCollection);
|
|
130
|
+
EntityRegistry.registerEntity(OpportunitySchema, OpportunityCollection);
|
|
131
|
+
EntityRegistry.registerEntity(OrganizationSchema, OrganizationCollection);
|
|
132
|
+
EntityRegistry.registerEntity(SiteSchema, SiteCollection);
|
|
133
|
+
EntityRegistry.registerEntity(SiteCandidateSchema, SiteCandidateCollection);
|
|
134
|
+
EntityRegistry.registerEntity(SiteTopPageSchema, SiteTopPageCollection);
|
|
135
|
+
EntityRegistry.registerEntity(SuggestionSchema, SuggestionCollection);
|
|
136
|
+
|
|
137
|
+
export default EntityRegistry;
|
|
@@ -0,0 +1,83 @@
|
|
|
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 type { ValidationError } from '../../errors';
|
|
14
|
+
|
|
15
|
+
export interface BaseModel {
|
|
16
|
+
getCreatedAt(): string;
|
|
17
|
+
getId(): string;
|
|
18
|
+
getUpdatedAt(): string;
|
|
19
|
+
remove(): Promise<this>;
|
|
20
|
+
save(): Promise<this>;
|
|
21
|
+
toJSON(): object;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface MultiStatusCreateResult<T> {
|
|
25
|
+
createdItems: T[],
|
|
26
|
+
errorItems: { item: object, error: ValidationError }[],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface QueryOptions {
|
|
30
|
+
index?: string;
|
|
31
|
+
limit?: number;
|
|
32
|
+
sort?: string;
|
|
33
|
+
attributes?: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface BaseCollection<T extends BaseModel> {
|
|
37
|
+
all(sortKeys?: object, options?: QueryOptions): Promise<T[]>;
|
|
38
|
+
allByIndexKeys(keys: object, options?: QueryOptions): Promise<T[]>;
|
|
39
|
+
create(item: object): Promise<T>;
|
|
40
|
+
createMany(items: object[]): Promise<MultiStatusCreateResult<T>>;
|
|
41
|
+
findByAll(sortKeys?: object, options?: QueryOptions): Promise<T>;
|
|
42
|
+
findById(id: string): Promise<T>;
|
|
43
|
+
findByIndexKeys(indexKeys: object): Promise<T>;
|
|
44
|
+
removeByIds(ids: string[]): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface EntityRegistry {
|
|
48
|
+
getCollection<T extends BaseModel>(collectionName: string): BaseCollection<T>;
|
|
49
|
+
getCollections(): BaseCollection<BaseModel>[];
|
|
50
|
+
getEntities(): object;
|
|
51
|
+
registerEntity(schema: object, collection: BaseCollection<BaseModel>): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface Reference {
|
|
55
|
+
getSortKeys(): string[];
|
|
56
|
+
getTarget(): string;
|
|
57
|
+
getType(): string;
|
|
58
|
+
isRemoveDependents(): boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface Schema {
|
|
62
|
+
getAttribute(name: string): object;
|
|
63
|
+
getAttributes(): object;
|
|
64
|
+
getCollectionName(): string;
|
|
65
|
+
getEntityName(): string;
|
|
66
|
+
getIdName(): string;
|
|
67
|
+
getIndexes(): object;
|
|
68
|
+
getIndexKeys(indexName: string): string[];
|
|
69
|
+
getModelClass(): object;
|
|
70
|
+
getModelName(): string;
|
|
71
|
+
getReferences(): Reference[];
|
|
72
|
+
getReferencesByType(referenceType: string): Reference[];
|
|
73
|
+
getReferenceByTypeAndTarget(referenceType: string, target: string): Reference | undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SchemaBuilder {
|
|
77
|
+
addAttribute(name: string, data: object): SchemaBuilder;
|
|
78
|
+
addAllIndexWithComposite(...attributeNames: string[]): SchemaBuilder
|
|
79
|
+
addAllIndexWithTemplateField(fieldName: string, template: string): SchemaBuilder;
|
|
80
|
+
addIndex(name: string, partitionKey: object, sortKey: object): SchemaBuilder;
|
|
81
|
+
addReference(referenceType: string, entityName: string, sortKeys?: string[]): SchemaBuilder;
|
|
82
|
+
build(): Schema;
|
|
83
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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 BaseModel from './base.model.js';
|
|
14
|
+
import BaseCollection from './base.collection.js';
|
|
15
|
+
import EntityRegistry from './entity.registry.js';
|
|
16
|
+
import Reference from './reference.js';
|
|
17
|
+
import Schema from './schema.js';
|
|
18
|
+
import SchemaBuilder from './schema.builder.js';
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
BaseModel,
|
|
22
|
+
BaseCollection,
|
|
23
|
+
EntityRegistry,
|
|
24
|
+
Reference,
|
|
25
|
+
Schema,
|
|
26
|
+
SchemaBuilder,
|
|
27
|
+
};
|