@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
|
@@ -0,0 +1,158 @@
|
|
|
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, isNonEmptyObject, isNumber } from '@adobe/spacecat-shared-utils';
|
|
14
|
+
|
|
15
|
+
import ValidationError from '../errors/validation.error.js';
|
|
16
|
+
|
|
17
|
+
function validateValue(context, keyName, value) {
|
|
18
|
+
const { type } = context.schema.getAttribute(keyName);
|
|
19
|
+
const validator = type === 'number' ? isNumber : hasText;
|
|
20
|
+
|
|
21
|
+
if (!validator(value)) {
|
|
22
|
+
throw new ValidationError(`${keyName} is required`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseAccessorArgs(context, requiredKeyNames, args) {
|
|
27
|
+
const keys = {};
|
|
28
|
+
for (let i = 0; i < requiredKeyNames.length; i += 1) {
|
|
29
|
+
const keyName = requiredKeyNames[i];
|
|
30
|
+
const keyValue = args[i];
|
|
31
|
+
|
|
32
|
+
validateValue(context, keyName, keyValue);
|
|
33
|
+
|
|
34
|
+
keys[keyName] = keyValue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let options = {};
|
|
38
|
+
|
|
39
|
+
if (args.length > requiredKeyNames.length) {
|
|
40
|
+
options = args[requiredKeyNames.length];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { keys, options };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validateConfig(config) {
|
|
47
|
+
if (!isNonEmptyObject(config)) {
|
|
48
|
+
throw new Error('Config is required');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const {
|
|
52
|
+
collection, context, name, requiredKeys,
|
|
53
|
+
} = config;
|
|
54
|
+
|
|
55
|
+
if (!isNonEmptyObject(collection)) {
|
|
56
|
+
throw new Error('Collection is required');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!isNonEmptyObject(context)) {
|
|
60
|
+
throw new Error('Context is required');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!hasText(name)) {
|
|
64
|
+
throw new Error('Name is required');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!Array.isArray(requiredKeys)) {
|
|
68
|
+
throw new Error('Required keys must be an array');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Create an accessor for a collection. The accessor can be used to query the collection.
|
|
74
|
+
* @param {object} config - The accessor configuration.
|
|
75
|
+
* @param {boolean} [config.all=false] - Whether to return all items in the collection.
|
|
76
|
+
* @param {boolean} [config.byId=false] - Whether to return an item by ID.
|
|
77
|
+
* @param {object} config.collection - The collection to query.
|
|
78
|
+
* @param {object} config.context - The context to attach the accessor to.
|
|
79
|
+
* @param {object} [config.foreignKey] - The foreign key to use when querying by ID.
|
|
80
|
+
* @param {string} config.name - The name of the accessor.
|
|
81
|
+
* @param {string[]} [config.requiredKeys] - The required keys for the accessor.
|
|
82
|
+
* @throws {Error} - If the configuration is invalid.
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
export function createAccessor(config) { /* eslint-disable no-underscore-dangle */
|
|
86
|
+
validateConfig(config);
|
|
87
|
+
|
|
88
|
+
const {
|
|
89
|
+
all = false,
|
|
90
|
+
byId = false,
|
|
91
|
+
collection,
|
|
92
|
+
context,
|
|
93
|
+
foreignKey,
|
|
94
|
+
name,
|
|
95
|
+
requiredKeys = [],
|
|
96
|
+
} = config;
|
|
97
|
+
if (!context._accessorCache) {
|
|
98
|
+
Object.defineProperty(context, '_accessorCache', {
|
|
99
|
+
enumerable: false,
|
|
100
|
+
configurable: true,
|
|
101
|
+
writable: true,
|
|
102
|
+
value: {},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const foreignKeys = {
|
|
107
|
+
...isNonEmptyObject(foreignKey) && { [foreignKey.name]: foreignKey.value },
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const accessor = async (...args) => {
|
|
111
|
+
const argsKey = args.length > 0 ? JSON.stringify(args) : '_';
|
|
112
|
+
const cacheKey = `${name}:${argsKey}`;
|
|
113
|
+
|
|
114
|
+
if (context._accessorCache[cacheKey] !== undefined) {
|
|
115
|
+
return context._accessorCache[cacheKey];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let result;
|
|
119
|
+
|
|
120
|
+
if (byId) {
|
|
121
|
+
if (!hasText(foreignKey.value)) {
|
|
122
|
+
result = null;
|
|
123
|
+
} else {
|
|
124
|
+
result = collection.findById(foreignKey.value);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
const { keys, options } = parseAccessorArgs(collection, requiredKeys, args);
|
|
128
|
+
const allKeys = { ...foreignKeys, ...keys };
|
|
129
|
+
|
|
130
|
+
result = all
|
|
131
|
+
? collection.allByIndexKeys(allKeys, options)
|
|
132
|
+
: collection.findByIndexKeys(allKeys, options);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
result = await result;
|
|
136
|
+
context._accessorCache[cacheKey] = result;
|
|
137
|
+
|
|
138
|
+
return result;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
Object.defineProperty(
|
|
142
|
+
context,
|
|
143
|
+
name,
|
|
144
|
+
{
|
|
145
|
+
enumerable: false,
|
|
146
|
+
configurable: false,
|
|
147
|
+
writable: true,
|
|
148
|
+
value: accessor,
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function createAccessors(configs, log) {
|
|
154
|
+
configs.forEach((config) => {
|
|
155
|
+
createAccessor(config);
|
|
156
|
+
log.info(`Created accessor ${config.name} for ${config.context.schema.getModelName()} to ${config.collection.schema.getModelName()}`);
|
|
157
|
+
});
|
|
158
|
+
}
|
package/src/v2/util/guards.d.ts
CHANGED
|
@@ -25,6 +25,13 @@ export function guardAny(
|
|
|
25
25
|
nullable?: boolean,
|
|
26
26
|
): void;
|
|
27
27
|
|
|
28
|
+
export function guardBoolean(
|
|
29
|
+
propertyName: string,
|
|
30
|
+
value: never,
|
|
31
|
+
entityName: string,
|
|
32
|
+
nullable?: boolean,
|
|
33
|
+
): void;
|
|
34
|
+
|
|
28
35
|
export function guardEnum(
|
|
29
36
|
propertyName: string,
|
|
30
37
|
value: never,
|
package/src/v2/util/guards.js
CHANGED
|
@@ -32,14 +32,16 @@ const checkNullable = (value, nullable) => nullable && (value === null || value
|
|
|
32
32
|
*/
|
|
33
33
|
const checkType = (value, type) => {
|
|
34
34
|
switch (type) {
|
|
35
|
+
case 'any':
|
|
36
|
+
return isObject(value);
|
|
37
|
+
case 'boolean':
|
|
38
|
+
return typeof value === 'boolean';
|
|
39
|
+
case 'map':
|
|
40
|
+
return isObject(value);
|
|
35
41
|
case 'string':
|
|
36
42
|
return typeof value === 'string';
|
|
37
43
|
case 'number':
|
|
38
44
|
return typeof value === 'number';
|
|
39
|
-
case 'boolean':
|
|
40
|
-
return typeof value === 'boolean';
|
|
41
|
-
case 'object':
|
|
42
|
-
return isObject(value);
|
|
43
45
|
default:
|
|
44
46
|
throw new ValidationError(`Unsupported type: ${type}`);
|
|
45
47
|
}
|
|
@@ -59,6 +61,21 @@ export const guardAny = (propertyName, value, entityName, nullable = false) => {
|
|
|
59
61
|
}
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Validates that a given property is a boolean.
|
|
66
|
+
* @param {String} propertyName - Name of the property being validated.
|
|
67
|
+
* @param {any} value - The value to validate.
|
|
68
|
+
* @param {String} entityName - Name of the entity containing this property.
|
|
69
|
+
* @param {boolean} [nullable] - Whether the value is nullable. Defaults to false.
|
|
70
|
+
* @throws Will throw an error if the value is not a valid boolean.
|
|
71
|
+
*/
|
|
72
|
+
export const guardBoolean = (propertyName, value, entityName, nullable = false) => {
|
|
73
|
+
if (checkNullable(value, nullable)) return;
|
|
74
|
+
if (typeof value !== 'boolean') {
|
|
75
|
+
throw new ValidationError(`Validation failed in ${entityName}: ${propertyName} must be a boolean`);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
62
79
|
export const guardArray = (propertyName, value, entityName, type = 'string', nullable = false) => {
|
|
63
80
|
if (checkNullable(value, nullable)) return;
|
|
64
81
|
if (!Array.isArray(value)) {
|
package/src/v2/util/index.js
CHANGED
package/src/v2/util/patcher.js
CHANGED
|
@@ -16,6 +16,7 @@ import ValidationError from '../errors/validation.error.js';
|
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
18
|
guardAny,
|
|
19
|
+
guardBoolean,
|
|
19
20
|
guardArray,
|
|
20
21
|
guardEnum,
|
|
21
22
|
guardId,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
guardSet,
|
|
25
26
|
guardString,
|
|
26
27
|
} from './index.js';
|
|
28
|
+
import { isNonEmptyArray } from './util.js';
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* Checks if a property is read-only and throws an error if it is.
|
|
@@ -39,12 +41,24 @@ const checkReadOnly = (propertyName, attribute) => {
|
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
class Patcher {
|
|
42
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new Patcher instance for an entity.
|
|
46
|
+
* @param {object} entity - The entity backing the record.
|
|
47
|
+
* @param {Schema} schema - The schema for the entity.
|
|
48
|
+
* @param {object} record - The record to patch.
|
|
49
|
+
*/
|
|
50
|
+
constructor(entity, schema, record) {
|
|
43
51
|
this.entity = entity;
|
|
44
|
-
this.entityName = this.entity.model.name.toLowerCase();
|
|
45
|
-
this.model = entity.model;
|
|
46
|
-
this.idName = `${this.model.name.toLowerCase()}Id`;
|
|
47
52
|
this.record = record;
|
|
53
|
+
|
|
54
|
+
this.entityName = schema.getEntityName();
|
|
55
|
+
this.model = entity.model;
|
|
56
|
+
this.idName = schema.getIdName();
|
|
57
|
+
|
|
58
|
+
// holds the previous value of updated attributes
|
|
59
|
+
this.previous = {};
|
|
60
|
+
|
|
61
|
+
// holds the updates to the attributes
|
|
48
62
|
this.updates = {};
|
|
49
63
|
|
|
50
64
|
this.patchRecord = null;
|
|
@@ -61,24 +75,25 @@ class Patcher {
|
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
/**
|
|
64
|
-
* Gets the composite values for a given key from the entity schema.
|
|
65
78
|
* Composite keys have to be provided to ElectroDB in order to update a record across
|
|
66
|
-
* multiple indexes.
|
|
67
|
-
*
|
|
68
|
-
* @
|
|
69
|
-
* @return {{}} - An object containing the composite values for the given key.
|
|
79
|
+
* multiple indexes. This method retrieves the composite values for the entity from
|
|
80
|
+
* the schema indexes and filters out any values that are being updated.
|
|
81
|
+
* @return {{}} - An object containing the composite values for the entity.
|
|
70
82
|
* @private
|
|
71
83
|
*/
|
|
72
|
-
#
|
|
84
|
+
#getCompositeValues() {
|
|
73
85
|
const { indexes } = this.model;
|
|
74
86
|
const result = {};
|
|
75
87
|
|
|
76
88
|
const processComposite = (index, compositeType) => {
|
|
77
89
|
const compositeArray = index[compositeType]?.facets;
|
|
78
|
-
if (
|
|
90
|
+
if (isNonEmptyArray(compositeArray)) {
|
|
79
91
|
compositeArray.forEach((compositeKey) => {
|
|
80
|
-
if (
|
|
81
|
-
|
|
92
|
+
if (
|
|
93
|
+
!Object.keys(this.updates).includes(compositeKey)
|
|
94
|
+
&& this.record[compositeKey] !== undefined
|
|
95
|
+
) {
|
|
96
|
+
result[compositeKey] = this.record[compositeKey];
|
|
82
97
|
}
|
|
83
98
|
});
|
|
84
99
|
}
|
|
@@ -94,18 +109,25 @@ class Patcher {
|
|
|
94
109
|
|
|
95
110
|
/**
|
|
96
111
|
* Sets a property on the record and updates the patch record.
|
|
97
|
-
* @param {string}
|
|
112
|
+
* @param {string} attribute - The attribute to set.
|
|
98
113
|
* @param {any} value - The value to set for the property.
|
|
99
114
|
* @private
|
|
100
115
|
*/
|
|
101
|
-
#set(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
[
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
116
|
+
#set(attribute, value) {
|
|
117
|
+
this.patchRecord = this.#getPatchRecord().set({ [attribute.name]: value });
|
|
118
|
+
|
|
119
|
+
const update = {
|
|
120
|
+
[attribute.name]: {
|
|
121
|
+
previous: this.record[attribute.name],
|
|
122
|
+
current: value,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// update the record with the update value for later save
|
|
127
|
+
this.record[attribute.name] = value;
|
|
128
|
+
|
|
129
|
+
// remember the update operation with the previous and current value
|
|
130
|
+
this.updates = { ...this.updates, ...update };
|
|
109
131
|
}
|
|
110
132
|
|
|
111
133
|
/**
|
|
@@ -145,6 +167,9 @@ class Patcher {
|
|
|
145
167
|
case 'any':
|
|
146
168
|
guardAny(propertyName, value, this.entityName, nullable);
|
|
147
169
|
break;
|
|
170
|
+
case 'boolean':
|
|
171
|
+
guardBoolean(propertyName, value, this.entityName, nullable);
|
|
172
|
+
break;
|
|
148
173
|
case 'enum':
|
|
149
174
|
guardEnum(propertyName, value, attribute.enumArray, this.entityName, nullable);
|
|
150
175
|
break;
|
|
@@ -168,7 +193,7 @@ class Patcher {
|
|
|
168
193
|
}
|
|
169
194
|
}
|
|
170
195
|
|
|
171
|
-
this.#set(
|
|
196
|
+
this.#set(attribute, value);
|
|
172
197
|
}
|
|
173
198
|
|
|
174
199
|
/**
|
|
@@ -180,8 +205,12 @@ class Patcher {
|
|
|
180
205
|
if (!this.hasUpdates()) {
|
|
181
206
|
return;
|
|
182
207
|
}
|
|
183
|
-
|
|
184
|
-
|
|
208
|
+
|
|
209
|
+
const compositeValues = this.#getCompositeValues();
|
|
210
|
+
await this.#getPatchRecord()
|
|
211
|
+
.composite(compositeValues)
|
|
212
|
+
.go();
|
|
213
|
+
this.record.updatedAt = new Date().toISOString();
|
|
185
214
|
}
|
|
186
215
|
|
|
187
216
|
getUpdates() {
|
|
@@ -0,0 +1,84 @@
|
|
|
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, isInteger } from '@adobe/spacecat-shared-utils';
|
|
14
|
+
import pluralize from 'pluralize';
|
|
15
|
+
|
|
16
|
+
const capitalize = (str) => (hasText(str) ? str[0].toUpperCase() + str.slice(1) : '');
|
|
17
|
+
|
|
18
|
+
const classExtends = (clazz, base) => (typeof clazz === 'function' && clazz.prototype instanceof base);
|
|
19
|
+
|
|
20
|
+
const decapitalize = (str) => (hasText(str) ? str[0].toLowerCase() + str.slice(1) : '');
|
|
21
|
+
|
|
22
|
+
const collectionNameToEntityName = (collectionName) => collectionName.replace('Collection', '');
|
|
23
|
+
|
|
24
|
+
const entityNameToCollectionName = (entityName) => `${capitalize(pluralize.singular(entityName))}Collection`;
|
|
25
|
+
|
|
26
|
+
const entityNameToIdName = (entityName) => `${decapitalize(pluralize.singular(entityName))}Id`;
|
|
27
|
+
|
|
28
|
+
const referenceToBaseMethodName = (reference) => {
|
|
29
|
+
const target = capitalize(reference.getTarget());
|
|
30
|
+
const baseName = reference.getType() === 'has_many'
|
|
31
|
+
? pluralize.plural(target)
|
|
32
|
+
: pluralize.singular(target);
|
|
33
|
+
|
|
34
|
+
return `get${baseName}`;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const entityNameToAllPKValue = (entityName) => `ALL_${pluralize.plural(entityName.toUpperCase())}`;
|
|
38
|
+
|
|
39
|
+
const idNameToEntityName = (idName) => capitalize(pluralize.singular(idName.replace('Id', '')));
|
|
40
|
+
|
|
41
|
+
const isPositiveInteger = (value) => isInteger(value) && value > 0;
|
|
42
|
+
|
|
43
|
+
const keyNamesToIndexName = (keyNames) => `by${keyNames.map(capitalize).join('And')}`;
|
|
44
|
+
|
|
45
|
+
const keyNamesToMethodName = (keyNames, prefix) => prefix + keyNames.map(capitalize).join('And');
|
|
46
|
+
|
|
47
|
+
const modelNameToEntityName = (modelName) => decapitalize(modelName);
|
|
48
|
+
|
|
49
|
+
const sanitizeTimestamps = (data) => {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
51
|
+
const { createdAt, updatedAt, ...rest } = data;
|
|
52
|
+
return rest;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const sanitizeIdAndAuditFields = (entityName, data) => {
|
|
56
|
+
const idName = entityNameToIdName(entityName);
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
58
|
+
const { [idName]: _, ...rest } = data;
|
|
59
|
+
return sanitizeTimestamps(rest);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const incrementVersion = (version) => (isInteger(version) ? parseInt(version, 10) + 1 : 1);
|
|
63
|
+
|
|
64
|
+
const isNonEmptyArray = (value) => Array.isArray(value) && value.length > 0;
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
capitalize,
|
|
68
|
+
classExtends,
|
|
69
|
+
collectionNameToEntityName,
|
|
70
|
+
decapitalize,
|
|
71
|
+
entityNameToAllPKValue,
|
|
72
|
+
entityNameToCollectionName,
|
|
73
|
+
entityNameToIdName,
|
|
74
|
+
idNameToEntityName,
|
|
75
|
+
incrementVersion,
|
|
76
|
+
isNonEmptyArray,
|
|
77
|
+
isPositiveInteger,
|
|
78
|
+
keyNamesToIndexName,
|
|
79
|
+
keyNamesToMethodName,
|
|
80
|
+
modelNameToEntityName,
|
|
81
|
+
referenceToBaseMethodName,
|
|
82
|
+
sanitizeIdAndAuditFields,
|
|
83
|
+
sanitizeTimestamps,
|
|
84
|
+
};
|