@autofleet/sadot 0.7.4-beta-5d31a6b9.0 → 0.7.5
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/.nvmrc +1 -1
- package/dist/events/index.js +21 -20
- package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js +1 -3
- package/dist/scopes/filter.js +2 -5
- package/dist/tests/mocks/definition.mock.js +9 -9
- package/dist/utils/helpers/index.d.ts +0 -1
- package/dist/utils/helpers/index.js +1 -27
- package/dist/utils/logger/index.d.ts +1 -1
- package/dist/utils/logger/index.js +5 -3
- package/package.json +15 -21
- package/src/api/v1/definition/index.ts +1 -2
- package/src/events/index.ts +25 -24
- package/src/hooks/create.ts +1 -2
- package/src/models/CustomFieldDefinition.ts +20 -20
- package/src/models/CustomFieldValue.ts +7 -7
- package/src/models/tests/AssociatedTestModel.ts +7 -7
- package/src/models/tests/TestModel.ts +7 -7
- package/src/models/tests/contextAwareModels/ContextAwareTestModel.ts +15 -17
- package/src/scopes/filter.ts +3 -3
- package/src/tests/mocks/definition.mock.ts +1 -1
- package/src/utils/helpers/index.ts +1 -34
- package/src/utils/logger/index.ts +1 -2
- package/.env +0 -3
- package/dist/utils/helpers/excludeCustomFieldFilterScope.d.ts +0 -0
- package/dist/utils/helpers/excludeCustomFieldFilterScope.js +0 -0
- package/src/utils/helpers/excludeCustomFieldFilterScope.ts +0 -0
package/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
22.9.0
|
package/dist/events/index.js
CHANGED
|
@@ -7,18 +7,18 @@ exports.sendDimEvent = void 0;
|
|
|
7
7
|
const events_1 = __importDefault(require("@autofleet/events"));
|
|
8
8
|
const logger_1 = __importDefault(require("../utils/logger"));
|
|
9
9
|
const events = new events_1.default({ logger: logger_1.default });
|
|
10
|
-
const KEYS_TO_CONVERT = ['value'];
|
|
11
|
-
const
|
|
12
|
-
if (Object.keys(savedObject).some((key) => keysToConvert.includes(key))) {
|
|
13
|
-
|
|
14
|
-
keysToConvert.forEach((key) => {
|
|
15
|
-
if (typeof savedObject[key] === 'boolean') {
|
|
16
|
-
objectToReturn[key] = savedObject[key].toString();
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
return objectToReturn;
|
|
10
|
+
const KEYS_TO_CONVERT = ['value', 'defaultValue'];
|
|
11
|
+
const stringifyBooleans = (savedObject, keysToConvert) => {
|
|
12
|
+
if (!Object.keys(savedObject).some((key) => keysToConvert.includes(key))) {
|
|
13
|
+
return savedObject;
|
|
20
14
|
}
|
|
21
|
-
|
|
15
|
+
const objectToReturn = { ...savedObject };
|
|
16
|
+
keysToConvert.forEach((key) => {
|
|
17
|
+
if (typeof savedObject[key] === 'boolean') {
|
|
18
|
+
objectToReturn[key] = savedObject[key].toString();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return objectToReturn;
|
|
22
22
|
};
|
|
23
23
|
const modelTableMapping = {
|
|
24
24
|
CustomFieldDefinition: {
|
|
@@ -32,16 +32,17 @@ const modelTableMapping = {
|
|
|
32
32
|
};
|
|
33
33
|
const sendDimEvent = (instance) => {
|
|
34
34
|
const mapping = modelTableMapping[instance.constructor.name];
|
|
35
|
-
if (mapping) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
if (!mapping) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let objectToSend = instance.get();
|
|
39
|
+
try {
|
|
40
|
+
objectToSend = stringifyBooleans(instance.get(), KEYS_TO_CONVERT);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
logger_1.default.error('Failed to convert booleans in dim event payload', err);
|
|
44
44
|
}
|
|
45
|
+
events.sendObject(mapping.tableName, mapping.eventVersion, objectToSend);
|
|
45
46
|
};
|
|
46
47
|
exports.sendDimEvent = sendDimEvent;
|
|
47
48
|
exports.default = events;
|
|
@@ -28,9 +28,7 @@ __decorate([
|
|
|
28
28
|
], ContextAwareTestModel.prototype, "id", void 0);
|
|
29
29
|
__decorate([
|
|
30
30
|
(0, sequelize_typescript_1.ForeignKey)(() => ContextTestModel_1.default),
|
|
31
|
-
(0, sequelize_typescript_1.Column)({
|
|
32
|
-
type: sequelize_typescript_1.DataType.UUID,
|
|
33
|
-
}),
|
|
31
|
+
(0, sequelize_typescript_1.Column)({ type: sequelize_typescript_1.DataType.UUID }),
|
|
34
32
|
__metadata("design:type", String)
|
|
35
33
|
], ContextAwareTestModel.prototype, "contextId", void 0);
|
|
36
34
|
__decorate([
|
package/dist/scopes/filter.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.customFieldsSortScope = exports.scopeName = exports.customFieldsFilterScope = void 0;
|
|
7
4
|
/* eslint-disable import/prefer-default-export */
|
|
8
5
|
const sequelize_1 = require("sequelize");
|
|
9
6
|
const sequelize_typescript_1 = require("sequelize-typescript");
|
|
10
7
|
const common_types_1 = require("@autofleet/common-types");
|
|
11
|
-
const moment_1 = __importDefault(require("moment"));
|
|
12
8
|
const helpers_1 = require("../utils/helpers");
|
|
13
9
|
const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
|
|
10
|
+
const isDate = (input) => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
|
|
14
11
|
const castIfNeeded = (conditionValue) => {
|
|
15
|
-
if (
|
|
12
|
+
if (isDate(conditionValue)) {
|
|
16
13
|
return '::timestamp';
|
|
17
14
|
}
|
|
18
15
|
if (!Number.isNaN(Number(conditionValue))) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createDefinitions = exports.createDefinition = exports.statusField = exports.selectField = exports.booleanField = exports.coolFieldDefinition3 = exports.coolFieldDefinition2 = exports.coolFieldDefinition = exports.contextAwareFieldDefinition = void 0;
|
|
4
|
-
const
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
5
|
exports.contextAwareFieldDefinition = {
|
|
6
6
|
name: 'cool field',
|
|
7
7
|
modelType: 'ContextAwareTestModel',
|
|
@@ -12,7 +12,7 @@ exports.coolFieldDefinition = {
|
|
|
12
12
|
name: 'cool field',
|
|
13
13
|
modelType: 'TestModel',
|
|
14
14
|
fieldType: 'number',
|
|
15
|
-
entityId: (0,
|
|
15
|
+
entityId: (0, node_crypto_1.randomUUID)(),
|
|
16
16
|
entityType: 'fleetId',
|
|
17
17
|
};
|
|
18
18
|
exports.coolFieldDefinition2 = {
|
|
@@ -27,7 +27,7 @@ const booleanField = (modelType) => ({
|
|
|
27
27
|
name: 'shapeless',
|
|
28
28
|
modelType,
|
|
29
29
|
fieldType: 'boolean',
|
|
30
|
-
entityId: (0,
|
|
30
|
+
entityId: (0, node_crypto_1.randomUUID)(),
|
|
31
31
|
entityType: 'fleetId',
|
|
32
32
|
});
|
|
33
33
|
exports.booleanField = booleanField;
|
|
@@ -36,7 +36,7 @@ const selectField = (modelType, options) => ({
|
|
|
36
36
|
modelType,
|
|
37
37
|
fieldType: 'select',
|
|
38
38
|
validation: options,
|
|
39
|
-
entityId: (0,
|
|
39
|
+
entityId: (0, node_crypto_1.randomUUID)(),
|
|
40
40
|
entityType: 'fleetId',
|
|
41
41
|
});
|
|
42
42
|
exports.selectField = selectField;
|
|
@@ -45,25 +45,25 @@ const statusField = (modelType, options) => ({
|
|
|
45
45
|
modelType,
|
|
46
46
|
fieldType: 'status',
|
|
47
47
|
validation: options,
|
|
48
|
-
entityId: (0,
|
|
48
|
+
entityId: (0, node_crypto_1.randomUUID)(),
|
|
49
49
|
entityType: 'fleetId',
|
|
50
50
|
});
|
|
51
51
|
exports.statusField = statusField;
|
|
52
52
|
// eslint-disable-next-line max-len
|
|
53
53
|
const createDefinition = (defaults) => ({
|
|
54
|
-
name: defaults?.name || `def_${(0,
|
|
54
|
+
name: defaults?.name || `def_${(0, node_crypto_1.randomUUID)()}`,
|
|
55
55
|
modelType: defaults?.modelType || 'TestModel',
|
|
56
56
|
fieldType: defaults?.fieldType || 'boolean',
|
|
57
|
-
entityId: defaults?.entityId || (0,
|
|
57
|
+
entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
|
|
58
58
|
entityType: defaults?.entityType || 'fleetId',
|
|
59
59
|
...(defaults?.defaultValue && { defaultValue: defaults.defaultValue }),
|
|
60
60
|
});
|
|
61
61
|
exports.createDefinition = createDefinition;
|
|
62
62
|
const createDefinitions = (defaults, length = 1) => (Array(length).fill({}).map((_) => ({
|
|
63
|
-
name: defaults?.name || `def_${(0,
|
|
63
|
+
name: defaults?.name || `def_${(0, node_crypto_1.randomUUID)()}`,
|
|
64
64
|
modelType: defaults?.modelType || 'TestModel',
|
|
65
65
|
fieldType: defaults?.fieldType || 'boolean',
|
|
66
|
-
entityId: defaults?.entityId || (0,
|
|
66
|
+
entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
|
|
67
67
|
entityType: defaults?.entityType || 'fleetId',
|
|
68
68
|
})));
|
|
69
69
|
exports.createDefinitions = createDefinitions;
|
|
@@ -23,5 +23,4 @@ interface CustomFieldsSearchPayload {
|
|
|
23
23
|
}
|
|
24
24
|
export declare const generateRandomString: (length?: number) => string;
|
|
25
25
|
export declare const generateCustomFieldSearchQueryPayload: (searchTerm: string, model: ModelStatic, entityId: string, customFieldsTypesToExclude?: CustomFieldDefinitionType[]) => CustomFieldsSearchPayload;
|
|
26
|
-
export declare const excludeCustomFieldFilterScope: (modelType: string, keyToExclude: string, valuesToExclude: string | string[]) => Omit<CustomFieldsSearchPayload, 'replacements'>;
|
|
27
26
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.generateCustomFieldSearchQueryPayload = exports.generateRandomString = void 0;
|
|
4
4
|
/* eslint-disable import/prefer-default-export */
|
|
5
5
|
const sequelize_1 = require("sequelize");
|
|
6
6
|
const sequelize_typescript_1 = require("sequelize-typescript");
|
|
@@ -38,29 +38,3 @@ const generateCustomFieldSearchQueryPayload = (searchTerm, model, entityId, cust
|
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
40
|
exports.generateCustomFieldSearchQueryPayload = generateCustomFieldSearchQueryPayload;
|
|
41
|
-
const excludeCustomFieldFilterScope = (modelType, keyToExclude, valuesToExclude) => {
|
|
42
|
-
const keyToIgnore = keyToExclude.split('.')[1];
|
|
43
|
-
const valsToIgnore = Array.isArray(valuesToExclude) ? valuesToExclude.map((v) => `'"${v}"'`).join(', ') : null;
|
|
44
|
-
const customFieldsQuery = valsToIgnore ? `AND cv.value IN (${valsToIgnore})` : '';
|
|
45
|
-
const existsCondition = `
|
|
46
|
-
EXISTS (
|
|
47
|
-
SELECT 1
|
|
48
|
-
FROM custom_field_values cv
|
|
49
|
-
INNER JOIN custom_field_definitions cd
|
|
50
|
-
ON cv.custom_field_definition_id = cd.id
|
|
51
|
-
WHERE
|
|
52
|
-
cv.model_id = "${modelType}"."id"
|
|
53
|
-
AND cd.model_type = '${modelType}'
|
|
54
|
-
AND cd.name = '${keyToIgnore}'
|
|
55
|
-
${customFieldsQuery}
|
|
56
|
-
)
|
|
57
|
-
`;
|
|
58
|
-
return {
|
|
59
|
-
where: {
|
|
60
|
-
[sequelize_1.Op.and]: [
|
|
61
|
-
sequelize_typescript_1.Sequelize.literal(existsCondition),
|
|
62
|
-
],
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
exports.excludeCustomFieldFilterScope = excludeCustomFieldFilterScope;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const logger:
|
|
1
|
+
declare const logger: import("@autofleet/logger").LoggerInstanceManager;
|
|
2
2
|
export default logger;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const logger = Logger();
|
|
6
|
+
const logger_1 = __importDefault(require("@autofleet/logger"));
|
|
7
|
+
const logger = (0, logger_1.default)();
|
|
6
8
|
exports.default = logger;
|
package/package.json
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sadot",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"start": "ts-node
|
|
7
|
+
"start": "ts-node src/index.ts",
|
|
8
8
|
"build": "rm -rf dist && tsc",
|
|
9
|
-
"linter": "
|
|
9
|
+
"linter": "eslint .",
|
|
10
10
|
"test": "jest --forceExit --runInBand",
|
|
11
11
|
"coverage": "jest --coverage --forceExit --runInBand && rm -rf ./coverage",
|
|
12
|
-
"build-to-local-repo": "
|
|
12
|
+
"build-to-local-repo": "node --run build && cp -r dist/* ../$REPO/node_modules/$npm_package_name/dist",
|
|
13
13
|
"dev": "nodemon",
|
|
14
14
|
"watch": "npm-watch build-to-local-repo",
|
|
15
|
-
"publish-dev": "
|
|
15
|
+
"publish-dev": "node --run build && npm publish --tag dev"
|
|
16
16
|
},
|
|
17
17
|
"watch": {
|
|
18
18
|
"build-to-local-repo": {
|
|
19
19
|
"extensions": [
|
|
20
20
|
"js",
|
|
21
|
-
"
|
|
22
|
-
"ts",
|
|
23
|
-
"tsx",
|
|
24
|
-
"css"
|
|
21
|
+
"ts"
|
|
25
22
|
],
|
|
26
23
|
"patterns": [
|
|
27
24
|
"src"
|
|
@@ -30,27 +27,24 @@
|
|
|
30
27
|
}
|
|
31
28
|
},
|
|
32
29
|
"dependencies": {
|
|
33
|
-
"@autofleet/common-types": "^1.7.
|
|
34
|
-
"@autofleet/errors": "^1.
|
|
30
|
+
"@autofleet/common-types": "^1.7.58",
|
|
31
|
+
"@autofleet/errors": "^1.2.3",
|
|
35
32
|
"@autofleet/events": "^2.0.0",
|
|
36
|
-
"@autofleet/logger": "^
|
|
33
|
+
"@autofleet/logger": "^4.1.0",
|
|
37
34
|
"express": "^4.18.2",
|
|
38
35
|
"joi": "^17.7.0",
|
|
39
|
-
"moment": "^2.30.1",
|
|
40
36
|
"pg": "^8.10.0",
|
|
41
37
|
"reflect-metadata": "^0.1.13",
|
|
42
38
|
"sequelize": "^6.31.1",
|
|
43
|
-
"sequelize-typescript": "^2.1.5"
|
|
44
|
-
"uuid": "^9.0.0"
|
|
39
|
+
"sequelize-typescript": "^2.1.5"
|
|
45
40
|
},
|
|
46
41
|
"devDependencies": {
|
|
47
42
|
"@types/express": "^4.17.17",
|
|
48
|
-
"@types/jest": "^
|
|
49
|
-
"@
|
|
50
|
-
"@typescript-eslint/
|
|
51
|
-
"
|
|
52
|
-
"eslint": "^
|
|
53
|
-
"eslint-config-airbnb-typescript": "^12.0.0",
|
|
43
|
+
"@types/jest": "^29.5.13",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
45
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
46
|
+
"eslint": "^8.57.0",
|
|
47
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
54
48
|
"eslint-plugin-import": "^2.22.1",
|
|
55
49
|
"jest": "^29.7.0",
|
|
56
50
|
"npm-watch": "^0.11.0",
|
|
@@ -65,8 +65,7 @@ router.get('/', async (req, res) => {
|
|
|
65
65
|
if (entityIds?.length > 0) {
|
|
66
66
|
where.entityId = entityIds;
|
|
67
67
|
}
|
|
68
|
-
const customFieldDefinitions = await DefinitionRepo.findAll({ ...where },
|
|
69
|
-
{ withDisabled: true });
|
|
68
|
+
const customFieldDefinitions = await DefinitionRepo.findAll({ ...where }, { withDisabled: true });
|
|
70
69
|
return res.json(customFieldDefinitions);
|
|
71
70
|
} catch (err) {
|
|
72
71
|
logger.error('Failed to fetch custom field definitions', err);
|
package/src/events/index.ts
CHANGED
|
@@ -3,19 +3,19 @@ import logger from '../utils/logger';
|
|
|
3
3
|
|
|
4
4
|
const events = new Events({ logger });
|
|
5
5
|
|
|
6
|
-
const KEYS_TO_CONVERT = ['value'];
|
|
6
|
+
const KEYS_TO_CONVERT = ['value', 'defaultValue'];
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
if (Object.keys(savedObject).some((key) => keysToConvert.includes(key))) {
|
|
10
|
-
|
|
11
|
-
keysToConvert.forEach((key) => {
|
|
12
|
-
if (typeof savedObject[key] === 'boolean') {
|
|
13
|
-
objectToReturn[key] = savedObject[key].toString();
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
return objectToReturn;
|
|
8
|
+
const stringifyBooleans = (savedObject: any, keysToConvert: Array<string>) => {
|
|
9
|
+
if (!Object.keys(savedObject).some((key) => keysToConvert.includes(key))) {
|
|
10
|
+
return savedObject;
|
|
17
11
|
}
|
|
18
|
-
|
|
12
|
+
const objectToReturn = { ...savedObject };
|
|
13
|
+
keysToConvert.forEach((key) => {
|
|
14
|
+
if (typeof savedObject[key] === 'boolean') {
|
|
15
|
+
objectToReturn[key] = savedObject[key].toString();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return objectToReturn;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const modelTableMapping = {
|
|
@@ -31,20 +31,21 @@ const modelTableMapping = {
|
|
|
31
31
|
|
|
32
32
|
export const sendDimEvent = (instance): void => {
|
|
33
33
|
const mapping = modelTableMapping[instance.constructor.name];
|
|
34
|
-
if (mapping) {
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
objectToSend = stringifyBools(instance.get(), KEYS_TO_CONVERT);
|
|
38
|
-
} catch (err) {
|
|
39
|
-
logger.error('Failed to convert booleans in dim event payload', err);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
events.sendObject(
|
|
43
|
-
mapping.tableName,
|
|
44
|
-
mapping.eventVersion,
|
|
45
|
-
objectToSend,
|
|
46
|
-
);
|
|
34
|
+
if (!mapping) {
|
|
35
|
+
return;
|
|
47
36
|
}
|
|
37
|
+
let objectToSend = instance.get();
|
|
38
|
+
try {
|
|
39
|
+
objectToSend = stringifyBooleans(instance.get(), KEYS_TO_CONVERT);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
logger.error('Failed to convert booleans in dim event payload', err);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
events.sendObject(
|
|
45
|
+
mapping.tableName,
|
|
46
|
+
mapping.eventVersion,
|
|
47
|
+
objectToSend,
|
|
48
|
+
);
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
export default events;
|
package/src/hooks/create.ts
CHANGED
|
@@ -28,8 +28,7 @@ export const beforeCreate = (scopeAttributes: string[], modelOptions: ModelOptio
|
|
|
28
28
|
const identifiers = applyScopeToInstance(instance, scopeAttributes);
|
|
29
29
|
|
|
30
30
|
// get all model's required definitions
|
|
31
|
-
const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType,
|
|
32
|
-
instance.id, identifiers, modelOptions);
|
|
31
|
+
const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType, instance.id, identifiers, modelOptions);
|
|
33
32
|
|
|
34
33
|
const customFieldsIdx = fields.indexOf('customFields');
|
|
35
34
|
const { customFields } = instance;
|
|
@@ -46,18 +46,18 @@ class CustomFieldDefinition extends Model {
|
|
|
46
46
|
defaultValue: DataType.UUIDV4,
|
|
47
47
|
allowNull: false,
|
|
48
48
|
})
|
|
49
|
-
|
|
49
|
+
id!: string;
|
|
50
50
|
|
|
51
51
|
@Column({
|
|
52
52
|
type: DataType.STRING,
|
|
53
53
|
allowNull: false,
|
|
54
54
|
})
|
|
55
|
-
|
|
55
|
+
name!: string;
|
|
56
56
|
|
|
57
57
|
@Column({
|
|
58
58
|
type: DataType.STRING,
|
|
59
59
|
})
|
|
60
|
-
|
|
60
|
+
displayName?: string; // Defaulted to name with beforeCreate hook
|
|
61
61
|
|
|
62
62
|
@Is('SupportedType', (value) => {
|
|
63
63
|
if (!Object.values(CustomFieldDefinitionType).includes(value as CustomFieldDefinitionType)) {
|
|
@@ -68,65 +68,65 @@ class CustomFieldDefinition extends Model {
|
|
|
68
68
|
type: DataType.STRING,
|
|
69
69
|
allowNull: false,
|
|
70
70
|
})
|
|
71
|
-
|
|
71
|
+
fieldType!: CustomFieldDefinitionType;
|
|
72
72
|
|
|
73
73
|
@Column({
|
|
74
74
|
type: DataType.JSONB,
|
|
75
75
|
})
|
|
76
|
-
|
|
76
|
+
validation?: any;
|
|
77
77
|
|
|
78
78
|
@Column({
|
|
79
79
|
type: DataType.UUID,
|
|
80
80
|
allowNull: false,
|
|
81
81
|
})
|
|
82
|
-
|
|
82
|
+
entityId!: string; /** Client association entity id */
|
|
83
83
|
|
|
84
84
|
@Column({
|
|
85
85
|
type: DataType.STRING,
|
|
86
86
|
allowNull: false,
|
|
87
87
|
})
|
|
88
|
-
|
|
88
|
+
entityType!: string; /** Client association entity type (demand source / fleet / etc.) */
|
|
89
89
|
|
|
90
90
|
@Column({
|
|
91
91
|
type: DataType.STRING,
|
|
92
92
|
allowNull: false,
|
|
93
93
|
})
|
|
94
|
-
|
|
94
|
+
modelType!: string; /** Model type. e.g. Vehicle / StopPoint / etc. */
|
|
95
95
|
|
|
96
96
|
@Column({
|
|
97
97
|
type: DataType.TEXT,
|
|
98
98
|
})
|
|
99
|
-
|
|
99
|
+
description?: string;
|
|
100
100
|
|
|
101
101
|
@Column({
|
|
102
102
|
type: DataType.BOOLEAN,
|
|
103
103
|
defaultValue: false,
|
|
104
104
|
})
|
|
105
|
-
|
|
105
|
+
required?: boolean;
|
|
106
106
|
|
|
107
107
|
@Column({
|
|
108
108
|
type: DataType.BOOLEAN,
|
|
109
109
|
defaultValue: false,
|
|
110
110
|
})
|
|
111
|
-
|
|
111
|
+
disabled?: boolean;
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
@Column({
|
|
114
|
+
type: DataType.JSONB,
|
|
115
|
+
allowNull: true,
|
|
116
|
+
})
|
|
117
|
+
defaultValue?: any;
|
|
118
118
|
|
|
119
119
|
@Column
|
|
120
|
-
|
|
120
|
+
createdAt?: Date;
|
|
121
121
|
|
|
122
122
|
@Column
|
|
123
|
-
|
|
123
|
+
updatedAt?: Date;
|
|
124
124
|
|
|
125
125
|
@Column
|
|
126
|
-
|
|
126
|
+
deletedAt?: Date;
|
|
127
127
|
|
|
128
128
|
@HasMany(() => CustomFieldValue)
|
|
129
|
-
|
|
129
|
+
values: CustomFieldValue[];
|
|
130
130
|
|
|
131
131
|
@BeforeCreate
|
|
132
132
|
static displayNameDefaultValue(instance: CustomFieldDefinition): void {
|
|
@@ -28,7 +28,7 @@ class CustomFieldValue extends Model {
|
|
|
28
28
|
type: DataType.UUID,
|
|
29
29
|
allowNull: false,
|
|
30
30
|
})
|
|
31
|
-
|
|
31
|
+
modelId!: string;
|
|
32
32
|
|
|
33
33
|
@PrimaryKey
|
|
34
34
|
@ForeignKey(() => CustomFieldDefinition)
|
|
@@ -36,25 +36,25 @@ class CustomFieldValue extends Model {
|
|
|
36
36
|
type: DataType.UUID,
|
|
37
37
|
allowNull: false,
|
|
38
38
|
})
|
|
39
|
-
|
|
39
|
+
customFieldDefinitionId!: string;
|
|
40
40
|
|
|
41
41
|
@Column({
|
|
42
42
|
type: DataType.JSONB,
|
|
43
43
|
allowNull: true,
|
|
44
44
|
})
|
|
45
|
-
|
|
45
|
+
value!: any;
|
|
46
46
|
|
|
47
47
|
@Column
|
|
48
|
-
|
|
48
|
+
createdAt?: Date;
|
|
49
49
|
|
|
50
50
|
@Column
|
|
51
|
-
|
|
51
|
+
updatedAt?: Date;
|
|
52
52
|
|
|
53
53
|
@Column
|
|
54
|
-
|
|
54
|
+
deletedAt?: Date;
|
|
55
55
|
|
|
56
56
|
@BelongsTo(() => CustomFieldDefinition, { scope: { disabled: false } })
|
|
57
|
-
|
|
57
|
+
customFieldDefinition: CustomFieldDefinition;
|
|
58
58
|
|
|
59
59
|
@BeforeBulkCreate
|
|
60
60
|
@BeforeBulkUpdate
|
|
@@ -18,40 +18,40 @@ class AssociatedTestModel extends Model {
|
|
|
18
18
|
defaultValue: DataType.UUIDV4,
|
|
19
19
|
allowNull: false,
|
|
20
20
|
})
|
|
21
|
-
|
|
21
|
+
id!: string;
|
|
22
22
|
|
|
23
23
|
@ForeignKey(() => TestModel)
|
|
24
24
|
@Column({
|
|
25
25
|
type: DataType.UUID,
|
|
26
26
|
allowNull: false,
|
|
27
27
|
})
|
|
28
|
-
|
|
28
|
+
testModelId!: string;
|
|
29
29
|
|
|
30
30
|
@Column({
|
|
31
31
|
type: DataType.UUID,
|
|
32
32
|
allowNull: false,
|
|
33
33
|
})
|
|
34
|
-
|
|
34
|
+
fleetId: string;
|
|
35
35
|
|
|
36
36
|
@Column({
|
|
37
37
|
type: DataType.UUID,
|
|
38
38
|
allowNull: true,
|
|
39
39
|
})
|
|
40
|
-
|
|
40
|
+
businessModelId: string;
|
|
41
41
|
|
|
42
42
|
@Column({
|
|
43
43
|
type: DataType.UUID,
|
|
44
44
|
allowNull: true,
|
|
45
45
|
})
|
|
46
|
-
|
|
46
|
+
demandSourceId: string;
|
|
47
47
|
|
|
48
48
|
@Column({
|
|
49
49
|
type: DataType.BOOLEAN,
|
|
50
50
|
})
|
|
51
|
-
|
|
51
|
+
anotherAttribute?: boolean;
|
|
52
52
|
|
|
53
53
|
@BelongsTo(() => TestModel)
|
|
54
|
-
|
|
54
|
+
testModel: TestModel;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export default AssociatedTestModel;
|
|
@@ -17,38 +17,38 @@ class TestModel extends Model {
|
|
|
17
17
|
defaultValue: DataType.UUIDV4,
|
|
18
18
|
allowNull: false,
|
|
19
19
|
})
|
|
20
|
-
|
|
20
|
+
id!: string;
|
|
21
21
|
|
|
22
22
|
@Column({
|
|
23
23
|
type: DataType.UUID,
|
|
24
24
|
allowNull: false,
|
|
25
25
|
})
|
|
26
|
-
|
|
26
|
+
fleetId: string;
|
|
27
27
|
|
|
28
28
|
@Column({
|
|
29
29
|
type: DataType.UUID,
|
|
30
30
|
allowNull: true,
|
|
31
31
|
})
|
|
32
|
-
|
|
32
|
+
businessModelId: string;
|
|
33
33
|
|
|
34
34
|
@Column({
|
|
35
35
|
type: DataType.UUID,
|
|
36
36
|
allowNull: true,
|
|
37
37
|
})
|
|
38
|
-
|
|
38
|
+
demandSourceId: string;
|
|
39
39
|
|
|
40
40
|
@Column({
|
|
41
41
|
type: DataType.BOOLEAN,
|
|
42
42
|
})
|
|
43
|
-
|
|
43
|
+
coolAttribute?: boolean;
|
|
44
44
|
|
|
45
45
|
@HasMany(() => AssociatedTestModel)
|
|
46
|
-
|
|
46
|
+
associatedModels: AssociatedTestModel[];
|
|
47
47
|
|
|
48
48
|
@Column({
|
|
49
49
|
type: DataType.VIRTUAL,
|
|
50
50
|
})
|
|
51
|
-
|
|
51
|
+
customFields?: any;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export default TestModel;
|
|
@@ -14,32 +14,30 @@ import ContextTestModel from './ContextTestModel';
|
|
|
14
14
|
|
|
15
15
|
@Table({ createdAt: false, updatedAt: false })
|
|
16
16
|
class ContextAwareTestModel extends Model {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
@PrimaryKey
|
|
18
|
+
@Column({
|
|
19
|
+
type: DataType.UUID,
|
|
20
|
+
defaultValue: DataType.UUIDV4,
|
|
21
|
+
allowNull: false,
|
|
22
|
+
})
|
|
23
23
|
id!: string;
|
|
24
24
|
|
|
25
25
|
@ForeignKey(() => ContextTestModel)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})
|
|
29
|
-
contextId: string;
|
|
26
|
+
@Column({ type: DataType.UUID })
|
|
27
|
+
contextId: string;
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
@Column({
|
|
30
|
+
type: DataType.BOOLEAN,
|
|
31
|
+
})
|
|
34
32
|
coolAttribute?: boolean;
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
@Column({
|
|
35
|
+
type: DataType.VIRTUAL,
|
|
36
|
+
})
|
|
39
37
|
customFields?: any;
|
|
40
38
|
|
|
41
39
|
@BelongsTo(() => ContextTestModel)
|
|
42
|
-
|
|
40
|
+
context: ContextTestModel;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
export default ContextAwareTestModel;
|
package/src/scopes/filter.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { Op, type WhereOptions } from 'sequelize';
|
|
3
3
|
import { Sequelize } from 'sequelize-typescript';
|
|
4
4
|
import { customFields } from '@autofleet/common-types';
|
|
5
|
-
import moment from 'moment';
|
|
6
5
|
import { generateRandomString } from '../utils/helpers';
|
|
7
6
|
|
|
8
7
|
const { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;
|
|
@@ -33,8 +32,10 @@ type customFieldsFilterScopeParams = {
|
|
|
33
32
|
scopeValue: Record<string, ConditionValue>;
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
|
|
36
|
+
|
|
36
37
|
const castIfNeeded = (conditionValue: string): string => {
|
|
37
|
-
if (
|
|
38
|
+
if (isDate(conditionValue)) {
|
|
38
39
|
return '::timestamp';
|
|
39
40
|
}
|
|
40
41
|
if (!Number.isNaN(Number(conditionValue))) {
|
|
@@ -112,7 +113,6 @@ export const customFieldsFilterScope = (
|
|
|
112
113
|
if (conditionsStrings.length === 0) {
|
|
113
114
|
return {};
|
|
114
115
|
}
|
|
115
|
-
|
|
116
116
|
const customFieldConditions = conditionsStrings.join(AND_DELIMETER);
|
|
117
117
|
const subQuery = `${'SELECT model_id FROM ('
|
|
118
118
|
+ 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
|
2
|
-
import {
|
|
3
|
-
type WhereOptions, Op, type BindOrReplacements,
|
|
4
|
-
} from 'sequelize';
|
|
2
|
+
import { type WhereOptions, Op, type BindOrReplacements } from 'sequelize';
|
|
5
3
|
import { type ModelStatic, Sequelize } from 'sequelize-typescript';
|
|
6
4
|
import { randomInt } from 'node:crypto';
|
|
7
5
|
import { CustomFieldDefinitionType } from '../constants';
|
|
@@ -66,34 +64,3 @@ export const generateCustomFieldSearchQueryPayload = (
|
|
|
66
64
|
replacements: { searchTerm: `%${searchTerm}%` },
|
|
67
65
|
};
|
|
68
66
|
};
|
|
69
|
-
|
|
70
|
-
export const excludeCustomFieldFilterScope = (
|
|
71
|
-
modelType: string,
|
|
72
|
-
keyToExclude: string,
|
|
73
|
-
valuesToExclude: string | string[],
|
|
74
|
-
): Omit<CustomFieldsSearchPayload, 'replacements'> => {
|
|
75
|
-
const keyToIgnore = keyToExclude.split('.')[1];
|
|
76
|
-
const valsToIgnore = Array.isArray(valuesToExclude) ? valuesToExclude.map((v) => `'"${v}"'`).join(', ') : null;
|
|
77
|
-
const customFieldsQuery = valsToIgnore ? `AND cv.value IN (${valsToIgnore})` : '';
|
|
78
|
-
const existsCondition = `
|
|
79
|
-
EXISTS (
|
|
80
|
-
SELECT 1
|
|
81
|
-
FROM custom_field_values cv
|
|
82
|
-
INNER JOIN custom_field_definitions cd
|
|
83
|
-
ON cv.custom_field_definition_id = cd.id
|
|
84
|
-
WHERE
|
|
85
|
-
cv.model_id = "${modelType}"."id"
|
|
86
|
-
AND cd.model_type = '${modelType}'
|
|
87
|
-
AND cd.name = '${keyToIgnore}'
|
|
88
|
-
${customFieldsQuery}
|
|
89
|
-
)
|
|
90
|
-
`;
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
where: {
|
|
94
|
-
[Op.and]: [
|
|
95
|
-
Sequelize.literal(existsCondition),
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
};
|
package/.env
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|