@autofleet/sadot 0.7.7-beta.0 → 0.7.7

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.
Files changed (99) hide show
  1. package/dist/api/v1/definition/validations.js +2 -24
  2. package/dist/events/index.js +20 -21
  3. package/dist/hooks/create.js +1 -1
  4. package/dist/models/CustomFieldDefinition.d.ts +0 -1
  5. package/dist/models/CustomFieldDefinition.js +0 -14
  6. package/dist/models/index.js +1 -1
  7. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js +3 -1
  8. package/dist/repository/value.d.ts +1 -1
  9. package/dist/repository/value.js +7 -36
  10. package/dist/scopes/filter.d.ts +3 -10
  11. package/dist/scopes/filter.js +40 -33
  12. package/dist/tests/mocks/definition.mock.d.ts +0 -2
  13. package/dist/tests/mocks/definition.mock.js +9 -10
  14. package/dist/types/definition/index.d.ts +0 -1
  15. package/dist/utils/logger/index.d.ts +1 -1
  16. package/dist/utils/logger/index.js +3 -5
  17. package/package.json +1 -2
  18. package/src/hooks/create.ts +42 -24
  19. package/src/repository/definition.ts +15 -6
  20. package/src/repository/value.ts +4 -20
  21. package/src/scopes/filter.ts +20 -18
  22. package/coverage/clover.xml +0 -1073
  23. package/coverage/coverage-final.json +0 -44
  24. package/coverage/lcov-report/base.css +0 -224
  25. package/coverage/lcov-report/block-navigation.js +0 -87
  26. package/coverage/lcov-report/favicon.png +0 -0
  27. package/coverage/lcov-report/index.html +0 -461
  28. package/coverage/lcov-report/prettify.css +0 -1
  29. package/coverage/lcov-report/prettify.js +0 -2
  30. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  31. package/coverage/lcov-report/sorter.js +0 -196
  32. package/coverage/lcov-report/src/api/index.html +0 -116
  33. package/coverage/lcov-report/src/api/index.ts.html +0 -112
  34. package/coverage/lcov-report/src/api/v1/definition/index.html +0 -131
  35. package/coverage/lcov-report/src/api/v1/definition/index.ts.html +0 -406
  36. package/coverage/lcov-report/src/api/v1/definition/validations.ts.html +0 -310
  37. package/coverage/lcov-report/src/api/v1/errors.ts.html +0 -133
  38. package/coverage/lcov-report/src/api/v1/index.html +0 -131
  39. package/coverage/lcov-report/src/api/v1/index.ts.html +0 -112
  40. package/coverage/lcov-report/src/errors/index.html +0 -116
  41. package/coverage/lcov-report/src/errors/index.ts.html +0 -211
  42. package/coverage/lcov-report/src/events/index.html +0 -116
  43. package/coverage/lcov-report/src/events/index.ts.html +0 -238
  44. package/coverage/lcov-report/src/hooks/create.ts.html +0 -262
  45. package/coverage/lcov-report/src/hooks/enrich.ts.html +0 -523
  46. package/coverage/lcov-report/src/hooks/find.ts.html +0 -166
  47. package/coverage/lcov-report/src/hooks/index.html +0 -191
  48. package/coverage/lcov-report/src/hooks/index.ts.html +0 -130
  49. package/coverage/lcov-report/src/hooks/update.ts.html +0 -211
  50. package/coverage/lcov-report/src/hooks/workaround.ts.html +0 -226
  51. package/coverage/lcov-report/src/index.html +0 -116
  52. package/coverage/lcov-report/src/index.ts.html +0 -235
  53. package/coverage/lcov-report/src/models/CustomFieldDefinition.ts.html +0 -550
  54. package/coverage/lcov-report/src/models/CustomFieldValue.ts.html +0 -415
  55. package/coverage/lcov-report/src/models/index.html +0 -146
  56. package/coverage/lcov-report/src/models/index.ts.html +0 -406
  57. package/coverage/lcov-report/src/models/tests/AssociatedTestModel.ts.html +0 -256
  58. package/coverage/lcov-report/src/models/tests/TestModel.ts.html +0 -247
  59. package/coverage/lcov-report/src/models/tests/contextAwareModels/ContextAwareTestModel.ts.html +0 -214
  60. package/coverage/lcov-report/src/models/tests/contextAwareModels/ContextTestModel.ts.html +0 -199
  61. package/coverage/lcov-report/src/models/tests/contextAwareModels/index.html +0 -131
  62. package/coverage/lcov-report/src/models/tests/index.html +0 -131
  63. package/coverage/lcov-report/src/repository/definition.ts.html +0 -466
  64. package/coverage/lcov-report/src/repository/index.html +0 -131
  65. package/coverage/lcov-report/src/repository/value.ts.html +0 -523
  66. package/coverage/lcov-report/src/scopes/filter.ts.html +0 -637
  67. package/coverage/lcov-report/src/scopes/index.html +0 -131
  68. package/coverage/lcov-report/src/scopes/index.ts.html +0 -103
  69. package/coverage/lcov-report/src/tests/api/index.html +0 -116
  70. package/coverage/lcov-report/src/tests/api/test-api.ts.html +0 -199
  71. package/coverage/lcov-report/src/tests/functional/searching/index.html +0 -116
  72. package/coverage/lcov-report/src/tests/functional/searching/index.ts.html +0 -202
  73. package/coverage/lcov-report/src/tests/helpers/database-config.ts.html +0 -130
  74. package/coverage/lcov-report/src/tests/helpers/index.html +0 -131
  75. package/coverage/lcov-report/src/tests/helpers/index.ts.html +0 -142
  76. package/coverage/lcov-report/src/tests/mocks/definition.mock.ts.html +0 -310
  77. package/coverage/lcov-report/src/tests/mocks/events.mock.ts.html +0 -139
  78. package/coverage/lcov-report/src/tests/mocks/index.html +0 -146
  79. package/coverage/lcov-report/src/tests/mocks/testModel.ts.html +0 -196
  80. package/coverage/lcov-report/src/utils/constants/index.html +0 -116
  81. package/coverage/lcov-report/src/utils/constants/index.ts.html +0 -160
  82. package/coverage/lcov-report/src/utils/db/index.html +0 -116
  83. package/coverage/lcov-report/src/utils/db/index.ts.html +0 -148
  84. package/coverage/lcov-report/src/utils/helpers/index.html +0 -116
  85. package/coverage/lcov-report/src/utils/helpers/index.ts.html +0 -283
  86. package/coverage/lcov-report/src/utils/index.html +0 -131
  87. package/coverage/lcov-report/src/utils/init.ts.html +0 -430
  88. package/coverage/lcov-report/src/utils/logger/index.html +0 -116
  89. package/coverage/lcov-report/src/utils/logger/index.ts.html +0 -100
  90. package/coverage/lcov-report/src/utils/scopeAttributes.ts.html +0 -121
  91. package/coverage/lcov-report/src/utils/validations/index.html +0 -116
  92. package/coverage/lcov-report/src/utils/validations/index.ts.html +0 -151
  93. package/coverage/lcov-report/src/utils/validations/schema/custom-fields.ts.html +0 -109
  94. package/coverage/lcov-report/src/utils/validations/schema/index.html +0 -116
  95. package/coverage/lcov-report/src/utils/validations/validators/index.html +0 -146
  96. package/coverage/lcov-report/src/utils/validations/validators/index.ts.html +0 -199
  97. package/coverage/lcov-report/src/utils/validations/validators/select.validator.ts.html +0 -118
  98. package/coverage/lcov-report/src/utils/validations/validators/status.validator.ts.html +0 -139
  99. package/coverage/lcov.info +0 -1818
@@ -6,17 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.validateCustomFieldDefinitionUpdate = exports.validateCustomFieldDefinitionCreation = void 0;
7
7
  const joi_1 = __importDefault(require("joi"));
8
8
  const constants_1 = require("../../../utils/constants");
9
- const FileValidationSchema = joi_1.default.object({
10
- name: joi_1.default.string().required(),
11
- type: joi_1.default.string(),
12
- size: joi_1.default.string(),
13
- addedBy: joi_1.default.string().uuid(),
14
- });
15
- const statusValidationObject = joi_1.default.object({
9
+ const statusValidationObjectSchema = joi_1.default.array().items(joi_1.default.object({
16
10
  value: joi_1.default.string().required(),
17
11
  color: joi_1.default.string().required(),
18
- });
19
- const statusValidationObjectSchema = joi_1.default.array().items(statusValidationObject).min(1).unique('value');
12
+ })).min(1).unique('value');
20
13
  /**
21
14
  * Schema for the validation of custom field definition
22
15
  * The only custom validation is for
@@ -35,24 +28,10 @@ const ValidationSchema = joi_1.default.when('fieldType', {
35
28
  then: statusValidationObjectSchema,
36
29
  otherwise: joi_1.default.any(),
37
30
  });
38
- const DefaultValueSchema = joi_1.default.when('fieldType', {
39
- switch: [
40
- { is: constants_1.CustomFieldDefinitionType.BOOLEAN, then: joi_1.default.boolean().allow(null) },
41
- { is: constants_1.CustomFieldDefinitionType.DATE, then: joi_1.default.date().allow(null) },
42
- { is: constants_1.CustomFieldDefinitionType.DATETIME, then: joi_1.default.date().allow(null) },
43
- { is: constants_1.CustomFieldDefinitionType.FILE, then: FileValidationSchema },
44
- { is: constants_1.CustomFieldDefinitionType.IMAGE, then: joi_1.default.string().uri().allow(null) },
45
- { is: constants_1.CustomFieldDefinitionType.NUMBER, then: joi_1.default.number().allow(null) },
46
- { is: constants_1.CustomFieldDefinitionType.SELECT, then: joi_1.default.string().allow(null) },
47
- { is: constants_1.CustomFieldDefinitionType.STATUS, then: statusValidationObject.allow(null) },
48
- { is: constants_1.CustomFieldDefinitionType.TEXT, then: joi_1.default.string().allow(null) },
49
- ],
50
- });
51
31
  const CustomFieldDefinitionCreationSchema = joi_1.default.object({
52
32
  name: joi_1.default.string().required(),
53
33
  displayName: joi_1.default.string().required(),
54
34
  validation: ValidationSchema,
55
- defaultValue: DefaultValueSchema,
56
35
  fieldType: joi_1.default.string().valid(...Object.values(constants_1.CustomFieldDefinitionType)).required(),
57
36
  entityId: joi_1.default.string().guid().required(),
58
37
  entityType: joi_1.default.string().required(),
@@ -63,7 +42,6 @@ const CustomFieldDefinitionCreationSchema = joi_1.default.object({
63
42
  const CustomFieldDefinitionUpdateSchema = joi_1.default.object({
64
43
  displayName: joi_1.default.string(),
65
44
  validation: ValidationSchema,
66
- defaultValue: DefaultValueSchema,
67
45
  fieldType: joi_1.default.string().valid(...Object.values(constants_1.CustomFieldDefinitionType)),
68
46
  description: joi_1.default.string().allow(null),
69
47
  required: joi_1.default.boolean(),
@@ -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', 'defaultValue'];
11
- const stringifyBooleans = (savedObject, keysToConvert) => {
12
- if (!Object.keys(savedObject).some((key) => keysToConvert.includes(key))) {
13
- return savedObject;
10
+ const KEYS_TO_CONVERT = ['value'];
11
+ const stringifyBools = (savedObject, keysToConvert) => {
12
+ if (Object.keys(savedObject).some((key) => keysToConvert.includes(key))) {
13
+ const objectToReturn = { ...savedObject };
14
+ keysToConvert.forEach((key) => {
15
+ if (typeof savedObject[key] === 'boolean') {
16
+ objectToReturn[key] = savedObject[key].toString();
17
+ }
18
+ });
19
+ return objectToReturn;
14
20
  }
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;
21
+ return savedObject;
22
22
  };
23
23
  const modelTableMapping = {
24
24
  CustomFieldDefinition: {
@@ -32,17 +32,16 @@ const modelTableMapping = {
32
32
  };
33
33
  const sendDimEvent = (instance) => {
34
34
  const mapping = modelTableMapping[instance.constructor.name];
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);
35
+ if (mapping) {
36
+ let objectToSend = instance.get();
37
+ try {
38
+ objectToSend = stringifyBools(instance.get(), KEYS_TO_CONVERT);
39
+ }
40
+ catch (err) {
41
+ logger_1.default.error('Failed to convert booleans in dim event payload', err);
42
+ }
43
+ events.sendObject(mapping.tableName, mapping.eventVersion, objectToSend);
44
44
  }
45
- events.sendObject(mapping.tableName, mapping.eventVersion, objectToSend);
46
45
  };
47
46
  exports.sendDimEvent = sendDimEvent;
48
47
  exports.default = events;
@@ -63,7 +63,7 @@ const beforeCreate = (scopeAttributes, modelOptions = {}) => async (instance, op
63
63
  await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, {
64
64
  transaction: options.transaction,
65
65
  modelOptions,
66
- }, true);
66
+ });
67
67
  // eslint-disable-next-line no-param-reassign
68
68
  fields.splice(customFieldsIdx, 1);
69
69
  }
@@ -13,7 +13,6 @@ declare class CustomFieldDefinition extends Model {
13
13
  description?: string;
14
14
  required?: boolean;
15
15
  disabled?: boolean;
16
- defaultValue?: any;
17
16
  createdAt?: Date;
18
17
  updatedAt?: Date;
19
18
  deletedAt?: Date;
@@ -19,19 +19,12 @@ const _1 = require(".");
19
19
  const events_1 = require("../events");
20
20
  const errors_1 = require("../errors");
21
21
  const logger_1 = __importDefault(require("../utils/logger"));
22
- const validations_1 = require("../utils/validations");
23
22
  let CustomFieldDefinition = class CustomFieldDefinition extends sequelize_typescript_1.Model {
24
23
  static displayNameDefaultValue(instance) {
25
24
  if (!instance?.displayName) {
26
25
  // eslint-disable-next-line no-param-reassign
27
26
  instance.displayName = instance.name;
28
27
  }
29
- if (![null, undefined].includes(instance.defaultValue)) {
30
- const isValid = (0, validations_1.validateValue)(instance.defaultValue, instance.fieldType, instance.validation);
31
- if (!isValid) {
32
- throw new errors_1.InvalidValueError(instance.defaultValue, instance.fieldType);
33
- }
34
- }
35
28
  }
36
29
  static afterSaveHandler(instance, options) {
37
30
  if (options.transaction) {
@@ -123,13 +116,6 @@ __decorate([
123
116
  }),
124
117
  __metadata("design:type", Boolean)
125
118
  ], CustomFieldDefinition.prototype, "disabled", void 0);
126
- __decorate([
127
- (0, sequelize_typescript_1.Column)({
128
- type: sequelize_typescript_1.DataType.JSONB,
129
- allowNull: true,
130
- }),
131
- __metadata("design:type", Object)
132
- ], CustomFieldDefinition.prototype, "defaultValue", void 0);
133
119
  __decorate([
134
120
  sequelize_typescript_1.Column,
135
121
  __metadata("design:type", Date)
@@ -22,7 +22,7 @@ exports.AssociatedTestModel = AssociatedTestModel_1.default;
22
22
  const productionModels = [CustomFieldDefinition_1.default, CustomFieldValue_1.default];
23
23
  const testModels = [TestModel_1.default, AssociatedTestModel_1.default, ContextAwareTestModel_1.default, ContextTestModel_1.default];
24
24
  const SADOT_MIGRATION_PREFIX = 'sadot-migration';
25
- const SCHEMA_VERSION = 2;
25
+ const SCHEMA_VERSION = 1;
26
26
  const CUSTOM_FIELDS_SCHEMA_VERSION = `${SADOT_MIGRATION_PREFIX}_${SCHEMA_VERSION}`;
27
27
  const initTables = async (sequelize, getUser) => {
28
28
  logger_1.default.info('custom-fields: initialize custom-fields tables');
@@ -28,7 +28,9 @@ __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)({ type: sequelize_typescript_1.DataType.UUID }),
31
+ (0, sequelize_typescript_1.Column)({
32
+ type: sequelize_typescript_1.DataType.UUID,
33
+ }),
32
34
  __metadata("design:type", String)
33
35
  ], ContextAwareTestModel.prototype, "contextId", void 0);
34
36
  __decorate([
@@ -24,5 +24,5 @@ export declare const findValuesByModelIds: (modelIds: string[], options?: any) =
24
24
  */
25
25
  export declare const updateValues: (modelType: string, modelId: string, identifiers: string[], valuesToUpdate: ValuesToUpdate, options?: FindOptions & {
26
26
  modelOptions?: ModelOptions;
27
- }, defineAllDefaults?: boolean) => Promise<CustomFieldValue[]>;
27
+ }) => Promise<CustomFieldValue[]>;
28
28
  export declare const deleteValue: (id: string, options?: any) => Promise<any>;
@@ -31,7 +31,6 @@ const models_1 = require("../models");
31
31
  const DefinitionRepo = __importStar(require("./definition"));
32
32
  const logger_1 = __importDefault(require("../utils/logger"));
33
33
  const errors_1 = require("../errors");
34
- const constants_1 = require("../utils/constants");
35
34
  const findByModelIdAndDefinition = async (modelId, customFieldDefinitionId) => models_1.CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [models_1.CustomFieldDefinition] });
36
35
  exports.findByModelIdAndDefinition = findByModelIdAndDefinition;
37
36
  const create = async (data, withAssociations = false) => {
@@ -67,24 +66,12 @@ const findValuesByModelIds = async (modelIds, options) => {
67
66
  });
68
67
  };
69
68
  exports.findValuesByModelIds = findValuesByModelIds;
70
- const formatFunctions = {
71
- [constants_1.CustomFieldDefinitionType.DATE]: (value) => {
72
- if (value) {
73
- const date = new Date(value);
74
- if (date.toString() === 'Invalid Date') {
75
- throw new Error(`Invalid date value: ${value}`);
76
- }
77
- return date.toISOString();
78
- }
79
- return null;
80
- },
81
- };
82
69
  /**
83
70
  * Try to update custom field values for a model instance.
84
71
  * Create new value record if not exists, but fails if value's definition not exist.
85
72
  * Return the updated values
86
73
  */
87
- const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}, defineAllDefaults = false) => {
74
+ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}) => {
88
75
  const names = Object.keys(valuesToUpdate);
89
76
  logger_1.default.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {
90
77
  names,
@@ -112,28 +99,12 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
112
99
  if (valuesWithDisabledDefinitions?.length > 0) {
113
100
  logger_1.default.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
114
101
  }
115
- const visitedFields = new Set();
116
- const values = names.map((name) => {
117
- const fieldDefinition = fieldDefinitions.find((def) => def.name === name);
118
- visitedFields.add(fieldDefinition);
119
- const formatFunction = formatFunctions[fieldDefinition.fieldType];
120
- return {
121
- modelId,
122
- value: (formatFunction ? formatFunction(valuesToUpdate[name]) : valuesToUpdate[name]) ?? fieldDefinition.defaultValue,
123
- updatedAt: new Date(),
124
- customFieldDefinitionId: fieldDefinition.id,
125
- };
126
- });
127
- if (defineAllDefaults) {
128
- fieldDefinitions.filter((def) => !visitedFields.has(def) && ![null, undefined].includes(def.defaultValue)).forEach(({ id, defaultValue }) => {
129
- values.push({
130
- modelId,
131
- value: defaultValue,
132
- updatedAt: new Date(),
133
- customFieldDefinitionId: id,
134
- });
135
- });
136
- }
102
+ const values = names.map((name) => ({
103
+ modelId,
104
+ value: valuesToUpdate[name],
105
+ updatedAt: new Date(),
106
+ customFieldDefinitionId: fieldDefinitions.find((def) => def.name === name).id,
107
+ }));
137
108
  return Promise.all(values.map(async (value) => {
138
109
  const [cfv] = await models_1.CustomFieldValue.upsert(value, {
139
110
  transaction: options.transaction,
@@ -17,10 +17,6 @@ export type CustomFieldFilterOptions = {
17
17
  where?: WhereOptions;
18
18
  replacements?: Record<string, string>;
19
19
  };
20
- type customFieldsFilterScopeParams = {
21
- replacementsMap: Record<string, string>;
22
- scopeValue: Record<string, ConditionValue>;
23
- };
24
20
  /**
25
21
  * A Sequelize scope for filtering models by custom fields.
26
22
  * This scope builds a WHERE clause to be applied on the main query.
@@ -28,12 +24,9 @@ type customFieldsFilterScopeParams = {
28
24
  * @param name - The model type name used to join custom_field_definitions.
29
25
  * @returns A function that takes conditions and returns the Sequelize options object.
30
26
  */
31
- export declare const customFieldsFilterScope: (name: string) => ({ replacementsMap: replacements, scopeValue: conditions, }: customFieldsFilterScopeParams) => CustomFieldFilterOptions;
27
+ export declare const customFieldsFilterScope: (name: string) => (conditions: Record<string, ConditionValue>) => CustomFieldFilterOptions;
32
28
  export declare const scopeName = "filterByCustomFields";
33
- export declare const customFieldsSortScope: (name: string) => ({ replacementsMap, scopeValue: sort }: {
34
- replacementsMap: any;
35
- scopeValue: any;
36
- }) => {
29
+ export declare const customFieldsSortScope: (name: string) => (sort: CustomFieldSort[]) => {
37
30
  attributes?: undefined;
38
31
  order?: undefined;
39
32
  replacements?: undefined;
@@ -42,6 +35,6 @@ export declare const customFieldsSortScope: (name: string) => ({ replacementsMap
42
35
  include: (string | import("sequelize/types/utils").Literal)[][];
43
36
  };
44
37
  order: import("sequelize/types/utils").Literal[];
45
- replacements: any;
38
+ replacements: Record<string, string>;
46
39
  };
47
40
  export {};
@@ -8,12 +8,11 @@ exports.customFieldsSortScope = exports.scopeName = exports.customFieldsFilterSc
8
8
  const sequelize_1 = require("sequelize");
9
9
  const sequelize_typescript_1 = require("sequelize-typescript");
10
10
  const common_types_1 = require("@autofleet/common-types");
11
+ const moment_1 = __importDefault(require("moment"));
11
12
  const helpers_1 = require("../utils/helpers");
12
- const logger_1 = __importDefault(require("../utils/logger"));
13
13
  const { CUSTOM_FIELDS_FILTER_SCOPE } = common_types_1.customFields;
14
- const isDate = (input) => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
15
14
  const castIfNeeded = (conditionValue) => {
16
- if (isDate(conditionValue)) {
15
+ if (moment_1.default.isDate(conditionValue)) {
17
16
  return '::timestamp';
18
17
  }
19
18
  if (!Number.isNaN(Number(conditionValue))) {
@@ -26,7 +25,8 @@ const OR_DELIMETER = ' OR ';
26
25
  const CD_TABLE_ALIAS = 'cd';
27
26
  const CD_NAME_COLUMN = `${CD_TABLE_ALIAS}.name`;
28
27
  const CV_TABLE_ALIAS = 'cv';
29
- const CV_VALUE_COLUMN = `(${CV_TABLE_ALIAS}.value::varchar)`;
28
+ const CV_VALUE_COLUMN = `(${CV_TABLE_ALIAS}.value)`;
29
+ const castValueToJsonb = (value) => `to_jsonb(${value}::text)`;
30
30
  /**
31
31
  * A Sequelize scope for filtering models by custom fields.
32
32
  * This scope builds a WHERE clause to be applied on the main query.
@@ -34,16 +34,18 @@ const CV_VALUE_COLUMN = `(${CV_TABLE_ALIAS}.value::varchar)`;
34
34
  * @param name - The model type name used to join custom_field_definitions.
35
35
  * @returns A function that takes conditions and returns the Sequelize options object.
36
36
  */
37
- const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scopeValue: conditions, }) => {
37
+ const customFieldsFilterScope = (name) => (conditions) => {
38
38
  if (!conditions || Object.keys(conditions).length === 0) {
39
39
  return {};
40
40
  }
41
+ const ConditionNameRandomStr = (0, helpers_1.generateRandomString)();
42
+ const replacements = {};
43
+ replacements[ConditionNameRandomStr] = `${name}`;
41
44
  // Build the WHERE clause for custom field filtering
42
45
  const conditionsStrings = Object.entries(conditions)
43
46
  .map(([key, condition]) => {
44
- const replacemetKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
45
- if (!replacemetKey)
46
- return false;
47
+ const replacemetKey = (0, helpers_1.generateRandomString)();
48
+ replacements[replacemetKey] = `${key}`;
47
49
  const columnCondition = `(${CD_NAME_COLUMN} = :${replacemetKey})`;
48
50
  if (Array.isArray(condition)) {
49
51
  if (condition.length === 0) {
@@ -52,24 +54,31 @@ const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scop
52
54
  }
53
55
  if (typeof condition[0] === 'string') {
54
56
  const values = condition.map((v) => {
55
- const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
56
- return `'"' || :${valRandom} || '"'`;
57
+ const valRandom = (0, helpers_1.generateRandomString)();
58
+ replacements[`${valRandom}`] = `${v}`;
59
+ return castValueToJsonb(`:${valRandom}`);
57
60
  }).join(',');
58
61
  return `(${columnCondition} AND ${CV_VALUE_COLUMN} IN ( ${values} ))`;
59
62
  }
60
63
  return condition
61
64
  .map((c) => {
62
- const valRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === c.value);
63
- return `( ${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(c.value)} ${c.operator} '"' || :${valRep} || '"' )`;
65
+ const valRep = (0, helpers_1.generateRandomString)();
66
+ replacements[valRep] = `${c.value}`;
67
+ const valueAsJsonb = castValueToJsonb(`:${valRep}`);
68
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(c.value)} ${c.operator} ${valueAsJsonb})`;
64
69
  }).join(AND_DELIMETER);
65
70
  }
66
71
  if (typeof condition === 'string' || typeof condition === 'number') {
67
- const conditionRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === condition);
68
- return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition)} = '"' || :${conditionRep} || '"')`;
72
+ const conditionRep = (0, helpers_1.generateRandomString)();
73
+ replacements[conditionRep] = `${condition}`;
74
+ const valueAsJsonb = castValueToJsonb(`:${conditionRep}`);
75
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition)} = ${valueAsJsonb})`;
69
76
  }
70
77
  if (condition?.operator) {
71
- const valueRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === condition.value);
72
- return `( ${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition.value)} ${condition.operator} '"' || :${valueRep} || '"')`;
78
+ const valueRep = (0, helpers_1.generateRandomString)();
79
+ replacements[valueRep] = `${condition.value}`;
80
+ const valueAsJsonb = castValueToJsonb(`:${valueRep}`);
81
+ return `( ${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition.value)} ${condition.operator} ${valueAsJsonb})`;
73
82
  }
74
83
  return false;
75
84
  })
@@ -79,15 +88,14 @@ const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scop
79
88
  }
80
89
  const customFieldConditions = conditionsStrings.join(OR_DELIMETER);
81
90
  const subQuery = `
82
- SELECT cv.model_id
83
- FROM custom_field_values AS cv
84
- INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
85
- AND cd.model_type = '${name}'
86
- WHERE ${customFieldConditions}
87
- GROUP BY cv.model_id
88
- HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${conditionsStrings.length}
89
- `.replace(/\n/g, '');
90
- logger_1.default.info('custom fields filter scope', { subQuery, replacements });
91
+ SELECT cv.model_id
92
+ FROM custom_field_values AS cv
93
+ INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
94
+ AND cd.model_type = :${ConditionNameRandomStr}
95
+ WHERE ${customFieldConditions}
96
+ GROUP BY cv.model_id
97
+ HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${conditionsStrings.length}
98
+ `.replace(/\n/g, '');
91
99
  return {
92
100
  where: {
93
101
  id: {
@@ -99,13 +107,15 @@ const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scop
99
107
  };
100
108
  exports.customFieldsFilterScope = customFieldsFilterScope;
101
109
  exports.scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
102
- const customFieldsSortScope = (name) => ({ replacementsMap, scopeValue: sort }) => {
110
+ const customFieldsSortScope = (name) => (sort) => {
103
111
  if (!sort || sort.length === 0) {
104
112
  return {};
105
113
  }
106
114
  const randomStr = (0, helpers_1.generateRandomString)();
115
+ const replacements = {};
107
116
  const includes = Object.entries(sort).map(([key]) => {
108
- const replacemetKey = Object.keys(replacementsMap).find((randomString) => replacementsMap[randomString] === key);
117
+ const keyRandomReplacement = (0, helpers_1.generateRandomString)();
118
+ replacements[keyRandomReplacement] = `${key}`;
109
119
  return ([
110
120
  sequelize_typescript_1.Sequelize.literal(`(
111
121
  SELECT value
@@ -114,22 +124,19 @@ const customFieldsSortScope = (name) => ({ replacementsMap, scopeValue: sort })
114
124
  ON cv.custom_field_definition_id = cd.id
115
125
  AND cd.model_type = '${name}'
116
126
  WHERE cv.model_id = "${name}"."id"
117
- AND cd.name = :${replacemetKey}
127
+ AND cd.name = :${keyRandomReplacement}
118
128
  ) AS CustomFieldAggregation
119
129
  )
120
130
  `), randomStr,
121
131
  ]);
122
132
  });
123
- const orders = Object.entries(sort).map(([, sortObject]) => {
124
- const direction = typeof sortObject === 'string' ? sortObject : Object.values(sortObject)[0];
125
- return sequelize_typescript_1.Sequelize.literal(`"${randomStr}" ${direction || 'ASC'}`);
126
- });
133
+ const orders = Object.entries(sort).map(([, value]) => sequelize_typescript_1.Sequelize.literal(`"${randomStr}" ${value}`));
127
134
  return {
128
135
  attributes: {
129
136
  include: includes,
130
137
  },
131
138
  order: orders,
132
- replacements: replacementsMap,
139
+ replacements,
133
140
  };
134
141
  };
135
142
  exports.customFieldsSortScope = customFieldsSortScope;
@@ -14,7 +14,6 @@ export declare const coolFieldDefinition2: {
14
14
  createdAt?: Date;
15
15
  updatedAt?: Date;
16
16
  deletedAt?: Date;
17
- defaultValue?: any;
18
17
  displayName?: string;
19
18
  validation?: any;
20
19
  fieldType: string;
@@ -30,7 +29,6 @@ export declare const coolFieldDefinition3: {
30
29
  createdAt?: Date;
31
30
  updatedAt?: Date;
32
31
  deletedAt?: Date;
33
- defaultValue?: any;
34
32
  displayName?: string;
35
33
  validation?: any;
36
34
  fieldType: string;
@@ -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 node_crypto_1 = require("node:crypto");
4
+ const uuid_1 = require("uuid");
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, node_crypto_1.randomUUID)(),
15
+ entityId: (0, uuid_1.v4)(),
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, node_crypto_1.randomUUID)(),
30
+ entityId: (0, uuid_1.v4)(),
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, node_crypto_1.randomUUID)(),
39
+ entityId: (0, uuid_1.v4)(),
40
40
  entityType: 'fleetId',
41
41
  });
42
42
  exports.selectField = selectField;
@@ -45,25 +45,24 @@ const statusField = (modelType, options) => ({
45
45
  modelType,
46
46
  fieldType: 'status',
47
47
  validation: options,
48
- entityId: (0, node_crypto_1.randomUUID)(),
48
+ entityId: (0, uuid_1.v4)(),
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, node_crypto_1.randomUUID)()}`,
54
+ name: defaults?.name || `def_${(0, uuid_1.v4)()}`,
55
55
  modelType: defaults?.modelType || 'TestModel',
56
56
  fieldType: defaults?.fieldType || 'boolean',
57
- entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
57
+ entityId: defaults?.entityId || (0, uuid_1.v4)(),
58
58
  entityType: defaults?.entityType || 'fleetId',
59
- ...(defaults?.defaultValue && { defaultValue: defaults.defaultValue }),
60
59
  });
61
60
  exports.createDefinition = createDefinition;
62
61
  const createDefinitions = (defaults, length = 1) => (Array(length).fill({}).map((_) => ({
63
- name: defaults?.name || `def_${(0, node_crypto_1.randomUUID)()}`,
62
+ name: defaults?.name || `def_${(0, uuid_1.v4)()}`,
64
63
  modelType: defaults?.modelType || 'TestModel',
65
64
  fieldType: defaults?.fieldType || 'boolean',
66
- entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
65
+ entityId: defaults?.entityId || (0, uuid_1.v4)(),
67
66
  entityType: defaults?.entityType || 'fleetId',
68
67
  })));
69
68
  exports.createDefinitions = createDefinitions;
@@ -3,7 +3,6 @@ export interface CustomFieldDefinitionDTO {
3
3
  name: string;
4
4
  displayName?: string;
5
5
  validation?: any;
6
- defaultValue?: any;
7
6
  fieldType: string;
8
7
  entityId: string;
9
8
  entityType: string;
@@ -1,2 +1,2 @@
1
- declare const logger: import("@autofleet/logger").LoggerInstanceManager;
1
+ declare const logger: any;
2
2
  export default logger;
@@ -1,8 +1,6 @@
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
- const logger_1 = __importDefault(require("@autofleet/logger"));
7
- const logger = (0, logger_1.default)();
3
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
4
+ const Logger = require('@autofleet/logger');
5
+ const logger = Logger();
8
6
  exports.default = logger;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.7.7-beta.0",
3
+ "version": "0.7.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -8,7 +8,6 @@
8
8
  "build": "rm -rf dist && tsc",
9
9
  "linter": "eslint .",
10
10
  "test": "jest --forceExit --runInBand",
11
- "test-debug": "node --inspect-brk node_modules/.bin/jest --runInBand --testTimeout=10000000",
12
11
  "coverage": "jest --coverage --forceExit --runInBand && rm -rf ./coverage",
13
12
  "build-to-local-repo": "node --run build && cp -r dist/* ../$REPO/node_modules/$npm_package_name/dist",
14
13
  "dev": "nodemon",