@adobe/spacecat-shared-data-access 2.13.2 → 2.14.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 +14 -0
- package/package.json +1 -1
- package/src/models/base/entity.registry.js +3 -0
- package/src/models/configuration/configuration.model.js +21 -12
- package/src/models/fix-entity/fix-entity.collection.js +26 -0
- package/src/models/fix-entity/fix-entity.model.js +33 -0
- package/src/models/fix-entity/fix-entity.schema.js +56 -0
- package/src/models/fix-entity/index.d.ts +40 -0
- package/src/models/fix-entity/index.js +19 -0
- package/src/models/index.d.ts +1 -0
- package/src/models/index.js +1 -0
- package/src/models/opportunity/index.d.ts +3 -1
- package/src/models/opportunity/opportunity.model.js +21 -0
- package/src/models/opportunity/opportunity.schema.js +1 -0
- package/src/models/suggestion/index.d.ts +3 -0
- package/src/models/suggestion/suggestion.schema.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-data-access-v2.14.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.13.3...@adobe/spacecat-shared-data-access-v2.14.0) (2025-04-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add FixEntity for keeping track of the suggestion fixes ([#671](https://github.com/adobe/spacecat-shared/issues/671)) ([3be02da](https://github.com/adobe/spacecat-shared/commit/3be02da115cbb2d106e863ee715a5904aa2c75d2))
|
|
7
|
+
|
|
8
|
+
# [@adobe/spacecat-shared-data-access-v2.13.3](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.13.2...@adobe/spacecat-shared-data-access-v2.13.3) (2025-04-08)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* configuration shouldn't check for enabled if audit is enabledByDefault ([#675](https://github.com/adobe/spacecat-shared/issues/675)) ([0d8538a](https://github.com/adobe/spacecat-shared/commit/0d8538ac967e2a69a08ebc462530985780584f0e))
|
|
14
|
+
|
|
1
15
|
# [@adobe/spacecat-shared-data-access-v2.13.2](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.13.1...@adobe/spacecat-shared-data-access-v2.13.2) (2025-04-01)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ import ApiKeyCollection from '../api-key/api-key.collection.js';
|
|
|
17
17
|
import AuditCollection from '../audit/audit.collection.js';
|
|
18
18
|
import ConfigurationCollection from '../configuration/configuration.collection.js';
|
|
19
19
|
import ExperimentCollection from '../experiment/experiment.collection.js';
|
|
20
|
+
import FixEntityCollection from '../fix-entity/fix-entity.collection.js';
|
|
20
21
|
import ImportJobCollection from '../import-job/import-job.collection.js';
|
|
21
22
|
import ImportUrlCollection from '../import-url/import-url.collection.js';
|
|
22
23
|
import KeyEventCollection from '../key-event/key-event.collection.js';
|
|
@@ -31,6 +32,7 @@ import SuggestionCollection from '../suggestion/suggestion.collection.js';
|
|
|
31
32
|
import ApiKeySchema from '../api-key/api-key.schema.js';
|
|
32
33
|
import AuditSchema from '../audit/audit.schema.js';
|
|
33
34
|
import ConfigurationSchema from '../configuration/configuration.schema.js';
|
|
35
|
+
import FixEntitySchema from '../fix-entity/fix-entity.schema.js';
|
|
34
36
|
import ExperimentSchema from '../experiment/experiment.schema.js';
|
|
35
37
|
import ImportJobSchema from '../import-job/import-job.schema.js';
|
|
36
38
|
import ImportUrlSchema from '../import-url/import-url.schema.js';
|
|
@@ -127,6 +129,7 @@ class EntityRegistry {
|
|
|
127
129
|
EntityRegistry.registerEntity(ApiKeySchema, ApiKeyCollection);
|
|
128
130
|
EntityRegistry.registerEntity(AuditSchema, AuditCollection);
|
|
129
131
|
EntityRegistry.registerEntity(ConfigurationSchema, ConfigurationCollection);
|
|
132
|
+
EntityRegistry.registerEntity(FixEntitySchema, FixEntityCollection);
|
|
130
133
|
EntityRegistry.registerEntity(ExperimentSchema, ExperimentCollection);
|
|
131
134
|
EntityRegistry.registerEntity(ImportJobSchema, ImportJobCollection);
|
|
132
135
|
EntityRegistry.registerEntity(ImportUrlSchema, ImportUrlCollection);
|
|
@@ -80,19 +80,24 @@ class Configuration extends BaseModel {
|
|
|
80
80
|
const siteId = site.getId();
|
|
81
81
|
const orgId = site.getOrganizationId();
|
|
82
82
|
|
|
83
|
+
if (handler.disabled) {
|
|
84
|
+
const sites = handler.disabled.sites || [];
|
|
85
|
+
const orgs = handler.disabled.orgs || [];
|
|
86
|
+
if (sites.includes(siteId) || orgs.includes(orgId)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (handler.enabledByDefault) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
83
94
|
if (handler.enabled) {
|
|
84
95
|
const sites = handler.enabled.sites || [];
|
|
85
96
|
const orgs = handler.enabled.orgs || [];
|
|
86
97
|
return sites.includes(siteId) || orgs.includes(orgId);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
|
|
90
|
-
const sites = handler.disabled.sites || [];
|
|
91
|
-
const orgs = handler.disabled.orgs || [];
|
|
92
|
-
return !(sites.includes(siteId) || orgs.includes(orgId));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return handler.enabledByDefault;
|
|
100
|
+
return false;
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
isHandlerEnabledForOrg(type, org) {
|
|
@@ -101,15 +106,19 @@ class Configuration extends BaseModel {
|
|
|
101
106
|
|
|
102
107
|
const orgId = org.getId();
|
|
103
108
|
|
|
104
|
-
if (handler.
|
|
105
|
-
return
|
|
109
|
+
if (handler.disabled && handler.disabled.orgs?.includes(orgId)) {
|
|
110
|
+
return false;
|
|
106
111
|
}
|
|
107
112
|
|
|
108
|
-
if (handler.
|
|
109
|
-
return
|
|
113
|
+
if (handler.enabledByDefault) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (handler.enabled) {
|
|
118
|
+
return handler.enabled.orgs?.includes(orgId);
|
|
110
119
|
}
|
|
111
120
|
|
|
112
|
-
return
|
|
121
|
+
return false;
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
#updatedHandler(type, entityId, enabled, entityKey) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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
|
+
import BaseCollection from '../base/base.collection.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* SiteCandidateCollection - A collection class responsible for managing FixEntities.
|
|
16
|
+
* Extends the BaseCollection to provide specific methods for interacting with
|
|
17
|
+
* FixEntity records.
|
|
18
|
+
*
|
|
19
|
+
* @class FixEntityCollection
|
|
20
|
+
* @extends BaseCollection
|
|
21
|
+
*/
|
|
22
|
+
class FixEntityCollection extends BaseCollection {
|
|
23
|
+
// add custom methods here
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default FixEntityCollection;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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
|
+
import BaseModel from '../base/base.model.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* FixEntity - A class representing a FixEntity for a Suggestion.
|
|
16
|
+
* Provides methods to access and manipulate FixEntity-specific data.
|
|
17
|
+
*
|
|
18
|
+
* @class FixEntity
|
|
19
|
+
* @extends BaseModel
|
|
20
|
+
*/
|
|
21
|
+
class FixEntity extends BaseModel {
|
|
22
|
+
static DEFAULT_UPDATED_BY = 'spacecat';
|
|
23
|
+
|
|
24
|
+
static STATUSES = {
|
|
25
|
+
PENDING: 'PENDING', // the fix is pending to be deployed
|
|
26
|
+
DEPLOYED: 'DEPLOYED', // the fix was successfully applied
|
|
27
|
+
PUBLISHED: 'PUBLISHED', // the fix is live in production
|
|
28
|
+
FAILED: 'FAILED', // failed to apply the fix
|
|
29
|
+
ROLLED_BACK: 'ROLLED_BACK', // the fix has been rolled_back
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default FixEntity;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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 { isIsoDate, isNonEmptyObject } from '@adobe/spacecat-shared-utils';
|
|
14
|
+
|
|
15
|
+
import SchemaBuilder from '../base/schema.builder.js';
|
|
16
|
+
import FixEntity from './fix-entity.model.js';
|
|
17
|
+
import FixEntityCollection from './fix-entity.collection.js';
|
|
18
|
+
import { Suggestion } from '../suggestion/index.js';
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
Schema Doc: https://electrodb.dev/en/modeling/schema/
|
|
22
|
+
Attribute Doc: https://electrodb.dev/en/modeling/attributes/
|
|
23
|
+
Indexes Doc: https://electrodb.dev/en/modeling/indexes/
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const schema = new SchemaBuilder(FixEntity, FixEntityCollection)
|
|
27
|
+
.addReference('has_many', 'Suggestion', ['status'])
|
|
28
|
+
.addReference('belongs_to', 'Opportunity', ['status'])
|
|
29
|
+
.addAttribute('type', {
|
|
30
|
+
type: Object.values(Suggestion.TYPES),
|
|
31
|
+
required: true,
|
|
32
|
+
readOnly: true,
|
|
33
|
+
})
|
|
34
|
+
.addAttribute('executedBy', {
|
|
35
|
+
type: 'string',
|
|
36
|
+
})
|
|
37
|
+
.addAttribute('executedAt', {
|
|
38
|
+
type: 'string',
|
|
39
|
+
validate: (value) => !value || isIsoDate(value),
|
|
40
|
+
})
|
|
41
|
+
.addAttribute('publishedAt', {
|
|
42
|
+
type: 'string',
|
|
43
|
+
validate: (value) => !value || isIsoDate(value),
|
|
44
|
+
})
|
|
45
|
+
.addAttribute('changeDetails', {
|
|
46
|
+
type: 'any',
|
|
47
|
+
required: true,
|
|
48
|
+
validate: (value) => isNonEmptyObject(value),
|
|
49
|
+
})
|
|
50
|
+
.addAttribute('status', {
|
|
51
|
+
type: Object.values(FixEntity.STATUSES),
|
|
52
|
+
required: true,
|
|
53
|
+
default: FixEntity.STATUSES.PENDING,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export default schema.build();
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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 {
|
|
14
|
+
BaseCollection,
|
|
15
|
+
BaseModel, MultiStatusCreateResult, Opportunity, Suggestion,
|
|
16
|
+
} from '../index';
|
|
17
|
+
|
|
18
|
+
export interface FixEntity extends BaseModel {
|
|
19
|
+
getChangeDetails(): object;
|
|
20
|
+
getExecutedBy(): string;
|
|
21
|
+
getExecutedAt(): string;
|
|
22
|
+
getPublishedAt(): string;
|
|
23
|
+
addSuggestions(suggestions: object[]): Promise<MultiStatusCreateResult<Suggestion>>;
|
|
24
|
+
getSuggestions(): Promise<Suggestion>;
|
|
25
|
+
getOpportunityId(): string;
|
|
26
|
+
getOpportunity(): Promise<Opportunity>;
|
|
27
|
+
getStatus(): string;
|
|
28
|
+
getType(): string;
|
|
29
|
+
setChangeDetails(changeDetails: object): FixEntity;
|
|
30
|
+
setType(rank: number): FixEntity;
|
|
31
|
+
setStatus(status: string): FixEntity;
|
|
32
|
+
setExecutedBy(executedBy: string): FixEntity;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface FixEntityCollection extends BaseCollection<FixEntity> {
|
|
36
|
+
allByOpportunityId(opportunityId: string): Promise<FixEntity[]>;
|
|
37
|
+
allByOpportunityIdAndStatus(opportunityId: string, status: string): Promise<FixEntity[]>;
|
|
38
|
+
findByOpportunityId(opportunityId: string): Promise<FixEntity | null>;
|
|
39
|
+
findByOpportunityIdAndStatus(opportunityId: string, status: string): Promise<FixEntity | null>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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 FixEntity from './fix-entity.model.js';
|
|
14
|
+
import FixEntityCollection from './fix-entity.collection.js';
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
FixEntity,
|
|
18
|
+
FixEntityCollection,
|
|
19
|
+
};
|
package/src/models/index.d.ts
CHANGED
package/src/models/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './api-key/index.js';
|
|
|
14
14
|
export * from './audit/index.js';
|
|
15
15
|
export * from './base/index.js';
|
|
16
16
|
export * from './configuration/index.js';
|
|
17
|
+
export * from './fix-entity/index.js';
|
|
17
18
|
export * from './experiment/index.js';
|
|
18
19
|
export * from './import-job/index.js';
|
|
19
20
|
export * from './import-url/index.js';
|
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type {
|
|
14
|
-
Audit, BaseCollection, BaseModel, MultiStatusCreateResult, Site, Suggestion,
|
|
14
|
+
Audit, BaseCollection, BaseModel, FixEntity, MultiStatusCreateResult, Site, Suggestion,
|
|
15
15
|
} from '../index';
|
|
16
16
|
|
|
17
17
|
export interface Opportunity extends BaseModel {
|
|
18
18
|
addSuggestions(suggestions: object[]): Promise<MultiStatusCreateResult<Suggestion>>;
|
|
19
|
+
addFixEntities(fixEntities: object[]): Promise<MultiStatusCreateResult<FixEntity>>;
|
|
19
20
|
getAudit(): Promise<Audit>;
|
|
20
21
|
getAuditId(): string;
|
|
21
22
|
getData(): object;
|
|
@@ -26,6 +27,7 @@ export interface Opportunity extends BaseModel {
|
|
|
26
27
|
getSite(): Promise<Site>;
|
|
27
28
|
getSiteId(): string;
|
|
28
29
|
getStatus(): string;
|
|
30
|
+
getFixEntities(): Promise<FixEntity[]>;
|
|
29
31
|
getSuggestions(): Promise<Suggestion[]>;
|
|
30
32
|
getSuggestionsByStatus(status: string): Promise<Suggestion[]>;
|
|
31
33
|
getSuggestionsByStatusAndRank(status: string, rank: string): Promise<Suggestion[]>;
|
|
@@ -55,6 +55,27 @@ class Opportunity extends BaseModel {
|
|
|
55
55
|
.getCollection('SuggestionCollection')
|
|
56
56
|
.createMany(childSuggestions, this);
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Adds the given fixEntities to this Opportunity. Sets this opportunity as the parent
|
|
61
|
+
* of each fixEntity, as such the opportunity ID does not need to be provided.
|
|
62
|
+
*
|
|
63
|
+
* @async
|
|
64
|
+
* @param {Array<Object>} fixEntities - An array of fixEntities objects to add.
|
|
65
|
+
* @return {Promise<{ createdItems: BaseModel[],
|
|
66
|
+
* errorItems: { item: Object, error: ValidationError }[] }>} - A promise that
|
|
67
|
+
* resolves to an object containing the created fixEntities items and any
|
|
68
|
+
* errors that occurred.
|
|
69
|
+
*/
|
|
70
|
+
async addFixEntities(fixEntities) {
|
|
71
|
+
const childFixEntities = fixEntities.map((fixEntity) => ({
|
|
72
|
+
...fixEntity,
|
|
73
|
+
[this.idName]: this.getId(),
|
|
74
|
+
}));
|
|
75
|
+
return this.entityRegistry
|
|
76
|
+
.getCollection('FixEntityCollection')
|
|
77
|
+
.createMany(childFixEntities, this);
|
|
78
|
+
}
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
export default Opportunity;
|
|
@@ -29,6 +29,7 @@ const schema = new SchemaBuilder(Opportunity, OpportunityCollection)
|
|
|
29
29
|
.addReference('belongs_to', 'Audit', ['updatedAt'], { required: false })
|
|
30
30
|
.addReference('belongs_to', 'LatestAudit', ['updatedAt'], { required: false })
|
|
31
31
|
.addReference('has_many', 'Suggestions', ['updatedAt'], { removeDependents: true })
|
|
32
|
+
.addReference('has_many', 'FixEntities', ['updatedAt'], { removeDependents: true })
|
|
32
33
|
.addAttribute('runbook', {
|
|
33
34
|
type: 'string',
|
|
34
35
|
validate: (value) => !value || isValidUrl(value),
|
|
@@ -17,6 +17,8 @@ export interface Suggestion extends BaseModel {
|
|
|
17
17
|
getKpiDeltas(): object;
|
|
18
18
|
getOpportunity(): Promise<Opportunity>;
|
|
19
19
|
getOpportunityId(): string;
|
|
20
|
+
getFixEntityId(): string;
|
|
21
|
+
getFixEntity(): Promise<object>;
|
|
20
22
|
getRank(): number;
|
|
21
23
|
getStatus(): string;
|
|
22
24
|
getType(): string;
|
|
@@ -29,6 +31,7 @@ export interface Suggestion extends BaseModel {
|
|
|
29
31
|
|
|
30
32
|
export interface SuggestionCollection extends BaseCollection<Suggestion> {
|
|
31
33
|
allByOpportunityId(opportunityId: string): Promise<Suggestion[]>;
|
|
34
|
+
allByFixEntityId(fixEntityId: string): Promise<Suggestion[]>;
|
|
32
35
|
allByOpportunityIdAndStatus(opportunityId: string, status: string): Promise<Suggestion[]>;
|
|
33
36
|
bulkUpdateStatus(suggestions: Suggestion[], status: string): Promise<Suggestion[]>;
|
|
34
37
|
findByOpportunityId(opportunityId: string): Promise<Suggestion | null>;
|
|
@@ -26,6 +26,7 @@ Indexes Doc: https://electrodb.dev/en/modeling/indexes/
|
|
|
26
26
|
|
|
27
27
|
const schema = new SchemaBuilder(Suggestion, SuggestionCollection)
|
|
28
28
|
.addReference('belongs_to', 'Opportunity', ['status', 'rank'])
|
|
29
|
+
.addReference('belongs_to', 'FixEntity', ['updatedAt'], { required: false })
|
|
29
30
|
.addAttribute('type', {
|
|
30
31
|
type: Object.values(Suggestion.TYPES),
|
|
31
32
|
required: true,
|