@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/scopes/filter.js
CHANGED
|
@@ -6,18 +6,8 @@ const sequelize_1 = require("sequelize");
|
|
|
6
6
|
const sequelize_typescript_1 = require("sequelize-typescript");
|
|
7
7
|
const common_types_1 = require("@autofleet/common-types");
|
|
8
8
|
const helpers_1 = require("../utils/helpers");
|
|
9
|
+
const filter_helpers_1 = require("./helpers/filter.helpers");
|
|
9
10
|
const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
|
|
10
|
-
const isDate = (input) => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
|
|
11
|
-
const castIfNeeded = (conditionValue) => {
|
|
12
|
-
if (isDate(conditionValue)) {
|
|
13
|
-
return '::timestamp';
|
|
14
|
-
}
|
|
15
|
-
if (!Number.isNaN(Number(conditionValue))) {
|
|
16
|
-
return '::numeric';
|
|
17
|
-
}
|
|
18
|
-
return '';
|
|
19
|
-
};
|
|
20
|
-
const AND_DELIMETER = ' AND ';
|
|
21
11
|
/**
|
|
22
12
|
* A Sequelize scope for filtering models by custom fields.
|
|
23
13
|
* This scope builds a WHERE clause to be applied on the main query.
|
|
@@ -25,56 +15,27 @@ const AND_DELIMETER = ' AND ';
|
|
|
25
15
|
* @param name - The model type name used to join custom_field_definitions.
|
|
26
16
|
* @returns A function that takes conditions and returns the Sequelize options object.
|
|
27
17
|
*/
|
|
28
|
-
const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scopeValue: conditions
|
|
18
|
+
const customFieldsFilterScope = (name, options) => ({ replacementsMap: replacements, scopeValue: conditions }) => {
|
|
29
19
|
if (!conditions || Object.keys(conditions).length === 0) {
|
|
30
20
|
return {};
|
|
31
21
|
}
|
|
22
|
+
const queryType = options?.useCustomFieldsEntries ? filter_helpers_1.SubQueryType.ENTRIES : filter_helpers_1.SubQueryType.VALUES;
|
|
23
|
+
const reverseReplacementsMap = new Map(Object.entries(replacements).map(([key, value]) => [value, key]));
|
|
32
24
|
// Build the WHERE clause for custom field filtering
|
|
33
|
-
const conditionsStrings = Object.entries(conditions)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// if empty array, the condition is ignored
|
|
25
|
+
const conditionsStrings = Object.entries(conditions).map(([key, condition]) => {
|
|
26
|
+
switch (queryType) {
|
|
27
|
+
case filter_helpers_1.SubQueryType.ENTRIES:
|
|
28
|
+
return (0, filter_helpers_1.formatConditionsForEntries)(key, condition, reverseReplacementsMap);
|
|
29
|
+
case filter_helpers_1.SubQueryType.VALUES:
|
|
30
|
+
return (0, filter_helpers_1.formatConditionsForValues)(key, condition, reverseReplacementsMap);
|
|
31
|
+
default:
|
|
41
32
|
return false;
|
|
42
|
-
}
|
|
43
|
-
if (typeof condition[0] === 'string') {
|
|
44
|
-
const values = condition.map((v) => {
|
|
45
|
-
const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
|
|
46
|
-
return ` :${valRandom} `;
|
|
47
|
-
}).join(',');
|
|
48
|
-
return `(custom_fields->> :${replacemetKey} ) IN ( ${values} )`;
|
|
49
|
-
}
|
|
50
|
-
return condition
|
|
51
|
-
.map((c) => {
|
|
52
|
-
const valRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === c.value);
|
|
53
|
-
return `(custom_fields->> :${replacemetKey} )${castIfNeeded(c.value)} ${c.operator} :${valRep}`;
|
|
54
|
-
}).join(AND_DELIMETER);
|
|
55
|
-
}
|
|
56
|
-
if (typeof condition === 'string' || typeof condition === 'number') {
|
|
57
|
-
const conditionRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === condition);
|
|
58
|
-
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition)} = :${conditionRep}`;
|
|
59
|
-
}
|
|
60
|
-
if (condition?.operator) {
|
|
61
|
-
const valueRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === condition.value);
|
|
62
|
-
return `(custom_fields->> :${replacemetKey} ) ${castIfNeeded(condition.value)} ${condition.operator} :${valueRep}`;
|
|
63
33
|
}
|
|
64
|
-
|
|
65
|
-
})
|
|
66
|
-
.filter(Boolean);
|
|
34
|
+
}).filter(Boolean);
|
|
67
35
|
if (conditionsStrings.length === 0) {
|
|
68
36
|
return {};
|
|
69
37
|
}
|
|
70
|
-
const
|
|
71
|
-
const subQuery = `${'SELECT model_id FROM ('
|
|
72
|
-
+ 'SELECT cv.model_id, jsonb_object_agg(cd.name, cv.value) AS custom_fields '
|
|
73
|
-
+ 'FROM custom_field_values AS cv '
|
|
74
|
-
+ 'INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id '
|
|
75
|
-
+ `AND cd.model_type = '${name}'`
|
|
76
|
-
+ 'GROUP BY cv.model_id'
|
|
77
|
-
+ ') AS CustomFieldAggregation WHERE '} ${customFieldConditions}`;
|
|
38
|
+
const subQuery = (0, filter_helpers_1.getFilterCustomFieldsSubQuery)(queryType, name, conditionsStrings);
|
|
78
39
|
return {
|
|
79
40
|
where: {
|
|
80
41
|
id: {
|
|
@@ -86,25 +47,17 @@ const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scop
|
|
|
86
47
|
};
|
|
87
48
|
exports.customFieldsFilterScope = customFieldsFilterScope;
|
|
88
49
|
exports.scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
|
|
89
|
-
const customFieldsSortScope = (name) => ({ replacementsMap, scopeValue: sort }) => {
|
|
50
|
+
const customFieldsSortScope = (name, options) => ({ replacementsMap, scopeValue: sort }) => {
|
|
90
51
|
if (!sort || sort.length === 0) {
|
|
91
52
|
return {};
|
|
92
53
|
}
|
|
54
|
+
const queryType = options?.useCustomFieldsEntries ? filter_helpers_1.SubQueryType.ENTRIES : filter_helpers_1.SubQueryType.VALUES;
|
|
93
55
|
const randomStr = (0, helpers_1.generateRandomString)();
|
|
94
56
|
const includes = Object.entries(sort).map(([key]) => {
|
|
95
|
-
const
|
|
57
|
+
const replacementKey = Object.keys(replacementsMap).find((randomString) => replacementsMap[randomString] === key);
|
|
96
58
|
return ([
|
|
97
|
-
sequelize_typescript_1.Sequelize.literal(
|
|
98
|
-
|
|
99
|
-
FROM (SELECT cv.model_id, cv.value
|
|
100
|
-
FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd
|
|
101
|
-
ON cv.custom_field_definition_id = cd.id
|
|
102
|
-
AND cd.model_type = '${name}'
|
|
103
|
-
WHERE cv.model_id = "${name}"."id"
|
|
104
|
-
AND cd.name = :${replacemetKey}
|
|
105
|
-
) AS CustomFieldAggregation
|
|
106
|
-
)
|
|
107
|
-
`), randomStr,
|
|
59
|
+
sequelize_typescript_1.Sequelize.literal((0, filter_helpers_1.getSortCustomFieldsSubQuery)(queryType, name, replacementKey)),
|
|
60
|
+
randomStr,
|
|
108
61
|
]);
|
|
109
62
|
});
|
|
110
63
|
const orders = Object.entries(sort).map(([, sortObject]) => {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { WhereOptions } from 'sequelize';
|
|
2
|
+
/**
|
|
3
|
+
* Type representing possible condition values.
|
|
4
|
+
* Currently supporting strings and arrays of strings.
|
|
5
|
+
* More types to be added (TBA).
|
|
6
|
+
*/
|
|
7
|
+
export 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
|
+
};
|
|
20
|
+
export declare enum SubQueryType {
|
|
21
|
+
VALUES = "values",
|
|
22
|
+
ENTRIES = "entries"
|
|
23
|
+
}
|
|
24
|
+
export declare const isConditionStringArray: (input: any) => input is string[];
|
|
25
|
+
export declare const isBooleanString: (input: string) => boolean;
|
|
26
|
+
export declare const isDate: (input: any) => input is Date;
|
|
27
|
+
export declare const castValueToJsonb: (value: string, type: string) => string;
|
|
28
|
+
export declare const castValueToJsonbText: (value: string) => string;
|
|
29
|
+
export declare const castValueToJsonbBoolean: (value: string) => string;
|
|
30
|
+
export declare const castValueToJsonbNumeric: (value: string) => string;
|
|
31
|
+
export declare const castIfNeeded: (columnName: string, conditionValue: string) => string;
|
|
32
|
+
export declare const AND_DELIMITER = " AND ";
|
|
33
|
+
export declare const OR_DELIMITER = " OR ";
|
|
34
|
+
export declare const CD_TABLE_ALIAS = "cd";
|
|
35
|
+
export declare const CD_NAME_COLUMN = "cd.name";
|
|
36
|
+
export declare const CV_TABLE_ALIAS = "cv";
|
|
37
|
+
export declare const CV_VALUE_COLUMN = "cv.value";
|
|
38
|
+
export declare const CE_TABLE_ALIAS = "ce";
|
|
39
|
+
export declare const getFilterCustomFieldsSubQuery: (queryType: SubQueryType, modelType: string, conditionsStrings: Array<string | boolean>) => string;
|
|
40
|
+
export declare const getSortCustomFieldsSubQuery: (queryType: SubQueryType, modelType: string, replacementKey: string) => string;
|
|
41
|
+
export declare const formatConditionsForValues: (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>) => string | false;
|
|
42
|
+
export declare const formatConditionsForEntries: (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>) => string | false;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatConditionsForEntries = exports.formatConditionsForValues = exports.getSortCustomFieldsSubQuery = exports.getFilterCustomFieldsSubQuery = exports.CE_TABLE_ALIAS = exports.CV_VALUE_COLUMN = exports.CV_TABLE_ALIAS = exports.CD_NAME_COLUMN = exports.CD_TABLE_ALIAS = exports.OR_DELIMITER = exports.AND_DELIMITER = exports.castIfNeeded = exports.castValueToJsonbNumeric = exports.castValueToJsonbBoolean = exports.castValueToJsonbText = exports.castValueToJsonb = exports.isDate = exports.isBooleanString = exports.isConditionStringArray = exports.SubQueryType = void 0;
|
|
4
|
+
var SubQueryType;
|
|
5
|
+
(function (SubQueryType) {
|
|
6
|
+
SubQueryType["VALUES"] = "values";
|
|
7
|
+
SubQueryType["ENTRIES"] = "entries";
|
|
8
|
+
})(SubQueryType || (exports.SubQueryType = SubQueryType = {}));
|
|
9
|
+
const isConditionStringArray = (input) => Array.isArray(input) && typeof input[0] === 'string';
|
|
10
|
+
exports.isConditionStringArray = isConditionStringArray;
|
|
11
|
+
const isBooleanString = (input) => ['true', 'false'].includes(input.toString());
|
|
12
|
+
exports.isBooleanString = isBooleanString;
|
|
13
|
+
const isDate = (input) => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
|
|
14
|
+
exports.isDate = isDate;
|
|
15
|
+
const castValueToJsonb = (value, type) => `to_jsonb(${value}::${type})`;
|
|
16
|
+
exports.castValueToJsonb = castValueToJsonb;
|
|
17
|
+
const castValueToJsonbText = (value) => (0, exports.castValueToJsonb)(value, 'text');
|
|
18
|
+
exports.castValueToJsonbText = castValueToJsonbText;
|
|
19
|
+
const castValueToJsonbBoolean = (value) => (0, exports.castValueToJsonb)(value, 'boolean');
|
|
20
|
+
exports.castValueToJsonbBoolean = castValueToJsonbBoolean;
|
|
21
|
+
const castValueToJsonbNumeric = (value) => (0, exports.castValueToJsonb)(value, 'numeric');
|
|
22
|
+
exports.castValueToJsonbNumeric = castValueToJsonbNumeric;
|
|
23
|
+
const castIfNeeded = (columnName, conditionValue) => {
|
|
24
|
+
if ((0, exports.isDate)(conditionValue)) {
|
|
25
|
+
return (0, exports.castValueToJsonb)(columnName, 'timestamp');
|
|
26
|
+
}
|
|
27
|
+
return columnName;
|
|
28
|
+
};
|
|
29
|
+
exports.castIfNeeded = castIfNeeded;
|
|
30
|
+
exports.AND_DELIMITER = ' AND ';
|
|
31
|
+
exports.OR_DELIMITER = ' OR ';
|
|
32
|
+
exports.CD_TABLE_ALIAS = 'cd';
|
|
33
|
+
exports.CD_NAME_COLUMN = `${exports.CD_TABLE_ALIAS}.name`;
|
|
34
|
+
exports.CV_TABLE_ALIAS = 'cv';
|
|
35
|
+
exports.CV_VALUE_COLUMN = `${exports.CV_TABLE_ALIAS}.value`;
|
|
36
|
+
exports.CE_TABLE_ALIAS = 'ce';
|
|
37
|
+
const getSingleConditionWithOperator = (value, operator, replacementKey, reverseReplacementsMap) => {
|
|
38
|
+
let type = 'text';
|
|
39
|
+
if ((0, exports.isDate)(value)) {
|
|
40
|
+
type = 'date';
|
|
41
|
+
}
|
|
42
|
+
else if (!Number.isNaN(Number(value))) {
|
|
43
|
+
type = 'numeric';
|
|
44
|
+
}
|
|
45
|
+
else if ((0, exports.isBooleanString)(value)) {
|
|
46
|
+
type = 'boolean';
|
|
47
|
+
}
|
|
48
|
+
const replacedValue = reverseReplacementsMap.get(value);
|
|
49
|
+
return `(jsonb_extract_path_text(${exports.CE_TABLE_ALIAS}.custom_fields, :${replacementKey})::${type}) ${operator} :${replacedValue}`;
|
|
50
|
+
};
|
|
51
|
+
const getFormattedValue = (value) => {
|
|
52
|
+
let formattedValue = value;
|
|
53
|
+
if ((0, exports.isBooleanString)(value)) {
|
|
54
|
+
formattedValue = value === 'true';
|
|
55
|
+
}
|
|
56
|
+
else if (!Number.isNaN(Number(value))) {
|
|
57
|
+
formattedValue = Number(value);
|
|
58
|
+
}
|
|
59
|
+
return formattedValue;
|
|
60
|
+
};
|
|
61
|
+
const getJSONSubQuery = (value, key) => {
|
|
62
|
+
const formattedValue = getFormattedValue(value);
|
|
63
|
+
const jsonQuery = JSON.stringify({ [key]: formattedValue });
|
|
64
|
+
let jsonQueryWithStringBoolean;
|
|
65
|
+
if ((0, exports.isBooleanString)(value)) {
|
|
66
|
+
jsonQueryWithStringBoolean = `${exports.CE_TABLE_ALIAS}.custom_fields @> '${JSON.stringify({ [key]: value })}'`;
|
|
67
|
+
}
|
|
68
|
+
return `
|
|
69
|
+
(
|
|
70
|
+
${jsonQueryWithStringBoolean ? `${jsonQueryWithStringBoolean} OR` : ''}
|
|
71
|
+
${exports.CE_TABLE_ALIAS}.custom_fields @> '${jsonQuery}'
|
|
72
|
+
)
|
|
73
|
+
`;
|
|
74
|
+
};
|
|
75
|
+
const getFilterCustomFieldsSubQuery = (queryType, modelType, conditionsStrings) => {
|
|
76
|
+
switch (queryType) {
|
|
77
|
+
case SubQueryType.VALUES:
|
|
78
|
+
return `
|
|
79
|
+
SELECT ${exports.CV_TABLE_ALIAS}.model_id
|
|
80
|
+
FROM custom_field_values AS ${exports.CV_TABLE_ALIAS}
|
|
81
|
+
INNER JOIN custom_field_definitions AS ${exports.CD_TABLE_ALIAS} ON ${exports.CV_TABLE_ALIAS}.custom_field_definition_id = ${exports.CD_TABLE_ALIAS}.id
|
|
82
|
+
${exports.AND_DELIMITER}${exports.CD_TABLE_ALIAS}.model_type = '${modelType}'
|
|
83
|
+
WHERE ${conditionsStrings.join(exports.OR_DELIMITER)}
|
|
84
|
+
${exports.AND_DELIMITER}${exports.CV_TABLE_ALIAS}.deleted_at IS NULL${exports.AND_DELIMITER}${exports.CD_TABLE_ALIAS}.deleted_at IS NULL
|
|
85
|
+
GROUP BY ${exports.CV_TABLE_ALIAS}.model_id
|
|
86
|
+
HAVING COUNT(DISTINCT ${exports.CV_TABLE_ALIAS}.custom_field_definition_id) = ${conditionsStrings.length}
|
|
87
|
+
`.replace(/\n/g, '');
|
|
88
|
+
case SubQueryType.ENTRIES:
|
|
89
|
+
return `
|
|
90
|
+
SELECT ce.model_id
|
|
91
|
+
FROM custom_field_entries ce
|
|
92
|
+
JOIN custom_field_definitions cfd
|
|
93
|
+
ON ce.model_type = cfd.model_type
|
|
94
|
+
AND ce.entity_id = cfd.entity_id
|
|
95
|
+
WHERE
|
|
96
|
+
cfd.deleted_at IS NULL AND
|
|
97
|
+
${conditionsStrings.join(exports.AND_DELIMITER)}
|
|
98
|
+
`;
|
|
99
|
+
default:
|
|
100
|
+
throw new Error('Invalid query type');
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
exports.getFilterCustomFieldsSubQuery = getFilterCustomFieldsSubQuery;
|
|
104
|
+
const getSortCustomFieldsSubQuery = (queryType, modelType, replacementKey) => {
|
|
105
|
+
switch (queryType) {
|
|
106
|
+
case SubQueryType.VALUES:
|
|
107
|
+
return `(
|
|
108
|
+
SELECT value
|
|
109
|
+
FROM (SELECT cv.model_id, cv.value
|
|
110
|
+
FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd
|
|
111
|
+
ON cv.custom_field_definition_id = cd.id
|
|
112
|
+
${exports.AND_DELIMITER}cd.model_type = '${modelType}'
|
|
113
|
+
WHERE cv.model_id = "${modelType}"."id"
|
|
114
|
+
${exports.AND_DELIMITER}cd.name = :${replacementKey}
|
|
115
|
+
) AS CustomFieldAggregation
|
|
116
|
+
)
|
|
117
|
+
`;
|
|
118
|
+
case SubQueryType.ENTRIES:
|
|
119
|
+
return `(
|
|
120
|
+
SELECT
|
|
121
|
+
customFields.value
|
|
122
|
+
FROM
|
|
123
|
+
custom_field_entries AS ${exports.CE_TABLE_ALIAS},
|
|
124
|
+
jsonb_each_text(custom_fields) AS customFields
|
|
125
|
+
WHERE
|
|
126
|
+
customFields.key = :${replacementKey}${exports.AND_DELIMITER}
|
|
127
|
+
${exports.CE_TABLE_ALIAS}.model_type = '${modelType}'${exports.AND_DELIMITER}
|
|
128
|
+
${exports.CE_TABLE_ALIAS}.model_id = "${modelType}"."id"
|
|
129
|
+
)
|
|
130
|
+
`;
|
|
131
|
+
default:
|
|
132
|
+
throw new Error('Invalid query type');
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
exports.getSortCustomFieldsSubQuery = getSortCustomFieldsSubQuery;
|
|
136
|
+
const formatConditionsForValues = (key, condition, reverseReplacementsMap) => {
|
|
137
|
+
const replacementKey = reverseReplacementsMap.get(key);
|
|
138
|
+
if (!replacementKey) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const columnCondition = `(${exports.CD_NAME_COLUMN} = :${replacementKey})`;
|
|
142
|
+
if (Array.isArray(condition)) {
|
|
143
|
+
if (condition.length === 0) {
|
|
144
|
+
// if empty array, the condition is ignored
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
if ((0, exports.isConditionStringArray)(condition)) {
|
|
148
|
+
const values = condition.flatMap((v) => {
|
|
149
|
+
const valRandom = reverseReplacementsMap.get(v);
|
|
150
|
+
if ((0, exports.isBooleanString)(v)) {
|
|
151
|
+
return [(0, exports.castValueToJsonbText)(`:${valRandom}`), (0, exports.castValueToJsonbBoolean)(`:${valRandom}`)];
|
|
152
|
+
}
|
|
153
|
+
if (!Number.isNaN(Number(v))) {
|
|
154
|
+
return (0, exports.castValueToJsonbNumeric)(`:${valRandom}`);
|
|
155
|
+
}
|
|
156
|
+
return (0, exports.castValueToJsonbText)(`:${valRandom}`);
|
|
157
|
+
}).join(',');
|
|
158
|
+
return `(${columnCondition}${exports.AND_DELIMITER}${exports.CV_VALUE_COLUMN} IN (${values}))`;
|
|
159
|
+
}
|
|
160
|
+
return condition.map((c) => {
|
|
161
|
+
const valRep = reverseReplacementsMap.get(c.value);
|
|
162
|
+
const valueAsJsonb = (0, exports.castValueToJsonbText)(`:${valRep}`);
|
|
163
|
+
return `(${columnCondition}${exports.AND_DELIMITER}${(0, exports.castIfNeeded)(exports.CV_VALUE_COLUMN, c.value)} ${c.operator} ${valueAsJsonb})`;
|
|
164
|
+
}).join(exports.AND_DELIMITER);
|
|
165
|
+
}
|
|
166
|
+
if (typeof condition === 'string' || typeof condition === 'number') {
|
|
167
|
+
const conditionRep = reverseReplacementsMap.get(condition);
|
|
168
|
+
const valueAsJsonb = !Number.isNaN(Number(condition)) ? (0, exports.castValueToJsonbNumeric)(`:${conditionRep}`) : (0, exports.castValueToJsonbText)(`:${conditionRep}`);
|
|
169
|
+
const valueAsJsonbBoolean = (0, exports.isBooleanString)(condition) ? `${exports.OR_DELIMITER}${exports.CV_VALUE_COLUMN} = ${(0, exports.castValueToJsonbBoolean)(`:${conditionRep}`)}` : '';
|
|
170
|
+
return `(${columnCondition}${exports.AND_DELIMITER}(${(0, exports.castIfNeeded)(exports.CV_VALUE_COLUMN, condition)} = ${valueAsJsonb}${valueAsJsonbBoolean}))`;
|
|
171
|
+
}
|
|
172
|
+
if (condition?.operator) {
|
|
173
|
+
const valueRep = reverseReplacementsMap.get(condition.value);
|
|
174
|
+
const valueAsJsonb = (0, exports.castValueToJsonbText)(`:${valueRep}`);
|
|
175
|
+
return `( ${columnCondition}${exports.AND_DELIMITER}${(0, exports.castIfNeeded)(exports.CV_VALUE_COLUMN, condition.value)} ${condition.operator} ${valueAsJsonb})`;
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
};
|
|
179
|
+
exports.formatConditionsForValues = formatConditionsForValues;
|
|
180
|
+
const formatConditionsForEntries = (key, condition, reverseReplacementsMap) => {
|
|
181
|
+
const replacementKey = reverseReplacementsMap.get(key);
|
|
182
|
+
if (!replacementKey) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (Array.isArray(condition)) {
|
|
186
|
+
if (condition.length === 0) {
|
|
187
|
+
// if empty array, the condition is ignored
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
if ((0, exports.isConditionStringArray)(condition)) {
|
|
191
|
+
const values = condition.map((value) => getJSONSubQuery(value, key)).join(`${exports.OR_DELIMITER}\n`);
|
|
192
|
+
return `( ${values})`;
|
|
193
|
+
}
|
|
194
|
+
return condition.map((c) => getSingleConditionWithOperator(c.value, c.operator, replacementKey, reverseReplacementsMap)).join(exports.AND_DELIMITER);
|
|
195
|
+
}
|
|
196
|
+
if (typeof condition === 'string' || typeof condition === 'number') {
|
|
197
|
+
return getJSONSubQuery(condition, key);
|
|
198
|
+
}
|
|
199
|
+
if (condition?.operator) {
|
|
200
|
+
return getSingleConditionWithOperator(condition.value, condition.operator, replacementKey, reverseReplacementsMap);
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
};
|
|
204
|
+
exports.formatConditionsForEntries = formatConditionsForEntries;
|
|
@@ -1,33 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
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;
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
4
|
};
|
|
25
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
const express_1 =
|
|
6
|
+
const express_1 = __importDefault(require("express"));
|
|
7
|
+
const node_common_1 = require("@autofleet/node-common");
|
|
8
|
+
const logger_1 = __importDefault(require("../../utils/logger"));
|
|
27
9
|
const models_1 = require("../../models");
|
|
28
10
|
const app = (0, express_1.default)();
|
|
29
11
|
app.use(express_1.default.json());
|
|
30
|
-
const api = (0,
|
|
12
|
+
const api = (0, node_common_1.Router)({ logger: logger_1.default });
|
|
31
13
|
api.get('/v1/test-models', async (req, res) => {
|
|
32
14
|
const testModels = await models_1.TestModel.findAll();
|
|
33
15
|
return res.json(testModels);
|
|
@@ -0,0 +1,62 @@
|
|
|
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.commonTestHooks = void 0;
|
|
30
|
+
const __1 = __importDefault(require("../.."));
|
|
31
|
+
const _1 = require(".");
|
|
32
|
+
const database_config_1 = __importDefault(require("./database-config"));
|
|
33
|
+
const db_1 = __importStar(require("../../utils/db"));
|
|
34
|
+
function commonTestHooks(app = null, models = [{ name: 'TestModel', scopeAttributes: ['fleetId'] }], options = {
|
|
35
|
+
useCustomFieldsEntries: false,
|
|
36
|
+
useValidators: false,
|
|
37
|
+
}) {
|
|
38
|
+
let sequelize;
|
|
39
|
+
beforeAll(async () => {
|
|
40
|
+
sequelize = (0, db_1.default)(database_config_1.default);
|
|
41
|
+
await (0, db_1.createSequelizeMeta)(sequelize);
|
|
42
|
+
await (0, __1.default)(app, _1.getModel, {
|
|
43
|
+
models,
|
|
44
|
+
databaseConfig: database_config_1.default,
|
|
45
|
+
getUser: () => undefined,
|
|
46
|
+
sequelize,
|
|
47
|
+
useCustomFieldsEntries: options.useCustomFieldsEntries,
|
|
48
|
+
useValidators: options.useValidators,
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
afterEach(async () => {
|
|
52
|
+
jest.clearAllMocks();
|
|
53
|
+
await (0, _1.cleanup)({
|
|
54
|
+
useCustomFieldsEntries: options.useCustomFieldsEntries,
|
|
55
|
+
useValidators: options.useValidators,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
afterAll(async () => {
|
|
59
|
+
await sequelize.close();
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
exports.commonTestHooks = commonTestHooks;
|
|
@@ -4,7 +4,7 @@ exports.default = {
|
|
|
4
4
|
test: {
|
|
5
5
|
username: process.env.DB_USERNAME || '',
|
|
6
6
|
password: process.env.DB_PASSWORD || null,
|
|
7
|
-
database: process.env.DB_NAME || '
|
|
7
|
+
database: process.env.DB_NAME || 'postgres',
|
|
8
8
|
host: process.env.DB_HOST || '127.0.0.1',
|
|
9
9
|
port: process.env.DB_PORT || 5432,
|
|
10
10
|
dialect: process.env.DB_TYPE || 'postgres',
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { CustomFieldOptions } from '../../types';
|
|
2
|
+
export declare const cleanup: (options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries' | 'useValidators'>) => Promise<void>;
|
|
2
3
|
export declare const getModel: (name: string) => any;
|
|
4
|
+
export declare const getReplacementMapWithScopeValue: (conditions: Record<string, any>) => {
|
|
5
|
+
replacementsMap: Record<string, string>;
|
|
6
|
+
scopeValue: Record<string, any>;
|
|
7
|
+
};
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getModel = exports.cleanup = void 0;
|
|
3
|
+
exports.getReplacementMapWithScopeValue = exports.getModel = exports.cleanup = void 0;
|
|
4
|
+
const sheilta_1 = require("@autofleet/sheilta");
|
|
4
5
|
const models_1 = require("../../models");
|
|
5
6
|
// eslint-disable-next-line import/prefer-default-export
|
|
6
|
-
const cleanup = async () => {
|
|
7
|
+
const cleanup = async (options) => {
|
|
7
8
|
if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'development') {
|
|
8
9
|
await models_1.CustomFieldDefinition.unscoped().destroy({ where: {} });
|
|
9
10
|
await models_1.TestModel.destroy({ where: {} });
|
|
10
11
|
await models_1.ContextAwareTestModel.destroy({ where: {} });
|
|
11
12
|
await models_1.ContextTestModel.destroy({ where: {} });
|
|
13
|
+
if (options?.useCustomFieldsEntries) {
|
|
14
|
+
await models_1.CustomFieldEntries.unscoped().destroy({ where: {} });
|
|
15
|
+
}
|
|
16
|
+
// Clean up validators if they were used
|
|
17
|
+
if (options?.useValidators) {
|
|
18
|
+
await models_1.CustomValidator.unscoped().destroy({ where: {} });
|
|
19
|
+
}
|
|
12
20
|
}
|
|
13
21
|
};
|
|
14
22
|
exports.cleanup = cleanup;
|
|
@@ -18,3 +26,8 @@ const getModel = (name) => {
|
|
|
18
26
|
return models[name];
|
|
19
27
|
};
|
|
20
28
|
exports.getModel = getModel;
|
|
29
|
+
const getReplacementMapWithScopeValue = (conditions) => ({
|
|
30
|
+
replacementsMap: (0, sheilta_1.generateFilterReplacements)(Object.fromEntries(Object.entries(conditions).map(([key, value]) => [`customFields.${key}`, value]))),
|
|
31
|
+
scopeValue: conditions,
|
|
32
|
+
});
|
|
33
|
+
exports.getReplacementMapWithScopeValue = getReplacementMapWithScopeValue;
|
|
@@ -15,9 +15,10 @@ export declare const coolFieldDefinition2: {
|
|
|
15
15
|
updatedAt?: Date;
|
|
16
16
|
deletedAt?: Date;
|
|
17
17
|
defaultValue?: any;
|
|
18
|
+
blockEditingFromUI?: boolean;
|
|
18
19
|
displayName?: string;
|
|
19
|
-
validation?: any;
|
|
20
20
|
fieldType: string;
|
|
21
|
+
validation?: any;
|
|
21
22
|
entityId: string;
|
|
22
23
|
entityType: string;
|
|
23
24
|
modelType: string;
|
|
@@ -31,9 +32,10 @@ export declare const coolFieldDefinition3: {
|
|
|
31
32
|
updatedAt?: Date;
|
|
32
33
|
deletedAt?: Date;
|
|
33
34
|
defaultValue?: any;
|
|
35
|
+
blockEditingFromUI?: boolean;
|
|
34
36
|
displayName?: string;
|
|
35
|
-
validation?: any;
|
|
36
37
|
fieldType: string;
|
|
38
|
+
validation?: any;
|
|
37
39
|
entityId: string;
|
|
38
40
|
entityType: string;
|
|
39
41
|
modelType: string;
|
|
@@ -41,5 +43,6 @@ export declare const coolFieldDefinition3: {
|
|
|
41
43
|
export declare const booleanField: (modelType: string) => CreateCustomFieldDefinition;
|
|
42
44
|
export declare const selectField: (modelType: string, options: any) => CreateCustomFieldDefinition;
|
|
43
45
|
export declare const statusField: (modelType: string, options: any) => CreateCustomFieldDefinition;
|
|
46
|
+
export declare const fileField: (modelType: string) => CreateCustomFieldDefinition;
|
|
44
47
|
export declare const createDefinition: (defaults: Partial<CustomFieldDefinitionDTO>) => CreateCustomFieldDefinition;
|
|
45
48
|
export declare const createDefinitions: (defaults: Partial<CustomFieldDefinitionDTO>, length?: number) => CreateCustomFieldDefinition[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createDefinitions = exports.createDefinition = exports.statusField = exports.selectField = exports.booleanField = exports.coolFieldDefinition3 = exports.coolFieldDefinition2 = exports.coolFieldDefinition = exports.contextAwareFieldDefinition = void 0;
|
|
3
|
+
exports.createDefinitions = exports.createDefinition = exports.fileField = exports.statusField = exports.selectField = exports.booleanField = exports.coolFieldDefinition3 = exports.coolFieldDefinition2 = exports.coolFieldDefinition = exports.contextAwareFieldDefinition = void 0;
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
5
|
exports.contextAwareFieldDefinition = {
|
|
6
6
|
name: 'cool field',
|
|
@@ -49,6 +49,14 @@ const statusField = (modelType, options) => ({
|
|
|
49
49
|
entityType: 'fleetId',
|
|
50
50
|
});
|
|
51
51
|
exports.statusField = statusField;
|
|
52
|
+
const fileField = (modelType) => ({
|
|
53
|
+
name: 'file',
|
|
54
|
+
modelType,
|
|
55
|
+
fieldType: 'file',
|
|
56
|
+
entityId: (0, node_crypto_1.randomUUID)(),
|
|
57
|
+
entityType: 'fleetId',
|
|
58
|
+
});
|
|
59
|
+
exports.fileField = fileField;
|
|
52
60
|
// eslint-disable-next-line max-len
|
|
53
61
|
const createDefinition = (defaults) => ({
|
|
54
62
|
name: defaults?.name || `def_${(0, node_crypto_1.randomUUID)()}`,
|
|
@@ -56,6 +64,7 @@ const createDefinition = (defaults) => ({
|
|
|
56
64
|
fieldType: defaults?.fieldType || 'boolean',
|
|
57
65
|
entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
|
|
58
66
|
entityType: defaults?.entityType || 'fleetId',
|
|
67
|
+
...(defaults?.validation && { validation: defaults.validation }),
|
|
59
68
|
...(defaults?.defaultValue && { defaultValue: defaults.defaultValue }),
|
|
60
69
|
});
|
|
61
70
|
exports.createDefinition = createDefinition;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare const mockEvent: (events: any, eventName: any, numberOfEvents: any) => any[];
|
|
2
2
|
export declare const mockDimCustomFieldDefinitionEvent: (events: any, numberOfEvents: any) => any[];
|
|
3
3
|
export declare const mockDimCustomFieldValueEvent: (events: any, numberOfEvents: any) => any[];
|
|
4
|
+
export declare const mockDimCustomFieldEntriesEvent: (events: any, numberOfEvents: any) => any[];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/* eslint-disable no-param-reassign */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.mockDimCustomFieldValueEvent = exports.mockDimCustomFieldDefinitionEvent = exports.mockEvent = void 0;
|
|
4
|
+
exports.mockDimCustomFieldEntriesEvent = exports.mockDimCustomFieldValueEvent = exports.mockDimCustomFieldDefinitionEvent = exports.mockEvent = void 0;
|
|
5
5
|
const mockEvent = (events, eventName, numberOfEvents) => {
|
|
6
|
-
events.sendObject = jest.fn();
|
|
6
|
+
events.sendObject = jest.fn().mockResolvedValue(true);
|
|
7
7
|
return [
|
|
8
8
|
events.sendObject,
|
|
9
9
|
() => {
|
|
@@ -17,3 +17,5 @@ const mockDimCustomFieldDefinitionEvent = (events, numberOfEvents) => (0, export
|
|
|
17
17
|
exports.mockDimCustomFieldDefinitionEvent = mockDimCustomFieldDefinitionEvent;
|
|
18
18
|
const mockDimCustomFieldValueEvent = (events, numberOfEvents) => (0, exports.mockEvent)(events, 'dim_custom_field_value', numberOfEvents);
|
|
19
19
|
exports.mockDimCustomFieldValueEvent = mockDimCustomFieldValueEvent;
|
|
20
|
+
const mockDimCustomFieldEntriesEvent = (events, numberOfEvents) => (0, exports.mockEvent)(events, 'dim_custom_field_entries', numberOfEvents);
|
|
21
|
+
exports.mockDimCustomFieldEntriesEvent = mockDimCustomFieldEntriesEvent;
|
|
@@ -14,6 +14,7 @@ export interface CustomFieldDefinitionDTO {
|
|
|
14
14
|
createdAt?: Date;
|
|
15
15
|
updatedAt?: Date;
|
|
16
16
|
deletedAt?: Date;
|
|
17
|
+
blockEditingFromUI?: boolean;
|
|
17
18
|
}
|
|
18
19
|
export type CreateCustomFieldDefinition = Omit<CustomFieldDefinitionDTO, 'id'>;
|
|
19
20
|
export type UpdateCustomFieldDefinition = Partial<CreateCustomFieldDefinition>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ValidationError } from 'joi';
|
|
2
|
+
export interface CustomFieldEntriesDTO {
|
|
3
|
+
modelId: string;
|
|
4
|
+
entityId: string;
|
|
5
|
+
modelType: string;
|
|
6
|
+
/**
|
|
7
|
+
* A collection of custom fields where each key is the name of a CustomFieldDefinition and
|
|
8
|
+
* each value is the value of that custom field for this specific `modelId`.
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
* {
|
|
12
|
+
* "vehicleColor": "Red",
|
|
13
|
+
* "vehicleType": "premium",
|
|
14
|
+
* "isActive": true
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
17
|
+
customFields: Record<string, any>;
|
|
18
|
+
createdAt?: Date;
|
|
19
|
+
updatedAt?: Date;
|
|
20
|
+
}
|
|
21
|
+
export interface EntriesValidationError {
|
|
22
|
+
value: any;
|
|
23
|
+
fieldDefinitionName: string;
|
|
24
|
+
joiValidationError: ValidationError;
|
|
25
|
+
}
|