@autofleet/sadot 0.5.4-beta.23 → 0.5.4-beta.26

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.
Files changed (35) hide show
  1. package/dist/hooks/create.js +5 -3
  2. package/dist/hooks/enrich.js +13 -6
  3. package/dist/hooks/update.js +2 -3
  4. package/dist/index.js +1 -0
  5. package/dist/models/index.d.ts +2 -2
  6. package/dist/models/index.js +5 -5
  7. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.d.ts +2 -2
  8. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js +4 -4
  9. package/dist/models/tests/contextAwareModels/{ContextModel.d.ts → ContextTestModel.d.ts} +2 -2
  10. package/dist/models/tests/contextAwareModels/{ContextModel.js → ContextTestModel.js} +7 -7
  11. package/dist/repository/definition.d.ts +6 -3
  12. package/dist/repository/definition.js +26 -13
  13. package/dist/repository/value.d.ts +5 -1
  14. package/dist/repository/value.js +8 -5
  15. package/dist/tests/helpers/index.js +1 -1
  16. package/dist/types/index.d.ts +16 -2
  17. package/dist/utils/init.d.ts +1 -0
  18. package/dist/utils/init.js +7 -1
  19. package/dist/utils/scopeAttributes.d.ts +2 -3
  20. package/dist/utils/scopeAttributes.js +5 -23
  21. package/package.json +1 -1
  22. package/src/hooks/create.ts +8 -5
  23. package/src/hooks/enrich.ts +15 -7
  24. package/src/hooks/find.ts +0 -1
  25. package/src/hooks/update.ts +3 -4
  26. package/src/index.ts +4 -1
  27. package/src/models/index.ts +4 -4
  28. package/src/models/tests/contextAwareModels/ContextAwareTestModel.ts +4 -4
  29. package/src/models/tests/contextAwareModels/{ContextModel.ts → ContextTestModel.ts} +2 -2
  30. package/src/repository/definition.ts +33 -13
  31. package/src/repository/value.ts +14 -10
  32. package/src/tests/helpers/index.ts +2 -2
  33. package/src/types/index.ts +18 -2
  34. package/src/utils/init.ts +7 -0
  35. package/src/utils/scopeAttributes.ts +5 -25
@@ -27,6 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.beforeCreate = exports.beforeBulkCreate = void 0;
30
+ const logger_1 = __importDefault(require("../utils/logger"));
30
31
  const ValueRepo = __importStar(require("../repository/value"));
31
32
  const DefinitionRepo = __importStar(require("../repository/definition"));
32
33
  const errors_1 = require("../errors");
@@ -45,12 +46,12 @@ exports.beforeBulkCreate = beforeBulkCreate;
45
46
  * TODO - cleanup if update fail
46
47
  */
47
48
  const beforeCreate = (scopeAttributes, modelOptions = {}) => async (instance, options) => {
49
+ logger_1.default.debug('sadot - before create hook');
48
50
  const { fields } = options;
49
51
  const modelType = instance.constructor.name;
50
- const { scopeAttributeReplacer } = modelOptions;
51
- const identifiers = await (0, scopeAttributes_1.default)(instance, scopeAttributes, scopeAttributeReplacer);
52
+ const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
52
53
  // get all model's required definitions
53
- const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType, instance.id, identifiers);
54
+ const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType, instance.id, identifiers, modelOptions);
54
55
  const customFieldsIdx = fields.indexOf('customFields');
55
56
  const { customFields } = instance;
56
57
  if (customFieldsIdx > -1 && customFields) {
@@ -61,6 +62,7 @@ const beforeCreate = (scopeAttributes, modelOptions = {}) => async (instance, op
61
62
  }
62
63
  await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, {
63
64
  transaction: options.transaction,
65
+ modelOptions,
64
66
  });
65
67
  // eslint-disable-next-line no-param-reassign
66
68
  fields.splice(customFieldsIdx, 1);
@@ -29,7 +29,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  /* eslint-disable no-param-reassign */
30
30
  const ValueRepo = __importStar(require("../repository/value"));
31
31
  const DefinitionRepo = __importStar(require("../repository/definition"));
32
- const logger_1 = __importDefault(require("../utils/logger"));
33
32
  const scopeAttributes_1 = __importDefault(require("../utils/scopeAttributes"));
34
33
  /**
35
34
  * Serialize custom fields value into the format of {[name] -> [fieldData]}
@@ -46,7 +45,6 @@ const serializeCustomFields = (customFieldValues, customFieldDefinitionsHash) =>
46
45
  * A hook to attach the custom fields when fetching a model instances.
47
46
  */
48
47
  const enrichResults = (modelType, scopeAttributes, hookType, modelOptions = {}) => async (instancesOrInstance, options) => {
49
- const { scopeAttributeReplacer } = modelOptions;
50
48
  if (options.originalAttributes?.length > 0
51
49
  && !options.originalAttributes?.includes?.('customFields')) {
52
50
  return;
@@ -56,20 +54,29 @@ const enrichResults = (modelType, scopeAttributes, hookType, modelOptions = {})
56
54
  ? instancesOrInstance
57
55
  : [instancesOrInstance];
58
56
  instances = instances.filter(Boolean);
59
- const identifiers = await (0, scopeAttributes_1.default)(instances, scopeAttributes, scopeAttributeReplacer);
60
- logger_1.default.info('enrichResults - sadot - indentifiers: ', identifiers);
57
+ const identifiers = (0, scopeAttributes_1.default)(instances, scopeAttributes);
61
58
  const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);
62
59
  const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({
63
60
  ...map,
64
61
  [identifier]: [],
65
62
  }), {});
66
- const customFieldDefinitions = await DefinitionRepo.findByEntityIds(modelType, uniqueIdentifiers, { transaction: options.transaction });
63
+ const customFieldDefinitions = await DefinitionRepo.findByEntityIds(modelType, uniqueIdentifiers, { transaction: options.transaction, modelOptions });
64
+ if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {
65
+ // if we pass useEntityIdFromInclude,
66
+ // map the entity from the options to the identifierCustomFieldDefinitionsMapping
67
+ modelOptions.include(identifiers).forEach(({ model }) => {
68
+ customFieldDefinitions.forEach((cfd) => {
69
+ const entityId = cfd[`${model.name}.entityId`];
70
+ identifierCustomFieldDefinitionsMapping[entityId] = [];
71
+ });
72
+ });
73
+ }
67
74
  const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({
68
75
  ...map,
69
76
  [definition.id]: definition,
70
77
  }), {});
71
78
  customFieldDefinitions.forEach((cfd) => {
72
- identifierCustomFieldDefinitionsMapping[cfd.entityId]?.push(cfd);
79
+ identifierCustomFieldDefinitionsMapping[cfd.entityId].push(cfd);
73
80
  });
74
81
  // Get the values per instates ids:
75
82
  const instancesIds = instances.map((i) => i[primaryKey]);
@@ -46,13 +46,12 @@ exports.beforeBulkUpdate = beforeBulkUpdate;
46
46
  const beforeUpdate = (scopeAttributes, modelOptions = {}) => async (instance, options) => {
47
47
  logger_1.default.debug('sadot - before update hook');
48
48
  const { fields } = options;
49
- const { scopeAttributeReplacer } = modelOptions;
50
49
  const modelType = instance.constructor.name;
51
- const identifiers = await (0, scopeAttributes_1.default)(instance, scopeAttributes, scopeAttributeReplacer);
50
+ const identifiers = (0, scopeAttributes_1.default)(instance, scopeAttributes);
52
51
  const customFieldsIdx = fields.indexOf('customFields');
53
52
  if (customFieldsIdx > -1) {
54
53
  const { customFields } = instance;
55
- await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, { transaction: options.transaction });
54
+ await ValueRepo.updateValues(modelType, instance.id, identifiers, customFields, { transaction: options.transaction, modelOptions });
56
55
  // eslint-disable-next-line no-param-reassign
57
56
  fields.splice(customFieldsIdx, 1);
58
57
  }
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ const useCustomFields = async (app, getModel, options) => {
42
42
  (0, init_1.addHooks)(models, getModel);
43
43
  await (0, models_1.initTables)(sequelize, options.getUser);
44
44
  (0, init_1.addScopes)(models, getModel);
45
+ (0, init_1.applyCustomAssociation)(models);
45
46
  logger_1.default.debug('sadot - custom fields finished initializing with models', models);
46
47
  return sequelize;
47
48
  };
@@ -3,8 +3,8 @@ import CustomFieldDefinition from './CustomFieldDefinition';
3
3
  import CustomFieldValue from './CustomFieldValue';
4
4
  import TestModel from './tests/TestModel';
5
5
  import ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';
6
- import ContextModel from './tests/contextAwareModels/ContextModel';
6
+ import ContextTestModel from './tests/contextAwareModels/ContextTestModel';
7
7
  import AssociatedTestModel from './tests/AssociatedTestModel';
8
8
  declare const initTables: (sequelize: Sequelize, getUser: any) => Promise<void>;
9
9
  declare const initTestModels: (sequelize: Sequelize) => Promise<void>;
10
- export { CustomFieldValue, CustomFieldDefinition, TestModel, AssociatedTestModel, ContextAwareTestModel, ContextModel, initTables, initTestModels, };
10
+ export { CustomFieldValue, CustomFieldDefinition, TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel, initTables, initTestModels, };
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.initTestModels = exports.initTables = exports.ContextModel = exports.ContextAwareTestModel = exports.AssociatedTestModel = exports.TestModel = exports.CustomFieldDefinition = exports.CustomFieldValue = void 0;
6
+ exports.initTestModels = exports.initTables = exports.ContextTestModel = exports.ContextAwareTestModel = exports.AssociatedTestModel = exports.TestModel = exports.CustomFieldDefinition = exports.CustomFieldValue = void 0;
7
7
  /* eslint-disable no-param-reassign */
8
8
  const sequelize_1 = require("sequelize");
9
9
  const logger_1 = __importDefault(require("../utils/logger"));
@@ -15,12 +15,12 @@ const TestModel_1 = __importDefault(require("./tests/TestModel"));
15
15
  exports.TestModel = TestModel_1.default;
16
16
  const ContextAwareTestModel_1 = __importDefault(require("./tests/contextAwareModels/ContextAwareTestModel"));
17
17
  exports.ContextAwareTestModel = ContextAwareTestModel_1.default;
18
- const ContextModel_1 = __importDefault(require("./tests/contextAwareModels/ContextModel"));
19
- exports.ContextModel = ContextModel_1.default;
18
+ const ContextTestModel_1 = __importDefault(require("./tests/contextAwareModels/ContextTestModel"));
19
+ exports.ContextTestModel = ContextTestModel_1.default;
20
20
  const AssociatedTestModel_1 = __importDefault(require("./tests/AssociatedTestModel"));
21
21
  exports.AssociatedTestModel = AssociatedTestModel_1.default;
22
22
  const productionModels = [CustomFieldDefinition_1.default, CustomFieldValue_1.default];
23
- const testModels = [TestModel_1.default, AssociatedTestModel_1.default, ContextAwareTestModel_1.default, ContextModel_1.default];
23
+ const testModels = [TestModel_1.default, AssociatedTestModel_1.default, ContextAwareTestModel_1.default, ContextTestModel_1.default];
24
24
  const SADOT_MIGRATION_PREFIX = 'sadot-migration';
25
25
  const SCHEMA_VERSION = 1;
26
26
  const CUSTOM_FIELDS_SCHEMA_VERSION = `${SADOT_MIGRATION_PREFIX}_${SCHEMA_VERSION}`;
@@ -86,7 +86,7 @@ const initTestModels = async (sequelize) => {
86
86
  logger_1.default.info('custom-fields: test models added');
87
87
  await TestModel_1.default.sync({ alter: true });
88
88
  await AssociatedTestModel_1.default.sync({ alter: true });
89
- await ContextModel_1.default.sync({ alter: true });
89
+ await ContextTestModel_1.default.sync({ alter: true });
90
90
  await ContextAwareTestModel_1.default.sync({ alter: true });
91
91
  logger_1.default.info('custom-fields: test models synced');
92
92
  };
@@ -1,10 +1,10 @@
1
1
  import { Model } from 'sequelize-typescript';
2
- import ContextModel from './ContextModel';
2
+ import ContextTestModel from './ContextTestModel';
3
3
  declare class ContextAwareTestModel extends Model {
4
4
  id: string;
5
5
  contextId: string;
6
6
  coolAttribute?: boolean;
7
7
  customFields?: any;
8
- context: ContextModel;
8
+ context: ContextTestModel;
9
9
  }
10
10
  export default ContextAwareTestModel;
@@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  /* eslint-disable @typescript-eslint/no-unused-vars */
16
16
  const sequelize_typescript_1 = require("sequelize-typescript");
17
- const ContextModel_1 = __importDefault(require("./ContextModel"));
17
+ const ContextTestModel_1 = __importDefault(require("./ContextTestModel"));
18
18
  let ContextAwareTestModel = class ContextAwareTestModel extends sequelize_typescript_1.Model {
19
19
  };
20
20
  __decorate([
@@ -27,7 +27,7 @@ __decorate([
27
27
  __metadata("design:type", String)
28
28
  ], ContextAwareTestModel.prototype, "id", void 0);
29
29
  __decorate([
30
- (0, sequelize_typescript_1.ForeignKey)(() => ContextModel_1.default),
30
+ (0, sequelize_typescript_1.ForeignKey)(() => ContextTestModel_1.default),
31
31
  (0, sequelize_typescript_1.Column)({
32
32
  type: sequelize_typescript_1.DataType.UUID,
33
33
  }),
@@ -46,8 +46,8 @@ __decorate([
46
46
  __metadata("design:type", Object)
47
47
  ], ContextAwareTestModel.prototype, "customFields", void 0);
48
48
  __decorate([
49
- (0, sequelize_typescript_1.BelongsTo)(() => ContextModel_1.default),
50
- __metadata("design:type", ContextModel_1.default)
49
+ (0, sequelize_typescript_1.BelongsTo)(() => ContextTestModel_1.default),
50
+ __metadata("design:type", ContextTestModel_1.default)
51
51
  ], ContextAwareTestModel.prototype, "context", void 0);
52
52
  ContextAwareTestModel = __decorate([
53
53
  (0, sequelize_typescript_1.Table)({ createdAt: false, updatedAt: false })
@@ -5,9 +5,9 @@ declare enum EEntityTypes {
5
5
  DEMAND_SOURCE = "demandSource",
6
6
  FLEET = "fleet"
7
7
  }
8
- declare class ContextModel extends Model {
8
+ declare class ContextTestModel extends Model {
9
9
  id: string;
10
10
  entityId: string;
11
11
  entityType: EEntityTypes;
12
12
  }
13
- export default ContextModel;
13
+ export default ContextTestModel;
@@ -19,7 +19,7 @@ var EEntityTypes;
19
19
  EEntityTypes["DEMAND_SOURCE"] = "demandSource";
20
20
  EEntityTypes["FLEET"] = "fleet";
21
21
  })(EEntityTypes || (EEntityTypes = {}));
22
- let ContextModel = class ContextModel extends sequelize_typescript_1.Model {
22
+ let ContextTestModel = class ContextTestModel extends sequelize_typescript_1.Model {
23
23
  };
24
24
  __decorate([
25
25
  sequelize_typescript_1.PrimaryKey,
@@ -28,20 +28,20 @@ __decorate([
28
28
  type: sequelize_typescript_1.DataType.UUID,
29
29
  }),
30
30
  __metadata("design:type", String)
31
- ], ContextModel.prototype, "id", void 0);
31
+ ], ContextTestModel.prototype, "id", void 0);
32
32
  __decorate([
33
33
  (0, sequelize_typescript_1.Column)({
34
34
  type: sequelize_typescript_1.DataType.UUID,
35
35
  }),
36
36
  __metadata("design:type", String)
37
- ], ContextModel.prototype, "entityId", void 0);
37
+ ], ContextTestModel.prototype, "entityId", void 0);
38
38
  __decorate([
39
39
  (0, sequelize_typescript_1.Column)({
40
40
  type: sequelize_typescript_1.DataType.ENUM(...Object.values(EEntityTypes)),
41
41
  }),
42
42
  __metadata("design:type", String)
43
- ], ContextModel.prototype, "entityType", void 0);
44
- ContextModel = __decorate([
43
+ ], ContextTestModel.prototype, "entityType", void 0);
44
+ ContextTestModel = __decorate([
45
45
  (0, sequelize_typescript_1.Table)({ createdAt: false, updatedAt: false })
46
- ], ContextModel);
47
- exports.default = ContextModel;
46
+ ], ContextTestModel);
47
+ exports.default = ContextTestModel;
@@ -1,11 +1,14 @@
1
- import { WhereOptions } from 'sequelize';
1
+ import { FindOptions, WhereOptions } from 'sequelize';
2
2
  import { CustomFieldDefinition } from '../models';
3
3
  import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
4
+ import { ModelOptions } from '../types';
4
5
  export declare const create: (data: CreateCustomFieldDefinition) => Promise<CustomFieldDefinition>;
5
6
  export declare const findAll: (where: WhereOptions, options?: any) => Promise<CustomFieldDefinition[]>;
6
7
  export declare const findByIds: (ids: string[], options?: any) => Promise<CustomFieldDefinition[]>;
7
8
  export declare const findById: (id: string, options?: any) => Promise<CustomFieldDefinition | null>;
8
- export declare const findByEntityIds: (modelType: string, entityIds: string[], options?: any) => Promise<CustomFieldDefinition[]>;
9
+ export declare const findByEntityIds: (modelType: string, entityIds: string[], options?: FindOptions & {
10
+ modelOptions?: ModelOptions;
11
+ }) => Promise<CustomFieldDefinition[]>;
9
12
  export declare const findByWhere: (where: any) => Promise<CustomFieldDefinition | null>;
10
13
  export declare const findDefinitionsByModels: (modelTypes: string[], options?: any) => Promise<CustomFieldDefinition[]>;
11
14
  export declare const update: (id: string, data: UpdateCustomFieldDefinition) => Promise<CustomFieldDefinition>;
@@ -14,4 +17,4 @@ export declare const destroy: (id: string) => Promise<any>;
14
17
  /**
15
18
  * Return the names of the required fields for a given model
16
19
  */
17
- export declare const getRequiredFields: (modelType: string, modelId: string | string[], entityId: string | string[]) => Promise<string[]>;
20
+ export declare const getRequiredFields: (modelType: string, modelId: string | string[], entityId: string | string[], modelOptions?: ModelOptions) => Promise<string[]>;
@@ -13,6 +13,7 @@ const findAll = (where, options = { withDisabled: false }) => {
13
13
  where,
14
14
  transaction: options.transaction,
15
15
  raw: true,
16
+ include: options.include,
16
17
  });
17
18
  };
18
19
  exports.findAll = findAll;
@@ -26,14 +27,21 @@ const findById = (id, options = { withDisabled: false }) => {
26
27
  return models_1.CustomFieldDefinition.scope('userScope').findByPk(id);
27
28
  };
28
29
  exports.findById = findById;
29
- const findByEntityIds = async (modelType, entityIds, options = {}) => models_1.CustomFieldDefinition.findAll({
30
- where: {
30
+ const findByEntityIds = async (modelType, entityIds, options = {}) => {
31
+ const { include, useEntityIdFromInclude } = options.modelOptions;
32
+ const where = {
31
33
  modelType,
32
- entityId: entityIds,
33
- },
34
- transaction: options.transaction,
35
- raw: true,
36
- });
34
+ };
35
+ if (!useEntityIdFromInclude) {
36
+ where.entityId = entityIds;
37
+ }
38
+ return models_1.CustomFieldDefinition.findAll({
39
+ where,
40
+ transaction: options.transaction,
41
+ include: include?.(entityIds),
42
+ raw: true,
43
+ });
44
+ };
37
45
  exports.findByEntityIds = findByEntityIds;
38
46
  const findByWhere = (where) => models_1.CustomFieldDefinition.scope('userScope').findOne({
39
47
  where,
@@ -63,14 +71,19 @@ exports.destroy = destroy;
63
71
  /**
64
72
  * Return the names of the required fields for a given model
65
73
  */
66
- const getRequiredFields = async (modelType, modelId, entityId) => {
74
+ const getRequiredFields = async (modelType, modelId, entityId, modelOptions = {}) => {
67
75
  const entityIds = Array.isArray(entityId) ? entityId : [entityId];
76
+ const { include, useEntityIdFromInclude } = modelOptions;
77
+ const where = {
78
+ modelType,
79
+ required: true,
80
+ };
81
+ if (!useEntityIdFromInclude) {
82
+ where.entityId = entityIds;
83
+ }
68
84
  const requiredFields = await models_1.CustomFieldDefinition.findAll({
69
- where: {
70
- required: true,
71
- modelType,
72
- entityId: { [sequelize_1.Op.in]: entityIds },
73
- },
85
+ where,
86
+ include: include?.(entityIds),
74
87
  logging: true,
75
88
  });
76
89
  const requiredFieldsNames = requiredFields.map((definition) => definition.name);
@@ -1,5 +1,7 @@
1
+ import type { FindOptions } from 'sequelize';
1
2
  import { CustomFieldValue } from '../models';
2
3
  import { CreateCustomFieldValue, ValuesToUpdate } from '../types/value';
4
+ import { ModelOptions } from '../types';
3
5
  export declare const findByModelIdAndDefinition: (modelId: string, customFieldDefinitionId: string) => Promise<CustomFieldValue[]>;
4
6
  export declare const create: (data: CreateCustomFieldValue, withAssociations?: boolean) => Promise<CustomFieldValue>;
5
7
  export declare const findAllValues: () => Promise<CustomFieldValue[]>;
@@ -20,5 +22,7 @@ export declare const findValuesByModelIds: (modelIds: string[], options?: any) =
20
22
  * Create new value record if not exists, but fails if value's definition not exist.
21
23
  * Return the updated values
22
24
  */
23
- export declare const updateValues: (modelType: string, modelId: string, identifiers: string[], valuesToUpdate: ValuesToUpdate, options?: any) => Promise<CustomFieldValue[]>;
25
+ export declare const updateValues: (modelType: string, modelId: string, identifiers: string[], valuesToUpdate: ValuesToUpdate, options?: FindOptions & {
26
+ modelOptions?: ModelOptions;
27
+ }) => Promise<CustomFieldValue[]>;
24
28
  export declare const deleteValue: (id: string, options?: any) => Promise<any>;
@@ -27,7 +27,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.deleteValue = exports.updateValues = exports.findValuesByModelIds = exports.findValuesByModelId = exports.findAllValues = exports.create = exports.findByModelIdAndDefinition = void 0;
30
- /* eslint-disable max-len */
31
30
  const models_1 = require("../models");
32
31
  const DefinitionRepo = __importStar(require("./definition"));
33
32
  const logger_1 = __importDefault(require("../utils/logger"));
@@ -75,13 +74,17 @@ exports.findValuesByModelIds = findValuesByModelIds;
75
74
  const updateValues = async (modelType, modelId, identifiers, valuesToUpdate, options = {}) => {
76
75
  const names = Object.keys(valuesToUpdate);
77
76
  logger_1.default.info(`custom-fields: updating values for ${modelType} ${modelId}`, {
78
- names, options, valuesToUpdate, entityId: identifiers,
77
+ names, options, valuesToUpdate, identifiers,
79
78
  });
80
- const fieldDefinitions = await DefinitionRepo.findAll({
79
+ const { modelOptions, transaction } = options;
80
+ const where = {
81
81
  modelType,
82
82
  name: names,
83
- entityId: identifiers,
84
- }, { withDisabled: true, transaction: options.transaction }) || [];
83
+ };
84
+ if (!options.modelOptions?.useEntityIdFromInclude) {
85
+ where.entityId = identifiers;
86
+ }
87
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) || [];
85
88
  const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
86
89
  if (fieldDefinitions.length !== names.length) {
87
90
  logger_1.default.info(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });
@@ -8,7 +8,7 @@ const cleanup = async () => {
8
8
  await models_1.CustomFieldDefinition.unscoped().destroy({ where: {} });
9
9
  await models_1.TestModel.destroy({ where: {} });
10
10
  await models_1.ContextAwareTestModel.destroy({ where: {} });
11
- await models_1.ContextModel.destroy({ where: {} });
11
+ await models_1.ContextTestModel.destroy({ where: {} });
12
12
  }
13
13
  };
14
14
  exports.cleanup = cleanup;
@@ -1,10 +1,24 @@
1
+ import { IncludeOptions } from 'sequelize';
2
+ import { ModelCtor } from 'sequelize-typescript';
1
3
  export type ModelFetcher = (name: string) => any;
2
4
  export type ModelOptions = {
3
- scopeAttributeReplacer?: (attributes?: string[]) => Promise<(string | undefined)[]>;
5
+ /**
6
+ * Include options for the model
7
+ */
8
+ include?: (entityIds: string[]) => IncludeOptions[];
9
+ /**
10
+ * Custom association for the model
11
+ * @param model - The model to associate with
12
+ */
13
+ customAssociation?: (model: ModelCtor) => void;
14
+ /**
15
+ * Whether to use the entity id from the instance per scope attribute
16
+ */
17
+ useEntityIdFromInclude?: boolean;
4
18
  };
5
19
  export type Models = {
6
20
  name: string;
7
- scopeAttributes: string[];
21
+ scopeAttributes: any[];
8
22
  modelOptions?: ModelOptions;
9
23
  creationWebhookHandler?: (instance: any) => any;
10
24
  updateWebhookHandler?: (instance: any) => any;
@@ -2,3 +2,4 @@ import type { ModelFetcher, Models } from '../types';
2
2
  export declare const addHooks: (models: Models[], getModel: ModelFetcher) => void;
3
3
  export declare const removeHooks: (models: Models[], getModel: ModelFetcher) => void;
4
4
  export declare const addScopes: (models: Models[], getModel: ModelFetcher) => void;
5
+ export declare const applyCustomAssociation: (models: Models[]) => void;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.addScopes = exports.removeHooks = exports.addHooks = void 0;
6
+ exports.applyCustomAssociation = exports.addScopes = exports.removeHooks = exports.addHooks = void 0;
7
7
  const sequelize_1 = require("sequelize");
8
8
  const common_types_1 = require("@autofleet/common-types");
9
9
  const models_1 = require("../models");
@@ -98,3 +98,9 @@ const addScopes = (models, getModel) => {
98
98
  });
99
99
  };
100
100
  exports.addScopes = addScopes;
101
+ const applyCustomAssociation = (models) => {
102
+ models.forEach(({ modelOptions }) => {
103
+ modelOptions?.customAssociation?.(models_1.CustomFieldDefinition);
104
+ });
105
+ };
106
+ exports.applyCustomAssociation = applyCustomAssociation;
@@ -1,3 +1,2 @@
1
- import { ModelOptions } from '../types';
2
- declare const getScopeAttributes: (instance: any, scopeAttributes: string[], scopeAttributeReplacer?: ModelOptions['scopeAttributeReplacer']) => Promise<string[]>;
3
- export default getScopeAttributes;
1
+ declare const applyScopeToInstance: (instance: any, scopeAttributes: string[]) => any[];
2
+ export default applyScopeToInstance;
@@ -1,29 +1,11 @@
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
- const logger_1 = __importDefault(require("./logger"));
7
- const attributeCache = new Map();
8
3
  const mapAttributeToInstance = (scopeAttributes, instance) => scopeAttributes.map((attr) => instance[attr]);
9
- const buildAttributesByInstance = (instance, scopeAttributes) => {
4
+ const applyScopeToInstance = (instance, scopeAttributes) => {
5
+ const uniqueAttributes = Array.from(new Set(scopeAttributes));
10
6
  if (Array.isArray(instance)) {
11
- return instance.flatMap((ins) => mapAttributeToInstance(scopeAttributes, ins));
12
- }
13
- return mapAttributeToInstance(scopeAttributes, instance);
14
- };
15
- const getScopeAttributes = async (instance, scopeAttributes, scopeAttributeReplacer) => {
16
- logger_1.default.info('Getting scope attributes', { instance, scopeAttributes });
17
- const attributes = buildAttributesByInstance(instance, scopeAttributes);
18
- const attributeCacheKey = attributes.join();
19
- const cachedAttributes = attributeCache.get(attributeCacheKey);
20
- if (cachedAttributes) {
21
- logger_1.default.info('Using cached attributes', { cachedAttributes });
22
- return cachedAttributes;
7
+ return instance.flatMap((ins) => mapAttributeToInstance(uniqueAttributes, ins));
23
8
  }
24
- const attributeResult = (scopeAttributeReplacer
25
- ? await scopeAttributeReplacer(attributes) : attributes);
26
- attributeCache.set(attributeCacheKey, attributeResult);
27
- return attributeResult;
9
+ return mapAttributeToInstance(uniqueAttributes, instance);
28
10
  };
29
- exports.default = getScopeAttributes;
11
+ exports.default = applyScopeToInstance;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "0.5.4-beta.23",
3
+ "version": "0.5.4-beta.26",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -1,8 +1,9 @@
1
+ import logger from '../utils/logger';
1
2
  import * as ValueRepo from '../repository/value';
2
3
  import * as DefinitionRepo from '../repository/definition';
3
4
  import { MissingRequiredCustomFieldError } from '../errors';
4
5
  import { ModelOptions } from '../types';
5
- import getScopeAttributes from '../utils/scopeAttributes';
6
+ import applyScopeToInstance from '../utils/scopeAttributes';
6
7
 
7
8
  /**
8
9
  * A hook to create the custom fields when updating a model (more then one instance).
@@ -20,15 +21,16 @@ export const beforeCreate = (scopeAttributes: string[], modelOptions: ModelOptio
20
21
  instance,
21
22
  options,
22
23
  ): Promise<void> => {
24
+ logger.debug('sadot - before create hook');
23
25
  const { fields } = options;
24
26
  const modelType = instance.constructor.name;
25
- const { scopeAttributeReplacer } = modelOptions;
26
27
 
27
- const identifiers = await getScopeAttributes(instance, scopeAttributes, scopeAttributeReplacer);
28
+ const identifiers = applyScopeToInstance(instance, scopeAttributes);
29
+
28
30
  // get all model's required definitions
29
31
  const requiredFieldsNames = await DefinitionRepo.getRequiredFields(modelType,
30
- instance.id,
31
- identifiers);
32
+ instance.id, identifiers, modelOptions);
33
+
32
34
  const customFieldsIdx = fields.indexOf('customFields');
33
35
  const { customFields } = instance;
34
36
  if (customFieldsIdx > -1 && customFields) {
@@ -45,6 +47,7 @@ export const beforeCreate = (scopeAttributes: string[], modelOptions: ModelOptio
45
47
  customFields,
46
48
  {
47
49
  transaction: options.transaction,
50
+ modelOptions,
48
51
  },
49
52
  );
50
53
 
@@ -4,9 +4,8 @@ import * as DefinitionRepo from '../repository/definition';
4
4
  import CustomFieldValue from '../models/CustomFieldValue';
5
5
  import CustomFieldDefinition from '../models/CustomFieldDefinition';
6
6
  import { SerializedCustomFields } from '../types/definition';
7
- import logger from '../utils/logger';
8
7
  import { ModelOptions } from '../types';
9
- import getScopeAttributes from '../utils/scopeAttributes';
8
+ import applyScopeToInstance from '../utils/scopeAttributes';
10
9
 
11
10
  type SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';
12
11
 
@@ -38,7 +37,6 @@ const enrichResults = (
38
37
  instancesOrInstance: any | any[],
39
38
  options,
40
39
  ): Promise<void> => {
41
- const { scopeAttributeReplacer } = modelOptions;
42
40
  if (
43
41
  options.originalAttributes?.length > 0
44
42
  && !options.originalAttributes?.includes?.('customFields')
@@ -53,8 +51,7 @@ const enrichResults = (
53
51
 
54
52
  instances = instances.filter(Boolean);
55
53
 
56
- const identifiers = await getScopeAttributes(instances, scopeAttributes, scopeAttributeReplacer);
57
- logger.info('enrichResults - sadot - indentifiers: ', identifiers);
54
+ const identifiers = applyScopeToInstance(instances, scopeAttributes);
58
55
 
59
56
  const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);
60
57
 
@@ -67,16 +64,27 @@ const enrichResults = (
67
64
  const customFieldDefinitions = await DefinitionRepo.findByEntityIds(
68
65
  modelType,
69
66
  uniqueIdentifiers,
70
- { transaction: options.transaction },
67
+ { transaction: options.transaction, modelOptions },
71
68
  );
72
69
 
70
+ if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {
71
+ // if we pass useEntityIdFromInclude,
72
+ // map the entity from the options to the identifierCustomFieldDefinitionsMapping
73
+ modelOptions.include(identifiers).forEach(({ model }) => {
74
+ customFieldDefinitions.forEach((cfd) => {
75
+ const entityId = cfd[`${model.name}.entityId`];
76
+ identifierCustomFieldDefinitionsMapping[entityId] = [];
77
+ });
78
+ });
79
+ }
80
+
73
81
  const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({
74
82
  ...map,
75
83
  [definition.id]: definition,
76
84
  }), {});
77
85
 
78
86
  customFieldDefinitions.forEach((cfd) => {
79
- identifierCustomFieldDefinitionsMapping[cfd.entityId]?.push(cfd);
87
+ identifierCustomFieldDefinitionsMapping[cfd.entityId].push(cfd);
80
88
  });
81
89
 
82
90
  // Get the values per instates ids:
package/src/hooks/find.ts CHANGED
@@ -16,7 +16,6 @@ const doScopeAttributesMissing = (
16
16
  // eslint-disable-next-line import/prefer-default-export
17
17
  export const beforeFind = (scopeAttributes: string[]) => (options): void => {
18
18
  const { attributes: queryAttributes } = options;
19
-
20
19
  if (queryAttributes?.includes?.('customFields')) {
21
20
  const missingScopeAttributes = doScopeAttributesMissing(scopeAttributes, queryAttributes);
22
21
  logger.debug('sadot - before find hook');
@@ -1,7 +1,7 @@
1
1
  import logger from '../utils/logger';
2
2
  import * as ValueRepo from '../repository/value';
3
3
  import { ModelOptions } from '../types';
4
- import getScopeAttributes from '../utils/scopeAttributes';
4
+ import applyScopeToInstance from '../utils/scopeAttributes';
5
5
 
6
6
  /**
7
7
  * A hook to update the custom fields when updating a model (more then one instance).
@@ -22,9 +22,8 @@ export const beforeUpdate = (scopeAttributes: string[], modelOptions: ModelOptio
22
22
  ): Promise<void> => {
23
23
  logger.debug('sadot - before update hook');
24
24
  const { fields } = options;
25
- const { scopeAttributeReplacer } = modelOptions;
26
25
  const modelType = instance.constructor.name;
27
- const identifiers = await getScopeAttributes(instance, scopeAttributes, scopeAttributeReplacer);
26
+ const identifiers = applyScopeToInstance(instance, scopeAttributes);
28
27
 
29
28
  const customFieldsIdx = fields.indexOf('customFields');
30
29
  if (customFieldsIdx > -1) {
@@ -34,7 +33,7 @@ export const beforeUpdate = (scopeAttributes: string[], modelOptions: ModelOptio
34
33
  instance.id,
35
34
  identifiers,
36
35
  customFields,
37
- { transaction: options.transaction },
36
+ { transaction: options.transaction, modelOptions },
38
37
 
39
38
  );
40
39
  // eslint-disable-next-line no-param-reassign
package/src/index.ts CHANGED
@@ -7,7 +7,9 @@ import api from './api';
7
7
  import initDB from './utils/db';
8
8
  import logger from './utils/logger';
9
9
  import type { CustomFieldOptions, ModelFetcher } from './types';
10
- import { addHooks, addScopes, removeHooks } from './utils/init';
10
+ import {
11
+ addHooks, addScopes, applyCustomAssociation, removeHooks,
12
+ } from './utils/init';
11
13
 
12
14
  export * from './utils/validations/custom-fields';
13
15
 
@@ -34,6 +36,7 @@ const useCustomFields = async (
34
36
  addHooks(models, getModel);
35
37
  await initTables(sequelize, options.getUser);
36
38
  addScopes(models, getModel);
39
+ applyCustomAssociation(models);
37
40
  logger.debug('sadot - custom fields finished initializing with models', models);
38
41
  return sequelize;
39
42
  };
@@ -6,11 +6,11 @@ import CustomFieldDefinition from './CustomFieldDefinition';
6
6
  import CustomFieldValue from './CustomFieldValue';
7
7
  import TestModel from './tests/TestModel';
8
8
  import ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';
9
- import ContextModel from './tests/contextAwareModels/ContextModel';
9
+ import ContextTestModel from './tests/contextAwareModels/ContextTestModel';
10
10
  import AssociatedTestModel from './tests/AssociatedTestModel';
11
11
 
12
12
  const productionModels = [CustomFieldDefinition, CustomFieldValue];
13
- const testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextModel];
13
+ const testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];
14
14
 
15
15
  const SADOT_MIGRATION_PREFIX = 'sadot-migration';
16
16
  const SCHEMA_VERSION = 1;
@@ -90,7 +90,7 @@ const initTestModels = async (sequelize: Sequelize): Promise<void> => {
90
90
  logger.info('custom-fields: test models added');
91
91
  await TestModel.sync({ alter: true });
92
92
  await AssociatedTestModel.sync({ alter: true });
93
- await ContextModel.sync({ alter: true });
93
+ await ContextTestModel.sync({ alter: true });
94
94
  await ContextAwareTestModel.sync({ alter: true });
95
95
  logger.info('custom-fields: test models synced');
96
96
  };
@@ -101,7 +101,7 @@ export {
101
101
  TestModel,
102
102
  AssociatedTestModel,
103
103
  ContextAwareTestModel,
104
- ContextModel,
104
+ ContextTestModel,
105
105
  initTables,
106
106
  initTestModels,
107
107
  };
@@ -10,7 +10,7 @@ import {
10
10
  ForeignKey,
11
11
  } from 'sequelize-typescript';
12
12
  import AssociatedTestModel from '../AssociatedTestModel';
13
- import ContextModel from './ContextModel';
13
+ import ContextTestModel from './ContextTestModel';
14
14
 
15
15
  @Table({ createdAt: false, updatedAt: false })
16
16
  class ContextAwareTestModel extends Model {
@@ -22,7 +22,7 @@ class ContextAwareTestModel extends Model {
22
22
  })
23
23
  id!: string;
24
24
 
25
- @ForeignKey(() => ContextModel)
25
+ @ForeignKey(() => ContextTestModel)
26
26
  @Column({
27
27
  type: DataType.UUID,
28
28
  })
@@ -38,8 +38,8 @@ class ContextAwareTestModel extends Model {
38
38
  })
39
39
  customFields?: any;
40
40
 
41
- @BelongsTo(() => ContextModel)
42
- context: ContextModel;
41
+ @BelongsTo(() => ContextTestModel)
42
+ context: ContextTestModel;
43
43
  }
44
44
 
45
45
  export default ContextAwareTestModel;
@@ -16,7 +16,7 @@ import {
16
16
  }
17
17
 
18
18
  @Table({ createdAt: false, updatedAt: false })
19
- class ContextModel extends Model {
19
+ class ContextTestModel extends Model {
20
20
  @PrimaryKey
21
21
  @Column({
22
22
  defaultValue: DataType.UUIDV4,
@@ -35,4 +35,4 @@ class ContextModel extends Model {
35
35
  entityType: EEntityTypes;
36
36
  }
37
37
 
38
- export default ContextModel;
38
+ export default ContextTestModel;
@@ -1,8 +1,10 @@
1
1
  import {
2
+ FindOptions,
2
3
  Op, WhereOptions,
3
4
  } from 'sequelize';
4
5
  import { CustomFieldDefinition } from '../models';
5
6
  import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
7
+ import { ModelOptions } from '../types';
6
8
 
7
9
  export const create = (data: CreateCustomFieldDefinition): Promise<CustomFieldDefinition> =>
8
10
  CustomFieldDefinition.create(data);
@@ -19,6 +21,7 @@ export const findAll = (
19
21
  where,
20
22
  transaction: options.transaction,
21
23
  raw: true,
24
+ include: options.include,
22
25
  });
23
26
  };
24
27
 
@@ -41,15 +44,23 @@ export const findById = (
41
44
  export const findByEntityIds = async (
42
45
  modelType: string,
43
46
  entityIds: string[],
44
- options: any = {},
45
- ): Promise<CustomFieldDefinition[]> => CustomFieldDefinition.findAll({
46
- where: {
47
+ options: FindOptions & { modelOptions?: ModelOptions } = {},
48
+ ): Promise<CustomFieldDefinition[]> => {
49
+ const { include, useEntityIdFromInclude } = options.modelOptions;
50
+ const where: WhereOptions = {
47
51
  modelType,
48
- entityId: entityIds,
49
- },
50
- transaction: options.transaction,
51
- raw: true,
52
- });
52
+ };
53
+
54
+ if (!useEntityIdFromInclude) {
55
+ where.entityId = entityIds;
56
+ }
57
+ return CustomFieldDefinition.findAll({
58
+ where,
59
+ transaction: options.transaction,
60
+ include: include?.(entityIds),
61
+ raw: true,
62
+ });
63
+ };
53
64
 
54
65
  export const findByWhere = (where): Promise<CustomFieldDefinition | null> =>
55
66
  CustomFieldDefinition.scope('userScope').findOne({
@@ -95,14 +106,23 @@ export const getRequiredFields = async (
95
106
  modelType: string,
96
107
  modelId: string | string[],
97
108
  entityId: string | string[],
109
+ modelOptions: ModelOptions = {},
98
110
  ): Promise<string[]> => {
99
111
  const entityIds = Array.isArray(entityId) ? entityId : [entityId];
112
+ const { include, useEntityIdFromInclude } = modelOptions;
113
+
114
+ const where: WhereOptions = {
115
+ modelType,
116
+ required: true,
117
+ };
118
+
119
+ if (!useEntityIdFromInclude) {
120
+ where.entityId = entityIds;
121
+ }
122
+
100
123
  const requiredFields = await CustomFieldDefinition.findAll({
101
- where: {
102
- required: true,
103
- modelType,
104
- entityId: { [Op.in]: entityIds },
105
- },
124
+ where,
125
+ include: include?.(entityIds),
106
126
  logging: true,
107
127
  });
108
128
  const requiredFieldsNames = requiredFields.map((definition) => definition.name);
@@ -1,9 +1,11 @@
1
1
  /* eslint-disable max-len */
2
+ import type { FindOptions, WhereOptions } from 'sequelize';
2
3
  import { CustomFieldValue, CustomFieldDefinition } from '../models';
3
4
  import * as DefinitionRepo from './definition';
4
5
  import { CreateCustomFieldValue, ValuesToUpdate } from '../types/value';
5
6
  import logger from '../utils/logger';
6
7
  import { MissingDefinitionError } from '../errors';
8
+ import { ModelOptions } from '../types';
7
9
 
8
10
  export const findByModelIdAndDefinition = async (modelId: string, customFieldDefinitionId: string) =>
9
11
  CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [CustomFieldDefinition] });
@@ -50,21 +52,23 @@ export const updateValues = async (
50
52
  modelId: string,
51
53
  identifiers: string[],
52
54
  valuesToUpdate: ValuesToUpdate,
53
- options: any = {},
55
+ options: FindOptions & { modelOptions?: ModelOptions } = {},
54
56
  ): Promise<CustomFieldValue[]> => {
55
57
  const names = Object.keys(valuesToUpdate);
56
58
  logger.info(`custom-fields: updating values for ${modelType} ${modelId}`, {
57
- names, options, valuesToUpdate, entityId: identifiers,
59
+ names, options, valuesToUpdate, identifiers,
58
60
  });
61
+ const { modelOptions, transaction } = options;
62
+
63
+ const where: WhereOptions = {
64
+ modelType,
65
+ name: names,
66
+ };
59
67
 
60
- const fieldDefinitions = await DefinitionRepo.findAll(
61
- {
62
- modelType,
63
- name: names,
64
- entityId: identifiers,
65
- },
66
- { withDisabled: true, transaction: options.transaction },
67
- ) || [];
68
+ if (!options.modelOptions?.useEntityIdFromInclude) {
69
+ where.entityId = identifiers;
70
+ }
71
+ const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) || [];
68
72
 
69
73
  const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
70
74
  if (fieldDefinitions.length !== names.length) {
@@ -1,5 +1,5 @@
1
1
  import {
2
- ContextAwareTestModel, ContextModel, CustomFieldDefinition, TestModel,
2
+ ContextAwareTestModel, ContextTestModel, CustomFieldDefinition, TestModel,
3
3
  } from '../../models';
4
4
 
5
5
  // eslint-disable-next-line import/prefer-default-export
@@ -8,7 +8,7 @@ export const cleanup = async (): Promise<void> => {
8
8
  await CustomFieldDefinition.unscoped().destroy({ where: {} });
9
9
  await TestModel.destroy({ where: {} });
10
10
  await ContextAwareTestModel.destroy({ where: {} });
11
- await ContextModel.destroy({ where: {} });
11
+ await ContextTestModel.destroy({ where: {} });
12
12
  }
13
13
  };
14
14
 
@@ -1,11 +1,27 @@
1
+ import { IncludeOptions } from 'sequelize';
2
+ import { ModelCtor } from 'sequelize-typescript';
3
+
1
4
  export type ModelFetcher = (name: string) => any;
2
5
 
3
6
  export type ModelOptions = {
4
- scopeAttributeReplacer?: (attributes?: string[]) => Promise<(string | undefined)[]>;
7
+ /**
8
+ * Include options for the model
9
+ */
10
+ include?: (entityIds: string[]) => IncludeOptions[];
11
+ /**
12
+ * Custom association for the model
13
+ * @param model - The model to associate with
14
+ */
15
+
16
+ customAssociation?: (model: ModelCtor) => void;
17
+ /**
18
+ * Whether to use the entity id from the instance per scope attribute
19
+ */
20
+ useEntityIdFromInclude?: boolean
5
21
  }
6
22
  export type Models = {
7
23
  name: string;
8
- scopeAttributes: string[];
24
+ scopeAttributes: any[];
9
25
  modelOptions?: ModelOptions;
10
26
  creationWebhookHandler?: (instance: any) => any;
11
27
  updateWebhookHandler?: (instance: any) => any;
package/src/utils/init.ts CHANGED
@@ -2,6 +2,7 @@ import { DataTypes } from 'sequelize';
2
2
  import { ModelCtor } from 'sequelize-typescript';
3
3
  import { customFields } from '@autofleet/common-types';
4
4
  import {
5
+ CustomFieldDefinition,
5
6
  CustomFieldValue,
6
7
  } from '../models';
7
8
  import {
@@ -103,3 +104,9 @@ export const addScopes = (models: Models[], getModel: ModelFetcher): void => {
103
104
  }
104
105
  });
105
106
  };
107
+
108
+ export const applyCustomAssociation = (models: Models[]): void => {
109
+ models.forEach(({ modelOptions }) => {
110
+ modelOptions?.customAssociation?.(CustomFieldDefinition);
111
+ });
112
+ };
@@ -1,32 +1,12 @@
1
- import { ModelOptions } from '../types';
2
- import logger from './logger';
3
-
4
- const attributeCache = new Map<string, string[]>();
5
-
6
1
  const mapAttributeToInstance = (scopeAttributes: string[], instance: any) =>
7
2
  scopeAttributes.map((attr) => instance[attr]);
8
3
 
9
- const buildAttributesByInstance = (instance: any, scopeAttributes: string[]) => {
4
+ const applyScopeToInstance = (instance: any, scopeAttributes: string[]) => {
5
+ const uniqueAttributes = Array.from(new Set(scopeAttributes));
10
6
  if (Array.isArray(instance)) {
11
- return instance.flatMap((ins) => mapAttributeToInstance(scopeAttributes, ins));
12
- }
13
- return mapAttributeToInstance(scopeAttributes, instance);
14
- };
15
-
16
- const getScopeAttributes = async (instance: any, scopeAttributes: string[],
17
- scopeAttributeReplacer?: ModelOptions['scopeAttributeReplacer']): Promise<string[]> => {
18
- logger.info('Getting scope attributes', { instance, scopeAttributes });
19
- const attributes = buildAttributesByInstance(instance, scopeAttributes);
20
- const attributeCacheKey = attributes.join();
21
- const cachedAttributes = attributeCache.get(attributeCacheKey);
22
- if (cachedAttributes) {
23
- logger.info('Using cached attributes', { cachedAttributes });
24
- return cachedAttributes;
7
+ return instance.flatMap((ins) => mapAttributeToInstance(uniqueAttributes, ins));
25
8
  }
26
- const attributeResult = (scopeAttributeReplacer
27
- ? await scopeAttributeReplacer(attributes) : attributes);
28
- attributeCache.set(attributeCacheKey, attributeResult);
29
- return attributeResult;
9
+ return mapAttributeToInstance(uniqueAttributes, instance);
30
10
  };
31
11
 
32
- export default getScopeAttributes;
12
+ export default applyScopeToInstance;