@autofleet/sadot 0.0.1-beta → 0.0.1-beta.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/dist/{src/api → api}/index.js +1 -0
- package/dist/api/index.js.map +1 -0
- package/dist/{src/api → api}/v1/definition/index.js +28 -25
- package/dist/api/v1/definition/index.js.map +1 -0
- package/dist/api/v1/definition/validations.js +36 -0
- package/dist/api/v1/definition/validations.js.map +1 -0
- package/dist/{src/api → api}/v1/errors.js +1 -0
- package/dist/api/v1/errors.js.map +1 -0
- package/dist/{src/api → api}/v1/index.js +2 -1
- package/dist/api/v1/index.js.map +1 -0
- package/dist/{src/events → events}/index.js +2 -21
- package/dist/events/index.js.map +1 -0
- package/dist/{src/hooks → hooks}/create.js +18 -15
- package/dist/hooks/create.js.map +1 -0
- package/dist/{src/hooks/enrich.js → hooks/find.js} +29 -52
- package/dist/hooks/find.js.map +1 -0
- package/dist/{src/hooks → hooks}/index.js +4 -5
- package/dist/hooks/index.js.map +1 -0
- package/dist/{src/hooks → hooks}/update.js +23 -8
- package/dist/hooks/update.js.map +1 -0
- package/dist/{src/hooks → hooks}/workaround.js +15 -5
- package/dist/hooks/workaround.js.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/{src/models → models}/CustomFieldDefinition.js +17 -22
- package/dist/models/CustomFieldDefinition.js.map +1 -0
- package/dist/{src/models → models}/CustomFieldValue.js +39 -24
- package/dist/models/CustomFieldValue.js.map +1 -0
- package/dist/models/index.js +50 -0
- package/dist/models/index.js.map +1 -0
- package/dist/{src/models → models}/tests/AssociatedTestModel.js +1 -0
- package/dist/models/tests/AssociatedTestModel.js.map +1 -0
- package/dist/{src/models → models}/tests/TestModel.js +1 -0
- package/dist/models/tests/TestModel.js.map +1 -0
- package/dist/repository/definition.js +107 -0
- package/dist/repository/definition.js.map +1 -0
- package/dist/{src/repository → repository}/value.js +36 -27
- package/dist/repository/value.js.map +1 -0
- package/dist/{src/tests → tests}/api/test-api.js +22 -12
- package/dist/tests/api/test-api.js.map +1 -0
- package/dist/tests/helpers/index.js +28 -0
- package/dist/tests/helpers/index.js.map +1 -0
- package/dist/tests/mocks/index.js +60 -0
- package/dist/tests/mocks/index.js.map +1 -0
- package/dist/{src/tests → tests}/mocks/testModel.js +18 -10
- package/dist/tests/mocks/testModel.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/{src/types → types}/definition/index.js +1 -0
- package/dist/types/definition/index.js.map +1 -0
- package/dist/{src/types → types}/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/{src/types → types}/value/index.js +1 -0
- package/dist/types/value/index.js.map +1 -0
- package/dist/{src/utils → utils}/db/index.js +1 -8
- package/dist/utils/db/index.js.map +1 -0
- package/dist/{src/utils → utils}/logger/index.js +2 -2
- package/dist/utils/logger/index.js.map +1 -0
- package/dist/{src/utils → utils}/validations/custom-fields.js +1 -0
- package/dist/utils/validations/custom-fields.js.map +1 -0
- package/dist/utils/validations/custom.js +58 -0
- package/dist/utils/validations/custom.js.map +1 -0
- package/dist/{src/utils → utils}/validations/index.js +1 -0
- package/dist/utils/validations/index.js.map +1 -0
- package/dist/utils/validations/type.js +32 -0
- package/dist/utils/validations/type.js.map +1 -0
- package/package.json +5 -12
- package/src/api/v1/definition/index.ts +13 -20
- package/src/api/v1/definition/validations.ts +27 -13
- package/src/api/v1/index.ts +1 -1
- package/src/events/index.ts +1 -23
- package/src/hooks/create.ts +6 -12
- package/src/hooks/find.ts +82 -23
- package/src/hooks/index.ts +2 -4
- package/src/hooks/update.ts +11 -5
- package/src/hooks/workaround.ts +2 -2
- package/src/index.ts +17 -60
- package/src/models/CustomFieldDefinition.ts +15 -23
- package/src/models/CustomFieldValue.ts +10 -10
- package/src/models/index.ts +17 -79
- package/src/models/tests/AssociatedTestModel.ts +1 -0
- package/src/models/tests/TestModel.ts +1 -0
- package/src/repository/definition.ts +41 -27
- package/src/repository/value.ts +11 -12
- package/src/tests/mocks/events.mock.ts +1 -1
- package/src/tests/mocks/{definition.mock.ts → index.ts} +6 -5
- package/src/tests/mocks/testModel.ts +7 -12
- package/src/types/definition/index.ts +1 -0
- package/src/types/index.ts +6 -4
- package/src/types/value/index.ts +2 -1
- package/src/utils/db/index.ts +0 -7
- package/src/utils/logger/index.ts +1 -3
- package/src/utils/validations/custom.ts +45 -28
- package/src/utils/validations/type.ts +6 -23
- package/tsconfig.json +26 -9
- package/dist/jest.config.d.ts +0 -12
- package/dist/src/api/index.d.ts +0 -2
- package/dist/src/api/v1/definition/index.d.ts +0 -2
- package/dist/src/api/v1/definition/validations.d.ts +0 -2
- package/dist/src/api/v1/definition/validations.js +0 -36
- package/dist/src/api/v1/errors.d.ts +0 -2
- package/dist/src/api/v1/index.d.ts +0 -2
- package/dist/src/errors/index.d.ts +0 -16
- package/dist/src/errors/index.js +0 -45
- package/dist/src/events/index.d.ts +0 -4
- package/dist/src/hooks/create.d.ts +0 -9
- package/dist/src/hooks/enrich.d.ts +0 -5
- package/dist/src/hooks/find.d.ts +0 -1
- package/dist/src/hooks/find.js +0 -29
- package/dist/src/hooks/index.d.ts +0 -6
- package/dist/src/hooks/update.d.ts +0 -9
- package/dist/src/hooks/workaround.d.ts +0 -10
- package/dist/src/index.d.ts +0 -11
- package/dist/src/index.js +0 -105
- package/dist/src/models/CustomFieldDefinition.d.ts +0 -23
- package/dist/src/models/CustomFieldValue.d.ts +0 -15
- package/dist/src/models/index.d.ts +0 -8
- package/dist/src/models/index.js +0 -87
- package/dist/src/models/tests/AssociatedTestModel.d.ts +0 -12
- package/dist/src/models/tests/TestModel.d.ts +0 -11
- package/dist/src/repository/definition.d.ts +0 -17
- package/dist/src/repository/definition.js +0 -80
- package/dist/src/repository/value.d.ts +0 -24
- package/dist/src/tests/api/test-api.d.ts +0 -2
- package/dist/src/tests/helpers/database-config.d.ts +0 -15
- package/dist/src/tests/helpers/database-config.js +0 -16
- package/dist/src/tests/helpers/index.d.ts +0 -2
- package/dist/src/tests/helpers/index.js +0 -18
- package/dist/src/tests/mocks/definition.mock.d.ts +0 -37
- package/dist/src/tests/mocks/definition.mock.js +0 -64
- package/dist/src/tests/mocks/events.mock.d.ts +0 -3
- package/dist/src/tests/mocks/events.mock.js +0 -19
- package/dist/src/tests/mocks/testModel.d.ts +0 -12
- package/dist/src/types/definition/index.d.ts +0 -23
- package/dist/src/types/index.d.ts +0 -13
- package/dist/src/types/value/index.d.ts +0 -15
- package/dist/src/utils/constants/index.d.ts +0 -1
- package/dist/src/utils/constants/index.js +0 -5
- package/dist/src/utils/db/index.d.ts +0 -4
- package/dist/src/utils/logger/index.d.ts +0 -2
- package/dist/src/utils/validations/custom-fields.d.ts +0 -2
- package/dist/src/utils/validations/custom.d.ts +0 -15
- package/dist/src/utils/validations/custom.js +0 -42
- package/dist/src/utils/validations/index.d.ts +0 -2
- package/dist/src/utils/validations/type.d.ts +0 -18
- package/dist/src/utils/validations/type.js +0 -50
- package/dist/src/utils/validations/validators.d.ts +0 -12
- package/dist/src/utils/validations/validators.js +0 -33
- package/src/errors/index.ts +0 -42
- package/src/hooks/enrich.ts +0 -125
- package/src/tests/helpers/database-config.ts +0 -14
- package/src/utils/constants/index.ts +0 -2
- package/src/utils/validations/validators.ts +0 -34
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
-
/* eslint-disable indent */
|
|
3
2
|
import {
|
|
4
3
|
Table,
|
|
5
4
|
Column,
|
|
@@ -14,18 +13,16 @@ import {
|
|
|
14
13
|
BeforeUpdate,
|
|
15
14
|
BeforeBulkCreate,
|
|
16
15
|
BeforeBulkUpdate,
|
|
17
|
-
Scopes,
|
|
18
16
|
} from 'sequelize-typescript';
|
|
19
17
|
import { sendDimEvent } from '../events';
|
|
20
18
|
import { CustomFieldDefinition } from '.';
|
|
21
19
|
import validateValue from '../utils/validations';
|
|
22
20
|
import * as CustomFieldDefinitionRepo from '../repository/definition';
|
|
23
21
|
import logger from '../utils/logger';
|
|
24
|
-
import { InvalidValueError } from '../errors';
|
|
25
22
|
|
|
26
23
|
@Table({
|
|
27
24
|
timestamps: true,
|
|
28
|
-
})
|
|
25
|
+
})
|
|
29
26
|
class CustomFieldValue extends Model {
|
|
30
27
|
@PrimaryKey
|
|
31
28
|
@Column({
|
|
@@ -44,7 +41,7 @@ class CustomFieldValue extends Model {
|
|
|
44
41
|
|
|
45
42
|
@Column({
|
|
46
43
|
type: DataType.JSONB,
|
|
47
|
-
allowNull:
|
|
44
|
+
allowNull: false,
|
|
48
45
|
})
|
|
49
46
|
value!: any;
|
|
50
47
|
|
|
@@ -63,7 +60,8 @@ class CustomFieldValue extends Model {
|
|
|
63
60
|
@BeforeBulkCreate
|
|
64
61
|
@BeforeBulkUpdate
|
|
65
62
|
static async validateValues(instances: CustomFieldValue[]): Promise<void> {
|
|
66
|
-
|
|
63
|
+
logger.info('CustomFieldValue BeforeBulkCreate/BeforeBulkUpdate', { instances });
|
|
64
|
+
const ids = instances.map(instance => instance.customFieldDefinitionId);
|
|
67
65
|
const uniqueIds = [...new Set(ids)];
|
|
68
66
|
const definitions = await CustomFieldDefinitionRepo.findByIds(
|
|
69
67
|
uniqueIds,
|
|
@@ -79,10 +77,10 @@ class CustomFieldValue extends Model {
|
|
|
79
77
|
validation,
|
|
80
78
|
fieldType,
|
|
81
79
|
} = definitions
|
|
82
|
-
.find(
|
|
80
|
+
.find(definition => definition.id === instance.customFieldDefinitionId);
|
|
83
81
|
const isValid = validateValue(instance.value, fieldType, validation);
|
|
84
82
|
if (!isValid) {
|
|
85
|
-
throw new
|
|
83
|
+
throw new Error('Invalid value');
|
|
86
84
|
}
|
|
87
85
|
});
|
|
88
86
|
}
|
|
@@ -91,18 +89,19 @@ class CustomFieldValue extends Model {
|
|
|
91
89
|
@BeforeCreate
|
|
92
90
|
@BeforeUpsert
|
|
93
91
|
static async validateValue(instance: CustomFieldValue): Promise<void> {
|
|
92
|
+
logger.info('CustomFieldValue BeforeCreate/BeforeUpdate', { instance });
|
|
94
93
|
const { customFieldDefinitionId } = instance;
|
|
95
|
-
// eslint-disable-next-line max-len
|
|
96
94
|
const cfd = await CustomFieldDefinitionRepo.findById(customFieldDefinitionId, { withDisabled: true });
|
|
97
95
|
const { validation, fieldType } = cfd;
|
|
98
96
|
const isValid = validateValue(instance.value, fieldType, validation);
|
|
99
97
|
if (!isValid) {
|
|
100
|
-
throw new
|
|
98
|
+
throw new Error('Invalid value');
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
@AfterUpsert
|
|
105
103
|
static afterSaveHandler(instance: CustomFieldValue, options): void {
|
|
104
|
+
logger.info('CustomFieldValue afterSave', { instance });
|
|
106
105
|
if (options.transaction) {
|
|
107
106
|
options.transaction.afterCommit(() => sendDimEvent(instance[0]));
|
|
108
107
|
} else {
|
|
@@ -112,3 +111,4 @@ class CustomFieldValue extends Model {
|
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
export default CustomFieldValue;
|
|
114
|
+
|
package/src/models/index.ts
CHANGED
|
@@ -1,101 +1,39 @@
|
|
|
1
1
|
/* eslint-disable no-param-reassign */
|
|
2
|
-
import { DataTypes } from 'sequelize';
|
|
3
2
|
import type { Sequelize } from 'sequelize-typescript';
|
|
4
3
|
import logger from '../utils/logger';
|
|
4
|
+
// import addPermanentHooks from '../hooks/permanent-hooks';
|
|
5
|
+
|
|
5
6
|
import CustomFieldDefinition from './CustomFieldDefinition';
|
|
6
7
|
import CustomFieldValue from './CustomFieldValue';
|
|
7
8
|
import TestModel from './tests/TestModel';
|
|
8
9
|
import AssociatedTestModel from './tests/AssociatedTestModel';
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
-
|
|
11
|
+
// export const CustomFieldDefinition = CustomFieldDefinitionModel;
|
|
12
|
+
// export { default as CustomFieldDefinition } from './custom-field-definition.model';
|
|
12
13
|
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const CUSTOM_FIELDS_SCHEMA_VERSION = `${SADOT_MIGRATION_PREFIX}_${SCHEMA_VERSION}`;
|
|
14
|
+
const productionModels = [CustomFieldDefinition, CustomFieldValue];
|
|
15
|
+
const testModels = [...productionModels, TestModel, AssociatedTestModel];
|
|
16
16
|
|
|
17
|
-
const initTables = async (sequelize: Sequelize
|
|
17
|
+
const initTables = async (sequelize: Sequelize): Promise<void> => {
|
|
18
18
|
logger.info('custom-fields: initialize custom-fields tables');
|
|
19
19
|
// Detect models and import them to the orm
|
|
20
20
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
21
21
|
if (!sequelize.addModels) {
|
|
22
22
|
throw new Error('sequelize instance must have addModels function');
|
|
23
23
|
}
|
|
24
|
-
sequelize.addModels(productionModels);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const user = getUser();
|
|
28
|
-
if (user?.permissions) {
|
|
29
|
-
return {
|
|
30
|
-
where: {
|
|
31
|
-
entityId: [
|
|
32
|
-
...Object.keys(user.permissions.fleets),
|
|
33
|
-
...Object.keys(user.permissions.businessModels),
|
|
34
|
-
...Object.keys(user.permissions.demandSources),
|
|
35
|
-
],
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
return {};
|
|
40
|
-
});
|
|
24
|
+
sequelize.addModels(process.env.NODE_ENV === 'test' ? testModels : productionModels);
|
|
25
|
+
await sequelize.dropSchema('custom-fields', { logging: false });
|
|
26
|
+
await sequelize.createSchema('custom-fields', { logging: false });
|
|
41
27
|
|
|
42
28
|
logger.info('custom-fields: models added');
|
|
29
|
+
await CustomFieldDefinition.sync({ alter: true });
|
|
30
|
+
await CustomFieldValue.sync({ alter: true });
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
{
|
|
47
|
-
name: {
|
|
48
|
-
type: DataTypes.STRING,
|
|
49
|
-
allowNull: false,
|
|
50
|
-
unique: true,
|
|
51
|
-
primaryKey: true,
|
|
52
|
-
autoIncrement: false,
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
tableName: 'SequelizeMeta',
|
|
57
|
-
timestamps: false,
|
|
58
|
-
schema: 'public',
|
|
59
|
-
},
|
|
60
|
-
);
|
|
61
|
-
const migrations = await SequelizeMeta.findAll({ raw: true });
|
|
62
|
-
const currentSadotSchemaVersion = migrations
|
|
63
|
-
.reverse().find((m: any) => m.name.includes(SADOT_MIGRATION_PREFIX));
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
!currentSadotSchemaVersion
|
|
67
|
-
|| (currentSadotSchemaVersion as any).name !== CUSTOM_FIELDS_SCHEMA_VERSION
|
|
68
|
-
) {
|
|
69
|
-
await CustomFieldDefinition.sync({ alter: true });
|
|
70
|
-
await CustomFieldValue.sync({ alter: true });
|
|
71
|
-
await SequelizeMeta.create({ name: CUSTOM_FIELDS_SCHEMA_VERSION });
|
|
72
|
-
logger.info('custom-fields: models synced');
|
|
32
|
+
if (process.env.NODE_ENV === 'test') {
|
|
33
|
+
await TestModel.sync({ alter: true });
|
|
34
|
+
await AssociatedTestModel.sync({ alter: true });
|
|
73
35
|
}
|
|
36
|
+
logger.info('custom-fields: models synced');
|
|
74
37
|
};
|
|
75
38
|
|
|
76
|
-
|
|
77
|
-
logger.info('custom-fields: initialize custom-fields test models');
|
|
78
|
-
// Detect models and import them to the orm
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
80
|
-
if (!sequelize.addModels) {
|
|
81
|
-
throw new Error('sequelize instance must have addModels function');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
sequelize.addModels(testModels);
|
|
85
|
-
await sequelize.dropSchema('custom-fields', { logging: false });
|
|
86
|
-
await sequelize.createSchema('custom-fields', { logging: false });
|
|
87
|
-
|
|
88
|
-
logger.info('custom-fields: test models added');
|
|
89
|
-
await TestModel.sync({ alter: true });
|
|
90
|
-
await AssociatedTestModel.sync({ alter: true });
|
|
91
|
-
logger.info('custom-fields: test models synced');
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
export {
|
|
95
|
-
CustomFieldValue,
|
|
96
|
-
CustomFieldDefinition,
|
|
97
|
-
TestModel,
|
|
98
|
-
AssociatedTestModel,
|
|
99
|
-
initTables,
|
|
100
|
-
initTestModels,
|
|
101
|
-
};
|
|
39
|
+
export { CustomFieldValue, CustomFieldDefinition, TestModel, AssociatedTestModel, initTables };
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { Op, WhereOptions } from 'sequelize';
|
|
2
|
-
import { CustomFieldDefinition } from '../models';
|
|
2
|
+
import { CustomFieldDefinition, CustomFieldValue } from '../models';
|
|
3
3
|
import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
|
|
4
4
|
|
|
5
5
|
export const create = (data: CreateCustomFieldDefinition): Promise<CustomFieldDefinition> =>
|
|
6
6
|
CustomFieldDefinition.create(data);
|
|
7
7
|
|
|
8
8
|
export const findAll = (
|
|
9
|
-
|
|
9
|
+
query: any,
|
|
10
10
|
options: any = { withDisabled: false },
|
|
11
11
|
): Promise<CustomFieldDefinition[]> => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
if (options.withDisabled) {
|
|
13
|
+
return CustomFieldDefinition.unscoped().findAll({
|
|
14
|
+
where: query,
|
|
15
|
+
include: [CustomFieldValue],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return CustomFieldDefinition.findAll({
|
|
20
|
+
where: query,
|
|
21
|
+
include: [CustomFieldValue],
|
|
19
22
|
});
|
|
20
23
|
};
|
|
21
24
|
|
|
@@ -30,9 +33,13 @@ export const findById = (
|
|
|
30
33
|
): Promise<CustomFieldDefinition | null> => {
|
|
31
34
|
const { withDisabled } = options;
|
|
32
35
|
if (withDisabled) {
|
|
33
|
-
return CustomFieldDefinition.unscoped().
|
|
36
|
+
return CustomFieldDefinition.unscoped().findByPk(id, {
|
|
37
|
+
include: [CustomFieldValue],
|
|
38
|
+
});
|
|
34
39
|
}
|
|
35
|
-
return CustomFieldDefinition.
|
|
40
|
+
return CustomFieldDefinition.findByPk(id, {
|
|
41
|
+
include: [CustomFieldValue],
|
|
42
|
+
});
|
|
36
43
|
};
|
|
37
44
|
|
|
38
45
|
export const findByEntityId = async (
|
|
@@ -43,22 +50,10 @@ export const findByEntityId = async (
|
|
|
43
50
|
transaction: options.transaction,
|
|
44
51
|
});
|
|
45
52
|
|
|
46
|
-
export const findByEntityIds = async (
|
|
47
|
-
modelType: string,
|
|
48
|
-
entityIds: string[],
|
|
49
|
-
options: any = {},
|
|
50
|
-
): Promise<CustomFieldDefinition[]> => CustomFieldDefinition.findAll({
|
|
51
|
-
where: {
|
|
52
|
-
modelType,
|
|
53
|
-
entityId: entityIds,
|
|
54
|
-
},
|
|
55
|
-
transaction: options.transaction,
|
|
56
|
-
raw: true,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
53
|
export const findByWhere = (where): Promise<CustomFieldDefinition | null> =>
|
|
60
|
-
CustomFieldDefinition.
|
|
54
|
+
CustomFieldDefinition.findOne({
|
|
61
55
|
where,
|
|
56
|
+
include: [CustomFieldValue],
|
|
62
57
|
});
|
|
63
58
|
|
|
64
59
|
export const findDefinitionsByModels = async (
|
|
@@ -68,6 +63,7 @@ export const findDefinitionsByModels = async (
|
|
|
68
63
|
const query: WhereOptions<CreateCustomFieldDefinition> = { modelType: { [Op.in]: modelTypes } };
|
|
69
64
|
return CustomFieldDefinition.findAll({
|
|
70
65
|
where: query,
|
|
66
|
+
include: [CustomFieldValue],
|
|
71
67
|
transaction: options?.transaction,
|
|
72
68
|
});
|
|
73
69
|
};
|
|
@@ -76,7 +72,7 @@ export const update = async (
|
|
|
76
72
|
id: string,
|
|
77
73
|
data: UpdateCustomFieldDefinition,
|
|
78
74
|
): Promise<CustomFieldDefinition> => {
|
|
79
|
-
const updatedDefinition = (await CustomFieldDefinition.
|
|
75
|
+
const updatedDefinition = (await CustomFieldDefinition.update(data, {
|
|
80
76
|
where: { id },
|
|
81
77
|
returning: true,
|
|
82
78
|
individualHooks: true,
|
|
@@ -93,6 +89,7 @@ export const disable = (id: string): Promise<any> =>
|
|
|
93
89
|
export const destroy = (id: string): Promise<any> =>
|
|
94
90
|
CustomFieldDefinition.destroy({ where: { id } });
|
|
95
91
|
|
|
92
|
+
|
|
96
93
|
/**
|
|
97
94
|
* Return the names of the required fields for a given model
|
|
98
95
|
*/
|
|
@@ -100,12 +97,29 @@ export const getRequiredFields = async (
|
|
|
100
97
|
modelType: string,
|
|
101
98
|
modelId: string | string[],
|
|
102
99
|
entityId: string | string[],
|
|
100
|
+
onlyNull = false,
|
|
103
101
|
): Promise<string[]> => {
|
|
104
102
|
const entityIds = Array.isArray(entityId) ? entityId : [entityId];
|
|
103
|
+
const modelIds = Array.isArray(modelId) ? modelId : [modelId];
|
|
104
|
+
// const valueQuery = Object.assign(
|
|
105
|
+
// {
|
|
106
|
+
// modelId: { [Op.in]: modelIds },
|
|
107
|
+
// },
|
|
108
|
+
// onlyNull ? { value: { [Op.eq]: null } } : null,
|
|
109
|
+
// );
|
|
110
|
+
const valueQuery = onlyNull ? {
|
|
111
|
+
modelId: { [Op.in]: modelIds },
|
|
112
|
+
value: { [Op.eq]: null },
|
|
113
|
+
} : {};
|
|
105
114
|
const requiredFields = await CustomFieldDefinition.findAll({
|
|
106
115
|
where: { required: true, modelType, entityId: { [Op.in]: entityIds } },
|
|
116
|
+
include: {
|
|
117
|
+
model: CustomFieldValue,
|
|
118
|
+
where: { ...valueQuery },
|
|
119
|
+
required: false,
|
|
120
|
+
},
|
|
107
121
|
logging: true,
|
|
108
122
|
});
|
|
109
|
-
const requiredFieldsNames = requiredFields.map(
|
|
123
|
+
const requiredFieldsNames = requiredFields.map(definition => definition.name);
|
|
110
124
|
return [...new Set(requiredFieldsNames)];
|
|
111
125
|
};
|
package/src/repository/value.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
|
+
import { Op } from 'sequelize';
|
|
3
|
+
|
|
2
4
|
import { CustomFieldValue, CustomFieldDefinition } from '../models';
|
|
3
5
|
import * as DefinitionRepo from './definition';
|
|
4
6
|
import { CreateCustomFieldValue, ValuesToUpdate } from '../types/value';
|
|
5
7
|
import logger from '../utils/logger';
|
|
6
|
-
import { MissingDefinitionError } from '../errors';
|
|
7
8
|
|
|
8
9
|
export const findByModelIdAndDefinition = async (modelId: string, customFieldDefinitionId: string) =>
|
|
9
10
|
CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [CustomFieldDefinition] });
|
|
@@ -34,9 +35,8 @@ export const findValuesByModelIds = async (modelIds: string[], options?): Promis
|
|
|
34
35
|
const { transaction } = options;
|
|
35
36
|
return CustomFieldValue.findAll({
|
|
36
37
|
where: { modelId: modelIds },
|
|
38
|
+
include: [CustomFieldDefinition],
|
|
37
39
|
transaction,
|
|
38
|
-
raw: true,
|
|
39
|
-
nest: true,
|
|
40
40
|
});
|
|
41
41
|
};
|
|
42
42
|
|
|
@@ -48,7 +48,6 @@ export const findValuesByModelIds = async (modelIds: string[], options?): Promis
|
|
|
48
48
|
export const updateValues = async (
|
|
49
49
|
modelType: string,
|
|
50
50
|
modelId: string,
|
|
51
|
-
identifiers: string[],
|
|
52
51
|
valuesToUpdate: ValuesToUpdate,
|
|
53
52
|
options: any = {},
|
|
54
53
|
): Promise<CustomFieldValue[]> => {
|
|
@@ -56,27 +55,27 @@ export const updateValues = async (
|
|
|
56
55
|
|
|
57
56
|
const names = Object.keys(valuesToUpdate);
|
|
58
57
|
const fieldDefinitions = await DefinitionRepo.findAll(
|
|
59
|
-
{ modelType, name:
|
|
58
|
+
{ modelType, name: { [Op.in]: names } },
|
|
60
59
|
{ withDisabled: true, transaction: options.transaction },
|
|
61
60
|
) || [];
|
|
62
61
|
|
|
63
|
-
const disabledDefinitions = fieldDefinitions.filter(
|
|
62
|
+
const disabledDefinitions = fieldDefinitions.filter(def => def.disabled);
|
|
64
63
|
if (fieldDefinitions.length !== names.length) {
|
|
65
|
-
const missingDefinitions = names.filter(
|
|
66
|
-
throw new
|
|
64
|
+
const missingDefinitions = names.filter(name => !fieldDefinitions.some(def => def.name === name));
|
|
65
|
+
throw new Error(`custom-fields: missing definitions for ${missingDefinitions.join(', ')}`);
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
const disabledNames = disabledDefinitions?.map(
|
|
70
|
-
const valuesWithDisabledDefinitions = names.filter(
|
|
68
|
+
const disabledNames = disabledDefinitions?.map(def => def.name) || [];
|
|
69
|
+
const valuesWithDisabledDefinitions = names.filter(name => disabledNames.includes(name));
|
|
71
70
|
if (valuesWithDisabledDefinitions?.length > 0) {
|
|
72
71
|
logger.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
|
|
73
72
|
}
|
|
74
73
|
|
|
75
|
-
const values: CreateCustomFieldValue[] = names.map(
|
|
74
|
+
const values: CreateCustomFieldValue[] = names.map(name => ({
|
|
76
75
|
modelId,
|
|
77
76
|
value: valuesToUpdate[name],
|
|
78
77
|
updatedAt: new Date(),
|
|
79
|
-
customFieldDefinitionId: fieldDefinitions.find(
|
|
78
|
+
customFieldDefinitionId: fieldDefinitions.find(def => def.name === name).id,
|
|
80
79
|
}));
|
|
81
80
|
|
|
82
81
|
return Promise.all(values.map(async (value) => {
|
|
@@ -5,7 +5,7 @@ export const mockEvent = (events: any, eventName, numberOfEvents) => {
|
|
|
5
5
|
return [
|
|
6
6
|
events.sendObject,
|
|
7
7
|
(): void => {
|
|
8
|
-
const matchingEvents = events.sendObject.mock.calls.filter(
|
|
8
|
+
const matchingEvents = events.sendObject.mock.calls.filter(call => call[0] === eventName);
|
|
9
9
|
expect(matchingEvents.length).toEqual(numberOfEvents);
|
|
10
10
|
},
|
|
11
11
|
];
|
|
@@ -30,8 +30,10 @@ export const booleanField = (modelType: string): CreateCustomFieldDefinition =>
|
|
|
30
30
|
export const enumField = (modelType: string, options): CreateCustomFieldDefinition => ({
|
|
31
31
|
name: 'choices',
|
|
32
32
|
modelType,
|
|
33
|
-
fieldType: '
|
|
34
|
-
validation:
|
|
33
|
+
fieldType: 'enum',
|
|
34
|
+
validation: {
|
|
35
|
+
enum: options,
|
|
36
|
+
},
|
|
35
37
|
entityId: uuidv4(),
|
|
36
38
|
entityType: 'fleetId',
|
|
37
39
|
});
|
|
@@ -47,7 +49,7 @@ export const rangeField = (modelType: string): CreateCustomFieldDefinition => ({
|
|
|
47
49
|
entityType: 'fleetId',
|
|
48
50
|
});
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
|
|
51
53
|
export const createDefinition = (defaults: Partial<CustomFieldDefinitionDTO>): CreateCustomFieldDefinition => ({
|
|
52
54
|
name: defaults?.name || `def_${uuidv4()}`,
|
|
53
55
|
modelType: defaults?.modelType || 'TestModel',
|
|
@@ -59,8 +61,7 @@ export const createDefinition = (defaults: Partial<CustomFieldDefinitionDTO>): C
|
|
|
59
61
|
export const createDefinitions = (
|
|
60
62
|
defaults: Partial<CustomFieldDefinitionDTO>,
|
|
61
63
|
length = 1,
|
|
62
|
-
|
|
63
|
-
): CreateCustomFieldDefinition[] => (Array(length).fill({}).map((_) => ({
|
|
64
|
+
): CreateCustomFieldDefinition[] => (Array(length).fill({}).map(_ => ({
|
|
64
65
|
name: defaults?.name || `def_${uuidv4()}`,
|
|
65
66
|
modelType: defaults?.modelType || 'TestModel',
|
|
66
67
|
fieldType: defaults?.fieldType || 'boolean',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TestModel, AssociatedTestModel } from '../../models';
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
export const createTestModel = (payload = {}) => TestModel.create(payload);
|
|
4
5
|
|
|
5
6
|
export const createTestModels = (fleetId, total: number) => {
|
|
@@ -10,28 +11,22 @@ export const createTestModels = (fleetId, total: number) => {
|
|
|
10
11
|
return Promise.all<TestModel>(models);
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
export const upsertTestModel =
|
|
14
|
+
export const upsertTestModel = payload => TestModel.upsert(payload);
|
|
14
15
|
|
|
15
16
|
export const destroyTestModels = () => TestModel.destroy({ truncate: true });
|
|
16
17
|
|
|
17
|
-
export const getTestModel = (
|
|
18
|
-
id: string,
|
|
19
|
-
options = {},
|
|
20
|
-
): Promise<TestModel> => TestModel.findByPk(id, options);
|
|
18
|
+
export const getTestModel = (id: string): Promise<TestModel> => TestModel.findByPk(id);
|
|
21
19
|
|
|
22
|
-
export const getSomeTestModels = (
|
|
23
|
-
options = { limit: 1 },
|
|
24
|
-
): Promise<TestModel[]> => TestModel.findAll(options);
|
|
20
|
+
export const getSomeTestModels = (limit = 1): Promise<TestModel[]> => TestModel.findAll({ limit });
|
|
25
21
|
|
|
26
22
|
export const updateTestModel = (payload, query) => TestModel.update(payload, query);
|
|
27
23
|
|
|
28
24
|
// Associations
|
|
29
25
|
export const createTestModelWithAssociation = async () => {
|
|
30
26
|
const model = await TestModel.create({});
|
|
31
|
-
await AssociatedTestModel.create({ testModelId: model.id });
|
|
27
|
+
const associatedTestModel = await AssociatedTestModel.create({ testModelId: model.id });
|
|
32
28
|
return model;
|
|
33
29
|
};
|
|
34
30
|
|
|
35
|
-
export const getTestModelWithAssociation = (limit = 1) => TestModel.findAll({
|
|
36
|
-
|
|
37
|
-
});
|
|
31
|
+
export const getTestModelWithAssociation = (limit = 1) => TestModel.findAll({ limit, include: [AssociatedTestModel] });
|
|
32
|
+
|
package/src/types/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Sequelize as InnerSequelize } from 'sequelize-typescript';
|
|
2
|
+
|
|
1
3
|
export type ModelFetcher = (name: string) => any;
|
|
2
4
|
|
|
3
5
|
export type ModelOptions = {
|
|
@@ -9,7 +11,7 @@ export type ModelOptions = {
|
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export type CustomFieldOptions= {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
14
|
+
models: ModelOptions[];
|
|
15
|
+
innerSequelize?: InnerSequelize;
|
|
16
|
+
databaseConfig: any;
|
|
17
|
+
};
|
package/src/types/value/index.ts
CHANGED
|
@@ -8,7 +8,8 @@ export interface CustomFieldValueDTO {
|
|
|
8
8
|
deletedAt?: Date;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export type ValuesToUpdate = {[name: string]: any };
|
|
12
11
|
export type CreateCustomFieldValue = Omit<CustomFieldValueDTO, 'id'>;
|
|
13
12
|
export type UpdateCustomFieldValue = ValuesToUpdate;
|
|
14
13
|
export type BulkUpdateCustomFieldValue = Partial<CustomFieldValueDTO>[];
|
|
14
|
+
|
|
15
|
+
export type ValuesToUpdate = {[name: string]: any };
|
package/src/utils/db/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Sequelize } from 'sequelize-typescript';
|
|
2
|
-
import { QueryTypes } from 'sequelize';
|
|
3
2
|
|
|
4
3
|
export default (databaseConfig: any): Sequelize => {
|
|
5
4
|
const ENV_DEV = 'test';
|
|
@@ -13,9 +12,3 @@ export default (databaseConfig: any): Sequelize => {
|
|
|
13
12
|
}
|
|
14
13
|
return sequelize;
|
|
15
14
|
};
|
|
16
|
-
|
|
17
|
-
export const createSequelizeMeta = (sequelize: Sequelize) => sequelize.query(`
|
|
18
|
-
CREATE TABLE IF NOT EXISTS "SequelizeMeta" (
|
|
19
|
-
name character varying(255) PRIMARY KEY
|
|
20
|
-
);
|
|
21
|
-
`, { type: QueryTypes.SELECT });
|
|
@@ -1,39 +1,56 @@
|
|
|
1
|
-
|
|
2
|
-
import logger from
|
|
3
|
-
import { CustomFieldDefinitionType } from './type';
|
|
4
|
-
import validators from './validators';
|
|
1
|
+
import { CustomFieldDefinitionType } from "../../models/CustomFieldDefinition";
|
|
2
|
+
import logger from "../logger";
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
enum CustomValidations {
|
|
5
|
+
ENUM = 'enum',
|
|
6
|
+
RANGE = 'between'
|
|
7
|
+
}
|
|
8
|
+
const mustHaveCustomValidation = {
|
|
9
|
+
[CustomFieldDefinitionType.ENUM]: true,
|
|
10
|
+
};
|
|
11
|
+
type Validator = (value, validation) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Validate {@link CustomValidations.ENUM Enum}
|
|
14
|
+
*/
|
|
15
|
+
const validateEnum: Validator = (value, enumValues) => (Array.isArray(enumValues)
|
|
16
|
+
&& enumValues.length > 0
|
|
17
|
+
&& enumValues.includes(value)
|
|
18
|
+
);
|
|
19
|
+
/**
|
|
20
|
+
* Validate {@link CustomValidations.RANGE Range}
|
|
21
|
+
*/
|
|
22
|
+
const validateRange: Validator = (value, range) => {
|
|
23
|
+
const [min, max] = range;
|
|
24
|
+
if (min === undefined || max === undefined) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return value >= range.min && value <= range.max;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Validators for custom fields
|
|
31
|
+
*/
|
|
32
|
+
const customValidators: { [key: string]: Validator } = {
|
|
33
|
+
[CustomValidations.ENUM]: validateEnum,
|
|
34
|
+
[CustomValidations.RANGE]: validateRange,
|
|
8
35
|
};
|
|
9
36
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!validation) {
|
|
16
|
-
if (mustHaveCustomValidation[valueType]) {
|
|
37
|
+
const customValidation = (value, valueType, validations) => {
|
|
38
|
+
const validator = customValidators[valueType];
|
|
39
|
+
const validation = validations[valueType];
|
|
40
|
+
if (mustHaveCustomValidation[valueType]) {
|
|
41
|
+
if (!validation) {
|
|
17
42
|
logger.error(`No custom validation for custom field type ${valueType} found`);
|
|
18
|
-
return false;
|
|
43
|
+
return false; // TODO: Return better error message
|
|
19
44
|
}
|
|
45
|
+
}
|
|
46
|
+
if (!validation) {
|
|
20
47
|
return true;
|
|
21
48
|
}
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Validates the given value against the custom validation rules for the specified field type.
|
|
27
|
-
* If no custom validation rules are provided, it falls back to the default validation.
|
|
28
|
-
* @returns true if the value is valid according to the validation rules, false otherwise.
|
|
29
|
-
*/
|
|
30
|
-
const customValidation = (value, valueType, validation) => {
|
|
31
|
-
const validator = validators?.[valueType];
|
|
32
|
-
if (!validation || !validator) {
|
|
33
|
-
return validateValidation(valueType, validation);
|
|
49
|
+
if (!validator) {
|
|
50
|
+
logger.error(`No validator for custom field type ${valueType} found`);
|
|
51
|
+
return false;
|
|
34
52
|
}
|
|
35
|
-
|
|
36
|
-
return value === null || validator(value, validation);
|
|
53
|
+
return validator(value, validation);
|
|
37
54
|
};
|
|
38
55
|
|
|
39
56
|
export default customValidation;
|