@autofleet/sadot 0.0.1-beta.8 → 0.0.2-beta

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 (146) hide show
  1. package/dist/jest.config.d.ts +12 -0
  2. package/dist/src/api/index.d.ts +2 -0
  3. package/dist/{api → src/api}/index.js +0 -1
  4. package/dist/src/api/v1/definition/index.d.ts +2 -0
  5. package/dist/{api → src/api}/v1/definition/index.js +23 -27
  6. package/dist/src/api/v1/definition/validations.d.ts +2 -0
  7. package/dist/{api → src/api}/v1/definition/validations.js +10 -10
  8. package/dist/src/api/v1/errors.d.ts +2 -0
  9. package/dist/{api → src/api}/v1/errors.js +0 -1
  10. package/dist/src/api/v1/index.d.ts +2 -0
  11. package/dist/{api → src/api}/v1/index.js +1 -2
  12. package/dist/src/errors/index.d.ts +16 -0
  13. package/dist/src/errors/index.js +45 -0
  14. package/dist/src/events/index.d.ts +4 -0
  15. package/dist/{events → src/events}/index.js +21 -2
  16. package/dist/src/hooks/create.d.ts +9 -0
  17. package/dist/{hooks → src/hooks}/create.js +14 -17
  18. package/dist/src/hooks/enrich.d.ts +5 -0
  19. package/dist/src/hooks/enrich.js +118 -0
  20. package/dist/src/hooks/find.d.ts +1 -0
  21. package/dist/src/hooks/find.js +29 -0
  22. package/dist/src/hooks/index.d.ts +6 -0
  23. package/dist/{hooks → src/hooks}/index.js +3 -3
  24. package/dist/src/hooks/update.d.ts +9 -0
  25. package/dist/{hooks → src/hooks}/update.js +7 -22
  26. package/dist/src/hooks/workaround.d.ts +10 -0
  27. package/dist/{hooks → src/hooks}/workaround.js +3 -13
  28. package/dist/src/index.d.ts +11 -0
  29. package/dist/src/index.js +105 -0
  30. package/dist/src/models/CustomFieldDefinition.d.ts +23 -0
  31. package/dist/{models → src/models}/CustomFieldDefinition.js +22 -18
  32. package/dist/src/models/CustomFieldValue.d.ts +15 -0
  33. package/dist/{models → src/models}/CustomFieldValue.js +24 -40
  34. package/dist/src/models/index.d.ts +8 -0
  35. package/dist/src/models/index.js +87 -0
  36. package/dist/src/models/tests/AssociatedTestModel.d.ts +12 -0
  37. package/dist/{models → src/models}/tests/AssociatedTestModel.js +0 -1
  38. package/dist/src/models/tests/TestModel.d.ts +11 -0
  39. package/dist/{models → src/models}/tests/TestModel.js +0 -1
  40. package/dist/src/repository/definition.d.ts +17 -0
  41. package/dist/src/repository/definition.js +80 -0
  42. package/dist/src/repository/value.d.ts +24 -0
  43. package/dist/{repository → src/repository}/value.js +22 -31
  44. package/dist/src/tests/api/test-api.d.ts +2 -0
  45. package/dist/{tests → src/tests}/api/test-api.js +12 -22
  46. package/dist/src/tests/helpers/database-config.d.ts +15 -0
  47. package/dist/{tests → src/tests}/helpers/database-config.js +0 -1
  48. package/dist/src/tests/helpers/index.d.ts +2 -0
  49. package/dist/src/tests/helpers/index.js +18 -0
  50. package/dist/src/tests/mocks/definition.mock.d.ts +37 -0
  51. package/dist/{tests/mocks/index.js → src/tests/mocks/definition.mock.js} +20 -17
  52. package/dist/src/tests/mocks/events.mock.d.ts +3 -0
  53. package/dist/{tests → src/tests}/mocks/events.mock.js +0 -1
  54. package/dist/src/tests/mocks/testModel.d.ts +12 -0
  55. package/dist/{tests → src/tests}/mocks/testModel.js +6 -16
  56. package/dist/src/types/definition/index.d.ts +23 -0
  57. package/dist/{types → src/types}/definition/index.js +0 -1
  58. package/dist/src/types/index.d.ts +13 -0
  59. package/dist/{types → src/types}/index.js +0 -1
  60. package/dist/src/types/value/index.d.ts +15 -0
  61. package/dist/{types → src/types}/value/index.js +0 -1
  62. package/dist/src/utils/constants/index.d.ts +1 -0
  63. package/dist/src/utils/constants/index.js +5 -0
  64. package/dist/src/utils/db/index.d.ts +4 -0
  65. package/dist/{utils → src/utils}/db/index.js +8 -1
  66. package/dist/src/utils/logger/index.d.ts +2 -0
  67. package/dist/{utils → src/utils}/logger/index.js +2 -2
  68. package/dist/src/utils/validations/custom-fields.d.ts +2 -0
  69. package/dist/{utils → src/utils}/validations/custom-fields.js +0 -1
  70. package/dist/src/utils/validations/custom.d.ts +15 -0
  71. package/dist/src/utils/validations/custom.js +42 -0
  72. package/dist/src/utils/validations/index.d.ts +2 -0
  73. package/dist/{utils → src/utils}/validations/index.js +0 -1
  74. package/dist/src/utils/validations/type.d.ts +18 -0
  75. package/dist/src/utils/validations/type.js +50 -0
  76. package/dist/src/utils/validations/validators.d.ts +12 -0
  77. package/dist/src/utils/validations/validators.js +33 -0
  78. package/package.json +3 -1
  79. package/src/api/v1/definition/index.ts +15 -8
  80. package/src/api/v1/definition/validations.ts +11 -25
  81. package/src/api/v1/index.ts +1 -1
  82. package/src/errors/index.ts +42 -0
  83. package/src/events/index.ts +23 -1
  84. package/src/hooks/create.ts +8 -3
  85. package/src/hooks/enrich.ts +125 -0
  86. package/src/hooks/find.ts +9 -102
  87. package/src/hooks/index.ts +3 -2
  88. package/src/hooks/update.ts +4 -14
  89. package/src/index.ts +53 -17
  90. package/src/models/CustomFieldDefinition.ts +23 -16
  91. package/src/models/CustomFieldValue.ts +7 -7
  92. package/src/models/index.ts +72 -16
  93. package/src/repository/definition.ts +26 -39
  94. package/src/repository/value.ts +6 -5
  95. package/src/tests/mocks/{index.ts → definition.mock.ts} +2 -4
  96. package/src/tests/mocks/testModel.ts +8 -3
  97. package/src/types/index.ts +4 -6
  98. package/src/utils/constants/index.ts +2 -0
  99. package/src/utils/db/index.ts +7 -0
  100. package/src/utils/logger/index.ts +3 -1
  101. package/src/utils/validations/custom.ts +26 -44
  102. package/src/utils/validations/type.ts +23 -6
  103. package/src/utils/validations/validators.ts +34 -0
  104. package/tsconfig.json +9 -25
  105. package/dist/api/index.js.map +0 -1
  106. package/dist/api/v1/definition/index.js.map +0 -1
  107. package/dist/api/v1/definition/validations.js.map +0 -1
  108. package/dist/api/v1/errors.js.map +0 -1
  109. package/dist/api/v1/index.js.map +0 -1
  110. package/dist/events/index.js.map +0 -1
  111. package/dist/hooks/create.js.map +0 -1
  112. package/dist/hooks/find.js +0 -127
  113. package/dist/hooks/find.js.map +0 -1
  114. package/dist/hooks/index.js.map +0 -1
  115. package/dist/hooks/update.js.map +0 -1
  116. package/dist/hooks/workaround.js.map +0 -1
  117. package/dist/index.js +0 -80
  118. package/dist/index.js.map +0 -1
  119. package/dist/models/CustomFieldDefinition.js.map +0 -1
  120. package/dist/models/CustomFieldValue.js.map +0 -1
  121. package/dist/models/index.js +0 -50
  122. package/dist/models/index.js.map +0 -1
  123. package/dist/models/tests/AssociatedTestModel.js.map +0 -1
  124. package/dist/models/tests/TestModel.js.map +0 -1
  125. package/dist/repository/definition.js +0 -107
  126. package/dist/repository/definition.js.map +0 -1
  127. package/dist/repository/value.js.map +0 -1
  128. package/dist/tests/api/test-api.js.map +0 -1
  129. package/dist/tests/helpers/database-config.js.map +0 -1
  130. package/dist/tests/helpers/index.js +0 -28
  131. package/dist/tests/helpers/index.js.map +0 -1
  132. package/dist/tests/mocks/events.mock.js.map +0 -1
  133. package/dist/tests/mocks/index.js.map +0 -1
  134. package/dist/tests/mocks/testModel.js.map +0 -1
  135. package/dist/tsconfig.tsbuildinfo +0 -1
  136. package/dist/types/definition/index.js.map +0 -1
  137. package/dist/types/index.js.map +0 -1
  138. package/dist/types/value/index.js.map +0 -1
  139. package/dist/utils/db/index.js.map +0 -1
  140. package/dist/utils/logger/index.js.map +0 -1
  141. package/dist/utils/validations/custom-fields.js.map +0 -1
  142. package/dist/utils/validations/custom.js +0 -59
  143. package/dist/utils/validations/custom.js.map +0 -1
  144. package/dist/utils/validations/index.js.map +0 -1
  145. package/dist/utils/validations/type.js +0 -32
  146. package/dist/utils/validations/type.js.map +0 -1
package/src/index.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import type { Application } from 'express';
2
2
  import { DataTypes } from 'sequelize';
3
- import { initTables } from './models';
3
+ import { Sequelize } from 'sequelize-typescript';
4
+ import { initTables, initTestModels } from './models';
4
5
  import api from './api';
5
6
  import {
6
7
  beforeFind,
7
- afterFind,
8
+ enrichResults,
8
9
  beforeBulkUpdate,
9
10
  beforeUpdate,
10
11
  beforeCreate,
@@ -20,19 +21,27 @@ const addHooks = (models: ModelOptions[], getModel: ModelFetcher) => {
20
21
  models.forEach(async ({ name, scopeAttributes }) => {
21
22
  try {
22
23
  const model = getModel(name);
23
- if (!model) return;
24
+ if (!model) {
25
+ logger.warn('sadot - tried to addHooks to a model that does not exist yet', {
26
+ name,
27
+ scopeAttributes,
28
+ });
29
+ return;
30
+ }
24
31
  model.rawAttributes.customFields = {
25
32
  type: DataTypes.VIRTUAL,
26
33
  };
27
34
  model.refreshAttributes();
28
35
  // TODO: Uncomment after tests are passed
29
36
  // model.addHook('afterFind', workaround);
30
- model.addHook('beforeFind', beforeFind(scopeAttributes));
31
- model.addHook('beforeBulkCreate', beforeBulkCreate);
32
- model.addHook('afterFind', afterFind(scopeAttributes));
33
- model.addHook('beforeBulkUpdate', beforeBulkUpdate);
34
- model.addHook('beforeCreate', beforeCreate(scopeAttributes));
35
- model.addHook('beforeUpdate', beforeUpdate(scopeAttributes));
37
+ model.addHook('beforeFind', 'sadot-beforeFind', beforeFind(scopeAttributes));
38
+ model.addHook('beforeBulkCreate', 'sadot-beforeBulkCreate', beforeBulkCreate);
39
+ model.addHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate', beforeBulkUpdate);
40
+ model.addHook('beforeCreate', 'sadot-beforeCreate', beforeCreate(scopeAttributes));
41
+ model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes));
42
+ model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes));
43
+ model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes));
44
+ model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes));
36
45
  } catch (e) {
37
46
  logger.error(`Could not add custom fields hook to model ${name}. `, e);
38
47
  }
@@ -47,19 +56,46 @@ const useCustomFields = async (
47
56
  app: Application | null,
48
57
  getModel: ModelFetcher,
49
58
  options: CustomFieldOptions,
50
- ): Promise<void> => {
51
- const { innerSequelize, models } = options;
52
- // deepAfterFindWorkAround(sequelize);
59
+ ): Promise<Sequelize> => {
60
+ const { models } = options;
53
61
  if (app) {
54
62
  app.use('/api', api);
55
63
  }
56
- if (!innerSequelize) {
57
- const moreInnerSequelize = initDB(options.databaseConfig);
58
- await initTables(moreInnerSequelize);
59
- } else {
60
- await initTables(innerSequelize);
64
+ const sequelize = initDB(options.databaseConfig);
65
+ if (process.env.NODE_ENV === 'test') {
66
+ await initTestModels(sequelize);
61
67
  }
62
68
  addHooks(models, getModel);
69
+ await initTables(sequelize, options.getUser);
70
+ logger.debug('sadot - custom fields finished initializing with models', models);
71
+ return sequelize;
63
72
  };
64
73
 
65
74
  export default useCustomFields;
75
+
76
+ const removeHooks = (models: ModelOptions[], getModel: ModelFetcher) => {
77
+ models.forEach(async ({ name }) => {
78
+ try {
79
+ const model = getModel(name);
80
+ if (!model) return;
81
+ if (model.rawAttributes.customFields) {
82
+ delete model.rawAttributes.customFields;
83
+ model.refreshAttributes();
84
+ }
85
+ // model.removeHook('afterFind', 'sadot-workaround');
86
+ model.removeHook('beforeFind', 'sadot-beforeFind');
87
+ model.removeHook('beforeBulkCreate', 'sadot-beforeBulkCreate');
88
+ model.removeHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate');
89
+ model.removeHook('beforeCreate', 'sadot-beforeCreate');
90
+ model.removeHook('beforeUpdate', 'sadot-beforeUpdate');
91
+ model.removeHook('afterFind', 'sadot-afterFind');
92
+ model.removeHook('afterUpdate', 'sadot-afterUpdate');
93
+ } catch (e) {
94
+ logger.error(`Could not add custom fields hook to model ${name}. `, e);
95
+ }
96
+ });
97
+ };
98
+
99
+ export const disableCustomFields = (models, getModel) => {
100
+ removeHooks(models, getModel);
101
+ };
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /* eslint-disable indent */
2
3
  import {
3
4
  Table,
4
5
  Column,
@@ -9,31 +10,32 @@ import {
9
10
  BeforeCreate,
10
11
  DefaultScope,
11
12
  AfterSave,
13
+ Is,
12
14
  } from 'sequelize-typescript';
15
+ import { validateValidation } from '../utils/validations/custom';
16
+ import { CustomFieldDefinitionType } from '../utils/validations/type';
13
17
  import { CustomFieldValue } from '.';
14
18
  import { sendDimEvent } from '../events';
15
-
16
- /**
17
- * Supported custom field types
18
- */
19
- // eslint-disable-next-line no-shadow
20
- export enum CustomFieldDefinitionType {
21
- NUMBER = 'number',
22
- BOOLEAN = 'boolean',
23
- DATE = 'date',
24
- DATETIME = 'datetime',
25
- TEXT = 'text',
26
- IMAGE = 'image',
27
- ENUM = 'enum',
28
- }
19
+ import { UnsupportedCustomFieldTypeError, UnsupportedCustomValidationError } from '../errors';
29
20
 
30
21
  @DefaultScope(() => ({ where: { disabled: false } }))
31
22
  @Table({
32
23
  indexes: [
33
- { name: "unique_name_model_type", fields: ["name", "model_type", "entity_id"], unique: true },
24
+ {
25
+ name: 'unique_name_model_type',
26
+ fields: ['model_type', 'entity_id', 'name'],
27
+ unique: true,
28
+ },
34
29
  ],
35
30
  timestamps: true,
36
- })
31
+ validate: {
32
+ validationByType(this: CustomFieldDefinition) {
33
+ if (!validateValidation(this.fieldType, this.validation)) {
34
+ throw new UnsupportedCustomValidationError(`Validation provided for "${this.fieldType}" is not supported`);
35
+ }
36
+ },
37
+ },
38
+ })
37
39
  class CustomFieldDefinition extends Model {
38
40
  @PrimaryKey
39
41
  @Column({
@@ -54,6 +56,11 @@ class CustomFieldDefinition extends Model {
54
56
  })
55
57
  displayName?: string; // Defaulted to name with beforeCreate hook
56
58
 
59
+ @Is('SupportedType', (value) => {
60
+ if (!Object.values(CustomFieldDefinitionType).includes(value as CustomFieldDefinitionType)) {
61
+ throw new UnsupportedCustomFieldTypeError(`"${value}" is not a supported type.`);
62
+ }
63
+ })
57
64
  @Column({
58
65
  type: DataType.STRING,
59
66
  allowNull: false,
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /* eslint-disable indent */
2
3
  import {
3
4
  Table,
4
5
  Column,
@@ -13,16 +14,18 @@ import {
13
14
  BeforeUpdate,
14
15
  BeforeBulkCreate,
15
16
  BeforeBulkUpdate,
17
+ Scopes,
16
18
  } from 'sequelize-typescript';
17
19
  import { sendDimEvent } from '../events';
18
20
  import { CustomFieldDefinition } from '.';
19
21
  import validateValue from '../utils/validations';
20
22
  import * as CustomFieldDefinitionRepo from '../repository/definition';
21
23
  import logger from '../utils/logger';
24
+ import { InvalidValueError } from '../errors';
22
25
 
23
26
  @Table({
24
27
  timestamps: true,
25
- })
28
+ })
26
29
  class CustomFieldValue extends Model {
27
30
  @PrimaryKey
28
31
  @Column({
@@ -41,7 +44,7 @@ class CustomFieldValue extends Model {
41
44
 
42
45
  @Column({
43
46
  type: DataType.JSONB,
44
- allowNull: false,
47
+ allowNull: true,
45
48
  })
46
49
  value!: any;
47
50
 
@@ -60,7 +63,6 @@ class CustomFieldValue extends Model {
60
63
  @BeforeBulkCreate
61
64
  @BeforeBulkUpdate
62
65
  static async validateValues(instances: CustomFieldValue[]): Promise<void> {
63
- logger.info('CustomFieldValue BeforeBulkCreate/BeforeBulkUpdate', { instances });
64
66
  const ids = instances.map((instance) => instance.customFieldDefinitionId);
65
67
  const uniqueIds = [...new Set(ids)];
66
68
  const definitions = await CustomFieldDefinitionRepo.findByIds(
@@ -80,7 +82,7 @@ class CustomFieldValue extends Model {
80
82
  .find((definition) => definition.id === instance.customFieldDefinitionId);
81
83
  const isValid = validateValue(instance.value, fieldType, validation);
82
84
  if (!isValid) {
83
- throw new Error('Invalid value');
85
+ throw new InvalidValueError(instance.value, fieldType);
84
86
  }
85
87
  });
86
88
  }
@@ -89,20 +91,18 @@ class CustomFieldValue extends Model {
89
91
  @BeforeCreate
90
92
  @BeforeUpsert
91
93
  static async validateValue(instance: CustomFieldValue): Promise<void> {
92
- logger.info('CustomFieldValue BeforeCreate/BeforeUpdate', { instance });
93
94
  const { customFieldDefinitionId } = instance;
94
95
  // eslint-disable-next-line max-len
95
96
  const cfd = await CustomFieldDefinitionRepo.findById(customFieldDefinitionId, { withDisabled: true });
96
97
  const { validation, fieldType } = cfd;
97
98
  const isValid = validateValue(instance.value, fieldType, validation);
98
99
  if (!isValid) {
99
- throw new Error('Invalid value');
100
+ throw new InvalidValueError(instance.value, fieldType);
100
101
  }
101
102
  }
102
103
 
103
104
  @AfterUpsert
104
105
  static afterSaveHandler(instance: CustomFieldValue, options): void {
105
- logger.info('CustomFieldValue afterSave', { instance });
106
106
  if (options.transaction) {
107
107
  options.transaction.afterCommit(() => sendDimEvent(instance[0]));
108
108
  } else {
@@ -1,39 +1,94 @@
1
1
  /* eslint-disable no-param-reassign */
2
+ import { DataTypes } from 'sequelize';
2
3
  import type { Sequelize } from 'sequelize-typescript';
3
4
  import logger from '../utils/logger';
4
- // import addPermanentHooks from '../hooks/permanent-hooks';
5
-
6
5
  import CustomFieldDefinition from './CustomFieldDefinition';
7
6
  import CustomFieldValue from './CustomFieldValue';
8
7
  import TestModel from './tests/TestModel';
9
8
  import AssociatedTestModel from './tests/AssociatedTestModel';
10
9
 
11
- // export const CustomFieldDefinition = CustomFieldDefinitionModel;
12
- // export { default as CustomFieldDefinition } from './custom-field-definition.model';
13
-
14
10
  const productionModels = [CustomFieldDefinition, CustomFieldValue];
15
- const testModels = [...productionModels, TestModel, AssociatedTestModel];
11
+ const testModels = [TestModel, AssociatedTestModel];
12
+
13
+ const SADOT_MIGRATION_PREFIX = 'sadot-migration';
14
+ const SCHEMA_VERSION = 1;
15
+ const CUSTOM_FIELDS_SCHEMA_VERSION = `${SADOT_MIGRATION_PREFIX}_${SCHEMA_VERSION}`;
16
16
 
17
- const initTables = async (sequelize: Sequelize): Promise<void> => {
17
+ const initTables = async (sequelize: Sequelize, getUser): Promise<void> => {
18
18
  logger.info('custom-fields: initialize custom-fields tables');
19
19
  // Detect models and import them to the orm
20
20
  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
21
21
  if (!sequelize.addModels) {
22
22
  throw new Error('sequelize instance must have addModels function');
23
23
  }
24
- sequelize.addModels(process.env.NODE_ENV === 'test' ? testModels : productionModels);
25
- await sequelize.dropSchema('custom-fields', { logging: false });
26
- await sequelize.createSchema('custom-fields', { logging: false });
24
+ sequelize.addModels(productionModels);
25
+
26
+ CustomFieldDefinition.addScope('userScope', () => {
27
+ const user = getUser();
28
+ if (user?.permissions) {
29
+ return {
30
+ where: {
31
+ entityId: [
32
+ ...Object.keys(user.permissions.fleets),
33
+ ...Object.keys(user.permissions.businessModels),
34
+ ...Object.keys(user.permissions.demandSources),
35
+ ],
36
+ },
37
+ };
38
+ }
39
+ return {};
40
+ });
27
41
 
28
42
  logger.info('custom-fields: models added');
29
- await CustomFieldDefinition.sync({ alter: true });
30
- await CustomFieldValue.sync({ alter: true });
31
43
 
32
- if (process.env.NODE_ENV === 'test') {
33
- await TestModel.sync({ alter: true });
34
- await AssociatedTestModel.sync({ alter: true });
44
+ const SequelizeMeta = sequelize.define(
45
+ 'SequelizeMeta',
46
+ {
47
+ name: {
48
+ type: DataTypes.STRING,
49
+ allowNull: false,
50
+ unique: true,
51
+ primaryKey: true,
52
+ autoIncrement: false,
53
+ },
54
+ },
55
+ {
56
+ tableName: 'SequelizeMeta',
57
+ timestamps: false,
58
+ schema: 'public',
59
+ },
60
+ );
61
+ const migrations = await SequelizeMeta.findAll({ raw: true });
62
+ const currentSadotSchemaVersion = migrations
63
+ .reverse().find((m: any) => m.name.includes(SADOT_MIGRATION_PREFIX));
64
+
65
+ if (
66
+ !currentSadotSchemaVersion
67
+ || (currentSadotSchemaVersion as any).name !== CUSTOM_FIELDS_SCHEMA_VERSION
68
+ ) {
69
+ await CustomFieldDefinition.sync({ alter: true });
70
+ await CustomFieldValue.sync({ alter: true });
71
+ await SequelizeMeta.create({ name: CUSTOM_FIELDS_SCHEMA_VERSION });
72
+ logger.info('custom-fields: models synced');
73
+ }
74
+ };
75
+
76
+ const initTestModels = async (sequelize: Sequelize): Promise<void> => {
77
+ logger.info('custom-fields: initialize custom-fields test models');
78
+ // Detect models and import them to the orm
79
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
80
+ if (!sequelize.addModels) {
81
+ throw new Error('sequelize instance must have addModels function');
35
82
  }
36
- logger.info('custom-fields: models synced');
83
+
84
+ sequelize.addModels(testModels);
85
+ await sequelize.dropSchema('custom-fields', { logging: false });
86
+ await sequelize.createSchema('custom-fields', { logging: false });
87
+
88
+ logger.info('custom-fields: test models added');
89
+ await TestModel.sync({ alter: true });
90
+ await AssociatedTestModel.sync({ alter: true });
91
+ logger.info('custom-fields: test models synced');
37
92
  };
38
93
 
39
94
  export {
@@ -42,4 +97,5 @@ export {
42
97
  TestModel,
43
98
  AssociatedTestModel,
44
99
  initTables,
100
+ initTestModels,
45
101
  };
@@ -1,24 +1,21 @@
1
1
  import { Op, WhereOptions } from 'sequelize';
2
- import { CustomFieldDefinition, CustomFieldValue } from '../models';
2
+ import { CustomFieldDefinition } from '../models';
3
3
  import type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';
4
4
 
5
5
  export const create = (data: CreateCustomFieldDefinition): Promise<CustomFieldDefinition> =>
6
6
  CustomFieldDefinition.create(data);
7
7
 
8
8
  export const findAll = (
9
- query: any,
9
+ where: any,
10
10
  options: any = { withDisabled: false },
11
11
  ): Promise<CustomFieldDefinition[]> => {
12
- if (options.withDisabled) {
13
- return CustomFieldDefinition.unscoped().findAll({
14
- where: query,
15
- include: [CustomFieldValue],
16
- });
17
- }
18
-
19
- return CustomFieldDefinition.findAll({
20
- where: query,
21
- include: [CustomFieldValue],
12
+ const queryModel = options.withDisabled
13
+ ? CustomFieldDefinition.unscoped()
14
+ : CustomFieldDefinition;
15
+ return queryModel.scope('userScope').findAll({
16
+ where,
17
+ transaction: options.transaction,
18
+ raw: true,
22
19
  });
23
20
  };
24
21
 
@@ -33,13 +30,9 @@ export const findById = (
33
30
  ): Promise<CustomFieldDefinition | null> => {
34
31
  const { withDisabled } = options;
35
32
  if (withDisabled) {
36
- return CustomFieldDefinition.unscoped().findByPk(id, {
37
- include: [CustomFieldValue],
38
- });
33
+ return CustomFieldDefinition.unscoped().scope('userScope').findByPk(id);
39
34
  }
40
- return CustomFieldDefinition.findByPk(id, {
41
- include: [CustomFieldValue],
42
- });
35
+ return CustomFieldDefinition.scope('userScope').findByPk(id);
43
36
  };
44
37
 
45
38
  export const findByEntityId = async (
@@ -50,10 +43,22 @@ export const findByEntityId = async (
50
43
  transaction: options.transaction,
51
44
  });
52
45
 
46
+ export const findByEntityIds = async (
47
+ modelType: string,
48
+ entityIds: string[],
49
+ options: any = {},
50
+ ): Promise<CustomFieldDefinition[]> => CustomFieldDefinition.findAll({
51
+ where: {
52
+ modelType,
53
+ entityId: entityIds,
54
+ },
55
+ transaction: options.transaction,
56
+ raw: true,
57
+ });
58
+
53
59
  export const findByWhere = (where): Promise<CustomFieldDefinition | null> =>
54
- CustomFieldDefinition.findOne({
60
+ CustomFieldDefinition.scope('userScope').findOne({
55
61
  where,
56
- include: [CustomFieldValue],
57
62
  });
58
63
 
59
64
  export const findDefinitionsByModels = async (
@@ -63,7 +68,6 @@ export const findDefinitionsByModels = async (
63
68
  const query: WhereOptions<CreateCustomFieldDefinition> = { modelType: { [Op.in]: modelTypes } };
64
69
  return CustomFieldDefinition.findAll({
65
70
  where: query,
66
- include: [CustomFieldValue],
67
71
  transaction: options?.transaction,
68
72
  });
69
73
  };
@@ -72,7 +76,7 @@ export const update = async (
72
76
  id: string,
73
77
  data: UpdateCustomFieldDefinition,
74
78
  ): Promise<CustomFieldDefinition> => {
75
- const updatedDefinition = (await CustomFieldDefinition.update(data, {
79
+ const updatedDefinition = (await CustomFieldDefinition.scope('userScope').update(data, {
76
80
  where: { id },
77
81
  returning: true,
78
82
  individualHooks: true,
@@ -96,27 +100,10 @@ export const getRequiredFields = async (
96
100
  modelType: string,
97
101
  modelId: string | string[],
98
102
  entityId: string | string[],
99
- onlyNull = false,
100
103
  ): Promise<string[]> => {
101
104
  const entityIds = Array.isArray(entityId) ? entityId : [entityId];
102
- const modelIds = Array.isArray(modelId) ? modelId : [modelId];
103
- // const valueQuery = Object.assign(
104
- // {
105
- // modelId: { [Op.in]: modelIds },
106
- // },
107
- // onlyNull ? { value: { [Op.eq]: null } } : null,
108
- // );
109
- const valueQuery = onlyNull ? {
110
- modelId: { [Op.in]: modelIds },
111
- value: { [Op.eq]: null },
112
- } : {};
113
105
  const requiredFields = await CustomFieldDefinition.findAll({
114
106
  where: { required: true, modelType, entityId: { [Op.in]: entityIds } },
115
- include: {
116
- model: CustomFieldValue,
117
- where: { ...valueQuery },
118
- required: false,
119
- },
120
107
  logging: true,
121
108
  });
122
109
  const requiredFieldsNames = requiredFields.map((definition) => definition.name);
@@ -1,10 +1,9 @@
1
1
  /* eslint-disable max-len */
2
- import { Op } from 'sequelize';
3
-
4
2
  import { CustomFieldValue, CustomFieldDefinition } from '../models';
5
3
  import * as DefinitionRepo from './definition';
6
4
  import { CreateCustomFieldValue, ValuesToUpdate } from '../types/value';
7
5
  import logger from '../utils/logger';
6
+ import { MissingDefinitionError } from '../errors';
8
7
 
9
8
  export const findByModelIdAndDefinition = async (modelId: string, customFieldDefinitionId: string) =>
10
9
  CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [CustomFieldDefinition] });
@@ -35,8 +34,9 @@ export const findValuesByModelIds = async (modelIds: string[], options?): Promis
35
34
  const { transaction } = options;
36
35
  return CustomFieldValue.findAll({
37
36
  where: { modelId: modelIds },
38
- include: [CustomFieldDefinition],
39
37
  transaction,
38
+ raw: true,
39
+ nest: true,
40
40
  });
41
41
  };
42
42
 
@@ -48,6 +48,7 @@ export const findValuesByModelIds = async (modelIds: string[], options?): Promis
48
48
  export const updateValues = async (
49
49
  modelType: string,
50
50
  modelId: string,
51
+ identifiers: string[],
51
52
  valuesToUpdate: ValuesToUpdate,
52
53
  options: any = {},
53
54
  ): Promise<CustomFieldValue[]> => {
@@ -55,14 +56,14 @@ export const updateValues = async (
55
56
 
56
57
  const names = Object.keys(valuesToUpdate);
57
58
  const fieldDefinitions = await DefinitionRepo.findAll(
58
- { modelType, name: { [Op.in]: names } },
59
+ { modelType, name: names, entityId: identifiers },
59
60
  { withDisabled: true, transaction: options.transaction },
60
61
  ) || [];
61
62
 
62
63
  const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);
63
64
  if (fieldDefinitions.length !== names.length) {
64
65
  const missingDefinitions = names.filter((name) => !fieldDefinitions.some((def) => def.name === name));
65
- throw new Error(`custom-fields: missing definitions for ${missingDefinitions.join(', ')}`);
66
+ throw new MissingDefinitionError(missingDefinitions);
66
67
  }
67
68
 
68
69
  const disabledNames = disabledDefinitions?.map((def) => def.name) || [];
@@ -30,10 +30,8 @@ export const booleanField = (modelType: string): CreateCustomFieldDefinition =>
30
30
  export const enumField = (modelType: string, options): CreateCustomFieldDefinition => ({
31
31
  name: 'choices',
32
32
  modelType,
33
- fieldType: 'enum',
34
- validation: {
35
- enum: options,
36
- },
33
+ fieldType: 'select',
34
+ validation: options,
37
35
  entityId: uuidv4(),
38
36
  entityType: 'fleetId',
39
37
  });
@@ -14,9 +14,14 @@ export const upsertTestModel = (payload) => TestModel.upsert(payload);
14
14
 
15
15
  export const destroyTestModels = () => TestModel.destroy({ truncate: true });
16
16
 
17
- export const getTestModel = (id: string): Promise<TestModel> => TestModel.findByPk(id);
18
-
19
- export const getSomeTestModels = (limit = 1): Promise<TestModel[]> => TestModel.findAll({ limit });
17
+ export const getTestModel = (
18
+ id: string,
19
+ options = {},
20
+ ): Promise<TestModel> => TestModel.findByPk(id, options);
21
+
22
+ export const getSomeTestModels = (
23
+ options = { limit: 1 },
24
+ ): Promise<TestModel[]> => TestModel.findAll(options);
20
25
 
21
26
  export const updateTestModel = (payload, query) => TestModel.update(payload, query);
22
27
 
@@ -1,5 +1,3 @@
1
- import type { Sequelize as InnerSequelize } from 'sequelize-typescript';
2
-
3
1
  export type ModelFetcher = (name: string) => any;
4
2
 
5
3
  export type ModelOptions = {
@@ -11,7 +9,7 @@ export type ModelOptions = {
11
9
  }
12
10
 
13
11
  export type CustomFieldOptions= {
14
- models: ModelOptions[];
15
- innerSequelize?: InnerSequelize;
16
- databaseConfig: any;
17
- };
12
+ models: ModelOptions[];
13
+ databaseConfig: any;
14
+ getUser: () => any;
15
+ };
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export const supportedEntities = ['businessModelId', 'fleetId', 'demandSourceId'];
@@ -1,4 +1,5 @@
1
1
  import { Sequelize } from 'sequelize-typescript';
2
+ import { QueryTypes } from 'sequelize';
2
3
 
3
4
  export default (databaseConfig: any): Sequelize => {
4
5
  const ENV_DEV = 'test';
@@ -12,3 +13,9 @@ export default (databaseConfig: any): Sequelize => {
12
13
  }
13
14
  return sequelize;
14
15
  };
16
+
17
+ export const createSequelizeMeta = (sequelize: Sequelize) => sequelize.query(`
18
+ CREATE TABLE IF NOT EXISTS "SequelizeMeta" (
19
+ name character varying(255) PRIMARY KEY
20
+ );
21
+ `, { type: QueryTypes.SELECT });
@@ -1,4 +1,6 @@
1
1
  // eslint-disable-next-line @typescript-eslint/no-var-requires
2
2
  const Logger = require('@autofleet/logger');
3
3
 
4
- export default Logger();
4
+ const logger = Logger();
5
+
6
+ export default logger;