@autofleet/sadot 0.13.1 → 0.13.2-beta.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.
@@ -36,6 +36,7 @@ const DefinitionRepo = __importStar(require("../repository/definition"));
36
36
  const errors_2 = require("../errors");
37
37
  const scopeAttributes_1 = __importDefault(require("../utils/scopeAttributes"));
38
38
  const updateInstanceValues_1 = __importDefault(require("./utils/updateInstanceValues"));
39
+ const constants_1 = require("../utils/constants");
39
40
  // Initialize Ajv with relaxed settings to avoid warnings
40
41
  const ajv = new ajv_1.default({
41
42
  allErrors: true,
@@ -195,16 +196,8 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
195
196
  }
196
197
  }
197
198
  };
198
- /**
199
- * Hook to handle validation and custom fields during creation
200
- */
201
- const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCustomFieldsEntries: false }) => async (instance, options) => {
202
- logger_1.default.debug('sadot - before create hook');
203
- const { fields } = options;
199
+ const getFieldDefinitions = async ({ modelType, modelOptions, identifiers, options }) => {
204
200
  const { include, useEntityIdFromInclude } = modelOptions;
205
- const modelType = instance.constructor.name;
206
- const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
207
- // Step 1: Handle custom fields default values and required fields
208
201
  const where = {
209
202
  modelType,
210
203
  disabled: false,
@@ -215,7 +208,32 @@ const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
215
208
  transaction: options.transaction,
216
209
  include: include?.(identifiers),
217
210
  });
218
- const requiredFieldsNames = Array.from(new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)));
211
+ return fieldDefinitions;
212
+ };
213
+ const formatDates = (fieldDefinitions = [], instance) => {
214
+ fieldDefinitions.forEach((fieldDefinition) => {
215
+ const { fieldType, name } = fieldDefinition;
216
+ if ([constants_1.CustomFieldDefinitionType.DATE, constants_1.CustomFieldDefinitionType.DATETIME].includes(fieldType)) {
217
+ const value = instance.customFields?.[name];
218
+ if (value) {
219
+ // eslint-disable-next-line no-param-reassign
220
+ instance.customFields[name] = new Date(value).toISOString();
221
+ }
222
+ }
223
+ });
224
+ };
225
+ /**
226
+ * Hook to handle validation and custom fields during creation
227
+ */
228
+ const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCustomFieldsEntries: false }) => async (instance, options) => {
229
+ logger_1.default.debug('sadot - before create hook');
230
+ const { fields } = options;
231
+ const modelType = instance.constructor.name;
232
+ const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
233
+ // Step 1: Handle custom fields default values and required fields
234
+ const fieldDefinitions = await getFieldDefinitions({
235
+ modelType, modelOptions, identifiers, options
236
+ });
219
237
  // Apply default values
220
238
  const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
221
239
  if (fieldsWithDefaultValue.length) {
@@ -229,6 +247,7 @@ const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
229
247
  });
230
248
  }
231
249
  // Check for required fields
250
+ const requiredFieldsNames = Array.from(new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)));
232
251
  const { customFields } = instance;
233
252
  const fieldsNames = Object.keys(customFields ?? {});
234
253
  const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
@@ -237,6 +256,8 @@ const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
237
256
  }
238
257
  // Step 2: Validate the model data (including custom fields)
239
258
  await validateModel(instance, options, scopeAttributes, true);
259
+ // format date and datetime fields
260
+ formatDates(fieldDefinitions, instance);
240
261
  // Step 3: Save custom field values if they exist
241
262
  const customFieldsIdx = fields.indexOf('customFields');
242
263
  if (customFieldsIdx === -1 || !customFields || !Object.keys(customFields).length) {
@@ -268,8 +289,13 @@ const beforeUpdate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
268
289
  const { fields } = options;
269
290
  const modelType = instance.constructor.name;
270
291
  const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
292
+ const fieldDefinitions = await getFieldDefinitions({
293
+ modelType, modelOptions, identifiers, options
294
+ });
271
295
  // Step 1: Validate the model data (including custom fields)
272
296
  await validateModel(instance, options, scopeAttributes, false);
297
+ // format date and datetime fields
298
+ formatDates(fieldDefinitions, instance);
273
299
  // Step 2: Update custom field values if they exist
274
300
  const customFieldsIdx = fields.indexOf('customFields');
275
301
  if (customFieldsIdx > -1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.13.1",
3
+ "version": "0.13.2-beta.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -8,6 +8,7 @@
8
8
  "build": "rm -rf dist && tsc",
9
9
  "linter": "eslint .",
10
10
  "test": "jest --runInBand",
11
+ "test-debug": "node --inspect-brk node_modules/.bin/jest --testTimeout=10000000",
11
12
  "coverage": "jest --coverage --runInBand",
12
13
  "build-to-local-repo": "node --run build && cp -r dist/* ../$REPO/node_modules/$npm_package_name/dist",
13
14
  "dev": "nodemon",
@@ -1,14 +1,17 @@
1
1
  import type { WhereOptions } from 'sequelize';
2
2
  import Ajv from 'ajv';
3
+ import Joi from 'joi';
3
4
  import addFormats from 'ajv-formats';
4
5
  import { BadRequest } from '@autofleet/errors';
5
6
  import logger from '../utils/logger';
6
7
  import * as ValidatorRepo from '../repository/validator';
7
8
  import * as DefinitionRepo from '../repository/definition';
8
- import { MissingRequiredCustomFieldError } from '../errors';
9
+ import { InvalidValueError, MissingRequiredCustomFieldError } from '../errors';
9
10
  import type { CustomFieldOptions, ModelOptions } from '../types';
10
11
  import applyScopeToInstance from '../utils/scopeAttributes';
11
12
  import updateInstanceValues from './utils/updateInstanceValues';
13
+ import { CustomFieldDefinitionType } from '../utils/constants';
14
+ import type { CustomFieldDefinition } from '../models';
12
15
 
13
16
  // Initialize Ajv with relaxed settings to avoid warnings
14
17
  const ajv = new Ajv({
@@ -218,6 +221,49 @@ const validateModel = async (
218
221
  }
219
222
  };
220
223
 
224
+ const getFieldDefinitions = async ({
225
+ modelType,
226
+ modelOptions,
227
+ identifiers,
228
+ options,
229
+ }: {
230
+ modelType: any,
231
+ modelOptions: ModelOptions,
232
+ identifiers: any[],
233
+ options: any
234
+ }) => {
235
+ const { include, useEntityIdFromInclude } = modelOptions;
236
+ const where: WhereOptions = {
237
+ modelType,
238
+ disabled: false,
239
+ ...(!useEntityIdFromInclude && { entityId: identifiers }),
240
+ };
241
+
242
+ const fieldDefinitions = await DefinitionRepo.findAll(where, {
243
+ withDisabled: false,
244
+ transaction: options.transaction,
245
+ include: include?.(identifiers),
246
+ });
247
+ return fieldDefinitions;
248
+ };
249
+
250
+ const formatDates = (fieldDefinitions: CustomFieldDefinition[], instance: any) => {
251
+ (fieldDefinitions || []).forEach((fieldDefinition) => {
252
+ const { fieldType, name } = fieldDefinition;
253
+ if ([CustomFieldDefinitionType.DATE, CustomFieldDefinitionType.DATETIME].includes(fieldType)) {
254
+ const value = instance.customFields?.[name];
255
+ if (value) {
256
+ const validationError = Joi.date().validate(value).error;
257
+ if (validationError) {
258
+ throw new InvalidValueError(value, name, validationError);
259
+ }
260
+ // eslint-disable-next-line no-param-reassign
261
+ instance.customFields[name] = new Date(value).toISOString();
262
+ }
263
+ }
264
+ });
265
+ };
266
+
221
267
  /**
222
268
  * Hook to handle validation and custom fields during creation
223
269
  */
@@ -231,28 +277,16 @@ export const beforeCreate = (
231
277
  ): Promise<void> => {
232
278
  logger.debug('sadot - before create hook');
233
279
  const { fields } = options;
234
- const { include, useEntityIdFromInclude } = modelOptions;
235
280
  const modelType = instance.constructor.name;
236
281
 
237
282
  const identifiers = applyScopeToInstance(instance, scopeAttributes);
238
283
 
239
284
  // Step 1: Handle custom fields default values and required fields
240
- const where: WhereOptions = {
241
- modelType,
242
- disabled: false,
243
- ...(!useEntityIdFromInclude && { entityId: identifiers }),
244
- };
245
285
 
246
- const fieldDefinitions = await DefinitionRepo.findAll(where, {
247
- withDisabled: false,
248
- transaction: options.transaction,
249
- include: include?.(identifiers),
286
+ const fieldDefinitions = await getFieldDefinitions({
287
+ modelType, modelOptions, identifiers, options,
250
288
  });
251
289
 
252
- const requiredFieldsNames = Array.from(
253
- new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)),
254
- );
255
-
256
290
  // Apply default values
257
291
  const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
258
292
  if (fieldsWithDefaultValue.length) {
@@ -267,6 +301,9 @@ export const beforeCreate = (
267
301
  }
268
302
 
269
303
  // Check for required fields
304
+ const requiredFieldsNames = Array.from(
305
+ new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)),
306
+ );
270
307
  const { customFields } = instance;
271
308
  const fieldsNames = Object.keys(customFields ?? {});
272
309
  const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
@@ -277,6 +314,9 @@ export const beforeCreate = (
277
314
  // Step 2: Validate the model data (including custom fields)
278
315
  await validateModel(instance, options, scopeAttributes, true);
279
316
 
317
+ // format date and datetime fields
318
+ formatDates(fieldDefinitions, instance);
319
+
280
320
  // Step 3: Save custom field values if they exist
281
321
  const customFieldsIdx = fields.indexOf('customFields');
282
322
  if (customFieldsIdx === -1 || !customFields || !Object.keys(customFields).length) {
@@ -318,9 +358,16 @@ export const beforeUpdate = (
318
358
  const modelType = instance.constructor.name;
319
359
  const identifiers = applyScopeToInstance(instance, scopeAttributes);
320
360
 
361
+ const fieldDefinitions = await getFieldDefinitions({
362
+ modelType, modelOptions, identifiers, options,
363
+ });
364
+
321
365
  // Step 1: Validate the model data (including custom fields)
322
366
  await validateModel(instance, options, scopeAttributes, false);
323
367
 
368
+ // format date and datetime fields
369
+ formatDates(fieldDefinitions, instance);
370
+
324
371
  // Step 2: Update custom field values if they exist
325
372
  const customFieldsIdx = fields.indexOf('customFields');
326
373
  if (customFieldsIdx > -1) {