@autofleet/sadot 1.0.0-beta.0 → 1.0.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/README.md +5 -0
- package/dist/api/index.d.ts +2 -1
- package/dist/api/index.js +3 -2
- package/dist/api/v1/definition/index.d.ts +2 -1
- package/dist/api/v1/definition/index.js +12 -14
- package/dist/api/v1/definition/validations.js +14 -12
- package/dist/api/v1/errors.d.ts +3 -1
- package/dist/api/v1/errors.js +1 -4
- package/dist/api/v1/index.d.ts +2 -1
- package/dist/api/v1/index.js +5 -2
- package/dist/api/v1/validator/index.d.ts +3 -0
- package/dist/api/v1/validator/index.js +143 -0
- package/dist/api/v1/validator/validations.d.ts +6 -0
- package/dist/api/v1/validator/validations.js +40 -0
- package/dist/errors/index.d.ts +9 -1
- package/dist/errors/index.js +25 -4
- package/dist/events/index.d.ts +2 -1
- package/dist/events/index.js +17 -11
- package/dist/hooks/create.d.ts +2 -2
- package/dist/hooks/create.js +40 -19
- package/dist/hooks/enrich.d.ts +20 -2
- package/dist/hooks/enrich.js +88 -16
- package/dist/hooks/hooks.d.ts +17 -0
- package/dist/hooks/hooks.js +379 -0
- package/dist/hooks/index.d.ts +2 -3
- package/dist/hooks/index.js +6 -7
- package/dist/hooks/update.d.ts +2 -2
- package/dist/hooks/update.js +16 -26
- package/dist/hooks/utils/updateInstanceValues.d.ts +15 -0
- package/dist/hooks/utils/updateInstanceValues.js +50 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +19 -6
- package/dist/models/CustomFieldDefinition.d.ts +1 -0
- package/dist/models/CustomFieldDefinition.js +10 -2
- package/dist/models/CustomFieldEntries.d.ts +15 -0
- package/dist/models/CustomFieldEntries.js +123 -0
- package/dist/models/CustomFieldValue.d.ts +3 -2
- package/dist/models/CustomFieldValue.js +22 -14
- package/dist/models/CustomValidator.d.ts +17 -0
- package/dist/models/CustomValidator.js +98 -0
- package/dist/models/index.d.ts +10 -2
- package/dist/models/index.js +60 -22
- package/dist/repository/definition.d.ts +23 -7
- package/dist/repository/definition.js +36 -7
- package/dist/repository/entries.d.ts +13 -0
- package/dist/repository/entries.js +92 -0
- package/dist/repository/utils/formatValues.d.ts +3 -0
- package/dist/repository/utils/formatValues.js +16 -0
- package/dist/repository/validator.d.ts +21 -0
- package/dist/repository/validator.js +62 -0
- package/dist/repository/value.d.ts +1 -1
- package/dist/repository/value.js +7 -32
- package/dist/scopes/filter.d.ts +5 -22
- package/dist/scopes/filter.js +18 -65
- package/dist/scopes/helpers/filter.helpers.d.ts +42 -0
- package/dist/scopes/helpers/filter.helpers.js +204 -0
- package/dist/tests/api/test-api.js +6 -24
- package/dist/tests/helpers/commonHooks.d.ts +6 -0
- package/dist/tests/helpers/commonHooks.js +62 -0
- package/dist/tests/helpers/database-config.js +1 -1
- package/dist/tests/helpers/index.d.ts +6 -1
- package/dist/tests/helpers/index.js +15 -2
- package/dist/tests/mocks/definition.mock.d.ts +5 -2
- package/dist/tests/mocks/definition.mock.js +10 -1
- package/dist/tests/mocks/events.mock.d.ts +1 -0
- package/dist/tests/mocks/events.mock.js +4 -2
- package/dist/types/definition/index.d.ts +1 -0
- package/dist/types/entries/index.d.ts +25 -0
- package/dist/types/entries/index.js +2 -0
- package/dist/types/index.d.ts +19 -3
- package/dist/utils/constants/index.d.ts +1 -1
- package/dist/utils/helpers/index.d.ts +4 -3
- package/dist/utils/helpers/index.js +22 -30
- package/dist/utils/init.d.ts +5 -3
- package/dist/utils/init.js +13 -11
- package/dist/utils/logger/index.d.ts +1 -0
- package/dist/utils/logger/index.js +34 -0
- package/dist/utils/validations/index.d.ts +7 -1
- package/dist/utils/validations/index.js +28 -7
- package/dist/utils/validations/schema/validator-schema.d.ts +9 -0
- package/dist/utils/validations/schema/validator-schema.js +95 -0
- package/dist/utils/validations/type.d.ts +2 -1
- package/dist/utils/validations/validators/index.js +9 -9
- package/dist/utils/validations/validators/select.validator.js +5 -2
- package/dist/utils/validations/validators/status.validator.js +8 -2
- package/package.json +28 -12
- package/src/api/index.ts +3 -2
- package/src/api/v1/definition/index.ts +20 -23
- package/src/api/v1/definition/validations.ts +16 -16
- package/src/api/v1/errors.ts +4 -7
- package/src/api/v1/index.ts +5 -3
- package/src/api/v1/validator/index.ts +141 -0
- package/src/api/v1/validator/validations.ts +39 -0
- package/src/errors/index.ts +31 -3
- package/src/events/index.ts +25 -13
- package/src/hooks/create.ts +50 -28
- package/src/hooks/enrich.ts +137 -28
- package/src/hooks/hooks.ts +467 -0
- package/src/hooks/index.ts +10 -5
- package/src/hooks/update.ts +20 -7
- package/src/hooks/utils/updateInstanceValues.ts +63 -0
- package/src/index.ts +10 -8
- package/src/models/CustomFieldDefinition.ts +9 -2
- package/src/models/CustomFieldEntries.ts +81 -0
- package/src/models/CustomFieldValue.ts +25 -17
- package/src/models/CustomValidator.ts +78 -0
- package/src/models/index.ts +83 -25
- package/src/repository/definition.ts +62 -14
- package/src/repository/entries.ts +88 -0
- package/src/repository/utils/formatValues.ts +14 -0
- package/src/repository/validator.ts +104 -0
- package/src/repository/value.ts +5 -35
- package/src/scopes/filter.ts +33 -106
- package/src/scopes/helpers/filter.helpers.ts +227 -0
- package/src/tests/api/test-api.ts +4 -2
- package/src/tests/helpers/commonHooks.ts +43 -0
- package/src/tests/helpers/database-config.ts +1 -1
- package/src/tests/helpers/index.ts +18 -2
- package/src/tests/mocks/definition.mock.ts +18 -9
- package/src/tests/mocks/events.mock.ts +4 -1
- package/src/types/definition/index.ts +1 -0
- package/src/types/entries/index.ts +27 -0
- package/src/types/index.ts +20 -3
- package/src/utils/helpers/index.ts +28 -35
- package/src/utils/init.ts +17 -12
- package/src/utils/logger/index.ts +9 -0
- package/src/utils/validations/index.ts +30 -6
- package/src/utils/validations/schema/README.md +93 -0
- package/src/utils/validations/schema/validator-schema.ts +106 -0
- package/src/utils/validations/type.ts +2 -1
- package/src/utils/validations/validators/index.ts +9 -9
- package/src/utils/validations/validators/select.validator.ts +3 -2
- package/src/utils/validations/validators/status.validator.ts +6 -2
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +1 -1
package/dist/models/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.initTestModels = exports.initTables = exports.ContextTestModel = exports.ContextAwareTestModel = exports.AssociatedTestModel = exports.TestModel = exports.CustomFieldDefinition = exports.CustomFieldValue = void 0;
|
|
6
|
+
exports.initTestModels = exports.initTables = exports.ContextTestModel = exports.ContextAwareTestModel = exports.AssociatedTestModel = exports.TestModel = exports.CustomValidator = exports.CustomFieldEntries = exports.CustomFieldDefinition = exports.CustomFieldValue = void 0;
|
|
7
7
|
/* eslint-disable no-param-reassign */
|
|
8
8
|
const sequelize_1 = require("sequelize");
|
|
9
9
|
const logger_1 = __importDefault(require("../utils/logger"));
|
|
@@ -19,33 +19,55 @@ const ContextTestModel_1 = __importDefault(require("./tests/contextAwareModels/C
|
|
|
19
19
|
exports.ContextTestModel = ContextTestModel_1.default;
|
|
20
20
|
const AssociatedTestModel_1 = __importDefault(require("./tests/AssociatedTestModel"));
|
|
21
21
|
exports.AssociatedTestModel = AssociatedTestModel_1.default;
|
|
22
|
-
const
|
|
22
|
+
const CustomFieldEntries_1 = __importDefault(require("./CustomFieldEntries"));
|
|
23
|
+
exports.CustomFieldEntries = CustomFieldEntries_1.default;
|
|
24
|
+
const CustomValidator_1 = __importDefault(require("./CustomValidator"));
|
|
25
|
+
exports.CustomValidator = CustomValidator_1.default;
|
|
26
|
+
const productionModels = [CustomFieldDefinition_1.default, CustomFieldValue_1.default, CustomValidator_1.default];
|
|
23
27
|
const testModels = [TestModel_1.default, AssociatedTestModel_1.default, ContextAwareTestModel_1.default, ContextTestModel_1.default];
|
|
24
28
|
const SADOT_MIGRATION_PREFIX = 'sadot-migration';
|
|
25
|
-
const SCHEMA_VERSION =
|
|
26
|
-
const
|
|
27
|
-
const
|
|
29
|
+
const SCHEMA_VERSION = '49c9dd1d-b1cc-445b-a911-fd349d783110';
|
|
30
|
+
const initTables = async (sequelize, getUser, { schemaPrefix = SADOT_MIGRATION_PREFIX, schemaVersion = SCHEMA_VERSION, useCustomFieldsEntries = false, } = {}) => {
|
|
31
|
+
const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;
|
|
28
32
|
logger_1.default.info('custom-fields: initialize custom-fields tables');
|
|
29
33
|
// Detect models and import them to the orm
|
|
30
34
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
31
35
|
if (!sequelize.addModels) {
|
|
32
36
|
throw new Error('sequelize instance must have addModels function');
|
|
33
37
|
}
|
|
38
|
+
if (useCustomFieldsEntries) {
|
|
39
|
+
productionModels.push(CustomFieldEntries_1.default);
|
|
40
|
+
}
|
|
34
41
|
sequelize.addModels(productionModels);
|
|
35
42
|
CustomFieldDefinition_1.default.addScope('userScope', () => {
|
|
36
43
|
const user = getUser();
|
|
37
|
-
if (user?.permissions) {
|
|
38
|
-
return {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
if (!user?.permissions) {
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
where: {
|
|
49
|
+
entityId: [
|
|
50
|
+
...Object.keys(user.permissions.fleets),
|
|
51
|
+
...Object.keys(user.permissions.businessModels),
|
|
52
|
+
...Object.keys(user.permissions.demandSources),
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
CustomValidator_1.default.addScope('userScope', () => {
|
|
58
|
+
const user = getUser();
|
|
59
|
+
if (!user?.permissions) {
|
|
60
|
+
return {};
|
|
47
61
|
}
|
|
48
|
-
return {
|
|
62
|
+
return {
|
|
63
|
+
where: {
|
|
64
|
+
entityId: [
|
|
65
|
+
...Object.keys(user.permissions.fleets),
|
|
66
|
+
...Object.keys(user.permissions.businessModels),
|
|
67
|
+
...Object.keys(user.permissions.demandSources),
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
};
|
|
49
71
|
});
|
|
50
72
|
logger_1.default.info('custom-fields: models added');
|
|
51
73
|
const SequelizeMeta = sequelize.define('SequelizeMeta', {
|
|
@@ -61,15 +83,31 @@ const initTables = async (sequelize, getUser) => {
|
|
|
61
83
|
timestamps: false,
|
|
62
84
|
schema: 'public',
|
|
63
85
|
});
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
86
|
+
logger_1.default.info('custom-fields: starting migrations');
|
|
87
|
+
const migrations = await SequelizeMeta.findAll({ where: { name: { [sequelize_1.Op.like]: `${schemaPrefix}%` } }, raw: true });
|
|
88
|
+
const currentSadotSchemaVersion = migrations.at(-1);
|
|
89
|
+
const expectedSchemaVersionIndex = migrations.findIndex((m) => m.name === CUSTOM_FIELDS_SCHEMA_VERSION);
|
|
90
|
+
logger_1.default.info('custom-fields: migrations', { migrations, currentSadotSchemaVersion, expectedSchemaVersionIndex });
|
|
91
|
+
if (!currentSadotSchemaVersion || currentSadotSchemaVersion.name !== CUSTOM_FIELDS_SCHEMA_VERSION) {
|
|
92
|
+
logger_1.default.info('custom-fields: syncing models');
|
|
69
93
|
await CustomFieldDefinition_1.default.sync({ alter: true });
|
|
70
94
|
await CustomFieldValue_1.default.sync({ alter: true });
|
|
71
|
-
|
|
95
|
+
// T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS
|
|
96
|
+
if (useCustomFieldsEntries) {
|
|
97
|
+
await CustomFieldEntries_1.default.sync({ alter: true });
|
|
98
|
+
}
|
|
99
|
+
// Always sync CustomValidator
|
|
100
|
+
await CustomValidator_1.default.sync({ alter: true });
|
|
101
|
+
if (expectedSchemaVersionIndex === -1) {
|
|
102
|
+
await SequelizeMeta.create({ name: CUSTOM_FIELDS_SCHEMA_VERSION });
|
|
103
|
+
}
|
|
72
104
|
logger_1.default.info('custom-fields: models synced');
|
|
105
|
+
if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {
|
|
106
|
+
// We have existing migrations, and we are calling `sync`.
|
|
107
|
+
// This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.
|
|
108
|
+
const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);
|
|
109
|
+
await SequelizeMeta.destroy({ where: { name: { [sequelize_1.Op.in]: migrationsToDelete.map((m) => m.name) } } });
|
|
110
|
+
}
|
|
73
111
|
}
|
|
74
112
|
};
|
|
75
113
|
exports.initTables = initTables;
|
|
@@ -1,20 +1,36 @@
|
|
|
1
|
-
import { type FindOptions, type WhereOptions } from 'sequelize';
|
|
2
|
-
import { CustomFieldDefinition } from '../models';
|
|
1
|
+
import { type Includeable, type Transaction, type FindOptions, type WhereOptions } from 'sequelize';
|
|
2
|
+
import { CustomFieldDefinition, type CustomFieldEntries } from '../models';
|
|
3
3
|
import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
|
|
4
4
|
import type { ModelOptions } from '../types';
|
|
5
5
|
export declare const create: (data: CreateCustomFieldDefinition) => Promise<CustomFieldDefinition>;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
interface SadotFindOptions {
|
|
7
|
+
withDisabled?: boolean;
|
|
8
|
+
transaction?: Transaction;
|
|
9
|
+
include?: Includeable | Includeable[];
|
|
10
|
+
}
|
|
11
|
+
type SadotGetDefinitionsByEntityIdsOptions = FindOptions & {
|
|
12
|
+
modelOptions?: ModelOptions;
|
|
13
|
+
} & Pick<SadotFindOptions, 'withDisabled'>;
|
|
14
|
+
export declare const findAll: (where: WhereOptions, options?: SadotFindOptions) => Promise<CustomFieldDefinition[]>;
|
|
15
|
+
export declare const findByIds: (ids: string[], options?: SadotFindOptions) => Promise<CustomFieldDefinition[]>;
|
|
16
|
+
export declare const findById: (id: string, options?: Pick<SadotFindOptions, 'withDisabled'>) => Promise<CustomFieldDefinition | null>;
|
|
9
17
|
export declare const findByEntityIds: (modelType: string, entityIds: string[], options?: FindOptions & {
|
|
10
18
|
modelOptions?: ModelOptions;
|
|
11
19
|
}) => Promise<CustomFieldDefinition[]>;
|
|
12
20
|
export declare const findByWhere: (where: any) => Promise<CustomFieldDefinition | null>;
|
|
13
21
|
export declare const findDefinitionsByModels: (modelTypes: string[], options?: any) => Promise<CustomFieldDefinition[]>;
|
|
14
22
|
export declare const update: (id: string, data: UpdateCustomFieldDefinition) => Promise<CustomFieldDefinition>;
|
|
15
|
-
export declare const disable: (id: string) => Promise<
|
|
16
|
-
export declare const destroy: (id: string) => Promise<
|
|
23
|
+
export declare const disable: (id: string) => Promise<[affectedCount: number]>;
|
|
24
|
+
export declare const destroy: (id: string) => Promise<number>;
|
|
17
25
|
/**
|
|
18
26
|
* Return the names of the required fields for a given model
|
|
19
27
|
*/
|
|
20
28
|
export declare const getRequiredFields: (modelType: string, modelId: string | string[], entityId: string | string[], modelOptions?: ModelOptions) => Promise<string[]>;
|
|
29
|
+
/**
|
|
30
|
+
* @returns A promise resolving with a dictionary of custom field definitions by name.
|
|
31
|
+
* @throws A {@link MissingDefinitionError} if any of the custom fields doesn't have a definition.
|
|
32
|
+
*/
|
|
33
|
+
export declare const getCustomFieldDefinitionsDictionary: (instances: CustomFieldEntries[], options?: SadotGetDefinitionsByEntityIdsOptions) => Promise<{
|
|
34
|
+
[definitionName: string]: CustomFieldDefinition;
|
|
35
|
+
}>;
|
|
36
|
+
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRequiredFields = exports.destroy = exports.disable = exports.update = exports.findDefinitionsByModels = exports.findByWhere = exports.findByEntityIds = exports.findById = exports.findByIds = exports.findAll = exports.create = void 0;
|
|
3
|
+
exports.getCustomFieldDefinitionsDictionary = exports.getRequiredFields = exports.destroy = exports.disable = exports.update = exports.findDefinitionsByModels = exports.findByWhere = exports.findByEntityIds = exports.findById = exports.findByIds = exports.findAll = exports.create = void 0;
|
|
4
4
|
const sequelize_1 = require("sequelize");
|
|
5
5
|
const models_1 = require("../models");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
6
7
|
const create = (data) => models_1.CustomFieldDefinition.create(data);
|
|
7
8
|
exports.create = create;
|
|
8
9
|
const findAll = (where, options = { withDisabled: false }) => {
|
|
@@ -31,10 +32,8 @@ const findByEntityIds = async (modelType, entityIds, options = {}) => {
|
|
|
31
32
|
const { include, useEntityIdFromInclude } = options.modelOptions;
|
|
32
33
|
const where = {
|
|
33
34
|
modelType,
|
|
35
|
+
...(!useEntityIdFromInclude && { entityId: { [sequelize_1.Op.in]: entityIds } }),
|
|
34
36
|
};
|
|
35
|
-
if (!useEntityIdFromInclude) {
|
|
36
|
-
where.entityId = entityIds;
|
|
37
|
-
}
|
|
38
37
|
return models_1.CustomFieldDefinition.findAll({
|
|
39
38
|
where,
|
|
40
39
|
transaction: options.transaction,
|
|
@@ -77,10 +76,8 @@ const getRequiredFields = async (modelType, modelId, entityId, modelOptions = {}
|
|
|
77
76
|
const where = {
|
|
78
77
|
modelType,
|
|
79
78
|
required: true,
|
|
79
|
+
...(!useEntityIdFromInclude && { entityId: { [sequelize_1.Op.in]: entityIds } }),
|
|
80
80
|
};
|
|
81
|
-
if (!useEntityIdFromInclude) {
|
|
82
|
-
where.entityId = entityIds;
|
|
83
|
-
}
|
|
84
81
|
const requiredFields = await models_1.CustomFieldDefinition.findAll({
|
|
85
82
|
where,
|
|
86
83
|
include: include?.(entityIds),
|
|
@@ -90,3 +87,35 @@ const getRequiredFields = async (modelType, modelId, entityId, modelOptions = {}
|
|
|
90
87
|
return [...new Set(requiredFieldsNames)];
|
|
91
88
|
};
|
|
92
89
|
exports.getRequiredFields = getRequiredFields;
|
|
90
|
+
/**
|
|
91
|
+
* @returns A promise resolving with a dictionary of custom field definitions by name.
|
|
92
|
+
* @throws A {@link MissingDefinitionError} if any of the custom fields doesn't have a definition.
|
|
93
|
+
*/
|
|
94
|
+
const getCustomFieldDefinitionsDictionary = async (instances, options = { withDisabled: false, modelOptions: {} }) => {
|
|
95
|
+
const { modelType } = instances[0]?.dataValues ?? {};
|
|
96
|
+
const customFields = new Set();
|
|
97
|
+
const modelIds = [];
|
|
98
|
+
const entityIds = new Set();
|
|
99
|
+
instances.forEach((instance) => {
|
|
100
|
+
const { dataValues: { modelId, entityId, customFields: instanceCustomFields } } = instance;
|
|
101
|
+
modelIds.push(modelId);
|
|
102
|
+
entityIds.add(entityId);
|
|
103
|
+
Object.keys(instanceCustomFields ?? {}).forEach((fieldName) => {
|
|
104
|
+
customFields.add(fieldName);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
const where = {
|
|
108
|
+
modelType,
|
|
109
|
+
entityId: { [sequelize_1.Op.in]: Array.from(entityIds) },
|
|
110
|
+
name: { [sequelize_1.Op.in]: Array.from(customFields) },
|
|
111
|
+
};
|
|
112
|
+
const definitions = await (0, exports.findAll)(where, { ...options });
|
|
113
|
+
const matchedDefinitions = definitions.filter((def) => customFields.has(def.name));
|
|
114
|
+
const matchedDefinitionsByName = Object.fromEntries(matchedDefinitions.map((definition) => [definition.name, definition]));
|
|
115
|
+
if (!definitions?.length || matchedDefinitions.length !== customFields.size) {
|
|
116
|
+
const unmatchedCustomFields = Array.from(customFields).filter((customField) => !matchedDefinitionsByName[customField]);
|
|
117
|
+
throw new errors_1.MissingDefinitionError(unmatchedCustomFields);
|
|
118
|
+
}
|
|
119
|
+
return matchedDefinitionsByName;
|
|
120
|
+
};
|
|
121
|
+
exports.getCustomFieldDefinitionsDictionary = getCustomFieldDefinitionsDictionary;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FindOptions, Includeable, Transaction } from 'sequelize';
|
|
2
|
+
import { CustomFieldEntries } from '../models';
|
|
3
|
+
import type { ModelOptions } from '../types';
|
|
4
|
+
type CustomFieldEntriesModelOptions = ModelOptions & {
|
|
5
|
+
include?: Includeable;
|
|
6
|
+
transaction?: Transaction;
|
|
7
|
+
};
|
|
8
|
+
export declare const findEntriesByModelId: (modelId: string, options?: CustomFieldEntriesModelOptions) => Promise<CustomFieldEntries>;
|
|
9
|
+
export declare const findEntriesByModelIds: (modelIds: string[], options?: CustomFieldEntriesModelOptions) => Promise<CustomFieldEntries[]>;
|
|
10
|
+
export declare const updateEntries: (modelId: string, modelType: string, customFields: Record<string, any>, identifiers: string[], options?: FindOptions & {
|
|
11
|
+
modelOptions?: ModelOptions;
|
|
12
|
+
}) => Promise<[CustomFieldEntries, boolean]>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.updateEntries = exports.findEntriesByModelIds = exports.findEntriesByModelId = void 0;
|
|
30
|
+
const models_1 = require("../models");
|
|
31
|
+
const logger_1 = __importDefault(require("../utils/logger"));
|
|
32
|
+
const errors_1 = require("../errors");
|
|
33
|
+
const DefinitionRepo = __importStar(require("./definition"));
|
|
34
|
+
const formatValues_1 = require("./utils/formatValues");
|
|
35
|
+
const findEntriesByModelId = async (modelId, options = {}) => {
|
|
36
|
+
const { transaction } = options;
|
|
37
|
+
return models_1.CustomFieldEntries.findOne({
|
|
38
|
+
where: { modelId },
|
|
39
|
+
transaction,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
exports.findEntriesByModelId = findEntriesByModelId;
|
|
43
|
+
const findEntriesByModelIds = async (modelIds, options = {}) => {
|
|
44
|
+
const { transaction } = options;
|
|
45
|
+
return models_1.CustomFieldEntries.findAll({
|
|
46
|
+
where: { modelId: modelIds },
|
|
47
|
+
transaction,
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
exports.findEntriesByModelIds = findEntriesByModelIds;
|
|
51
|
+
const updateEntries = async (modelId, modelType, customFields, identifiers, options = {}) => {
|
|
52
|
+
const customFieldsNames = Object.keys(customFields);
|
|
53
|
+
logger_1.default.debug(`custom-fields: updating entries for ${modelType} ${modelId}`, {
|
|
54
|
+
customFieldsNames,
|
|
55
|
+
optionsKeys: options ? Object.keys(options) : null,
|
|
56
|
+
customFields,
|
|
57
|
+
identifiers,
|
|
58
|
+
});
|
|
59
|
+
const { modelOptions, transaction } = options;
|
|
60
|
+
const where = {
|
|
61
|
+
modelType,
|
|
62
|
+
name: customFieldsNames,
|
|
63
|
+
...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),
|
|
64
|
+
};
|
|
65
|
+
const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) ?? [];
|
|
66
|
+
const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
|
|
67
|
+
if (fieldDefinitions.length !== customFieldsNames.length) {
|
|
68
|
+
logger_1.default.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names: customFieldsNames, fieldDefinitions });
|
|
69
|
+
const missingDefinitions = customFieldsNames.filter((name) => !fieldDefinitions.some((def) => def.name === name));
|
|
70
|
+
throw new errors_1.MissingDefinitionError(missingDefinitions);
|
|
71
|
+
}
|
|
72
|
+
const disabledNames = disabledDefinitions?.map((def) => def.name) || [];
|
|
73
|
+
const valuesWithDisabledDefinitions = customFieldsNames.filter((name) => disabledNames.includes(name));
|
|
74
|
+
if (valuesWithDisabledDefinitions?.length > 0) {
|
|
75
|
+
logger_1.default.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
|
|
76
|
+
}
|
|
77
|
+
const definitionsByName = Object.fromEntries(fieldDefinitions.map((definition) => [definition.name, definition]));
|
|
78
|
+
// If we need to format the value before we save it
|
|
79
|
+
Object.entries(customFields)
|
|
80
|
+
.filter(([definitionName]) => formatValues_1.formatFunctions[definitionsByName[definitionName].fieldType])
|
|
81
|
+
.forEach(([definitionName, value]) => {
|
|
82
|
+
const { fieldType } = definitionsByName[definitionName];
|
|
83
|
+
customFields[definitionName] = formatValues_1.formatFunctions[fieldType](value);
|
|
84
|
+
});
|
|
85
|
+
return models_1.CustomFieldEntries.upsert({
|
|
86
|
+
modelId,
|
|
87
|
+
entityId: fieldDefinitions[0].entityId,
|
|
88
|
+
modelType,
|
|
89
|
+
customFields,
|
|
90
|
+
}, options);
|
|
91
|
+
};
|
|
92
|
+
exports.updateEntries = updateEntries;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatFunctions = void 0;
|
|
4
|
+
const constants_1 = require("../../utils/constants");
|
|
5
|
+
exports.formatFunctions = {
|
|
6
|
+
[constants_1.CustomFieldDefinitionType.DATE]: (value) => {
|
|
7
|
+
if (value) {
|
|
8
|
+
const date = new Date(value);
|
|
9
|
+
if (date.toString() === 'Invalid Date') {
|
|
10
|
+
throw new Error(`Invalid date value: ${value}`);
|
|
11
|
+
}
|
|
12
|
+
return date.toISOString();
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IncludeOptions, Transactionable } from 'sequelize';
|
|
2
|
+
import { CustomValidator } from '../models';
|
|
3
|
+
export interface FindValidatorOptions extends Transactionable {
|
|
4
|
+
withDisabled?: boolean;
|
|
5
|
+
attributes?: string[];
|
|
6
|
+
raw?: boolean;
|
|
7
|
+
include?: IncludeOptions[];
|
|
8
|
+
}
|
|
9
|
+
export interface ValidatorAttributes {
|
|
10
|
+
entityId: string;
|
|
11
|
+
entityType: string;
|
|
12
|
+
modelType: string;
|
|
13
|
+
schema: CustomValidator['schema'];
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
export declare const create: (validatorAttributes: ValidatorAttributes, options?: Transactionable) => Promise<CustomValidator>;
|
|
18
|
+
export declare const findAll: (where?: {}, options?: FindValidatorOptions) => Promise<CustomValidator[]>;
|
|
19
|
+
export declare const findAllByModelType: (modelType: string, entityId: string, options?: FindValidatorOptions) => Promise<CustomValidator[]>;
|
|
20
|
+
export declare const update: (id: string, updates: Partial<ValidatorAttributes>, options?: Transactionable) => Promise<[number, CustomValidator[]]>;
|
|
21
|
+
export declare const disable: (id: string, options?: Transactionable) => Promise<[number, CustomValidator[]]>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.disable = exports.update = exports.findAllByModelType = exports.findAll = exports.create = void 0;
|
|
7
|
+
const logger_1 = __importDefault(require("../utils/logger"));
|
|
8
|
+
const models_1 = require("../models");
|
|
9
|
+
const create = async (validatorAttributes, options = {}) => {
|
|
10
|
+
logger_1.default.debug('custom-validator - create validator');
|
|
11
|
+
// Use unknown type to bypass TypeScript errors while maintaining compatibility
|
|
12
|
+
const validator = await models_1.CustomValidator.create(validatorAttributes, options);
|
|
13
|
+
return validator;
|
|
14
|
+
};
|
|
15
|
+
exports.create = create;
|
|
16
|
+
const findAll = async (where = {}, options = { withDisabled: false }) => {
|
|
17
|
+
logger_1.default.debug('custom-validator - find all validators');
|
|
18
|
+
const { transaction, withDisabled } = options;
|
|
19
|
+
let validators;
|
|
20
|
+
if (withDisabled) {
|
|
21
|
+
// If withDisabled is true, use unscoped to ignore the default scope that filters disabled items
|
|
22
|
+
// Apply the userScope separately to maintain permission filtering
|
|
23
|
+
validators = await models_1.CustomValidator.unscoped().scope('userScope').findAll({
|
|
24
|
+
where,
|
|
25
|
+
transaction,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Use defaultScope and userScope to filter both disabled and by permissions
|
|
30
|
+
// The defaultScope keeps only non-disabled validators
|
|
31
|
+
validators = await models_1.CustomValidator.scope(['defaultScope', 'userScope']).findAll({
|
|
32
|
+
where,
|
|
33
|
+
transaction,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return validators;
|
|
37
|
+
};
|
|
38
|
+
exports.findAll = findAll;
|
|
39
|
+
const findAllByModelType = async (modelType, entityId, options = { withDisabled: false }) => {
|
|
40
|
+
logger_1.default.debug('custom-validator - find all validators by model type');
|
|
41
|
+
return (0, exports.findAll)({
|
|
42
|
+
modelType,
|
|
43
|
+
...(!options.include && {
|
|
44
|
+
entityId,
|
|
45
|
+
}),
|
|
46
|
+
}, options);
|
|
47
|
+
};
|
|
48
|
+
exports.findAllByModelType = findAllByModelType;
|
|
49
|
+
const update = async (id, updates, options) => {
|
|
50
|
+
logger_1.default.debug('custom-validator - update validator');
|
|
51
|
+
return models_1.CustomValidator.update(updates, {
|
|
52
|
+
where: { id },
|
|
53
|
+
returning: true,
|
|
54
|
+
...options,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
exports.update = update;
|
|
58
|
+
const disable = async (id, options) => {
|
|
59
|
+
logger_1.default.debug('custom-validator - disable validator');
|
|
60
|
+
return (0, exports.update)(id, { disabled: true }, options);
|
|
61
|
+
};
|
|
62
|
+
exports.disable = disable;
|
|
@@ -24,5 +24,5 @@ export declare const findValuesByModelIds: (modelIds: string[], options?: any) =
|
|
|
24
24
|
*/
|
|
25
25
|
export declare const updateValues: (modelType: string, modelId: string, identifiers: string[], valuesToUpdate: ValuesToUpdate, options?: FindOptions & {
|
|
26
26
|
modelOptions?: ModelOptions;
|
|
27
|
-
}
|
|
27
|
+
}) => Promise<CustomFieldValue[]>;
|
|
28
28
|
export declare const deleteValue: (id: string, options?: any) => Promise<any>;
|
package/dist/repository/value.js
CHANGED
|
@@ -31,7 +31,7 @@ const models_1 = require("../models");
|
|
|
31
31
|
const DefinitionRepo = __importStar(require("./definition"));
|
|
32
32
|
const logger_1 = __importDefault(require("../utils/logger"));
|
|
33
33
|
const errors_1 = require("../errors");
|
|
34
|
-
const
|
|
34
|
+
const formatValues_1 = require("./utils/formatValues");
|
|
35
35
|
const findByModelIdAndDefinition = async (modelId, customFieldDefinitionId) => models_1.CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [models_1.CustomFieldDefinition] });
|
|
36
36
|
exports.findByModelIdAndDefinition = findByModelIdAndDefinition;
|
|
37
37
|
const create = async (data, withAssociations = false) => {
|
|
@@ -67,24 +67,12 @@ const findValuesByModelIds = async (modelIds, options) => {
|
|
|
67
67
|
});
|
|
68
68
|
};
|
|
69
69
|
exports.findValuesByModelIds = findValuesByModelIds;
|
|
70
|
-
const formatFunctions = {
|
|
71
|
-
[constants_1.CustomFieldDefinitionType.DATE]: (value) => {
|
|
72
|
-
if (value) {
|
|
73
|
-
const date = new Date(value);
|
|
74
|
-
if (date.toString() === 'Invalid Date') {
|
|
75
|
-
throw new Error(`Invalid date value: ${value}`);
|
|
76
|
-
}
|
|
77
|
-
return date.toISOString();
|
|
78
|
-
}
|
|
79
|
-
return null;
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
70
|
/**
|
|
83
71
|
* Try to update custom field values for a model instance.
|
|
84
72
|
* Create new value record if not exists, but fails if value's definition not exist.
|
|
85
73
|
* Return the updated values
|
|
86
74
|
*/
|
|
87
|
-
const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}
|
|
75
|
+
const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}) => {
|
|
88
76
|
const names = Object.keys(valuesToUpdate);
|
|
89
77
|
logger_1.default.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {
|
|
90
78
|
names,
|
|
@@ -96,11 +84,9 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
|
|
|
96
84
|
const where = {
|
|
97
85
|
modelType,
|
|
98
86
|
name: names,
|
|
87
|
+
...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),
|
|
99
88
|
};
|
|
100
|
-
|
|
101
|
-
where.entityId = identifiers;
|
|
102
|
-
}
|
|
103
|
-
const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) || [];
|
|
89
|
+
const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) ?? [];
|
|
104
90
|
const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
|
|
105
91
|
if (fieldDefinitions.length !== names.length) {
|
|
106
92
|
logger_1.default.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });
|
|
@@ -112,28 +98,17 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
|
|
|
112
98
|
if (valuesWithDisabledDefinitions?.length > 0) {
|
|
113
99
|
logger_1.default.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
|
|
114
100
|
}
|
|
115
|
-
const visitedFields = new Set();
|
|
116
101
|
const values = names.map((name) => {
|
|
117
102
|
const fieldDefinition = fieldDefinitions.find((def) => def.name === name);
|
|
118
|
-
|
|
119
|
-
const
|
|
103
|
+
const formatFunction = formatValues_1.formatFunctions[fieldDefinition.fieldType];
|
|
104
|
+
const value = formatFunction ? formatFunction(valuesToUpdate[name]) : valuesToUpdate[name];
|
|
120
105
|
return {
|
|
121
106
|
modelId,
|
|
122
|
-
value: (formatFunction ? formatFunction(valuesToUpdate[name]) : valuesToUpdate[name]) ?? fieldDefinition.defaultValue,
|
|
123
107
|
updatedAt: new Date(),
|
|
124
108
|
customFieldDefinitionId: fieldDefinition.id,
|
|
109
|
+
value: value !== undefined ? value : fieldDefinition.defaultValue,
|
|
125
110
|
};
|
|
126
111
|
});
|
|
127
|
-
if (defineAllDefaults) {
|
|
128
|
-
fieldDefinitions.filter((def) => !visitedFields.has(def) && ![null, undefined].includes(def.defaultValue)).forEach(({ id, defaultValue }) => {
|
|
129
|
-
values.push({
|
|
130
|
-
modelId,
|
|
131
|
-
value: defaultValue,
|
|
132
|
-
updatedAt: new Date(),
|
|
133
|
-
customFieldDefinitionId: id,
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
112
|
return Promise.all(values.map(async (value) => {
|
|
138
113
|
const [cfv] = await models_1.CustomFieldValue.upsert(value, {
|
|
139
114
|
transaction: options.transaction,
|
package/dist/scopes/filter.d.ts
CHANGED
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
* Type representing possible condition values.
|
|
4
|
-
* Currently supporting strings and arrays of strings.
|
|
5
|
-
* More types to be added (TBA).
|
|
6
|
-
*/
|
|
7
|
-
type ConditionWithOperator = {
|
|
8
|
-
operator: string;
|
|
9
|
-
value: string;
|
|
10
|
-
};
|
|
11
|
-
export type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
|
|
12
|
-
export type CustomFieldSort = {
|
|
13
|
-
field: string;
|
|
14
|
-
direction: 'ASC' | 'DESC';
|
|
15
|
-
};
|
|
16
|
-
export type CustomFieldFilterOptions = {
|
|
17
|
-
where?: WhereOptions;
|
|
18
|
-
replacements?: Record<string, string>;
|
|
19
|
-
};
|
|
1
|
+
import type { CustomFieldOptions } from '../types';
|
|
2
|
+
import { type ConditionValue, type CustomFieldFilterOptions } from './helpers/filter.helpers';
|
|
20
3
|
type customFieldsFilterScopeParams = {
|
|
21
4
|
replacementsMap: Record<string, string>;
|
|
22
5
|
scopeValue: Record<string, ConditionValue>;
|
|
@@ -28,9 +11,9 @@ type customFieldsFilterScopeParams = {
|
|
|
28
11
|
* @param name - The model type name used to join custom_field_definitions.
|
|
29
12
|
* @returns A function that takes conditions and returns the Sequelize options object.
|
|
30
13
|
*/
|
|
31
|
-
export declare const customFieldsFilterScope: (name: string) => ({ replacementsMap: replacements, scopeValue: conditions
|
|
32
|
-
export declare const scopeName
|
|
33
|
-
export declare const customFieldsSortScope: (name: string) => ({ replacementsMap, scopeValue: sort }: {
|
|
14
|
+
export declare const customFieldsFilterScope: (name: string, options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>) => ({ replacementsMap: replacements, scopeValue: conditions }: customFieldsFilterScopeParams) => CustomFieldFilterOptions;
|
|
15
|
+
export declare const scopeName: "filterByCustomFields";
|
|
16
|
+
export declare const customFieldsSortScope: (name: string, options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>) => ({ replacementsMap, scopeValue: sort }: {
|
|
34
17
|
replacementsMap: any;
|
|
35
18
|
scopeValue: any;
|
|
36
19
|
}) => {
|