@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.
- package/dist/hooks/hooks.js +36 -10
- package/package.json +2 -1
- package/src/hooks/hooks.ts +62 -15
package/dist/hooks/hooks.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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",
|
package/src/hooks/hooks.ts
CHANGED
|
@@ -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
|
|
247
|
-
|
|
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) {
|