@autofleet/sadot 0.13.2-beta.100 → 0.13.2-beta.2

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.
@@ -1,5 +1,6 @@
1
+ import type { Transaction } from 'sequelize';
1
2
  import type CustomFieldValue from '../models/CustomFieldValue';
2
- import type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';
3
+ import type { CustomFieldOptions, ModelOptions } from '../types';
3
4
  type SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';
4
5
  type CustomFieldEntries = Record<string, any>;
5
6
  interface GetValuesGroupByInstanceResponse {
@@ -10,16 +11,20 @@ interface GetCustomFieldEntriesByInstanceIdResponse {
10
11
  }
11
12
  export declare const getCustomFieldEntriesByInstanceId: ({ instancesIds, options, sadotOptions, }: {
12
13
  instancesIds: string[];
13
- options?: TransactionOptions;
14
+ options?: {
15
+ transaction: Transaction;
16
+ };
14
17
  sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;
15
18
  }) => Promise<GetCustomFieldEntriesByInstanceIdResponse>;
16
19
  export declare const getValuesGroupByInstance: ({ instancesIds, options, sadotOptions, }: {
17
20
  instancesIds: string[];
18
- options?: TransactionOptions;
21
+ options?: {
22
+ transaction: Transaction;
23
+ };
19
24
  sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>;
20
25
  }) => Promise<GetValuesGroupByInstanceResponse>;
21
26
  /**
22
27
  * A hook to attach the custom fields when fetching a model instances.
23
28
  */
24
- declare const enrichResults: (modelType: string, scopeAttributes: string[], hookType?: SupportedHookTypes, modelOptions?: ModelOptions, sadotOptions?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>) => (instancesOrInstance: any | any[], options: TransactionOptions) => Promise<void>;
29
+ declare const enrichResults: (modelType: string, scopeAttributes: string[], hookType?: SupportedHookTypes, modelOptions?: ModelOptions, sadotOptions?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>) => (instancesOrInstance: any | any[], options: any) => Promise<void>;
25
30
  export default enrichResults;
@@ -27,12 +27,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.getValuesGroupByInstance = exports.getCustomFieldEntriesByInstanceId = void 0;
30
- /* eslint-disable no-param-reassign */
31
30
  const ValueRepo = __importStar(require("../repository/value"));
32
31
  const DefinitionRepo = __importStar(require("../repository/definition"));
33
32
  const EntriesRepo = __importStar(require("../repository/entries"));
34
33
  const scopeAttributes_1 = __importDefault(require("../utils/scopeAttributes"));
35
- const CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = ['id', 'name', 'entityId'];
36
34
  const getCustomFieldEntriesByInstanceId = async ({ instancesIds, options, sadotOptions, }) => {
37
35
  if (!sadotOptions.useCustomFieldsEntries) {
38
36
  return {};
@@ -95,37 +93,7 @@ const enrichResults = (modelType, scopeAttributes, hookType, modelOptions = {},
95
93
  ...map,
96
94
  [identifier]: [],
97
95
  }), {});
98
- // Cache for definitions by model type and transaction to avoid redundant DB queries
99
- let customFieldDefinitionsPromise;
100
- let cacheKey;
101
- // Check if caching is disabled via environment variable
102
- const cachingDisabled = process.env.SADOT_DISABLE_DEFINITION_CACHE === 'true';
103
- if (options.transaction && !cachingDisabled) {
104
- // Initialize definition cache Map if not already present directly on the transaction object
105
- options.transaction.definitionCache = options.transaction.definitionCache || new Map();
106
- // Create a unique cache key combining model type and sorted identifiers
107
- cacheKey = `${modelType}:${uniqueIdentifiers.sort().join(',')}`;
108
- // Check if these definitions are already cached for this transaction
109
- if (options.transaction.definitionCache.has(cacheKey)) {
110
- // Use cached result to avoid duplicate database queries
111
- customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);
112
- }
113
- }
114
- if (!customFieldDefinitionsPromise) {
115
- // Fetch from database (either first time in this transaction or no transaction)
116
- customFieldDefinitionsPromise = DefinitionRepo.findByEntityIds(modelType, uniqueIdentifiers, { transaction: options.transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL });
117
- // Store in cache if within a transaction and caching isn't disabled
118
- if (options.transaction && options.transaction.definitionCache) {
119
- options.transaction.definitionCache.set(cacheKey, customFieldDefinitionsPromise);
120
- }
121
- }
122
- const customFieldDefinitions = await customFieldDefinitionsPromise;
123
- if (customFieldDefinitions.length === 0) {
124
- // if no custom fields, we can return
125
- instances.forEach((instance) => {
126
- instance.customFields = {};
127
- });
128
- }
96
+ const customFieldDefinitions = await DefinitionRepo.findByEntityIds(modelType, uniqueIdentifiers, { transaction: options.transaction, modelOptions });
129
97
  if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {
130
98
  // if we pass useEntityIdFromInclude,
131
99
  // map the entity from the options to the identifierCustomFieldDefinitionsMapping
@@ -146,18 +114,16 @@ const enrichResults = (modelType, scopeAttributes, hookType, modelOptions = {},
146
114
  // Get the values per instates ids:
147
115
  const instancesIds = instances.map((i) => i[primaryKey]);
148
116
  // Group fields by modelId
149
- const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([
150
- (0, exports.getValuesGroupByInstance)({
151
- instancesIds,
152
- options,
153
- sadotOptions,
154
- }),
155
- (0, exports.getCustomFieldEntriesByInstanceId)({
156
- instancesIds,
157
- options,
158
- sadotOptions,
159
- }),
160
- ]);
117
+ const valuesGroupByInstance = await (0, exports.getValuesGroupByInstance)({
118
+ instancesIds,
119
+ options,
120
+ sadotOptions,
121
+ });
122
+ const customFieldEntriesByInstanceId = await (0, exports.getCustomFieldEntriesByInstanceId)({
123
+ instancesIds,
124
+ options,
125
+ sadotOptions,
126
+ });
161
127
  // Attach custom fields to the instances
162
128
  instances.forEach((instance) => {
163
129
  const { id } = instance;
@@ -28,7 +28,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.beforeBulkUpdate = exports.beforeBulkCreate = exports.beforeUpdate = exports.beforeCreate = void 0;
30
30
  const ajv_1 = __importDefault(require("ajv"));
31
- const joi_1 = __importDefault(require("joi"));
32
31
  const ajv_formats_1 = __importDefault(require("ajv-formats"));
33
32
  const errors_1 = require("@autofleet/errors");
34
33
  const logger_1 = __importDefault(require("../utils/logger"));
@@ -106,24 +105,7 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
106
105
  logger_1.default.debug('sadot - skipping validation: no entityId');
107
106
  return;
108
107
  }
109
- let validatorsPromise;
110
- let cacheKey;
111
- if (options.transaction) {
112
- // eslint-disable-next-line no-param-reassign
113
- options.transaction.validationsCache = options.transaction.validationsCache || new Map();
114
- cacheKey = `${modelType}-${entityId}`;
115
- validatorsPromise = options.transaction.validationsCache.get(cacheKey);
116
- }
117
- if (!validatorsPromise) {
118
- validatorsPromise = ValidatorRepo.findAllByModelType(modelType, entityId, {
119
- transaction: options.transaction,
120
- attributes: ['schema'],
121
- });
122
- if (options.transaction) {
123
- options.transaction.validationsCache.set(cacheKey, validatorsPromise);
124
- }
125
- }
126
- const validators = await validatorsPromise;
108
+ const validators = await ValidatorRepo.findAllByModelType(modelType, entityId, { transaction: options.transaction });
127
109
  logger_1.default.debug('sadot - validators found', { count: validators.length });
128
110
  if (!validators.length) {
129
111
  logger_1.default.debug('sadot - skipping validation: no validators found');
@@ -142,6 +124,16 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
142
124
  const completeCustomFields = !isCreate
143
125
  ? await getCompleteCustomFields(instance, options)
144
126
  : instance.customFields || {};
127
+ // For debugging in case of update
128
+ if (!isCreate && process.env.NODE_ENV !== 'production') {
129
+ // Create after object for logging
130
+ const logAfterObj = manualObjectCopy(instance.dataValues, { customFields: completeCustomFields });
131
+ logger_1.default.debug('sadot - validate with values', {
132
+ before: originalValues,
133
+ after: logAfterObj,
134
+ schema: validators[0].schema,
135
+ });
136
+ }
145
137
  // eslint-disable-next-line no-restricted-syntax
146
138
  for (const validator of validators) {
147
139
  const { schema } = validator;
@@ -204,7 +196,7 @@ const validateModel = async (instance, options, scopeAttributes, isCreate = fals
204
196
  }
205
197
  }
206
198
  };
207
- const getFieldDefinitions = async ({ modelType, modelOptions, identifiers, options, }) => {
199
+ const getFieldDefinitions = async ({ modelType, modelOptions, identifiers, options }) => {
208
200
  const { include, useEntityIdFromInclude } = modelOptions;
209
201
  const where = {
210
202
  modelType,
@@ -218,18 +210,14 @@ const getFieldDefinitions = async ({ modelType, modelOptions, identifiers, optio
218
210
  });
219
211
  return fieldDefinitions;
220
212
  };
221
- const formatDates = (fieldDefinitions, instance) => {
222
- (fieldDefinitions || []).forEach((fieldDefinition) => {
213
+ const formatDates = (fieldDefinitions = [], instance) => {
214
+ fieldDefinitions.forEach((fieldDefinition) => {
223
215
  const { fieldType, name } = fieldDefinition;
224
216
  if ([constants_1.CustomFieldDefinitionType.DATE, constants_1.CustomFieldDefinitionType.DATETIME].includes(fieldType)) {
225
217
  const value = instance.customFields?.[name];
226
218
  if (value) {
227
- const { value: joiValue, error: validationError } = joi_1.default.date().validate(value);
228
- if (validationError) {
229
- throw new errors_2.InvalidValueError(value, name, validationError);
230
- }
231
219
  // eslint-disable-next-line no-param-reassign
232
- instance.customFields[name] = joiValue.toISOString();
220
+ instance.customFields[name] = new Date(value).toISOString();
233
221
  }
234
222
  }
235
223
  });
@@ -244,7 +232,7 @@ const beforeCreate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
244
232
  const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
245
233
  // Step 1: Handle custom fields default values and required fields
246
234
  const fieldDefinitions = await getFieldDefinitions({
247
- modelType, modelOptions, identifiers, options,
235
+ modelType, modelOptions, identifiers, options
248
236
  });
249
237
  // Apply default values
250
238
  const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
@@ -302,7 +290,7 @@ const beforeUpdate = (scopeAttributes, modelOptions = {}, sadotOptions = { useCu
302
290
  const modelType = instance.constructor.name;
303
291
  const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
304
292
  const fieldDefinitions = await getFieldDefinitions({
305
- modelType, modelOptions, identifiers, options,
293
+ modelType, modelOptions, identifiers, options
306
294
  });
307
295
  // Step 1: Validate the model data (including custom fields)
308
296
  await validateModel(instance, options, scopeAttributes, false);
@@ -26,8 +26,12 @@ exports.CustomValidator = CustomValidator_1.default;
26
26
  const productionModels = [CustomFieldDefinition_1.default, CustomFieldValue_1.default, CustomValidator_1.default];
27
27
  const testModels = [TestModel_1.default, AssociatedTestModel_1.default, ContextAwareTestModel_1.default, ContextTestModel_1.default];
28
28
  const SADOT_MIGRATION_PREFIX = 'sadot-migration';
29
- const SCHEMA_VERSION = '49c9dd1d-b1cc-445b-a911-fd349d783110';
30
- const initTables = async (sequelize, getUser, { schemaPrefix = SADOT_MIGRATION_PREFIX, schemaVersion = SCHEMA_VERSION, useCustomFieldsEntries = false, } = {}) => {
29
+ const SCHEMA_VERSION = 'fb0fa867-1241-4816-b08d-5ed9060c7ae5';
30
+ const initTables = async (sequelize, getUser, { schemaPrefix, schemaVersion, useCustomFieldsEntries, } = {
31
+ schemaPrefix: SADOT_MIGRATION_PREFIX,
32
+ schemaVersion: SCHEMA_VERSION,
33
+ useCustomFieldsEntries: false,
34
+ }) => {
31
35
  const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;
32
36
  logger_1.default.info('custom-fields: initialize custom-fields tables');
33
37
  // Detect models and import them to the orm
@@ -83,13 +87,10 @@ const initTables = async (sequelize, getUser, { schemaPrefix = SADOT_MIGRATION_P
83
87
  timestamps: false,
84
88
  schema: 'public',
85
89
  });
86
- logger_1.default.info('custom-fields: starting migrations');
87
90
  const migrations = await SequelizeMeta.findAll({ where: { name: { [sequelize_1.Op.like]: `${schemaPrefix}%` } }, raw: true });
88
91
  const currentSadotSchemaVersion = migrations.at(-1);
89
92
  const expectedSchemaVersionIndex = migrations.findIndex((m) => m.name === CUSTOM_FIELDS_SCHEMA_VERSION);
90
- logger_1.default.info('custom-fields: migrations', { migrations, currentSadotSchemaVersion, expectedSchemaVersionIndex });
91
93
  if (!currentSadotSchemaVersion || currentSadotSchemaVersion.name !== CUSTOM_FIELDS_SCHEMA_VERSION) {
92
- logger_1.default.info('custom-fields: syncing models');
93
94
  await CustomFieldDefinition_1.default.sync({ alter: true });
94
95
  await CustomFieldValue_1.default.sync({ alter: true });
95
96
  // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS
@@ -2,7 +2,6 @@ import type { Transactionable } from 'sequelize';
2
2
  import { CustomValidator } from '../models';
3
3
  export interface FindValidatorOptions extends Transactionable {
4
4
  withDisabled?: boolean;
5
- attributes?: string[];
6
5
  }
7
6
  export interface ValidatorAttributes {
8
7
  entityId: string;
@@ -1,13 +1,7 @@
1
- import type { IncludeOptions, Transaction } from 'sequelize';
1
+ import type { IncludeOptions } from 'sequelize';
2
2
  import type { ModelCtor, Sequelize } from 'sequelize-typescript';
3
3
  import type { getUser as GetUserType } from '@autofleet/zehut';
4
- import type CustomFieldDefinition from '../models/CustomFieldDefinition';
5
4
  export type ModelFetcher = (name: string) => any;
6
- export interface TransactionOptions extends Record<string, any> {
7
- transaction?: Transaction & {
8
- definitionCache?: Map<string, CustomFieldDefinition[]>;
9
- };
10
- }
11
5
  export type ModelOptions = {
12
6
  /**
13
7
  * Include options for the model
@@ -22,10 +16,6 @@ export type ModelOptions = {
22
16
  * Whether to use the entity id from the instance per scope attribute
23
17
  */
24
18
  useEntityIdFromInclude?: boolean;
25
- /**
26
- * Which attributes to include in the model
27
- */
28
- attributes?: string[];
29
19
  };
30
20
  export type Models = {
31
21
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.13.2-beta.100",
3
+ "version": "0.13.2-beta.2",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -1,15 +1,14 @@
1
1
  /* eslint-disable no-param-reassign */
2
+ import type { Transaction } from 'sequelize';
2
3
  import * as ValueRepo from '../repository/value';
3
4
  import * as DefinitionRepo from '../repository/definition';
4
5
  import * as EntriesRepo from '../repository/entries';
5
6
  import type CustomFieldValue from '../models/CustomFieldValue';
6
7
  import type CustomFieldDefinition from '../models/CustomFieldDefinition';
7
8
  import type { SerializedCustomFields } from '../types/definition';
8
- import type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';
9
+ import type { CustomFieldOptions, ModelOptions } from '../types';
9
10
  import applyScopeToInstance from '../utils/scopeAttributes';
10
11
 
11
- const CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = ['id', 'name', 'entityId'];
12
-
13
12
  type SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';
14
13
 
15
14
  type CustomFieldEntries = Record<string, any>;
@@ -28,7 +27,7 @@ export const getCustomFieldEntriesByInstanceId = async ({
28
27
  sadotOptions,
29
28
  }: {
30
29
  instancesIds: string[],
31
- options?: TransactionOptions,
30
+ options?: { transaction: Transaction },
32
31
  sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,
33
32
  }): Promise<GetCustomFieldEntriesByInstanceIdResponse> => {
34
33
  if (!sadotOptions.useCustomFieldsEntries) {
@@ -61,7 +60,7 @@ export const getValuesGroupByInstance = async ({
61
60
  sadotOptions,
62
61
  }: {
63
62
  instancesIds: string[],
64
- options?: TransactionOptions,
63
+ options?: { transaction: Transaction },
65
64
  sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,
66
65
  }): Promise<GetValuesGroupByInstanceResponse> => {
67
66
  if (sadotOptions.useCustomFieldsEntries) {
@@ -109,7 +108,7 @@ const enrichResults = (
109
108
  sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false },
110
109
  ) => async (
111
110
  instancesOrInstance: any | any[],
112
- options: TransactionOptions,
111
+ options,
113
112
  ): Promise<void> => {
114
113
  if (
115
114
  options.originalAttributes?.length > 0
@@ -132,50 +131,14 @@ const enrichResults = (
132
131
  const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({
133
132
  ...map,
134
133
  [identifier]: [],
135
- }), {});
136
-
137
- // Cache for definitions by model type and transaction to avoid redundant DB queries
138
- let customFieldDefinitionsPromise;
139
- let cacheKey;
140
-
141
- // Check if caching is disabled via environment variable
142
- const cachingDisabled = process.env.SADOT_DISABLE_DEFINITION_CACHE === 'true';
143
-
144
- if (options.transaction && !cachingDisabled) {
145
- // Initialize definition cache Map if not already present directly on the transaction object
146
- options.transaction.definitionCache = options.transaction.definitionCache || new Map();
147
134
 
148
- // Create a unique cache key combining model type and sorted identifiers
149
- cacheKey = `${modelType}:${uniqueIdentifiers.sort().join(',')}`;
150
-
151
- // Check if these definitions are already cached for this transaction
152
- if (options.transaction.definitionCache.has(cacheKey)) {
153
- // Use cached result to avoid duplicate database queries
154
- customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);
155
- }
156
- }
157
-
158
- if (!customFieldDefinitionsPromise) {
159
- // Fetch from database (either first time in this transaction or no transaction)
160
- customFieldDefinitionsPromise = DefinitionRepo.findByEntityIds(
161
- modelType,
162
- uniqueIdentifiers,
163
- { transaction: options.transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL },
164
- );
165
-
166
- // Store in cache if within a transaction and caching isn't disabled
167
- if (options.transaction && options.transaction.definitionCache) {
168
- options.transaction.definitionCache.set(cacheKey, customFieldDefinitionsPromise);
169
- }
170
- }
171
- const customFieldDefinitions = await customFieldDefinitionsPromise;
135
+ }), {});
172
136
 
173
- if (customFieldDefinitions.length === 0) {
174
- // if no custom fields, we can return
175
- instances.forEach((instance) => {
176
- instance.customFields = {};
177
- });
178
- }
137
+ const customFieldDefinitions = await DefinitionRepo.findByEntityIds(
138
+ modelType,
139
+ uniqueIdentifiers,
140
+ { transaction: options.transaction, modelOptions },
141
+ );
179
142
 
180
143
  if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {
181
144
  // if we pass useEntityIdFromInclude,
@@ -201,18 +164,17 @@ const enrichResults = (
201
164
  const instancesIds = instances.map((i) => i[primaryKey]);
202
165
 
203
166
  // Group fields by modelId
204
- const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([
205
- getValuesGroupByInstance({
206
- instancesIds,
207
- options,
208
- sadotOptions,
209
- }),
210
- getCustomFieldEntriesByInstanceId({
211
- instancesIds,
212
- options,
213
- sadotOptions,
214
- }),
215
- ]);
167
+ const valuesGroupByInstance = await getValuesGroupByInstance({
168
+ instancesIds,
169
+ options,
170
+ sadotOptions,
171
+ });
172
+
173
+ const customFieldEntriesByInstanceId = await getCustomFieldEntriesByInstanceId({
174
+ instancesIds,
175
+ options,
176
+ sadotOptions,
177
+ });
216
178
 
217
179
  // Attach custom fields to the instances
218
180
  instances.forEach((instance) => {
@@ -105,29 +105,11 @@ const validateModel = async (
105
105
  return;
106
106
  }
107
107
 
108
- let validatorsPromise;
109
- let cacheKey;
110
- if (options.transaction) {
111
- // eslint-disable-next-line no-param-reassign
112
- options.transaction.validationsCache = options.transaction.validationsCache || new Map();
113
- cacheKey = `${modelType}-${entityId}`;
114
- validatorsPromise = options.transaction.validationsCache.get(cacheKey);
115
- }
116
-
117
- if (!validatorsPromise) {
118
- validatorsPromise = ValidatorRepo.findAllByModelType(
119
- modelType,
120
- entityId,
121
- {
122
- transaction: options.transaction,
123
- attributes: ['schema'],
124
- },
125
- );
126
- if (options.transaction) {
127
- options.transaction.validationsCache.set(cacheKey, validatorsPromise);
128
- }
129
- }
130
- const validators = await validatorsPromise;
108
+ const validators = await ValidatorRepo.findAllByModelType(
109
+ modelType,
110
+ entityId,
111
+ { transaction: options.transaction },
112
+ );
131
113
 
132
114
  logger.debug('sadot - validators found', { count: validators.length });
133
115
 
@@ -152,6 +134,17 @@ const validateModel = async (
152
134
  ? await getCompleteCustomFields(instance, options)
153
135
  : instance.customFields || {};
154
136
 
137
+ // For debugging in case of update
138
+ if (!isCreate && process.env.NODE_ENV !== 'production') {
139
+ // Create after object for logging
140
+ const logAfterObj = manualObjectCopy(instance.dataValues, { customFields: completeCustomFields });
141
+
142
+ logger.debug('sadot - validate with values', {
143
+ before: originalValues,
144
+ after: logAfterObj,
145
+ schema: validators[0].schema,
146
+ });
147
+ }
155
148
 
156
149
  // eslint-disable-next-line no-restricted-syntax
157
150
  for (const validator of validators) {
@@ -265,7 +258,10 @@ const formatDates = (fieldDefinitions: CustomFieldDefinition[], instance: any) =
265
258
  throw new InvalidValueError(value, name, validationError);
266
259
  }
267
260
  // eslint-disable-next-line no-param-reassign
261
+ const typeofjoi = typeof joiValue;
262
+ logger.info('sadot - formatting date', { name, value, joiValue, type: typeof joiValue });
268
263
  instance.customFields[name] = joiValue.toISOString();
264
+ new Date().toString
269
265
  }
270
266
  }
271
267
  });
@@ -282,72 +278,72 @@ export const beforeCreate = (
282
278
  instance,
283
279
  options,
284
280
  ): Promise<void> => {
285
- logger.debug('sadot - before create hook');
286
- const { fields } = options;
287
- const modelType = instance.constructor.name;
281
+ logger.debug('sadot - before create hook');
282
+ const { fields } = options;
283
+ const modelType = instance.constructor.name;
288
284
 
289
- const identifiers = applyScopeToInstance(instance, scopeAttributes);
285
+ const identifiers = applyScopeToInstance(instance, scopeAttributes);
290
286
 
291
- // Step 1: Handle custom fields default values and required fields
287
+ // Step 1: Handle custom fields default values and required fields
292
288
 
293
- const fieldDefinitions = await getFieldDefinitions({
294
- modelType, modelOptions, identifiers, options,
295
- });
289
+ const fieldDefinitions = await getFieldDefinitions({
290
+ modelType, modelOptions, identifiers, options,
291
+ });
296
292
 
297
- // Apply default values
298
- const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
299
- if (fieldsWithDefaultValue.length) {
300
- // eslint-disable-next-line no-param-reassign
301
- instance.customFields ||= {};
302
- fieldsWithDefaultValue
303
- .filter((def) => (instance.customFields?.[def.name] === undefined))
304
- .forEach(({ name, defaultValue }) => {
305
- // eslint-disable-next-line no-param-reassign
306
- instance.customFields[name] = defaultValue;
307
- });
308
- }
293
+ // Apply default values
294
+ const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));
295
+ if (fieldsWithDefaultValue.length) {
296
+ // eslint-disable-next-line no-param-reassign
297
+ instance.customFields ||= {};
298
+ fieldsWithDefaultValue
299
+ .filter((def) => (instance.customFields?.[def.name] === undefined))
300
+ .forEach(({ name, defaultValue }) => {
301
+ // eslint-disable-next-line no-param-reassign
302
+ instance.customFields[name] = defaultValue;
303
+ });
304
+ }
309
305
 
310
- // Check for required fields
311
- const requiredFieldsNames = Array.from(
312
- new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)),
313
- );
314
- const { customFields } = instance;
315
- const fieldsNames = Object.keys(customFields ?? {});
316
- const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
317
- if (missingFields?.length) {
318
- throw new MissingRequiredCustomFieldError(missingFields);
319
- }
306
+ // Check for required fields
307
+ const requiredFieldsNames = Array.from(
308
+ new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)),
309
+ );
310
+ const { customFields } = instance;
311
+ const fieldsNames = Object.keys(customFields ?? {});
312
+ const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));
313
+ if (missingFields?.length) {
314
+ throw new MissingRequiredCustomFieldError(missingFields);
315
+ }
320
316
 
321
- // Step 2: Validate the model data (including custom fields)
322
- await validateModel(instance, options, scopeAttributes, true);
317
+ // Step 2: Validate the model data (including custom fields)
318
+ await validateModel(instance, options, scopeAttributes, true);
323
319
 
324
- // format date and datetime fields
325
- formatDates(fieldDefinitions, instance);
320
+ // format date and datetime fields
321
+ formatDates(fieldDefinitions, instance);
326
322
 
327
- // Step 3: Save custom field values if they exist
328
- const customFieldsIdx = fields.indexOf('customFields');
329
- if (customFieldsIdx === -1 || !customFields || !Object.keys(customFields).length) {
330
- // No custom fields to update
331
- return;
332
- }
323
+ // Step 3: Save custom field values if they exist
324
+ const customFieldsIdx = fields.indexOf('customFields');
325
+ if (customFieldsIdx === -1 || !customFields || !Object.keys(customFields).length) {
326
+ // No custom fields to update
327
+ return;
328
+ }
333
329
 
334
- // Save custom field values
335
- await updateInstanceValues({
336
- modelId: instance.id,
337
- modelType,
338
- identifiers,
339
- customFields,
340
- options: {
341
- useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,
342
- transaction: options.transaction,
343
- modelOptions,
344
- },
345
- });
330
+ // Save custom field values
331
+ await updateInstanceValues({
332
+ modelId: instance.id,
333
+ modelType,
334
+ identifiers,
335
+ customFields,
336
+ options: {
337
+ useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,
338
+ transaction: options.transaction,
339
+ modelOptions,
340
+ },
341
+ });
346
342
 
347
- // Remove customFields from fields array after handling
348
- // eslint-disable-next-line no-param-reassign
349
- fields.splice(customFieldsIdx, 1);
350
- };
343
+ // Remove customFields from fields array after handling
344
+ // eslint-disable-next-line no-param-reassign
345
+ fields.splice(customFieldsIdx, 1);
346
+ };
351
347
 
352
348
  /**
353
349
  * Hook to handle validation and custom fields during update
@@ -360,48 +356,48 @@ export const beforeUpdate = (
360
356
  instance,
361
357
  options,
362
358
  ): Promise<void> => {
363
- logger.debug('sadot - before update hook');
364
- const { fields } = options;
365
- const modelType = instance.constructor.name;
366
- const identifiers = applyScopeToInstance(instance, scopeAttributes);
359
+ logger.debug('sadot - before update hook');
360
+ const { fields } = options;
361
+ const modelType = instance.constructor.name;
362
+ const identifiers = applyScopeToInstance(instance, scopeAttributes);
367
363
 
368
- const fieldDefinitions = await getFieldDefinitions({
369
- modelType, modelOptions, identifiers, options,
370
- });
364
+ const fieldDefinitions = await getFieldDefinitions({
365
+ modelType, modelOptions, identifiers, options,
366
+ });
371
367
 
372
- // Step 1: Validate the model data (including custom fields)
373
- await validateModel(instance, options, scopeAttributes, false);
368
+ // Step 1: Validate the model data (including custom fields)
369
+ await validateModel(instance, options, scopeAttributes, false);
374
370
 
375
- // format date and datetime fields
376
- formatDates(fieldDefinitions, instance);
371
+ // format date and datetime fields
372
+ formatDates(fieldDefinitions, instance);
377
373
 
378
- // Step 2: Update custom field values if they exist
379
- const customFieldsIdx = fields.indexOf('customFields');
380
- if (customFieldsIdx > -1) {
381
- const { customFields } = instance;
374
+ // Step 2: Update custom field values if they exist
375
+ const customFieldsIdx = fields.indexOf('customFields');
376
+ if (customFieldsIdx > -1) {
377
+ const { customFields } = instance;
382
378
 
383
- if (!Object.keys(customFields).length) {
384
- return;
385
- }
379
+ if (!Object.keys(customFields).length) {
380
+ return;
381
+ }
386
382
 
387
- // Save custom field values
388
- await updateInstanceValues({
389
- modelId: instance.id,
390
- modelType,
391
- identifiers,
392
- customFields,
393
- options: {
394
- useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,
395
- transaction: options.transaction,
396
- modelOptions,
397
- },
398
- });
383
+ // Save custom field values
384
+ await updateInstanceValues({
385
+ modelId: instance.id,
386
+ modelType,
387
+ identifiers,
388
+ customFields,
389
+ options: {
390
+ useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,
391
+ transaction: options.transaction,
392
+ modelOptions,
393
+ },
394
+ });
399
395
 
400
- // Remove customFields from fields array after handling
401
- // eslint-disable-next-line no-param-reassign
402
- fields.splice(customFieldsIdx, 1);
403
- }
404
- };
396
+ // Remove customFields from fields array after handling
397
+ // eslint-disable-next-line no-param-reassign
398
+ fields.splice(customFieldsIdx, 1);
399
+ }
400
+ };
405
401
 
406
402
  /**
407
403
  * Hook to enable individual hooks for bulk create operations
@@ -29,10 +29,14 @@ const initTables = async (
29
29
  sequelize: Sequelize,
30
30
  getUser: CustomFieldOptions['getUser'],
31
31
  {
32
- schemaPrefix = SADOT_MIGRATION_PREFIX,
33
- schemaVersion = SCHEMA_VERSION,
34
- useCustomFieldsEntries = false,
35
- }: InitTablesOptions = {},
32
+ schemaPrefix,
33
+ schemaVersion,
34
+ useCustomFieldsEntries,
35
+ }: InitTablesOptions = {
36
+ schemaPrefix: SADOT_MIGRATION_PREFIX,
37
+ schemaVersion: SCHEMA_VERSION,
38
+ useCustomFieldsEntries: false,
39
+ },
36
40
  ): Promise<void> => {
37
41
  const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;
38
42
  logger.info('custom-fields: initialize custom-fields tables');
@@ -100,7 +104,6 @@ const initTables = async (
100
104
  },
101
105
  );
102
106
 
103
- logger.info('custom-fields: starting migrations');
104
107
  const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });
105
108
  const currentSadotSchemaVersion = migrations.at(-1);
106
109
  const expectedSchemaVersionIndex = migrations.findIndex((m) => (m as any).name === CUSTOM_FIELDS_SCHEMA_VERSION);
@@ -4,7 +4,6 @@ import { CustomValidator } from '../models';
4
4
 
5
5
  export interface FindValidatorOptions extends Transactionable {
6
6
  withDisabled?: boolean;
7
- attributes?: string[];
8
7
  }
9
8
 
10
9
  // Make sure this interface is compatible with the Sequelize model
@@ -1,16 +1,9 @@
1
- import type { IncludeOptions, Transaction } from 'sequelize';
1
+ import type { IncludeOptions } from 'sequelize';
2
2
  import type { ModelCtor, Sequelize } from 'sequelize-typescript';
3
3
  import type { getUser as GetUserType } from '@autofleet/zehut';
4
- import type CustomFieldDefinition from '../models/CustomFieldDefinition';
5
4
 
6
5
  export type ModelFetcher = (name: string) => any;
7
6
 
8
- export interface TransactionOptions extends Record<string, any> {
9
- transaction?: Transaction & {
10
- definitionCache?: Map<string, CustomFieldDefinition[]>;
11
- };
12
- }
13
-
14
7
  export type ModelOptions = {
15
8
  /**
16
9
  * Include options for the model
@@ -26,10 +19,6 @@ export type ModelOptions = {
26
19
  * Whether to use the entity id from the instance per scope attribute
27
20
  */
28
21
  useEntityIdFromInclude?: boolean
29
- /**
30
- * Which attributes to include in the model
31
- */
32
- attributes?: string[];
33
22
  }
34
23
  export type Models = {
35
24
  name: string;