@autofleet/sadot 1.2.0 → 1.2.1-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 (337) hide show
  1. package/.nvmrc +1 -0
  2. package/dist/api/index.d.ts +3 -0
  3. package/dist/api/index.js +12 -2
  4. package/dist/api/v1/definition/index.d.ts +3 -0
  5. package/dist/api/v1/definition/index.js +116 -2
  6. package/dist/api/v1/definition/validations.d.ts +2 -0
  7. package/dist/api/v1/definition/validations.js +77 -2
  8. package/dist/api/v1/errors.d.ts +4 -0
  9. package/dist/api/v1/errors.js +12 -2
  10. package/dist/api/v1/index.d.ts +3 -0
  11. package/dist/api/v1/index.js +13 -2
  12. package/dist/api/v1/validator/index.d.ts +3 -0
  13. package/dist/api/v1/validator/index.js +143 -2
  14. package/dist/api/v1/validator/validations.d.ts +6 -23
  15. package/dist/api/v1/validator/validations.js +38 -2
  16. package/dist/errors/index.d.ts +24 -0
  17. package/dist/errors/index.js +66 -3
  18. package/dist/events/index.d.ts +5 -0
  19. package/dist/events/index.js +54 -2
  20. package/dist/hooks/create.d.ts +10 -0
  21. package/dist/hooks/create.js +95 -0
  22. package/dist/hooks/enrich.d.ts +25 -0
  23. package/dist/hooks/enrich.js +198 -2
  24. package/dist/hooks/find.d.ts +1 -0
  25. package/dist/hooks/find.js +29 -2
  26. package/dist/hooks/hooks.d.ts +17 -0
  27. package/dist/hooks/hooks.js +388 -2
  28. package/dist/hooks/index.d.ts +5 -0
  29. package/dist/hooks/index.js +17 -1
  30. package/dist/hooks/update.d.ts +10 -0
  31. package/dist/hooks/update.js +49 -0
  32. package/dist/hooks/utils/updateInstanceValues.d.ts +15 -0
  33. package/dist/hooks/utils/updateInstanceValues.js +50 -2
  34. package/dist/hooks/workaround.d.ts +10 -0
  35. package/dist/hooks/workaround.js +37 -0
  36. package/dist/index.d.ts +12 -22
  37. package/dist/index.js +67 -2
  38. package/dist/models/CustomFieldDefinition.d.ts +23 -31
  39. package/dist/models/CustomFieldDefinition.js +192 -2
  40. package/dist/models/CustomFieldEntries.d.ts +13 -14
  41. package/dist/models/CustomFieldEntries.js +123 -2
  42. package/dist/models/CustomFieldValue.d.ts +14 -19
  43. package/dist/models/CustomFieldValue.js +151 -2
  44. package/dist/models/CustomValidator.d.ts +15 -17
  45. package/dist/models/CustomValidator.js +98 -2
  46. package/dist/models/index.d.ts +18 -7
  47. package/dist/models/index.js +131 -2
  48. package/dist/models/tests/AssociatedTestModel.d.ts +12 -0
  49. package/dist/models/tests/AssociatedTestModel.js +71 -2
  50. package/dist/models/tests/TestModel.d.ts +12 -0
  51. package/dist/models/tests/TestModel.js +69 -2
  52. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.d.ts +10 -0
  53. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js +53 -2
  54. package/dist/models/tests/contextAwareModels/ContextTestModel.d.ts +13 -0
  55. package/dist/models/tests/contextAwareModels/ContextTestModel.js +47 -2
  56. package/dist/repository/definition.d.ts +36 -0
  57. package/dist/repository/definition.js +121 -2
  58. package/dist/repository/entries.d.ts +13 -0
  59. package/dist/repository/entries.js +92 -2
  60. package/dist/repository/utils/formatValues.d.ts +3 -0
  61. package/dist/repository/utils/formatValues.js +16 -2
  62. package/dist/repository/validator.d.ts +27 -0
  63. package/dist/repository/validator.js +69 -2
  64. package/dist/repository/value.d.ts +28 -0
  65. package/dist/repository/value.js +124 -2
  66. package/dist/scopes/filter.d.ts +29 -22
  67. package/dist/scopes/filter.js +75 -2
  68. package/dist/scopes/helpers/filter.helpers.d.ts +40 -15
  69. package/dist/scopes/helpers/filter.helpers.js +183 -25
  70. package/dist/scopes/index.d.ts +2 -0
  71. package/dist/scopes/index.js +6 -1
  72. package/dist/tests/api/test-api.d.ts +2 -0
  73. package/dist/tests/api/test-api.js +38 -0
  74. package/dist/tests/functional/searching/index.d.ts +8 -0
  75. package/dist/tests/functional/searching/index.js +44 -0
  76. package/dist/tests/helpers/commonHooks.d.ts +6 -0
  77. package/dist/tests/helpers/commonHooks.js +62 -0
  78. package/dist/tests/helpers/database-config.d.ts +16 -0
  79. package/dist/tests/helpers/database-config.js +17 -0
  80. package/dist/tests/helpers/index.d.ts +7 -0
  81. package/dist/tests/helpers/index.js +33 -0
  82. package/dist/tests/mocks/definition.mock.d.ts +48 -0
  83. package/dist/tests/mocks/definition.mock.js +78 -0
  84. package/dist/tests/mocks/events.mock.d.ts +4 -0
  85. package/dist/tests/mocks/events.mock.js +21 -0
  86. package/dist/tests/mocks/testModel.d.ts +12 -0
  87. package/dist/tests/mocks/testModel.js +35 -0
  88. package/dist/types/definition/index.d.ts +25 -0
  89. package/dist/types/definition/index.js +2 -0
  90. package/dist/types/entries/index.d.ts +25 -0
  91. package/dist/types/entries/index.js +2 -0
  92. package/dist/types/index.d.ts +46 -48
  93. package/dist/types/index.js +2 -0
  94. package/dist/types/value/index.d.ts +15 -0
  95. package/dist/types/value/index.js +2 -0
  96. package/dist/utils/constants/index.d.ts +17 -20
  97. package/dist/utils/constants/index.js +22 -2
  98. package/dist/utils/db/index.d.ts +4 -0
  99. package/dist/utils/db/index.js +24 -2
  100. package/dist/utils/helpers/index.d.ts +23 -28
  101. package/dist/utils/helpers/index.js +40 -2
  102. package/dist/utils/init.d.ts +7 -0
  103. package/dist/utils/init.js +112 -2
  104. package/dist/utils/logger/index.d.ts +3 -0
  105. package/dist/utils/logger/index.js +42 -2
  106. package/dist/utils/scopeAttributes.d.ts +2 -0
  107. package/dist/utils/scopeAttributes.js +11 -2
  108. package/dist/utils/validations/index.d.ts +8 -0
  109. package/dist/utils/validations/index.js +41 -2
  110. package/dist/utils/validations/schema/custom-fields.d.ts +2 -6
  111. package/dist/utils/validations/schema/custom-fields.js +9 -2
  112. package/dist/utils/validations/schema/validator-schema.d.ts +9 -0
  113. package/dist/utils/validations/schema/validator-schema.js +95 -2
  114. package/dist/utils/validations/type.d.ts +15 -0
  115. package/dist/utils/validations/type.js +2 -0
  116. package/dist/utils/validations/validators/index.d.ts +14 -0
  117. package/dist/utils/validations/validators/index.js +40 -2
  118. package/dist/utils/validations/validators/select.validator.d.ts +5 -0
  119. package/dist/utils/validations/validators/select.validator.js +12 -2
  120. package/dist/utils/validations/validators/status.validator.d.ts +12 -0
  121. package/dist/utils/validations/validators/status.validator.js +15 -2
  122. package/package.json +39 -40
  123. package/src/api/index.ts +10 -0
  124. package/src/api/v1/definition/index.ts +104 -0
  125. package/src/api/v1/definition/validations.ts +75 -0
  126. package/src/api/v1/errors.ts +13 -0
  127. package/src/api/v1/index.ts +11 -0
  128. package/src/api/v1/validator/index.ts +141 -0
  129. package/src/api/v1/validator/validations.ts +39 -0
  130. package/src/errors/index.ts +70 -0
  131. package/src/events/index.ts +63 -0
  132. package/src/hooks/create.ts +81 -0
  133. package/src/hooks/enrich.ts +255 -0
  134. package/src/hooks/find.ts +27 -0
  135. package/src/hooks/hooks.ts +464 -0
  136. package/src/hooks/index.ts +20 -0
  137. package/src/hooks/update.ts +55 -0
  138. package/src/hooks/utils/updateInstanceValues.ts +63 -0
  139. package/src/hooks/workaround.ts +47 -0
  140. package/src/index.ts +52 -0
  141. package/src/models/CustomFieldDefinition.ts +162 -0
  142. package/src/models/CustomFieldEntries.ts +81 -0
  143. package/src/models/CustomFieldValue.ts +118 -0
  144. package/src/models/CustomValidator.ts +78 -0
  145. package/src/models/index.ts +165 -0
  146. package/src/models/tests/AssociatedTestModel.ts +57 -0
  147. package/src/models/tests/TestModel.ts +54 -0
  148. package/src/models/tests/contextAwareModels/ContextAwareTestModel.ts +43 -0
  149. package/src/models/tests/contextAwareModels/ContextTestModel.ts +38 -0
  150. package/src/repository/definition.ts +175 -0
  151. package/src/repository/entries.ts +88 -0
  152. package/src/repository/utils/formatValues.ts +14 -0
  153. package/src/repository/validator.ts +116 -0
  154. package/src/repository/value.ts +116 -0
  155. package/src/scopes/filter.ts +100 -0
  156. package/src/scopes/helpers/filter.helpers.ts +227 -0
  157. package/src/scopes/index.ts +6 -0
  158. package/src/tests/api/test-api.ts +40 -0
  159. package/src/tests/functional/searching/index.ts +39 -0
  160. package/src/tests/helpers/commonHooks.ts +43 -0
  161. package/src/tests/helpers/database-config.ts +15 -0
  162. package/src/tests/helpers/index.ts +35 -0
  163. package/src/tests/mocks/definition.mock.ts +84 -0
  164. package/src/tests/mocks/events.mock.ts +21 -0
  165. package/src/tests/mocks/testModel.ts +37 -0
  166. package/src/types/definition/index.ts +24 -0
  167. package/src/types/entries/index.ts +27 -0
  168. package/src/types/index.ts +52 -0
  169. package/src/types/value/index.ts +14 -0
  170. package/src/utils/constants/index.ts +25 -0
  171. package/src/utils/db/index.ts +21 -0
  172. package/src/utils/helpers/index.ts +66 -0
  173. package/src/utils/init.ts +122 -0
  174. package/src/utils/logger/index.ts +14 -0
  175. package/src/utils/scopeAttributes.ts +12 -0
  176. package/src/utils/validations/index.ts +46 -0
  177. package/src/utils/validations/schema/README.md +93 -0
  178. package/src/utils/validations/schema/custom-fields.ts +8 -0
  179. package/src/utils/validations/schema/validator-schema.ts +106 -0
  180. package/src/utils/validations/type.ts +20 -0
  181. package/src/utils/validations/validators/index.ts +38 -0
  182. package/src/utils/validations/validators/select.validator.ts +12 -0
  183. package/src/utils/validations/validators/status.validator.ts +22 -0
  184. package/tsconfig.build.json +7 -0
  185. package/tsconfig.json +16 -0
  186. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorate.cjs +0 -1
  187. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorate.js +0 -1
  188. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorateMetadata.cjs +0 -1
  189. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorateMetadata.js +0 -1
  190. package/dist/_virtual/rolldown_runtime.cjs +0 -1
  191. package/dist/api/index.cjs +0 -2
  192. package/dist/api/index.cjs.map +0 -1
  193. package/dist/api/index.js.map +0 -1
  194. package/dist/api/v1/definition/index.cjs +0 -2
  195. package/dist/api/v1/definition/index.cjs.map +0 -1
  196. package/dist/api/v1/definition/index.js.map +0 -1
  197. package/dist/api/v1/definition/validations.cjs +0 -2
  198. package/dist/api/v1/definition/validations.cjs.map +0 -1
  199. package/dist/api/v1/definition/validations.js.map +0 -1
  200. package/dist/api/v1/errors.cjs +0 -2
  201. package/dist/api/v1/errors.cjs.map +0 -1
  202. package/dist/api/v1/errors.js.map +0 -1
  203. package/dist/api/v1/index.cjs +0 -2
  204. package/dist/api/v1/index.cjs.map +0 -1
  205. package/dist/api/v1/index.js.map +0 -1
  206. package/dist/api/v1/validator/index.cjs +0 -2
  207. package/dist/api/v1/validator/index.cjs.map +0 -1
  208. package/dist/api/v1/validator/index.js.map +0 -1
  209. package/dist/api/v1/validator/validations.cjs +0 -2
  210. package/dist/api/v1/validator/validations.cjs.map +0 -1
  211. package/dist/api/v1/validator/validations.d.cts +0 -23
  212. package/dist/api/v1/validator/validations.js.map +0 -1
  213. package/dist/errors/index.cjs +0 -3
  214. package/dist/errors/index.cjs.map +0 -1
  215. package/dist/errors/index.js.map +0 -1
  216. package/dist/events/index.cjs +0 -2
  217. package/dist/events/index.cjs.map +0 -1
  218. package/dist/events/index.js.map +0 -1
  219. package/dist/hooks/enrich.cjs +0 -2
  220. package/dist/hooks/enrich.cjs.map +0 -1
  221. package/dist/hooks/enrich.js.map +0 -1
  222. package/dist/hooks/find.cjs +0 -2
  223. package/dist/hooks/find.cjs.map +0 -1
  224. package/dist/hooks/find.js.map +0 -1
  225. package/dist/hooks/hooks.cjs +0 -2
  226. package/dist/hooks/hooks.cjs.map +0 -1
  227. package/dist/hooks/hooks.js.map +0 -1
  228. package/dist/hooks/index.cjs +0 -1
  229. package/dist/hooks/utils/updateInstanceValues.cjs +0 -2
  230. package/dist/hooks/utils/updateInstanceValues.cjs.map +0 -1
  231. package/dist/hooks/utils/updateInstanceValues.js.map +0 -1
  232. package/dist/index.cjs +0 -2
  233. package/dist/index.cjs.map +0 -1
  234. package/dist/index.d.cts +0 -23
  235. package/dist/index.js.map +0 -1
  236. package/dist/models/CustomFieldDefinition.cjs +0 -2
  237. package/dist/models/CustomFieldDefinition.cjs.map +0 -1
  238. package/dist/models/CustomFieldDefinition.d.cts +0 -33
  239. package/dist/models/CustomFieldDefinition.js.map +0 -1
  240. package/dist/models/CustomFieldEntries.cjs +0 -2
  241. package/dist/models/CustomFieldEntries.cjs.map +0 -1
  242. package/dist/models/CustomFieldEntries.d.cts +0 -16
  243. package/dist/models/CustomFieldEntries.js.map +0 -1
  244. package/dist/models/CustomFieldModelTypeMap.cjs +0 -2
  245. package/dist/models/CustomFieldModelTypeMap.cjs.map +0 -1
  246. package/dist/models/CustomFieldModelTypeMap.d.cts +0 -15
  247. package/dist/models/CustomFieldModelTypeMap.d.ts +0 -15
  248. package/dist/models/CustomFieldModelTypeMap.js +0 -2
  249. package/dist/models/CustomFieldModelTypeMap.js.map +0 -1
  250. package/dist/models/CustomFieldValue.cjs +0 -2
  251. package/dist/models/CustomFieldValue.cjs.map +0 -1
  252. package/dist/models/CustomFieldValue.d.cts +0 -21
  253. package/dist/models/CustomFieldValue.js.map +0 -1
  254. package/dist/models/CustomValidator.cjs +0 -2
  255. package/dist/models/CustomValidator.cjs.map +0 -1
  256. package/dist/models/CustomValidator.d.cts +0 -19
  257. package/dist/models/CustomValidator.js.map +0 -1
  258. package/dist/models/index.cjs +0 -2
  259. package/dist/models/index.cjs.map +0 -1
  260. package/dist/models/index.d.cts +0 -7
  261. package/dist/models/index.js.map +0 -1
  262. package/dist/models/tests/AssociatedTestModel.cjs +0 -2
  263. package/dist/models/tests/AssociatedTestModel.cjs.map +0 -1
  264. package/dist/models/tests/AssociatedTestModel.js.map +0 -1
  265. package/dist/models/tests/TestModel.cjs +0 -2
  266. package/dist/models/tests/TestModel.cjs.map +0 -1
  267. package/dist/models/tests/TestModel.js.map +0 -1
  268. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.cjs +0 -2
  269. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.cjs.map +0 -1
  270. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js.map +0 -1
  271. package/dist/models/tests/contextAwareModels/ContextTestModel.cjs +0 -2
  272. package/dist/models/tests/contextAwareModels/ContextTestModel.cjs.map +0 -1
  273. package/dist/models/tests/contextAwareModels/ContextTestModel.js.map +0 -1
  274. package/dist/repository/definition.cjs +0 -2
  275. package/dist/repository/definition.cjs.map +0 -1
  276. package/dist/repository/definition.js.map +0 -1
  277. package/dist/repository/entries.cjs +0 -2
  278. package/dist/repository/entries.cjs.map +0 -1
  279. package/dist/repository/entries.js.map +0 -1
  280. package/dist/repository/utils/formatValues.cjs +0 -2
  281. package/dist/repository/utils/formatValues.cjs.map +0 -1
  282. package/dist/repository/utils/formatValues.js.map +0 -1
  283. package/dist/repository/validator.cjs +0 -2
  284. package/dist/repository/validator.cjs.map +0 -1
  285. package/dist/repository/validator.js.map +0 -1
  286. package/dist/repository/value.cjs +0 -2
  287. package/dist/repository/value.cjs.map +0 -1
  288. package/dist/repository/value.js.map +0 -1
  289. package/dist/scopes/filter.cjs +0 -2
  290. package/dist/scopes/filter.cjs.map +0 -1
  291. package/dist/scopes/filter.d.cts +0 -23
  292. package/dist/scopes/filter.js.map +0 -1
  293. package/dist/scopes/helpers/filter.helpers.cjs +0 -46
  294. package/dist/scopes/helpers/filter.helpers.cjs.map +0 -1
  295. package/dist/scopes/helpers/filter.helpers.d.cts +0 -17
  296. package/dist/scopes/helpers/filter.helpers.js.map +0 -1
  297. package/dist/scopes/index.cjs +0 -1
  298. package/dist/types/index.d.cts +0 -48
  299. package/dist/utils/constants/index.cjs +0 -2
  300. package/dist/utils/constants/index.cjs.map +0 -1
  301. package/dist/utils/constants/index.d.cts +0 -22
  302. package/dist/utils/constants/index.js.map +0 -1
  303. package/dist/utils/db/index.cjs +0 -2
  304. package/dist/utils/db/index.cjs.map +0 -1
  305. package/dist/utils/db/index.js.map +0 -1
  306. package/dist/utils/helpers/index.cjs +0 -2
  307. package/dist/utils/helpers/index.cjs.map +0 -1
  308. package/dist/utils/helpers/index.d.cts +0 -31
  309. package/dist/utils/helpers/index.js.map +0 -1
  310. package/dist/utils/init.cjs +0 -2
  311. package/dist/utils/init.cjs.map +0 -1
  312. package/dist/utils/init.js.map +0 -1
  313. package/dist/utils/logger/index.cjs +0 -2
  314. package/dist/utils/logger/index.cjs.map +0 -1
  315. package/dist/utils/logger/index.js.map +0 -1
  316. package/dist/utils/scopeAttributes.cjs +0 -2
  317. package/dist/utils/scopeAttributes.cjs.map +0 -1
  318. package/dist/utils/scopeAttributes.js.map +0 -1
  319. package/dist/utils/validations/index.cjs +0 -2
  320. package/dist/utils/validations/index.cjs.map +0 -1
  321. package/dist/utils/validations/index.js.map +0 -1
  322. package/dist/utils/validations/schema/custom-fields.cjs +0 -2
  323. package/dist/utils/validations/schema/custom-fields.cjs.map +0 -1
  324. package/dist/utils/validations/schema/custom-fields.d.cts +0 -7
  325. package/dist/utils/validations/schema/custom-fields.js.map +0 -1
  326. package/dist/utils/validations/schema/validator-schema.cjs +0 -2
  327. package/dist/utils/validations/schema/validator-schema.cjs.map +0 -1
  328. package/dist/utils/validations/schema/validator-schema.js.map +0 -1
  329. package/dist/utils/validations/validators/index.cjs +0 -2
  330. package/dist/utils/validations/validators/index.cjs.map +0 -1
  331. package/dist/utils/validations/validators/index.js.map +0 -1
  332. package/dist/utils/validations/validators/select.validator.cjs +0 -2
  333. package/dist/utils/validations/validators/select.validator.cjs.map +0 -1
  334. package/dist/utils/validations/validators/select.validator.js.map +0 -1
  335. package/dist/utils/validations/validators/status.validator.cjs +0 -2
  336. package/dist/utils/validations/validators/status.validator.cjs.map +0 -1
  337. package/dist/utils/validations/validators/status.validator.js.map +0 -1
@@ -0,0 +1,162 @@
1
+ import {
2
+ Table,
3
+ Column,
4
+ Model,
5
+ DataType,
6
+ HasMany,
7
+ PrimaryKey,
8
+ BeforeCreate,
9
+ DefaultScope,
10
+ AfterSave,
11
+ Is,
12
+ } from 'sequelize-typescript';
13
+ import { CustomFieldDefinitionType } from '../utils/constants';
14
+ import { CustomValidationTypes } from '../utils/validations/validators';
15
+ import { CustomFieldValue } from '.';
16
+ import { sendDimEvent } from '../events';
17
+ import { InvalidValueError, UnsupportedCustomFieldTypeError, UnsupportedCustomValidationError } from '../errors';
18
+ import logger from '../utils/logger';
19
+ import { validateValue } from '../utils/validations';
20
+
21
+ @DefaultScope(() => ({ where: { disabled: false } }))
22
+ @Table({
23
+ indexes: [
24
+ {
25
+ name: 'unique_name_model_type',
26
+ fields: ['model_type', 'entity_id', 'name'],
27
+ unique: true,
28
+ },
29
+ ],
30
+ timestamps: true,
31
+ validate: {
32
+ validationByType(this: CustomFieldDefinition) {
33
+ // Verify the validation is provided if needed
34
+ if (!this.validation && CustomValidationTypes[this.fieldType]) {
35
+ // TODO: enforce the validation-object schema based on the fieldType
36
+ logger.error(`No custom validation for custom field type ${this.fieldType} found`);
37
+ throw new UnsupportedCustomValidationError(`Validation provided for "${this.fieldType}" is not supported`);
38
+ }
39
+ },
40
+ },
41
+ })
42
+ class CustomFieldDefinition extends Model {
43
+ @PrimaryKey
44
+ @Column({
45
+ type: DataType.UUID,
46
+ defaultValue: DataType.UUIDV4,
47
+ allowNull: false,
48
+ })
49
+ id!: string;
50
+
51
+ @Column({
52
+ type: DataType.STRING,
53
+ allowNull: false,
54
+ })
55
+ name!: string;
56
+
57
+ @Column({
58
+ type: DataType.STRING,
59
+ })
60
+ displayName?: string; // Defaulted to name with beforeCreate hook
61
+
62
+ @Is('SupportedType', (value) => {
63
+ if (!Object.values(CustomFieldDefinitionType).includes(value as CustomFieldDefinitionType)) {
64
+ throw new UnsupportedCustomFieldTypeError(`"${value}" is not a supported type.`);
65
+ }
66
+ })
67
+ @Column({
68
+ type: DataType.STRING,
69
+ allowNull: false,
70
+ })
71
+ fieldType!: CustomFieldDefinitionType;
72
+
73
+ @Column({
74
+ type: DataType.JSONB,
75
+ })
76
+ validation?: any;
77
+
78
+ @Column({
79
+ type: DataType.UUID,
80
+ allowNull: false,
81
+ })
82
+ entityId!: string; /** Client association entity id */
83
+
84
+ @Column({
85
+ type: DataType.STRING,
86
+ allowNull: false,
87
+ })
88
+ entityType!: string; /** Client association entity type (demand source / fleet / etc.) */
89
+
90
+ @Column({
91
+ type: DataType.STRING,
92
+ allowNull: false,
93
+ })
94
+ modelType!: string; /** Model type. e.g. Vehicle / StopPoint / etc. */
95
+
96
+ @Column({
97
+ type: DataType.TEXT,
98
+ })
99
+ description?: string;
100
+
101
+ @Column({
102
+ type: DataType.BOOLEAN,
103
+ defaultValue: false,
104
+ })
105
+ required?: boolean;
106
+
107
+ @Column({
108
+ type: DataType.BOOLEAN,
109
+ defaultValue: false,
110
+ })
111
+ disabled?: boolean;
112
+
113
+ @Column({
114
+ type: DataType.JSONB,
115
+ allowNull: true,
116
+ })
117
+ defaultValue?: any;
118
+
119
+ @Column
120
+ createdAt?: Date;
121
+
122
+ @Column
123
+ updatedAt?: Date;
124
+
125
+ @Column
126
+ deletedAt?: Date;
127
+
128
+ @Column({
129
+ type: DataType.BOOLEAN,
130
+ defaultValue: false,
131
+ allowNull: false,
132
+ })
133
+ blockEditingFromUI!: boolean;
134
+
135
+ @HasMany(() => CustomFieldValue)
136
+ values: CustomFieldValue[];
137
+
138
+ @BeforeCreate
139
+ static displayNameDefaultValue(instance: CustomFieldDefinition): void {
140
+ if (!instance?.displayName) {
141
+ // eslint-disable-next-line no-param-reassign
142
+ instance.displayName = instance.name;
143
+ }
144
+ if (![null, undefined].includes(instance.defaultValue)) {
145
+ const isValid = validateValue(instance.defaultValue, instance.fieldType, instance.validation);
146
+ if (isValid.error) {
147
+ throw new InvalidValueError(instance.defaultValue, instance.name, isValid.error);
148
+ }
149
+ }
150
+ }
151
+
152
+ @AfterSave
153
+ static afterSaveHandler(instance: CustomFieldDefinition, options): void {
154
+ if (options.transaction) {
155
+ options.transaction.afterCommit(() => sendDimEvent(instance));
156
+ } else {
157
+ sendDimEvent(instance);
158
+ }
159
+ }
160
+ }
161
+
162
+ export default CustomFieldDefinition;
@@ -0,0 +1,81 @@
1
+ import {
2
+ Table,
3
+ Column,
4
+ Model,
5
+ PrimaryKey,
6
+ DataType,
7
+ AfterUpsert,
8
+ } from 'sequelize-typescript';
9
+ import { sendDimEvent } from '../events';
10
+ import * as CustomFieldDefinitionRepo from '../repository/definition';
11
+ import { validateInstanceCustomFieldEntries } from '../utils/validations';
12
+
13
+ @Table({
14
+ timestamps: true,
15
+ indexes: [
16
+ {
17
+ name: 'idx_cfe_custom_fields',
18
+ using: 'gin',
19
+ operator: 'jsonb_path_ops',
20
+ fields: ['custom_fields'],
21
+ },
22
+ ],
23
+ validate: {
24
+ async validationByType(this: CustomFieldEntries) {
25
+ if (!Object.keys(this.customFields ?? {}).length) {
26
+ return;
27
+ }
28
+
29
+ const definitionsByName = await CustomFieldDefinitionRepo.getCustomFieldDefinitionsDictionary([this]);
30
+ validateInstanceCustomFieldEntries(this, definitionsByName);
31
+ },
32
+ },
33
+ })
34
+ class CustomFieldEntries extends Model {
35
+ @PrimaryKey
36
+ @Column({
37
+ type: DataType.UUID,
38
+ allowNull: false,
39
+ })
40
+ /** The ID of the model of which this row hold the custom field entries of, e.g. vehicleId / stopPointId / etc. */
41
+ modelId!: string;
42
+
43
+ @Column({
44
+ type: DataType.UUID,
45
+ allowNull: false,
46
+ })
47
+ /** The ID of the entity of which this row hold the custom field entries of, e.g. fleetId / etc. */
48
+ entityId!: string;
49
+
50
+ @Column({
51
+ type: DataType.JSONB,
52
+ allowNull: false,
53
+ defaultValue: {},
54
+ })
55
+ /** A dictionary of customFields and values with the following structure: `{ customFieldName: 'CustomFieldValue' }` */
56
+ customFields!: Record<string, any>;
57
+
58
+ @Column({
59
+ type: DataType.STRING,
60
+ allowNull: false,
61
+ })
62
+ /** The type of model which this custom field entry represents. e.g. Vehicle / StopPoint / etc. */
63
+ modelType!: string;
64
+
65
+ @Column
66
+ createdAt?: Date;
67
+
68
+ @Column
69
+ updatedAt?: Date;
70
+
71
+ @AfterUpsert
72
+ static afterSaveHandler(instance: CustomFieldEntries, options): void {
73
+ if (options.transaction) {
74
+ options.transaction.afterCommit(() => sendDimEvent(instance[0]));
75
+ } else {
76
+ sendDimEvent(instance[0]);
77
+ }
78
+ }
79
+ }
80
+
81
+ export default CustomFieldEntries;
@@ -0,0 +1,118 @@
1
+ import {
2
+ Table,
3
+ Column,
4
+ Model,
5
+ PrimaryKey,
6
+ DataType,
7
+ BelongsTo,
8
+ ForeignKey,
9
+ BeforeCreate,
10
+ BeforeUpsert,
11
+ AfterUpsert,
12
+ BeforeUpdate,
13
+ BeforeBulkCreate,
14
+ BeforeBulkUpdate,
15
+ } from 'sequelize-typescript';
16
+ import { sendDimEvent } from '../events';
17
+ import { CustomFieldDefinition } from '.';
18
+ import { validateFieldType, validateValue } from '../utils/validations';
19
+ import * as CustomFieldDefinitionRepo from '../repository/definition';
20
+ import { InvalidFieldTypeError, InvalidValueError } from '../errors';
21
+
22
+ @Table({
23
+ timestamps: true,
24
+ })
25
+ class CustomFieldValue extends Model {
26
+ @PrimaryKey
27
+ @Column({
28
+ type: DataType.UUID,
29
+ allowNull: false,
30
+ })
31
+ modelId!: string;
32
+
33
+ @PrimaryKey
34
+ @ForeignKey(() => CustomFieldDefinition)
35
+ @Column({
36
+ type: DataType.UUID,
37
+ allowNull: false,
38
+ })
39
+ customFieldDefinitionId!: string;
40
+
41
+ @Column({
42
+ type: DataType.JSONB,
43
+ allowNull: true,
44
+ })
45
+ value!: any;
46
+
47
+ @Column
48
+ createdAt?: Date;
49
+
50
+ @Column
51
+ updatedAt?: Date;
52
+
53
+ @Column
54
+ deletedAt?: Date;
55
+
56
+ @BelongsTo(() => CustomFieldDefinition, { scope: { disabled: false } })
57
+ customFieldDefinition: CustomFieldDefinition;
58
+
59
+ private static validateValueAgainstDefinition(
60
+ instance: CustomFieldValue,
61
+ definition: CustomFieldDefinition,
62
+ ): void {
63
+ const { validation, fieldType, name } = definition;
64
+ const isValidFieldType = validateFieldType(fieldType);
65
+ if (!isValidFieldType) {
66
+ throw new InvalidFieldTypeError(fieldType);
67
+ }
68
+ // Always allow null values
69
+ if (instance.value === null) return;
70
+ const validateValueResponse = validateValue(instance.value, fieldType, validation);
71
+ if (validateValueResponse.error) {
72
+ throw new InvalidValueError(instance.value, name, validateValueResponse.error);
73
+ }
74
+ }
75
+
76
+ @BeforeBulkCreate
77
+ @BeforeBulkUpdate
78
+ static async validateCustomFieldValues(instances: CustomFieldValue[]): Promise<void> {
79
+ const ids = instances.map((instance) => instance.customFieldDefinitionId);
80
+ const uniqueIds = [...new Set(ids)];
81
+ const definitions = await CustomFieldDefinitionRepo.findByIds(
82
+ uniqueIds,
83
+ { withDisabled: true },
84
+ );
85
+
86
+ if (!definitions || definitions.length !== uniqueIds.length) {
87
+ throw new Error('Definitions not found');
88
+ }
89
+
90
+ instances.forEach((instance) => {
91
+ const definition = definitions.find((d) => d.id === instance.customFieldDefinitionId);
92
+ if (definition) {
93
+ this.validateValueAgainstDefinition(instance, definition);
94
+ }
95
+ });
96
+ }
97
+
98
+ @BeforeUpdate
99
+ @BeforeCreate
100
+ @BeforeUpsert
101
+ static async validateCustomFieldValue(instance: CustomFieldValue): Promise<void> {
102
+ const { customFieldDefinitionId } = instance;
103
+ // eslint-disable-next-line max-len
104
+ const cfd = await CustomFieldDefinitionRepo.findById(customFieldDefinitionId, { withDisabled: true });
105
+ this.validateValueAgainstDefinition(instance, cfd);
106
+ }
107
+
108
+ @AfterUpsert
109
+ static afterSaveHandler(instance: CustomFieldValue, options): void {
110
+ if (options.transaction) {
111
+ options.transaction.afterCommit(() => sendDimEvent(instance[0]));
112
+ } else {
113
+ sendDimEvent(instance[0]);
114
+ }
115
+ }
116
+ }
117
+
118
+ export default CustomFieldValue;
@@ -0,0 +1,78 @@
1
+ import {
2
+ Table,
3
+ Column,
4
+ Model,
5
+ PrimaryKey,
6
+ DataType,
7
+ Default,
8
+ AfterUpsert,
9
+ DefaultScope,
10
+ } from 'sequelize-typescript';
11
+ import { randomUUID } from 'node:crypto';
12
+ import { sendDimEvent } from '../events';
13
+
14
+ @DefaultScope(() => ({ where: { disabled: false } }))
15
+ @Table({
16
+ timestamps: true,
17
+ })
18
+ class CustomValidator extends Model {
19
+ @PrimaryKey
20
+ @Default(() => randomUUID())
21
+ @Column({
22
+ type: DataType.UUID,
23
+ allowNull: false,
24
+ })
25
+ id!: string;
26
+
27
+ @Column({
28
+ type: DataType.UUID,
29
+ allowNull: false,
30
+ })
31
+ /** The ID of the entity for which this validator is defined, e.g. fleetId / etc. */
32
+ entityId!: string;
33
+
34
+ @Column({
35
+ type: DataType.STRING,
36
+ allowNull: false,
37
+ })
38
+ /** The type of entity (fleet, businessModel, etc). */
39
+ entityType!: string;
40
+
41
+ @Column({
42
+ type: DataType.STRING,
43
+ allowNull: false,
44
+ })
45
+ /** The type of model this validator applies to. e.g. Vehicle / StopPoint / etc. */
46
+ modelType!: string;
47
+
48
+ @Column({
49
+ type: DataType.JSONB,
50
+ allowNull: false,
51
+ })
52
+ /** JSON Schema to validate models against */
53
+ schema!: Record<string, unknown>;
54
+
55
+ @Column({
56
+ type: DataType.BOOLEAN,
57
+ allowNull: false,
58
+ defaultValue: false,
59
+ })
60
+ disabled!: boolean;
61
+
62
+ @Column
63
+ createdAt?: Date;
64
+
65
+ @Column
66
+ updatedAt?: Date;
67
+
68
+ @AfterUpsert
69
+ static afterSaveHandler(instance: CustomValidator, options): void {
70
+ if (options.transaction) {
71
+ options.transaction.afterCommit(() => sendDimEvent(instance));
72
+ } else {
73
+ sendDimEvent(instance);
74
+ }
75
+ }
76
+ }
77
+
78
+ export default CustomValidator;
@@ -0,0 +1,165 @@
1
+ /* eslint-disable no-param-reassign */
2
+ import { DataTypes, Op } from 'sequelize';
3
+ import type { Sequelize } from 'sequelize-typescript';
4
+ import logger from '../utils/logger';
5
+ import CustomFieldDefinition from './CustomFieldDefinition';
6
+ import CustomFieldValue from './CustomFieldValue';
7
+ import TestModel from './tests/TestModel';
8
+ import ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';
9
+ import ContextTestModel from './tests/contextAwareModels/ContextTestModel';
10
+ import AssociatedTestModel from './tests/AssociatedTestModel';
11
+ import type { CustomFieldOptions } from '../types';
12
+ import CustomFieldEntries from './CustomFieldEntries';
13
+ import CustomValidator from './CustomValidator';
14
+
15
+ type ProductionModel = typeof CustomFieldDefinition | typeof CustomFieldValue | typeof CustomFieldEntries | typeof CustomValidator
16
+ interface InitTablesOptions {
17
+ schemaPrefix?: string
18
+ schemaVersion?: string
19
+ useCustomFieldsEntries?: boolean
20
+ }
21
+
22
+ const productionModels: ProductionModel[] = [CustomFieldDefinition, CustomFieldValue, CustomValidator];
23
+ const testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];
24
+
25
+ const SADOT_MIGRATION_PREFIX = 'sadot-migration';
26
+ const SCHEMA_VERSION = '49c9dd1d-b1cc-445b-a911-fd349d783110';
27
+
28
+ const initTables = async (
29
+ sequelize: Sequelize,
30
+ getUser: CustomFieldOptions['getUser'],
31
+ {
32
+ schemaPrefix = SADOT_MIGRATION_PREFIX,
33
+ schemaVersion = SCHEMA_VERSION,
34
+ useCustomFieldsEntries = false,
35
+ }: InitTablesOptions = {},
36
+ ): Promise<void> => {
37
+ const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;
38
+ logger.info('custom-fields: initialize custom-fields tables');
39
+ // Detect models and import them to the orm
40
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
41
+ if (!sequelize.addModels) {
42
+ throw new Error('sequelize instance must have addModels function');
43
+ }
44
+
45
+ if (useCustomFieldsEntries) {
46
+ productionModels.push(CustomFieldEntries);
47
+ }
48
+
49
+ sequelize.addModels(productionModels);
50
+
51
+ CustomFieldDefinition.addScope('userScope', () => {
52
+ const user = getUser();
53
+ if (!user?.permissions) {
54
+ return {};
55
+ }
56
+ return {
57
+ where: {
58
+ entityId: [
59
+ ...Object.keys(user.permissions.fleets),
60
+ ...Object.keys(user.permissions.businessModels),
61
+ ...Object.keys(user.permissions.demandSources),
62
+ ],
63
+ },
64
+ };
65
+ });
66
+
67
+ CustomValidator.addScope('userScope', () => {
68
+ const user = getUser();
69
+ if (!user?.permissions) {
70
+ return {};
71
+ }
72
+ return {
73
+ where: {
74
+ entityId: [
75
+ ...Object.keys(user.permissions.fleets),
76
+ ...Object.keys(user.permissions.businessModels),
77
+ ...Object.keys(user.permissions.demandSources),
78
+ ],
79
+ },
80
+ };
81
+ });
82
+
83
+ logger.info('custom-fields: models added');
84
+
85
+ const SequelizeMeta = sequelize.define(
86
+ 'SequelizeMeta',
87
+ {
88
+ name: {
89
+ type: DataTypes.STRING,
90
+ allowNull: false,
91
+ unique: true,
92
+ primaryKey: true,
93
+ autoIncrement: false,
94
+ },
95
+ },
96
+ {
97
+ tableName: 'SequelizeMeta',
98
+ timestamps: false,
99
+ schema: 'public',
100
+ },
101
+ );
102
+
103
+ logger.info('custom-fields: starting migrations');
104
+ const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });
105
+ const currentSadotSchemaVersion = migrations.at(-1);
106
+ const expectedSchemaVersionIndex = migrations.findIndex((m) => (m as any).name === CUSTOM_FIELDS_SCHEMA_VERSION);
107
+
108
+ logger.info('custom-fields: migrations', { migrations, currentSadotSchemaVersion, expectedSchemaVersionIndex });
109
+ if (!currentSadotSchemaVersion || (currentSadotSchemaVersion as any).name !== CUSTOM_FIELDS_SCHEMA_VERSION) {
110
+ logger.info('custom-fields: syncing models');
111
+ await CustomFieldDefinition.sync({ alter: true });
112
+ await CustomFieldValue.sync({ alter: true });
113
+ // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS
114
+ if (useCustomFieldsEntries) {
115
+ await CustomFieldEntries.sync({ alter: true });
116
+ }
117
+
118
+ // Always sync CustomValidator
119
+ await CustomValidator.sync({ alter: true });
120
+
121
+ if (expectedSchemaVersionIndex === -1) {
122
+ await SequelizeMeta.create({ name: CUSTOM_FIELDS_SCHEMA_VERSION });
123
+ }
124
+ logger.info('custom-fields: models synced');
125
+ if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {
126
+ // We have existing migrations, and we are calling `sync`.
127
+ // This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.
128
+ const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);
129
+ await SequelizeMeta.destroy({ where: { name: { [Op.in]: migrationsToDelete.map((m) => (m as any).name) } } });
130
+ }
131
+ }
132
+ };
133
+
134
+ const initTestModels = async (sequelize: Sequelize): Promise<void> => {
135
+ logger.info('custom-fields: initialize custom-fields test models');
136
+ // Detect models and import them to the orm
137
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
138
+ if (!sequelize.addModels) {
139
+ throw new Error('sequelize instance must have addModels function');
140
+ }
141
+
142
+ sequelize.addModels(testModels);
143
+ await sequelize.dropSchema('custom-fields', { logging: false });
144
+ await sequelize.createSchema('custom-fields', { logging: false });
145
+
146
+ logger.info('custom-fields: test models added');
147
+ await TestModel.sync({ alter: true });
148
+ await AssociatedTestModel.sync({ alter: true });
149
+ await ContextTestModel.sync({ alter: true });
150
+ await ContextAwareTestModel.sync({ alter: true });
151
+ logger.info('custom-fields: test models synced');
152
+ };
153
+
154
+ export {
155
+ CustomFieldValue,
156
+ CustomFieldDefinition,
157
+ CustomFieldEntries,
158
+ CustomValidator,
159
+ TestModel,
160
+ AssociatedTestModel,
161
+ ContextAwareTestModel,
162
+ ContextTestModel,
163
+ initTables,
164
+ initTestModels,
165
+ };
@@ -0,0 +1,57 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import {
3
+ Table,
4
+ Column,
5
+ Model,
6
+ PrimaryKey,
7
+ DataType,
8
+ ForeignKey,
9
+ BelongsTo,
10
+ } from 'sequelize-typescript';
11
+ import TestModel from './TestModel';
12
+
13
+ @Table({ schema: 'custom-fields', createdAt: false, updatedAt: false })
14
+ class AssociatedTestModel extends Model {
15
+ @PrimaryKey
16
+ @Column({
17
+ type: DataType.UUID,
18
+ defaultValue: DataType.UUIDV4,
19
+ allowNull: false,
20
+ })
21
+ id!: string;
22
+
23
+ @ForeignKey(() => TestModel)
24
+ @Column({
25
+ type: DataType.UUID,
26
+ allowNull: false,
27
+ })
28
+ testModelId!: string;
29
+
30
+ @Column({
31
+ type: DataType.UUID,
32
+ allowNull: false,
33
+ })
34
+ fleetId: string;
35
+
36
+ @Column({
37
+ type: DataType.UUID,
38
+ allowNull: true,
39
+ })
40
+ businessModelId: string;
41
+
42
+ @Column({
43
+ type: DataType.UUID,
44
+ allowNull: true,
45
+ })
46
+ demandSourceId: string;
47
+
48
+ @Column({
49
+ type: DataType.BOOLEAN,
50
+ })
51
+ anotherAttribute?: boolean;
52
+
53
+ @BelongsTo(() => TestModel)
54
+ testModel: TestModel;
55
+ }
56
+
57
+ export default AssociatedTestModel;
@@ -0,0 +1,54 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import {
3
+ Table,
4
+ Column,
5
+ Model,
6
+ PrimaryKey,
7
+ DataType,
8
+ HasMany,
9
+ } from 'sequelize-typescript';
10
+ import AssociatedTestModel from './AssociatedTestModel';
11
+
12
+ @Table({ schema: 'custom-fields', createdAt: false, updatedAt: false })
13
+ class TestModel extends Model {
14
+ @PrimaryKey
15
+ @Column({
16
+ type: DataType.UUID,
17
+ defaultValue: DataType.UUIDV4,
18
+ allowNull: false,
19
+ })
20
+ id!: string;
21
+
22
+ @Column({
23
+ type: DataType.UUID,
24
+ allowNull: false,
25
+ })
26
+ fleetId: string;
27
+
28
+ @Column({
29
+ type: DataType.UUID,
30
+ allowNull: true,
31
+ })
32
+ businessModelId: string;
33
+
34
+ @Column({
35
+ type: DataType.UUID,
36
+ allowNull: true,
37
+ })
38
+ demandSourceId: string;
39
+
40
+ @Column({
41
+ type: DataType.BOOLEAN,
42
+ })
43
+ coolAttribute?: boolean;
44
+
45
+ @HasMany(() => AssociatedTestModel)
46
+ associatedModels: AssociatedTestModel[];
47
+
48
+ @Column({
49
+ type: DataType.VIRTUAL,
50
+ })
51
+ customFields?: any;
52
+ }
53
+
54
+ export default TestModel;