@autofleet/sadot 0.7.4 → 0.7.6-beta-0ecad376.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- 18.17.1
1
+ 22.9.0
@@ -48,27 +48,38 @@ 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
+ ...(!useEntityIdFromInclude && { entityId: identifiers }),
57
+ };
58
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: false, transaction: options.transaction, include: include?.(identifiers) });
59
+ const requiredFieldsNames = Array.from(new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)));
55
60
  const customFieldsIdx = fields.indexOf('customFields');
61
+ if ((customFieldsIdx === -1 || !instance.customFields) && requiredFieldsNames?.length > 0) {
62
+ throw new errors_1.MissingRequiredCustomFieldError(requiredFieldsNames);
63
+ }
64
+ // eslint-disable-next-line no-param-reassign
65
+ instance.customFields || (instance.customFields = {});
56
66
  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
- }, true);
67
- // eslint-disable-next-line no-param-reassign
68
- fields.splice(customFieldsIdx, 1);
67
+ fieldDefinitions.filter((def) => !(def.name in customFields) && ![null, undefined].includes(def.defaultValue)).forEach(({ name, defaultValue }) => {
68
+ customFields[name] = defaultValue;
69
+ });
70
+ if (customFieldsIdx === -1) {
71
+ return;
69
72
  }
70
- else if (requiredFieldsNames?.length > 0) {
71
- throw new errors_1.MissingRequiredCustomFieldError(requiredFieldsNames);
73
+ const fieldsNames = Object.keys(customFields);
74
+ const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
75
+ if (missingFields?.length > 0) {
76
+ throw new errors_1.MissingRequiredCustomFieldError(missingFields);
72
77
  }
78
+ await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, {
79
+ transaction: options.transaction,
80
+ modelOptions,
81
+ });
82
+ // eslint-disable-next-line no-param-reassign
83
+ fields.splice(customFieldsIdx, 1);
73
84
  };
74
85
  exports.beforeCreate = beforeCreate;
@@ -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 {};
@@ -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>;
@@ -84,7 +84,7 @@ const formatFunctions = {
84
84
  * Create new value record if not exists, but fails if value's definition not exist.
85
85
  * Return the updated values
86
86
  */
87
- const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}, defineAllDefaults = false) => {
87
+ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}) => {
88
88
  const names = Object.keys(valuesToUpdate);
89
89
  logger_1.default.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {
90
90
  names,
@@ -96,11 +96,9 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
96
96
  const where = {
97
97
  modelType,
98
98
  name: names,
99
+ ...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),
99
100
  };
100
- if (!options.modelOptions?.useEntityIdFromInclude) {
101
- where.entityId = identifiers;
102
- }
103
- 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) }) ?? [];
104
102
  const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
105
103
  if (fieldDefinitions.length !== names.length) {
106
104
  logger_1.default.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });
@@ -112,10 +110,8 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
112
110
  if (valuesWithDisabledDefinitions?.length > 0) {
113
111
  logger_1.default.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
114
112
  }
115
- const visitedFields = new Set();
116
113
  const values = names.map((name) => {
117
114
  const fieldDefinition = fieldDefinitions.find((def) => def.name === name);
118
- visitedFields.add(fieldDefinition);
119
115
  const formatFunction = formatFunctions[fieldDefinition.fieldType];
120
116
  return {
121
117
  modelId,
@@ -124,16 +120,6 @@ const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, opt
124
120
  customFieldDefinitionId: fieldDefinition.id,
125
121
  };
126
122
  });
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
- }
137
123
  return Promise.all(values.map(async (value) => {
138
124
  const [cfv] = await models_1.CustomFieldValue.upsert(value, {
139
125
  transaction: options.transaction,
@@ -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))) {
@@ -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,25 +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
59
  ...(defaults?.defaultValue && { defaultValue: defaults.defaultValue }),
60
60
  });
61
61
  exports.createDefinition = createDefinition;
62
62
  const createDefinitions = (defaults, length = 1) => (Array(length).fill({}).map((_) => ({
63
- name: defaults?.name || `def_${(0, uuid_1.v4)()}`,
63
+ name: defaults?.name || `def_${(0, node_crypto_1.randomUUID)()}`,
64
64
  modelType: defaults?.modelType || 'TestModel',
65
65
  fieldType: defaults?.fieldType || 'boolean',
66
- entityId: defaults?.entityId || (0, uuid_1.v4)(),
66
+ entityId: defaults?.entityId || (0, node_crypto_1.randomUUID)(),
67
67
  entityType: defaults?.entityType || 'fleetId',
68
68
  })));
69
69
  exports.createDefinitions = createDefinitions;
@@ -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,27 +1,24 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.7.4",
3
+ "version": "0.7.6-beta-0ecad376.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
- "start": "ts-node src/index.ts",
7
+ "start": "ts-node src/index.ts",
8
8
  "build": "rm -rf dist && tsc",
9
- "linter": "./node_modules/.bin/eslint .",
9
+ "linter": "eslint .",
10
10
  "test": "jest --forceExit --runInBand",
11
11
  "coverage": "jest --coverage --forceExit --runInBand && rm -rf ./coverage",
12
- "build-to-local-repo": "npm run build && cp -r dist/* ../$REPO/node_modules/$npm_package_name/dist",
12
+ "build-to-local-repo": "node --run build && cp -r dist/* ../$REPO/node_modules/$npm_package_name/dist",
13
13
  "dev": "nodemon",
14
14
  "watch": "npm-watch build-to-local-repo",
15
- "publish-dev": "npm run build && npm publish --tag dev"
15
+ "publish-dev": "node --run build && npm publish --tag dev"
16
16
  },
17
17
  "watch": {
18
18
  "build-to-local-repo": {
19
19
  "extensions": [
20
20
  "js",
21
- "jsx",
22
- "ts",
23
- "tsx",
24
- "css"
21
+ "ts"
25
22
  ],
26
23
  "patterns": [
27
24
  "src"
@@ -30,27 +27,24 @@
30
27
  }
31
28
  },
32
29
  "dependencies": {
33
- "@autofleet/common-types": "^1.7.42",
34
- "@autofleet/errors": "^1.0.10",
30
+ "@autofleet/common-types": "^1.7.58",
31
+ "@autofleet/errors": "^1.2.3",
35
32
  "@autofleet/events": "^2.0.0",
36
- "@autofleet/logger": "^2.0.5",
33
+ "@autofleet/logger": "^4.1.0",
37
34
  "express": "^4.18.2",
38
35
  "joi": "^17.7.0",
39
- "moment": "^2.30.1",
40
36
  "pg": "^8.10.0",
41
37
  "reflect-metadata": "^0.1.13",
42
38
  "sequelize": "^6.31.1",
43
- "sequelize-typescript": "^2.1.5",
44
- "uuid": "^9.0.0"
39
+ "sequelize-typescript": "^2.1.5"
45
40
  },
46
41
  "devDependencies": {
47
42
  "@types/express": "^4.17.17",
48
- "@types/jest": "^27.0.9",
49
- "@types/uuid": "^9.0.2",
50
- "@typescript-eslint/eslint-plugin": "^6.4.0",
51
- "@typescript-eslint/parser": "^6.4.0",
52
- "eslint": "^7.32.0",
53
- "eslint-config-airbnb-typescript": "^12.0.0",
43
+ "@types/jest": "^29.5.13",
44
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
45
+ "@typescript-eslint/parser": "^7.18.0",
46
+ "eslint": "^8.57.0",
47
+ "eslint-config-airbnb-base": "^15.0.0",
54
48
  "eslint-plugin-import": "^2.22.1",
55
49
  "jest": "^29.7.0",
56
50
  "npm-watch": "^0.11.0",
@@ -65,8 +65,7 @@ router.get('/', async (req, res) => {
65
65
  if (entityIds?.length > 0) {
66
66
  where.entityId = entityIds;
67
67
  }
68
- const customFieldDefinitions = await DefinitionRepo.findAll({ ...where },
69
- { withDisabled: true });
68
+ const customFieldDefinitions = await DefinitionRepo.findAll({ ...where }, { withDisabled: true });
70
69
  return res.json(customFieldDefinitions);
71
70
  } catch (err) {
72
71
  logger.error('Failed to fetch custom field definitions', err);
@@ -1,3 +1,4 @@
1
+ import type { WhereOptions } from 'sequelize';
1
2
  import logger from '../utils/logger';
2
3
  import * as ValueRepo from '../repository/value';
3
4
  import * as DefinitionRepo from '../repository/definition';
@@ -23,38 +24,49 @@ export const beforeCreate = (scopeAttributes: string[], modelOptions: ModelOptio
23
24
  ): Promise<void> => {
24
25
  logger.debug('sadot - before create hook');
25
26
  const { fields } = options;
27
+ const { include, useEntityIdFromInclude } = modelOptions;
26
28
  const modelType = instance.constructor.name;
27
29
 
28
30
  const identifiers = applyScopeToInstance(instance, scopeAttributes);
29
31
 
30
- // get all model's required definitions
31
- const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType,
32
- instance.id, identifiers, modelOptions);
32
+ const where: WhereOptions = {
33
+ modelType,
34
+ ...(!useEntityIdFromInclude && { entityId: identifiers }),
35
+ };
36
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: false, transaction: options.transaction, include: include?.(identifiers) });
37
+ const requiredFieldsNames = Array.from(new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)));
33
38
 
34
39
  const customFieldsIdx = fields.indexOf('customFields');
35
- const { customFields } = instance;
36
- if (customFieldsIdx > -1 && customFields) {
37
- const fieldsNames = Object.keys(customFields);
38
- const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
39
- if (missingFields?.length > 0) {
40
- throw new MissingRequiredCustomFieldError(missingFields);
41
- }
42
-
43
- await ValueRepo.updateValues(
44
- modelType,
45
- instance.id,
46
- identifiers,
47
- customFields,
48
- {
49
- transaction: options.transaction,
50
- modelOptions,
51
- },
52
- true,
53
- );
54
40
 
55
- // eslint-disable-next-line no-param-reassign
56
- fields.splice(customFieldsIdx, 1);
57
- } else if (requiredFieldsNames?.length > 0) {
41
+ if ((customFieldsIdx === -1 || !instance.customFields) && requiredFieldsNames?.length > 0) {
58
42
  throw new MissingRequiredCustomFieldError(requiredFieldsNames);
59
43
  }
44
+ // eslint-disable-next-line no-param-reassign
45
+ instance.customFields ||= {};
46
+ const { customFields } = instance;
47
+ fieldDefinitions.filter((def) => !(def.name in customFields) && ![null, undefined].includes(def.defaultValue)).forEach(({ name, defaultValue }) => {
48
+ customFields[name] = defaultValue;
49
+ });
50
+ if (customFieldsIdx === -1) {
51
+ return;
52
+ }
53
+ const fieldsNames = Object.keys(customFields);
54
+ const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
55
+ if (missingFields?.length > 0) {
56
+ throw new MissingRequiredCustomFieldError(missingFields);
57
+ }
58
+
59
+ await ValueRepo.updateValues(
60
+ modelType,
61
+ instance.id,
62
+ identifiers,
63
+ customFields,
64
+ {
65
+ transaction: options.transaction,
66
+ modelOptions,
67
+ },
68
+ );
69
+
70
+ // eslint-disable-next-line no-param-reassign
71
+ fields.splice(customFieldsIdx, 1);
60
72
  };
@@ -46,18 +46,18 @@ class CustomFieldDefinition extends Model {
46
46
  defaultValue: DataType.UUIDV4,
47
47
  allowNull: false,
48
48
  })
49
- id!: string;
49
+ id!: string;
50
50
 
51
51
  @Column({
52
52
  type: DataType.STRING,
53
53
  allowNull: false,
54
54
  })
55
- name!: string;
55
+ name!: string;
56
56
 
57
57
  @Column({
58
58
  type: DataType.STRING,
59
59
  })
60
- displayName?: string; // Defaulted to name with beforeCreate hook
60
+ displayName?: string; // Defaulted to name with beforeCreate hook
61
61
 
62
62
  @Is('SupportedType', (value) => {
63
63
  if (!Object.values(CustomFieldDefinitionType).includes(value as CustomFieldDefinitionType)) {
@@ -68,65 +68,65 @@ class CustomFieldDefinition extends Model {
68
68
  type: DataType.STRING,
69
69
  allowNull: false,
70
70
  })
71
- fieldType!: CustomFieldDefinitionType;
71
+ fieldType!: CustomFieldDefinitionType;
72
72
 
73
73
  @Column({
74
74
  type: DataType.JSONB,
75
75
  })
76
- validation?: any;
76
+ validation?: any;
77
77
 
78
78
  @Column({
79
79
  type: DataType.UUID,
80
80
  allowNull: false,
81
81
  })
82
- entityId!: string; /** Client association entity id */
82
+ entityId!: string; /** Client association entity id */
83
83
 
84
84
  @Column({
85
85
  type: DataType.STRING,
86
86
  allowNull: false,
87
87
  })
88
- entityType!: string; /** Client association entity type (demand source / fleet / etc.) */
88
+ entityType!: string; /** Client association entity type (demand source / fleet / etc.) */
89
89
 
90
90
  @Column({
91
91
  type: DataType.STRING,
92
92
  allowNull: false,
93
93
  })
94
- modelType!: string; /** Model type. e.g. Vehicle / StopPoint / etc. */
94
+ modelType!: string; /** Model type. e.g. Vehicle / StopPoint / etc. */
95
95
 
96
96
  @Column({
97
97
  type: DataType.TEXT,
98
98
  })
99
- description?: string;
99
+ description?: string;
100
100
 
101
101
  @Column({
102
102
  type: DataType.BOOLEAN,
103
103
  defaultValue: false,
104
104
  })
105
- required?: boolean;
105
+ required?: boolean;
106
106
 
107
107
  @Column({
108
108
  type: DataType.BOOLEAN,
109
109
  defaultValue: false,
110
110
  })
111
- disabled?: boolean;
111
+ disabled?: boolean;
112
112
 
113
- @Column({
114
- type: DataType.JSONB,
115
- allowNull: true,
116
- })
117
- defaultValue?: any;
113
+ @Column({
114
+ type: DataType.JSONB,
115
+ allowNull: true,
116
+ })
117
+ defaultValue?: any;
118
118
 
119
119
  @Column
120
- createdAt?: Date;
120
+ createdAt?: Date;
121
121
 
122
122
  @Column
123
- updatedAt?: Date;
123
+ updatedAt?: Date;
124
124
 
125
125
  @Column
126
- deletedAt?: Date;
126
+ deletedAt?: Date;
127
127
 
128
128
  @HasMany(() => CustomFieldValue)
129
- values: CustomFieldValue[];
129
+ values: CustomFieldValue[];
130
130
 
131
131
  @BeforeCreate
132
132
  static displayNameDefaultValue(instance: CustomFieldDefinition): void {
@@ -28,7 +28,7 @@ class CustomFieldValue extends Model {
28
28
  type: DataType.UUID,
29
29
  allowNull: false,
30
30
  })
31
- modelId!: string;
31
+ modelId!: string;
32
32
 
33
33
  @PrimaryKey
34
34
  @ForeignKey(() => CustomFieldDefinition)
@@ -36,25 +36,25 @@ class CustomFieldValue extends Model {
36
36
  type: DataType.UUID,
37
37
  allowNull: false,
38
38
  })
39
- customFieldDefinitionId!: string;
39
+ customFieldDefinitionId!: string;
40
40
 
41
41
  @Column({
42
42
  type: DataType.JSONB,
43
43
  allowNull: true,
44
44
  })
45
- value!: any;
45
+ value!: any;
46
46
 
47
47
  @Column
48
- createdAt?: Date;
48
+ createdAt?: Date;
49
49
 
50
50
  @Column
51
- updatedAt?: Date;
51
+ updatedAt?: Date;
52
52
 
53
53
  @Column
54
- deletedAt?: Date;
54
+ deletedAt?: Date;
55
55
 
56
56
  @BelongsTo(() => CustomFieldDefinition, { scope: { disabled: false } })
57
- customFieldDefinition: CustomFieldDefinition;
57
+ customFieldDefinition: CustomFieldDefinition;
58
58
 
59
59
  @BeforeBulkCreate
60
60
  @BeforeBulkUpdate
@@ -18,40 +18,40 @@ class AssociatedTestModel extends Model {
18
18
  defaultValue: DataType.UUIDV4,
19
19
  allowNull: false,
20
20
  })
21
- id!: string;
21
+ id!: string;
22
22
 
23
23
  @ForeignKey(() => TestModel)
24
24
  @Column({
25
25
  type: DataType.UUID,
26
26
  allowNull: false,
27
27
  })
28
- testModelId!: string;
28
+ testModelId!: string;
29
29
 
30
30
  @Column({
31
31
  type: DataType.UUID,
32
32
  allowNull: false,
33
33
  })
34
- fleetId: string;
34
+ fleetId: string;
35
35
 
36
36
  @Column({
37
37
  type: DataType.UUID,
38
38
  allowNull: true,
39
39
  })
40
- businessModelId: string;
40
+ businessModelId: string;
41
41
 
42
42
  @Column({
43
43
  type: DataType.UUID,
44
44
  allowNull: true,
45
45
  })
46
- demandSourceId: string;
46
+ demandSourceId: string;
47
47
 
48
48
  @Column({
49
49
  type: DataType.BOOLEAN,
50
50
  })
51
- anotherAttribute?: boolean;
51
+ anotherAttribute?: boolean;
52
52
 
53
53
  @BelongsTo(() => TestModel)
54
- testModel: TestModel;
54
+ testModel: TestModel;
55
55
  }
56
56
 
57
57
  export default AssociatedTestModel;
@@ -17,38 +17,38 @@ class TestModel extends Model {
17
17
  defaultValue: DataType.UUIDV4,
18
18
  allowNull: false,
19
19
  })
20
- id!: string;
20
+ id!: string;
21
21
 
22
22
  @Column({
23
23
  type: DataType.UUID,
24
24
  allowNull: false,
25
25
  })
26
- fleetId: string;
26
+ fleetId: string;
27
27
 
28
28
  @Column({
29
29
  type: DataType.UUID,
30
30
  allowNull: true,
31
31
  })
32
- businessModelId: string;
32
+ businessModelId: string;
33
33
 
34
34
  @Column({
35
35
  type: DataType.UUID,
36
36
  allowNull: true,
37
37
  })
38
- demandSourceId: string;
38
+ demandSourceId: string;
39
39
 
40
40
  @Column({
41
41
  type: DataType.BOOLEAN,
42
42
  })
43
- coolAttribute?: boolean;
43
+ coolAttribute?: boolean;
44
44
 
45
45
  @HasMany(() => AssociatedTestModel)
46
- associatedModels: AssociatedTestModel[];
46
+ associatedModels: AssociatedTestModel[];
47
47
 
48
48
  @Column({
49
49
  type: DataType.VIRTUAL,
50
50
  })
51
- customFields?: any;
51
+ customFields?: any;
52
52
  }
53
53
 
54
54
  export default TestModel;
@@ -14,32 +14,30 @@ import ContextTestModel from './ContextTestModel';
14
14
 
15
15
  @Table({ createdAt: false, updatedAt: false })
16
16
  class ContextAwareTestModel extends Model {
17
- @PrimaryKey
18
- @Column({
19
- type: DataType.UUID,
20
- defaultValue: DataType.UUIDV4,
21
- allowNull: false,
22
- })
17
+ @PrimaryKey
18
+ @Column({
19
+ type: DataType.UUID,
20
+ defaultValue: DataType.UUIDV4,
21
+ allowNull: false,
22
+ })
23
23
  id!: string;
24
24
 
25
25
  @ForeignKey(() => ContextTestModel)
26
- @Column({
27
- type: DataType.UUID,
28
- })
29
- contextId: string;
26
+ @Column({ type: DataType.UUID })
27
+ contextId: string;
30
28
 
31
- @Column({
32
- type: DataType.BOOLEAN,
33
- })
29
+ @Column({
30
+ type: DataType.BOOLEAN,
31
+ })
34
32
  coolAttribute?: boolean;
35
33
 
36
- @Column({
37
- type: DataType.VIRTUAL,
38
- })
34
+ @Column({
35
+ type: DataType.VIRTUAL,
36
+ })
39
37
  customFields?: any;
40
38
 
41
39
  @BelongsTo(() => ContextTestModel)
42
- context: ContextTestModel;
40
+ context: ContextTestModel;
43
41
  }
44
42
 
45
43
  export default ContextAwareTestModel;
@@ -1,4 +1,7 @@
1
- import { Op, type FindOptions, type WhereOptions } from 'sequelize';
1
+ import {
2
+ Op,
3
+ type Includeable, type Transaction, type FindOptions, type WhereOptions,
4
+ } from 'sequelize';
2
5
  import { CustomFieldDefinition } from '../models';
3
6
  import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
4
7
  import type { ModelOptions } from '../types';
@@ -6,9 +9,15 @@ import type { ModelOptions } from '../types';
6
9
  export const create = (data: CreateCustomFieldDefinition): Promise<CustomFieldDefinition> =>
7
10
  CustomFieldDefinition.create(data);
8
11
 
12
+ interface SadotFindOptions {
13
+ withDisabled?: boolean;
14
+ transaction?: Transaction;
15
+ include?: Includeable | Includeable[];
16
+ }
17
+
9
18
  export const findAll = (
10
19
  where: WhereOptions,
11
- options: any = { withDisabled: false },
20
+ options: SadotFindOptions = { withDisabled: false },
12
21
  ): Promise<CustomFieldDefinition[]> => {
13
22
  const queryModel = options.withDisabled
14
23
  ? CustomFieldDefinition.unscoped()
@@ -24,12 +33,12 @@ export const findAll = (
24
33
 
25
34
  export const findByIds = (
26
35
  ids: string[],
27
- options: any = { withDisabled: false },
36
+ options: SadotFindOptions = { withDisabled: false },
28
37
  ): Promise<CustomFieldDefinition[]> => findAll({ id: { [Op.in]: ids } }, options);
29
38
 
30
39
  export const findById = (
31
40
  id: string,
32
- options: any = { withDisabled: false },
41
+ options: Pick<SadotFindOptions, 'withDisabled'> = { withDisabled: false },
33
42
  ): Promise<CustomFieldDefinition | null> => {
34
43
  const { withDisabled } = options;
35
44
  if (withDisabled) {
@@ -87,13 +96,13 @@ export const update = async (
87
96
  return updatedDefinition;
88
97
  };
89
98
 
90
- export const disable = (id: string): Promise<any> =>
99
+ export const disable = (id: string): Promise<[affectedCount: number]> =>
91
100
  CustomFieldDefinition.update(
92
101
  { disabled: true },
93
102
  { where: { id } },
94
103
  );
95
104
 
96
- export const destroy = (id: string): Promise<any> =>
105
+ export const destroy = (id: string): Promise<number> =>
97
106
  CustomFieldDefinition.destroy({ where: { id } });
98
107
 
99
108
  /**
@@ -67,7 +67,6 @@ export const updateValues = async (
67
67
  identifiers: string[],
68
68
  valuesToUpdate: ValuesToUpdate,
69
69
  options: FindOptions & { modelOptions?: ModelOptions } = {},
70
- defineAllDefaults = false,
71
70
  ): Promise<CustomFieldValue[]> => {
72
71
  const names = Object.keys(valuesToUpdate);
73
72
  logger.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {
@@ -81,12 +80,10 @@ export const updateValues = async (
81
80
  const where: WhereOptions = {
82
81
  modelType,
83
82
  name: names,
83
+ ...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),
84
84
  };
85
85
 
86
- if (!options.modelOptions?.useEntityIdFromInclude) {
87
- where.entityId = identifiers;
88
- }
89
- const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) || [];
86
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) ?? [];
90
87
 
91
88
  const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
92
89
  if (fieldDefinitions.length !== names.length) {
@@ -101,11 +98,8 @@ export const updateValues = async (
101
98
  logger.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);
102
99
  }
103
100
 
104
- const visitedFields = new Set<CustomFieldDefinition>();
105
-
106
101
  const values: CreateCustomFieldValue[] = names.map((name) => {
107
102
  const fieldDefinition = fieldDefinitions.find((def) => def.name === name);
108
- visitedFields.add(fieldDefinition);
109
103
  const formatFunction = formatFunctions[fieldDefinition.fieldType];
110
104
  return {
111
105
  modelId,
@@ -115,17 +109,6 @@ export const updateValues = async (
115
109
  };
116
110
  });
117
111
 
118
- if (defineAllDefaults) {
119
- fieldDefinitions.filter((def) => !visitedFields.has(def) && ![null, undefined].includes(def.defaultValue)).forEach(({ id, defaultValue }) => {
120
- values.push({
121
- modelId,
122
- value: defaultValue,
123
- updatedAt: new Date(),
124
- customFieldDefinitionId: id,
125
- });
126
- });
127
- }
128
-
129
112
  return Promise.all(values.map(async (value) => {
130
113
  const [cfv] = await CustomFieldValue.upsert(value, {
131
114
  transaction: options.transaction,
@@ -2,7 +2,6 @@
2
2
  import { Op, type WhereOptions } from 'sequelize';
3
3
  import { Sequelize } from 'sequelize-typescript';
4
4
  import { customFields } from '@autofleet/common-types';
5
- import moment from 'moment';
6
5
  import { generateRandomString } from '../utils/helpers';
7
6
 
8
7
  const { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;
@@ -33,8 +32,10 @@ type customFieldsFilterScopeParams = {
33
32
  scopeValue: Record<string, ConditionValue>;
34
33
  }
35
34
 
35
+ const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
36
+
36
37
  const castIfNeeded = (conditionValue: string): string => {
37
- if (moment.isDate(conditionValue)) {
38
+ if (isDate(conditionValue)) {
38
39
  return '::timestamp';
39
40
  }
40
41
  if (!Number.isNaN(Number(conditionValue))) {
@@ -1,4 +1,4 @@
1
- import { v4 as uuidv4 } from 'uuid';
1
+ import { randomUUID as uuidv4 } from 'node:crypto';
2
2
  import type { CreateCustomFieldDefinition, CustomFieldDefinitionDTO } from '../../types/definition';
3
3
 
4
4
  export const contextAwareFieldDefinition = {
@@ -1,5 +1,4 @@
1
- // eslint-disable-next-line @typescript-eslint/no-var-requires
2
- const Logger = require('@autofleet/logger');
1
+ import Logger from '@autofleet/logger';
3
2
 
4
3
  const logger = Logger();
5
4