@autofleet/sadot 0.7.8-beta-1 → 0.7.8-beta--beta-1.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.
@@ -6,10 +6,17 @@ 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 statusValidationObjectSchema = joi_1.default.array().items(joi_1.default.object({
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({
10
16
  value: joi_1.default.string().required(),
11
17
  color: joi_1.default.string().required(),
12
- })).min(1).unique('value');
18
+ });
19
+ const statusValidationObjectSchema = joi_1.default.array().items(statusValidationObject).min(1).unique('value');
13
20
  /**
14
21
  * Schema for the validation of custom field definition
15
22
  * The only custom validation is for
@@ -28,10 +35,24 @@ const ValidationSchema = joi_1.default.when('fieldType', {
28
35
  then: statusValidationObjectSchema,
29
36
  otherwise: joi_1.default.any(),
30
37
  });
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
+ });
31
51
  const CustomFieldDefinitionCreationSchema = joi_1.default.object({
32
52
  name: joi_1.default.string().required(),
33
53
  displayName: joi_1.default.string().required(),
34
54
  validation: ValidationSchema,
55
+ defaultValue: DefaultValueSchema,
35
56
  fieldType: joi_1.default.string().valid(...Object.values(constants_1.CustomFieldDefinitionType)).required(),
36
57
  entityId: joi_1.default.string().guid().required(),
37
58
  entityType: joi_1.default.string().required(),
@@ -42,6 +63,7 @@ const CustomFieldDefinitionCreationSchema = joi_1.default.object({
42
63
  const CustomFieldDefinitionUpdateSchema = joi_1.default.object({
43
64
  displayName: joi_1.default.string(),
44
65
  validation: ValidationSchema,
66
+ defaultValue: DefaultValueSchema,
45
67
  fieldType: joi_1.default.string().valid(...Object.values(constants_1.CustomFieldDefinitionType)),
46
68
  description: joi_1.default.string().allow(null),
47
69
  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'];
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;
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
- return savedObject;
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
- 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);
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;
@@ -48,27 +48,43 @@ exports.beforeBulkCreate = beforeBulkCreate;
48
48
  const beforeCreate = (scopeAttributes, modelOptions = {}) => async (instance, options) => {
49
49
  logger_1.default.debug('sadot - before create hook');
50
50
  const { fields } = options;
51
+ const { include, useEntityIdFromInclude } = modelOptions;
51
52
  const modelType = instance.constructor.name;
52
53
  const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
53
- // get all model's required definitions
54
- const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType, instance.id, identifiers, modelOptions);
54
+ const where = {
55
+ modelType,
56
+ disabled: false,
57
+ ...(!useEntityIdFromInclude && { entityId: identifiers }),
58
+ };
59
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: false, transaction: options.transaction, include: include?.(identifiers) });
60
+ const requiredFieldsNames = Array.from(new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)));
55
61
  const customFieldsIdx = fields.indexOf('customFields');
56
- const { customFields } = instance;
57
- if (customFieldsIdx > -1 && customFields) {
58
- const fieldsNames = Object.keys(customFields);
59
- const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
60
- if (missingFields?.length > 0) {
61
- throw new errors_1.MissingRequiredCustomFieldError(missingFields);
62
- }
63
- await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, {
64
- transaction: options.transaction,
65
- modelOptions,
66
- });
62
+ if ((customFieldsIdx === -1 || !instance.customFields) && requiredFieldsNames?.length > 0) {
63
+ throw new errors_1.MissingRequiredCustomFieldError(requiredFieldsNames);
64
+ }
65
+ const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
66
+ if (fieldsWithDefaultValue.length) {
67
67
  // eslint-disable-next-line no-param-reassign
68
- fields.splice(customFieldsIdx, 1);
68
+ instance.customFields || (instance.customFields = {});
69
+ fieldsWithDefaultValue.filter((def) => !(def.name in instance.customFields)).forEach(({ name, defaultValue }) => {
70
+ // eslint-disable-next-line no-param-reassign
71
+ instance.customFields[name] = defaultValue;
72
+ });
69
73
  }
70
- else if (requiredFieldsNames?.length > 0) {
71
- throw new errors_1.MissingRequiredCustomFieldError(requiredFieldsNames);
74
+ const { customFields } = instance;
75
+ if (customFieldsIdx === -1 || !customFields) {
76
+ return;
72
77
  }
78
+ const fieldsNames = Object.keys(customFields);
79
+ const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
80
+ if (missingFields?.length > 0) {
81
+ throw new errors_1.MissingRequiredCustomFieldError(missingFields);
82
+ }
83
+ await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, {
84
+ transaction: options.transaction,
85
+ modelOptions,
86
+ });
87
+ // eslint-disable-next-line no-param-reassign
88
+ fields.splice(customFieldsIdx, 1);
73
89
  };
74
90
  exports.beforeCreate = beforeCreate;
@@ -13,6 +13,7 @@ declare class CustomFieldDefinition extends Model {
13
13
  description?: string;
14
14
  required?: boolean;
15
15
  disabled?: boolean;
16
+ defaultValue?: any;
16
17
  createdAt?: Date;
17
18
  updatedAt?: Date;
18
19
  deletedAt?: Date;
@@ -19,12 +19,19 @@ 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");
22
23
  let CustomFieldDefinition = class CustomFieldDefinition extends sequelize_typescript_1.Model {
23
24
  static displayNameDefaultValue(instance) {
24
25
  if (!instance?.displayName) {
25
26
  // eslint-disable-next-line no-param-reassign
26
27
  instance.displayName = instance.name;
27
28
  }
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
+ }
28
35
  }
29
36
  static afterSaveHandler(instance, options) {
30
37
  if (options.transaction) {
@@ -116,6 +123,13 @@ __decorate([
116
123
  }),
117
124
  __metadata("design:type", Boolean)
118
125
  ], 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);
119
133
  __decorate([
120
134
  sequelize_typescript_1.Column,
121
135
  __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 = 1;
25
+ const SCHEMA_VERSION = 2;
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,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([
@@ -1,20 +1,26 @@
1
- import { type FindOptions, type WhereOptions } from 'sequelize';
1
+ import { type Includeable, type Transaction, type FindOptions, type WhereOptions } from 'sequelize';
2
2
  import { CustomFieldDefinition } from '../models';
3
3
  import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
4
4
  import type { ModelOptions } from '../types';
5
5
  export declare const create: (data: CreateCustomFieldDefinition) => Promise<CustomFieldDefinition>;
6
- export declare const findAll: (where: WhereOptions, options?: any) => Promise<CustomFieldDefinition[]>;
7
- export declare const findByIds: (ids: string[], options?: any) => Promise<CustomFieldDefinition[]>;
8
- export declare const findById: (id: string, options?: any) => Promise<CustomFieldDefinition | null>;
6
+ interface SadotFindOptions {
7
+ withDisabled?: boolean;
8
+ transaction?: Transaction;
9
+ include?: Includeable | Includeable[];
10
+ }
11
+ export declare const findAll: (where: WhereOptions, options?: SadotFindOptions) => Promise<CustomFieldDefinition[]>;
12
+ export declare const findByIds: (ids: string[], options?: SadotFindOptions) => Promise<CustomFieldDefinition[]>;
13
+ export declare const findById: (id: string, options?: Pick<SadotFindOptions, 'withDisabled'>) => Promise<CustomFieldDefinition | null>;
9
14
  export declare const findByEntityIds: (modelType: string, entityIds: string[], options?: FindOptions & {
10
15
  modelOptions?: ModelOptions;
11
16
  }) => Promise<CustomFieldDefinition[]>;
12
17
  export declare const findByWhere: (where: any) => Promise<CustomFieldDefinition | null>;
13
18
  export declare const findDefinitionsByModels: (modelTypes: string[], options?: any) => Promise<CustomFieldDefinition[]>;
14
19
  export declare const update: (id: string, data: UpdateCustomFieldDefinition) => Promise<CustomFieldDefinition>;
15
- export declare const disable: (id: string) => Promise<any>;
16
- export declare const destroy: (id: string) => Promise<any>;
20
+ export declare const disable: (id: string) => Promise<[affectedCount: number]>;
21
+ export declare const destroy: (id: string) => Promise<number>;
17
22
  /**
18
23
  * Return the names of the required fields for a given model
19
24
  */
20
25
  export declare const getRequiredFields: (modelType: string, modelId: string | string[], entityId: string | string[], modelOptions?: ModelOptions) => Promise<string[]>;
26
+ export {};
@@ -31,6 +31,7 @@ const models_1 = require("../models");
31
31
  const DefinitionRepo = __importStar(require("./definition"));
32
32
  const logger_1 = __importDefault(require("../utils/logger"));
33
33
  const errors_1 = require("../errors");
34
+ const constants_1 = require("../utils/constants");
34
35
  const findByModelIdAndDefinition = async (modelId, customFieldDefinitionId) => models_1.CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [models_1.CustomFieldDefinition] });
35
36
  exports.findByModelIdAndDefinition = findByModelIdAndDefinition;
36
37
  const create = async (data, withAssociations = false) => {
@@ -66,6 +67,18 @@ const findValuesByModelIds = async (modelIds, options) => {
66
67
  });
67
68
  };
68
69
  exports.findValuesByModelIds = findValuesByModelIds;
70
+ const formatFunctions = {
71
+ [constants_1.CustomFieldDefinitionType.DATE]: (value) => {
72
+ if (value) {
73
+ const date = new Date(value);
74
+ if (date.toString() === 'Invalid Date') {
75
+ throw new Error(`Invalid date value: ${value}`);
76
+ }
77
+ return date.toISOString();
78
+ }
79
+ return null;
80
+ },
81
+ };
69
82
  /**
70
83
  * Try to update custom field values for a model instance.
71
84
  * Create new value record if not exists, but fails if value's definition not exist.
@@ -83,11 +96,9 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
83
96
  const where = {
84
97
  modelType,
85
98
  name: names,
99
+ ...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),
86
100
  };
87
- if (!options.modelOptions?.useEntityIdFromInclude) {
88
- where.entityId = identifiers;
89
- }
90
- const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) || [];
101
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) ?? [];
91
102
  const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
92
103
  if (fieldDefinitions.length !== names.length) {
93
104
  logger_1.default.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });
@@ -99,12 +110,17 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
99
110
  if (valuesWithDisabledDefinitions?.length > 0) {
100
111
  logger_1.default.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
101
112
  }
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
- }));
113
+ const values = names.map((name) => {
114
+ const fieldDefinition = fieldDefinitions.find((def) => def.name === name);
115
+ const formatFunction = formatFunctions[fieldDefinition.fieldType];
116
+ const value = formatFunction ? formatFunction(valuesToUpdate[name]) : valuesToUpdate[name];
117
+ return {
118
+ modelId,
119
+ updatedAt: new Date(),
120
+ customFieldDefinitionId: fieldDefinition.id,
121
+ value: value !== undefined ? value : fieldDefinition.defaultValue,
122
+ };
123
+ });
108
124
  return Promise.all(values.map(async (value) => {
109
125
  const [cfv] = await models_1.CustomFieldValue.upsert(value, {
110
126
  transaction: options.transaction,
@@ -17,6 +17,10 @@ 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
+ };
20
24
  /**
21
25
  * A Sequelize scope for filtering models by custom fields.
22
26
  * This scope builds a WHERE clause to be applied on the main query.
@@ -24,9 +28,12 @@ export type CustomFieldFilterOptions = {
24
28
  * @param name - The model type name used to join custom_field_definitions.
25
29
  * @returns A function that takes conditions and returns the Sequelize options object.
26
30
  */
27
- export declare const customFieldsFilterScope: (name: string) => (conditions: Record<string, ConditionValue>) => CustomFieldFilterOptions;
31
+ export declare const customFieldsFilterScope: (name: string) => ({ replacementsMap: replacements, scopeValue: conditions, }: customFieldsFilterScopeParams) => CustomFieldFilterOptions;
28
32
  export declare const scopeName = "filterByCustomFields";
29
- export declare const customFieldsSortScope: (name: string) => (sort: CustomFieldSort[]) => {
33
+ export declare const customFieldsSortScope: (name: string) => ({ replacementsMap, scopeValue: sort }: {
34
+ replacementsMap: any;
35
+ scopeValue: any;
36
+ }) => {
30
37
  attributes?: undefined;
31
38
  order?: undefined;
32
39
  replacements?: undefined;
@@ -35,6 +42,6 @@ export declare const customFieldsSortScope: (name: string) => (sort: CustomField
35
42
  include: (string | import("sequelize/types/utils").Literal)[][];
36
43
  };
37
44
  order: import("sequelize/types/utils").Literal[];
38
- replacements: Record<string, string>;
45
+ replacements: any;
39
46
  };
40
47
  export {};
@@ -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 (moment_1.default.isDate(conditionValue)) {
12
+ if (isDate(conditionValue)) {
16
13
  return '::timestamp';
17
14
  }
18
15
  if (!Number.isNaN(Number(conditionValue))) {
@@ -34,19 +31,17 @@ const castValueToJsonb = (value) => `to_jsonb(${value}::text)`;
34
31
  * @param name - The model type name used to join custom_field_definitions.
35
32
  * @returns A function that takes conditions and returns the Sequelize options object.
36
33
  */
37
- const customFieldsFilterScope = (name) => (conditions) => {
34
+ const customFieldsFilterScope = (name) => ({ replacementsMap: replacements, scopeValue: conditions, }) => {
38
35
  if (!conditions || Object.keys(conditions).length === 0) {
39
36
  return {};
40
37
  }
41
- const ConditionNameRandomStr = (0, helpers_1.generateRandomString)();
42
- const replacements = {};
43
- replacements[ConditionNameRandomStr] = `${name}`;
44
38
  // Build the WHERE clause for custom field filtering
45
39
  const conditionsStrings = Object.entries(conditions)
46
40
  .map(([key, condition]) => {
47
- const replacemetKey = (0, helpers_1.generateRandomString)();
48
- replacements[replacemetKey] = `${key}`;
41
+ const replacemetKey = Object.keys(replacements).find((randomString) => replacements[randomString] === key);
49
42
  const columnCondition = `(${CD_NAME_COLUMN} = :${replacemetKey})`;
43
+ if (!replacemetKey)
44
+ return false;
50
45
  if (Array.isArray(condition)) {
51
46
  if (condition.length === 0) {
52
47
  // if empty array, the condition is ignored
@@ -54,29 +49,25 @@ const customFieldsFilterScope = (name) => (conditions) => {
54
49
  }
55
50
  if (typeof condition[0] === 'string') {
56
51
  const values = condition.map((v) => {
57
- const valRandom = (0, helpers_1.generateRandomString)();
58
- replacements[`${valRandom}`] = `${v}`;
52
+ const valRandom = Object.keys(replacements).find((randomString) => replacements[randomString] === v);
59
53
  return castValueToJsonb(`:${valRandom}`);
60
54
  }).join(',');
61
- return `(${columnCondition} AND ${CV_VALUE_COLUMN} IN ( ${values} ))`;
55
+ return `(${columnCondition} AND ${CV_VALUE_COLUMN} IN (${values}))`;
62
56
  }
63
57
  return condition
64
58
  .map((c) => {
65
- const valRep = (0, helpers_1.generateRandomString)();
66
- replacements[valRep] = `${c.value}`;
59
+ const valRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === c.value);
67
60
  const valueAsJsonb = castValueToJsonb(`:${valRep}`);
68
61
  return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(c.value)} ${c.operator} ${valueAsJsonb})`;
69
62
  }).join(AND_DELIMETER);
70
63
  }
71
64
  if (typeof condition === 'string' || typeof condition === 'number') {
72
- const conditionRep = (0, helpers_1.generateRandomString)();
73
- replacements[conditionRep] = `${condition}`;
65
+ const conditionRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === condition);
74
66
  const valueAsJsonb = castValueToJsonb(`:${conditionRep}`);
75
67
  return `(${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition)} = ${valueAsJsonb})`;
76
68
  }
77
69
  if (condition?.operator) {
78
- const valueRep = (0, helpers_1.generateRandomString)();
79
- replacements[valueRep] = `${condition.value}`;
70
+ const valueRep = Object.keys(replacements).find((replacementKey) => replacements[replacementKey] === condition.value);
80
71
  const valueAsJsonb = castValueToJsonb(`:${valueRep}`);
81
72
  return `( ${columnCondition} AND ${CV_VALUE_COLUMN}${castIfNeeded(condition.value)} ${condition.operator} ${valueAsJsonb})`;
82
73
  }
@@ -91,8 +82,9 @@ const customFieldsFilterScope = (name) => (conditions) => {
91
82
  SELECT cv.model_id
92
83
  FROM custom_field_values AS cv
93
84
  INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
94
- AND cd.model_type = :${ConditionNameRandomStr}
85
+ AND cd.model_type = '${name}'
95
86
  WHERE ${customFieldConditions}
87
+ AND cv.deleted_at IS NULL AND cd.deleted_at IS NULL
96
88
  GROUP BY cv.model_id
97
89
  HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${conditionsStrings.length}
98
90
  `.replace(/\n/g, '');
@@ -107,15 +99,13 @@ const customFieldsFilterScope = (name) => (conditions) => {
107
99
  };
108
100
  exports.customFieldsFilterScope = customFieldsFilterScope;
109
101
  exports.scopeName = CUSTOM_FIELDS_FILTER_SCOPE;
110
- const customFieldsSortScope = (name) => (sort) => {
102
+ const customFieldsSortScope = (name) => ({ replacementsMap, scopeValue: sort }) => {
111
103
  if (!sort || sort.length === 0) {
112
104
  return {};
113
105
  }
114
106
  const randomStr = (0, helpers_1.generateRandomString)();
115
- const replacements = {};
116
107
  const includes = Object.entries(sort).map(([key]) => {
117
- const keyRandomReplacement = (0, helpers_1.generateRandomString)();
118
- replacements[keyRandomReplacement] = `${key}`;
108
+ const replacemetKey = Object.keys(replacementsMap).find((randomString) => replacementsMap[randomString] === key);
119
109
  return ([
120
110
  sequelize_typescript_1.Sequelize.literal(`(
121
111
  SELECT value
@@ -124,19 +114,22 @@ const customFieldsSortScope = (name) => (sort) => {
124
114
  ON cv.custom_field_definition_id = cd.id
125
115
  AND cd.model_type = '${name}'
126
116
  WHERE cv.model_id = "${name}"."id"
127
- AND cd.name = :${keyRandomReplacement}
117
+ AND cd.name = :${replacemetKey}
128
118
  ) AS CustomFieldAggregation
129
119
  )
130
120
  `), randomStr,
131
121
  ]);
132
122
  });
133
- const orders = Object.entries(sort).map(([, value]) => sequelize_typescript_1.Sequelize.literal(`"${randomStr}" ${value}`));
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
+ });
134
127
  return {
135
128
  attributes: {
136
129
  include: includes,
137
130
  },
138
131
  order: orders,
139
- replacements,
132
+ replacements: replacementsMap,
140
133
  };
141
134
  };
142
135
  exports.customFieldsSortScope = customFieldsSortScope;
@@ -14,6 +14,7 @@ export declare const coolFieldDefinition2: {
14
14
  createdAt?: Date;
15
15
  updatedAt?: Date;
16
16
  deletedAt?: Date;
17
+ defaultValue?: any;
17
18
  displayName?: string;
18
19
  validation?: any;
19
20
  fieldType: string;
@@ -29,6 +30,7 @@ export declare const coolFieldDefinition3: {
29
30
  createdAt?: Date;
30
31
  updatedAt?: Date;
31
32
  deletedAt?: Date;
33
+ defaultValue?: any;
32
34
  displayName?: string;
33
35
  validation?: any;
34
36
  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 uuid_1 = require("uuid");
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, uuid_1.v4)(),
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, uuid_1.v4)(),
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, uuid_1.v4)(),
39
+ entityId: (0, node_crypto_1.randomUUID)(),
40
40
  entityType: 'fleetId',
41
41
  });
42
42
  exports.selectField = selectField;
@@ -45,24 +45,25 @@ const statusField = (modelType, options) => ({
45
45
  modelType,
46
46
  fieldType: 'status',
47
47
  validation: options,
48
- entityId: (0, uuid_1.v4)(),
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, uuid_1.v4)()}`,
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, uuid_1.v4)(),
57
+ entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
58
58
  entityType: defaults?.entityType || 'fleetId',
59
+ ...(defaults?.defaultValue && { defaultValue: defaults.defaultValue }),
59
60
  });
60
61
  exports.createDefinition = createDefinition;
61
62
  const createDefinitions = (defaults, length = 1) => (Array(length).fill({}).map((_) => ({
62
- name: defaults?.name || `def_${(0, uuid_1.v4)()}`,
63
+ name: defaults?.name || `def_${(0, node_crypto_1.randomUUID)()}`,
63
64
  modelType: defaults?.modelType || 'TestModel',
64
65
  fieldType: defaults?.fieldType || 'boolean',
65
- entityId: defaults?.entityId || (0, uuid_1.v4)(),
66
+ entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
66
67
  entityType: defaults?.entityType || 'fleetId',
67
68
  })));
68
69
  exports.createDefinitions = createDefinitions;
@@ -3,6 +3,7 @@ export interface CustomFieldDefinitionDTO {
3
3
  name: string;
4
4
  displayName?: string;
5
5
  validation?: any;
6
+ defaultValue?: any;
6
7
  fieldType: string;
7
8
  entityId: string;
8
9
  entityType: string;
@@ -1,2 +1,2 @@
1
- declare const logger: any;
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
- // eslint-disable-next-line @typescript-eslint/no-var-requires
4
- const Logger = require('@autofleet/logger');
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.7.8-beta-1",
3
+ "version": "0.7.8-beta--beta-1.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {