@autofleet/sadot 1.0.8 → 1.0.10

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 (192) hide show
  1. package/dist/index.cjs +46 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +255 -8
  4. package/dist/index.d.ts +255 -8
  5. package/dist/index.js +46 -1
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/dist/_virtual/_@oxc-project_runtime@0.89.0/helpers/decorate.cjs +0 -1
  9. package/dist/_virtual/_@oxc-project_runtime@0.89.0/helpers/decorate.js +0 -1
  10. package/dist/_virtual/_@oxc-project_runtime@0.89.0/helpers/decorateMetadata.cjs +0 -1
  11. package/dist/_virtual/_@oxc-project_runtime@0.89.0/helpers/decorateMetadata.js +0 -1
  12. package/dist/_virtual/rolldown_runtime.cjs +0 -1
  13. package/dist/api/index.cjs +0 -2
  14. package/dist/api/index.cjs.map +0 -1
  15. package/dist/api/index.js +0 -2
  16. package/dist/api/index.js.map +0 -1
  17. package/dist/api/v1/definition/index.cjs +0 -2
  18. package/dist/api/v1/definition/index.cjs.map +0 -1
  19. package/dist/api/v1/definition/index.js +0 -2
  20. package/dist/api/v1/definition/index.js.map +0 -1
  21. package/dist/api/v1/definition/validations.cjs +0 -2
  22. package/dist/api/v1/definition/validations.cjs.map +0 -1
  23. package/dist/api/v1/definition/validations.js +0 -2
  24. package/dist/api/v1/definition/validations.js.map +0 -1
  25. package/dist/api/v1/errors.cjs +0 -2
  26. package/dist/api/v1/errors.cjs.map +0 -1
  27. package/dist/api/v1/errors.js +0 -2
  28. package/dist/api/v1/errors.js.map +0 -1
  29. package/dist/api/v1/index.cjs +0 -2
  30. package/dist/api/v1/index.cjs.map +0 -1
  31. package/dist/api/v1/index.js +0 -2
  32. package/dist/api/v1/index.js.map +0 -1
  33. package/dist/api/v1/validator/index.cjs +0 -2
  34. package/dist/api/v1/validator/index.cjs.map +0 -1
  35. package/dist/api/v1/validator/index.js +0 -2
  36. package/dist/api/v1/validator/index.js.map +0 -1
  37. package/dist/api/v1/validator/validations.cjs +0 -2
  38. package/dist/api/v1/validator/validations.cjs.map +0 -1
  39. package/dist/api/v1/validator/validations.js +0 -2
  40. package/dist/api/v1/validator/validations.js.map +0 -1
  41. package/dist/errors/index.cjs +0 -3
  42. package/dist/errors/index.cjs.map +0 -1
  43. package/dist/errors/index.js +0 -3
  44. package/dist/errors/index.js.map +0 -1
  45. package/dist/events/index.cjs +0 -2
  46. package/dist/events/index.cjs.map +0 -1
  47. package/dist/events/index.js +0 -2
  48. package/dist/events/index.js.map +0 -1
  49. package/dist/hooks/enrich.cjs +0 -2
  50. package/dist/hooks/enrich.cjs.map +0 -1
  51. package/dist/hooks/enrich.js +0 -2
  52. package/dist/hooks/enrich.js.map +0 -1
  53. package/dist/hooks/find.cjs +0 -2
  54. package/dist/hooks/find.cjs.map +0 -1
  55. package/dist/hooks/find.js +0 -2
  56. package/dist/hooks/find.js.map +0 -1
  57. package/dist/hooks/hooks.cjs +0 -2
  58. package/dist/hooks/hooks.cjs.map +0 -1
  59. package/dist/hooks/hooks.js +0 -2
  60. package/dist/hooks/hooks.js.map +0 -1
  61. package/dist/hooks/index.cjs +0 -1
  62. package/dist/hooks/index.js +0 -1
  63. package/dist/hooks/utils/updateInstanceValues.cjs +0 -2
  64. package/dist/hooks/utils/updateInstanceValues.cjs.map +0 -1
  65. package/dist/hooks/utils/updateInstanceValues.js +0 -2
  66. package/dist/hooks/utils/updateInstanceValues.js.map +0 -1
  67. package/dist/models/CustomFieldDefinition.cjs +0 -2
  68. package/dist/models/CustomFieldDefinition.cjs.map +0 -1
  69. package/dist/models/CustomFieldDefinition.js +0 -2
  70. package/dist/models/CustomFieldDefinition.js.map +0 -1
  71. package/dist/models/CustomFieldEntries.cjs +0 -2
  72. package/dist/models/CustomFieldEntries.cjs.map +0 -1
  73. package/dist/models/CustomFieldEntries.js +0 -2
  74. package/dist/models/CustomFieldEntries.js.map +0 -1
  75. package/dist/models/CustomFieldValue.cjs +0 -2
  76. package/dist/models/CustomFieldValue.cjs.map +0 -1
  77. package/dist/models/CustomFieldValue.js +0 -2
  78. package/dist/models/CustomFieldValue.js.map +0 -1
  79. package/dist/models/CustomValidator.cjs +0 -2
  80. package/dist/models/CustomValidator.cjs.map +0 -1
  81. package/dist/models/CustomValidator.js +0 -2
  82. package/dist/models/CustomValidator.js.map +0 -1
  83. package/dist/models/index.cjs +0 -2
  84. package/dist/models/index.cjs.map +0 -1
  85. package/dist/models/index.js +0 -2
  86. package/dist/models/index.js.map +0 -1
  87. package/dist/models/tests/AssociatedTestModel.cjs +0 -2
  88. package/dist/models/tests/AssociatedTestModel.cjs.map +0 -1
  89. package/dist/models/tests/AssociatedTestModel.js +0 -2
  90. package/dist/models/tests/AssociatedTestModel.js.map +0 -1
  91. package/dist/models/tests/TestModel.cjs +0 -2
  92. package/dist/models/tests/TestModel.cjs.map +0 -1
  93. package/dist/models/tests/TestModel.js +0 -2
  94. package/dist/models/tests/TestModel.js.map +0 -1
  95. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.cjs +0 -2
  96. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.cjs.map +0 -1
  97. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js +0 -2
  98. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js.map +0 -1
  99. package/dist/models/tests/contextAwareModels/ContextTestModel.cjs +0 -2
  100. package/dist/models/tests/contextAwareModels/ContextTestModel.cjs.map +0 -1
  101. package/dist/models/tests/contextAwareModels/ContextTestModel.js +0 -2
  102. package/dist/models/tests/contextAwareModels/ContextTestModel.js.map +0 -1
  103. package/dist/repository/definition.cjs +0 -2
  104. package/dist/repository/definition.cjs.map +0 -1
  105. package/dist/repository/definition.js +0 -2
  106. package/dist/repository/definition.js.map +0 -1
  107. package/dist/repository/entries.cjs +0 -2
  108. package/dist/repository/entries.cjs.map +0 -1
  109. package/dist/repository/entries.js +0 -2
  110. package/dist/repository/entries.js.map +0 -1
  111. package/dist/repository/utils/formatValues.cjs +0 -2
  112. package/dist/repository/utils/formatValues.cjs.map +0 -1
  113. package/dist/repository/utils/formatValues.js +0 -2
  114. package/dist/repository/utils/formatValues.js.map +0 -1
  115. package/dist/repository/validator.cjs +0 -2
  116. package/dist/repository/validator.cjs.map +0 -1
  117. package/dist/repository/validator.js +0 -2
  118. package/dist/repository/validator.js.map +0 -1
  119. package/dist/repository/value.cjs +0 -2
  120. package/dist/repository/value.cjs.map +0 -1
  121. package/dist/repository/value.js +0 -2
  122. package/dist/repository/value.js.map +0 -1
  123. package/dist/scopes/filter.cjs +0 -2
  124. package/dist/scopes/filter.cjs.map +0 -1
  125. package/dist/scopes/filter.d.cts +0 -23
  126. package/dist/scopes/filter.d.ts +0 -23
  127. package/dist/scopes/filter.js +0 -2
  128. package/dist/scopes/filter.js.map +0 -1
  129. package/dist/scopes/helpers/filter.helpers.cjs +0 -46
  130. package/dist/scopes/helpers/filter.helpers.cjs.map +0 -1
  131. package/dist/scopes/helpers/filter.helpers.d.cts +0 -17
  132. package/dist/scopes/helpers/filter.helpers.d.ts +0 -17
  133. package/dist/scopes/helpers/filter.helpers.js +0 -46
  134. package/dist/scopes/helpers/filter.helpers.js.map +0 -1
  135. package/dist/scopes/index.cjs +0 -1
  136. package/dist/scopes/index.js +0 -1
  137. package/dist/types/index.d.cts +0 -44
  138. package/dist/types/index.d.ts +0 -44
  139. package/dist/utils/constants/index.cjs +0 -2
  140. package/dist/utils/constants/index.cjs.map +0 -1
  141. package/dist/utils/constants/index.d.cts +0 -22
  142. package/dist/utils/constants/index.d.ts +0 -22
  143. package/dist/utils/constants/index.js +0 -2
  144. package/dist/utils/constants/index.js.map +0 -1
  145. package/dist/utils/db/index.cjs +0 -2
  146. package/dist/utils/db/index.cjs.map +0 -1
  147. package/dist/utils/db/index.js +0 -2
  148. package/dist/utils/db/index.js.map +0 -1
  149. package/dist/utils/helpers/index.cjs +0 -2
  150. package/dist/utils/helpers/index.cjs.map +0 -1
  151. package/dist/utils/helpers/index.d.cts +0 -31
  152. package/dist/utils/helpers/index.d.ts +0 -31
  153. package/dist/utils/helpers/index.js +0 -2
  154. package/dist/utils/helpers/index.js.map +0 -1
  155. package/dist/utils/init.cjs +0 -2
  156. package/dist/utils/init.cjs.map +0 -1
  157. package/dist/utils/init.js +0 -2
  158. package/dist/utils/init.js.map +0 -1
  159. package/dist/utils/logger/index.cjs +0 -2
  160. package/dist/utils/logger/index.cjs.map +0 -1
  161. package/dist/utils/logger/index.js +0 -2
  162. package/dist/utils/logger/index.js.map +0 -1
  163. package/dist/utils/scopeAttributes.cjs +0 -2
  164. package/dist/utils/scopeAttributes.cjs.map +0 -1
  165. package/dist/utils/scopeAttributes.js +0 -2
  166. package/dist/utils/scopeAttributes.js.map +0 -1
  167. package/dist/utils/validations/index.cjs +0 -2
  168. package/dist/utils/validations/index.cjs.map +0 -1
  169. package/dist/utils/validations/index.js +0 -2
  170. package/dist/utils/validations/index.js.map +0 -1
  171. package/dist/utils/validations/schema/custom-fields.cjs +0 -2
  172. package/dist/utils/validations/schema/custom-fields.cjs.map +0 -1
  173. package/dist/utils/validations/schema/custom-fields.d.cts +0 -7
  174. package/dist/utils/validations/schema/custom-fields.d.ts +0 -7
  175. package/dist/utils/validations/schema/custom-fields.js +0 -2
  176. package/dist/utils/validations/schema/custom-fields.js.map +0 -1
  177. package/dist/utils/validations/schema/validator-schema.cjs +0 -2
  178. package/dist/utils/validations/schema/validator-schema.cjs.map +0 -1
  179. package/dist/utils/validations/schema/validator-schema.js +0 -2
  180. package/dist/utils/validations/schema/validator-schema.js.map +0 -1
  181. package/dist/utils/validations/validators/index.cjs +0 -2
  182. package/dist/utils/validations/validators/index.cjs.map +0 -1
  183. package/dist/utils/validations/validators/index.js +0 -2
  184. package/dist/utils/validations/validators/index.js.map +0 -1
  185. package/dist/utils/validations/validators/select.validator.cjs +0 -2
  186. package/dist/utils/validations/validators/select.validator.cjs.map +0 -1
  187. package/dist/utils/validations/validators/select.validator.js +0 -2
  188. package/dist/utils/validations/validators/select.validator.js.map +0 -1
  189. package/dist/utils/validations/validators/status.validator.cjs +0 -2
  190. package/dist/utils/validations/validators/status.validator.cjs.map +0 -1
  191. package/dist/utils/validations/validators/status.validator.js +0 -2
  192. package/dist/utils/validations/validators/status.validator.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,2 +1,47 @@
1
- Object.defineProperty(exports,`__esModule`,{value:!0});const e=require(`./utils/logger/index.cjs`),t=require(`./utils/constants/index.cjs`),n=require(`./models/index.cjs`),r=require(`./api/index.cjs`),i=require(`./utils/db/index.cjs`),a=require(`./utils/helpers/index.cjs`),o=require(`./scopes/filter.cjs`),s=require(`./utils/init.cjs`),c=require(`./utils/validations/schema/custom-fields.cjs`),l=async(t,a,o)=>{e.tryAddingTraceIdMiddleware().catch(()=>null);let{models:c,useCustomFieldsEntries:l}=o;t&&t.use(`/api`,r.default);let u=o.sequelize??i.default(o.databaseConfig);return process.env.NODE_ENV===`test`&&await n.initTestModels(u),s.addHooks(c,a,{useCustomFieldsEntries:l}),await n.initTables(u,o.getUser,{useCustomFieldsEntries:l}),s.addScopes(c,a,{useCustomFieldsEntries:l}),s.applyCustomAssociation(c),e.default.debug(`sadot - custom fields finished initializing with models`,c),u};var u=l;const d=(e,t)=>{s.removeHooks(e,t)};exports.CUSTOM_FIELDS_FILTER_SCOPE=t.CUSTOM_FIELDS_FILTER_SCOPE,exports.CustomFieldDefinitionType=t.CustomFieldDefinitionType,exports.CustomFieldsSchema=c.CustomFieldsSchema,exports.customFieldsSortScope=o.customFieldsSortScope,exports.default=u,exports.disableCustomFields=d,exports.generateCustomFieldSearchQueryPayload=a.generateCustomFieldSearchQueryPayload,exports.generateRandomString=a.generateRandomString,exports.supportedEntities=t.supportedEntities;
1
+ Object.defineProperty(exports,`__esModule`,{value:!0});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`sequelize`);c=s(c);let l=require(`@autofleet/logger`);l=s(l);let u=require(`sequelize-typescript`);u=s(u);let d=require(`@autofleet/common-types`);d=s(d);let f=require(`joi`);f=s(f);let p=require(`@autofleet/events`);p=s(p);let m=require(`@autofleet/zehut`);m=s(m);let h=require(`@autofleet/errors`);h=s(h);let g=require(`node:crypto`);g=s(g);let _=require(`@autofleet/node-common`);_=s(_);let v=require(`http-status-codes`);v=s(v);let ee=require(`ajv`);ee=s(ee);let y=require(`ajv-formats`);y=s(y);let te=require(`@autofleet/common-types/lib/custom-fields`);te=s(te);let ne=require(`ajv-errors`);ne=s(ne);const re=(0,l.default)();async function ie(){try{let{outbreak:e}=await import(`@autofleet/zehut`);re.addContextMiddleware(()=>({traceId:e.getCurrentContextTraceId()}))}catch(e){re.error(`Failed to add traceId middleware`,{err:e})}}var b=re;const ae=[`businessModelId`,`fleetId`,`demandSourceId`];let x=function(e){return e.NUMBER=`number`,e.BOOLEAN=`boolean`,e.DATE=`date`,e.DATETIME=`datetime`,e.TEXT=`text`,e.IMAGE=`image`,e.SELECT=`select`,e.STATUS=`status`,e.FILE=`file`,e}({});const oe=d.customFields.CUSTOM_FIELDS_FILTER_SCOPE,se=(e,t)=>f.default.string().allow(null).valid(...t).validate(e),ce=(e,t)=>f.default.string().allow(null).valid(...t.map(e=>e.value)).validate(e),le={[x.SELECT]:x.SELECT,[x.STATUS]:x.STATUS},ue={[x.SELECT]:se,[x.STATUS]:ce,[x.TEXT]:e=>f.default.string().min(0).validate(e),[x.NUMBER]:e=>f.default.number().strict(!0).validate(e),[x.BOOLEAN]:e=>f.default.boolean().strict().validate(e),[x.DATE]:e=>f.default.date().validate(e),[x.DATETIME]:e=>f.default.date().validate(e),[x.IMAGE]:e=>f.default.array().min(1).unique().items(f.default.string().uri()).validate(e),[x.FILE]:e=>f.default.array().min(1).unique().items(f.default.object({name:f.default.string().required(),type:f.default.string(),size:f.default.string(),addedBy:f.default.string().uuid()})).validate(e)},de=new p.default({logger:b,getUserId:e=>e?.user_id??(0,m.getUser)()?.id??null}),fe=[`value`,`defaultValue`,`blockEditingFromUI`],pe=(e,t)=>{let n=new Set(Object.keys(e));return t.every(e=>!n.has(e))?e:{...e,...Object.fromEntries(t.map(t=>[t,typeof e[t]==`boolean`?e[t].toString():e[t]]))}},me={CustomFieldDefinition:{tableName:`dim_custom_field_definition`,eventVersion:`1`},CustomFieldValue:{tableName:`dim_custom_field_value`,eventVersion:`1`},CustomFieldEntries:{tableName:`dim_custom_field_entries`,eventVersion:`1`}},S=e=>{let t=me[e.constructor.name];if(!t)return;let n=e.get();try{n=pe(e.get(),fe)}catch(e){b.error(`Failed to convert booleans in dim event payload`,e)}de.sendObject(t.tableName,t.eventVersion,n).catch(()=>{})};var he=class extends h.BadRequest{constructor(e){let t=Error(`The following custom fields are required: ${e.join(`,`)}`);super([t],null,e),this.message=`MISSING_REQUIRED_CUSTOM_FIELDS`}},ge=class extends h.BadRequest{constructor(e){let t=Error(`Type "${e}" is not supported`);super([t],null,null),this.message=`UNSUPPORTED_CUSTOM_FIELD_TYPE`}},_e=class extends h.BadRequest{constructor(e){let t=Error(`Validation for "${e}" is not supported`);super([t],null,null),this.message=`UNSUPPORTED_CUSTOM_VALIDATION_TYPE`}},ve=class extends h.BadRequest{constructor(e){let t=Error(`Invalid field type ${e}`);super([t],null,null),this.message=`INVALID_FIELD_TYPE`}},C=class extends h.BadRequest{constructor(e,t,n){let r=n.message.replace(/"/g,``).replace(`value`,`'${t}'`),i=typeof e==`object`?JSON.stringify(e):e,a=`Invalid Value on field '${t}'. ${r}. received: '${i}'`;super([Error(a)],null,null),this.message=a}},ye=class extends h.BadRequest{constructor(e,t){let n=t.map(e=>new C(e.value,e.fieldDefinitionName,e.joiValidationError));super(n,null,null),this.message=`Invalid entries on ${e}\n${t.map(e=>`${e.fieldDefinitionName} - ${e.joiValidationError.message}`).join(`
2
+ `)}`}},be=class extends h.BadRequest{constructor(e){let t=Error(`Missing custom field definition for field ${e.join(`,`)}`);super([t],null,null),this.message=`MISSING_DEFINITION`}};const xe=e=>Object.keys(ue).includes(e),Se=(e,t,n)=>{let r=ue[t];return r(e,n)},Ce=(e,t,n=Se)=>{let r=Object.entries(e.customFields).map(([e,r])=>{if(r===null)return null;let{validation:i,fieldType:a}=t[e],o=n(r,a,i);return o?.error?{joiValidationError:o.error,fieldDefinitionName:e,value:r}:null}).filter(e=>!!e);if(r?.length)throw new ye(e.modelId,r)};function w(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function T(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}var we,Te,Ee,De,Oe,ke;let E=class extends u.Model{static displayNameDefaultValue(e){if(e?.displayName||(e.displayName=e.name),![null,void 0].includes(e.defaultValue)){let t=Se(e.defaultValue,e.fieldType,e.validation);if(t.error)throw new C(e.defaultValue,e.name,t.error)}}static afterSaveHandler(e,t){t.transaction?t.transaction.afterCommit(()=>S(e)):S(e)}};T([u.PrimaryKey,(0,u.Column)({type:u.DataType.UUID,defaultValue:u.DataType.UUIDV4,allowNull:!1}),w(`design:type`,String)],E.prototype,`id`,void 0),T([(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,String)],E.prototype,`name`,void 0),T([(0,u.Column)({type:u.DataType.STRING}),w(`design:type`,String)],E.prototype,`displayName`,void 0),T([(0,u.Is)(`SupportedType`,e=>{if(!Object.values(x).includes(e))throw new ge(`"${e}" is not a supported type.`)}),(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,typeof(we=x!==void 0&&x)==`function`?we:Object)],E.prototype,`fieldType`,void 0),T([(0,u.Column)({type:u.DataType.JSONB}),w(`design:type`,Object)],E.prototype,`validation`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],E.prototype,`entityId`,void 0),T([(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,String)],E.prototype,`entityType`,void 0),T([(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,String)],E.prototype,`modelType`,void 0),T([(0,u.Column)({type:u.DataType.TEXT}),w(`design:type`,String)],E.prototype,`description`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN,defaultValue:!1}),w(`design:type`,Boolean)],E.prototype,`required`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN,defaultValue:!1}),w(`design:type`,Boolean)],E.prototype,`disabled`,void 0),T([(0,u.Column)({type:u.DataType.JSONB,allowNull:!0}),w(`design:type`,Object)],E.prototype,`defaultValue`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!1}),w(`design:type`,typeof(Te=typeof Date<`u`&&Date)==`function`?Te:Object)],E.prototype,`createdAt`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!0}),w(`design:type`,typeof(Ee=typeof Date<`u`&&Date)==`function`?Ee:Object)],E.prototype,`updatedAt`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!0}),w(`design:type`,typeof(De=typeof Date<`u`&&Date)==`function`?De:Object)],E.prototype,`deletedAt`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN,defaultValue:!1,allowNull:!1}),w(`design:type`,Boolean)],E.prototype,`blockEditingFromUI`,void 0),T([(0,u.HasMany)(()=>A),w(`design:type`,Array)],E.prototype,`values`,void 0),T([u.BeforeCreate,w(`design:type`,Function),w(`design:paramtypes`,[typeof(Oe=E!==void 0&&E)==`function`?Oe:Object]),w(`design:returntype`,void 0)],E,`displayNameDefaultValue`,null),T([u.AfterSave,w(`design:type`,Function),w(`design:paramtypes`,[typeof(ke=E!==void 0&&E)==`function`?ke:Object,Object]),w(`design:returntype`,void 0)],E,`afterSaveHandler`,null),E=T([(0,u.DefaultScope)(()=>({where:{disabled:!1}})),(0,u.Table)({tableName:`custom_field_definitions`,indexes:[{name:`unique_name_model_type`,fields:[`model_type`,`entity_id`,`name`],unique:!0}],timestamps:!0,validate:{validationByType(){if(!this.validation&&le[this.fieldType])throw b.error(`No custom validation for custom field type ${this.fieldType} found`),new _e(`Validation provided for "${this.fieldType}" is not supported`)}}})],E);var D=E;const Ae=e=>D.create(e),O=(e,t={withDisabled:!1})=>(t.withDisabled?D.unscoped():D).scope(`userScope`).findAll({where:e,transaction:t.transaction,raw:!0,include:t.include}),je=(e,t={withDisabled:!1})=>O({id:{[c.Op.in]:e}},t),Me=(e,t={withDisabled:!1})=>{let{withDisabled:n}=t;return n?D.unscoped().scope(`userScope`).findByPk(e):D.scope(`userScope`).findByPk(e)},Ne=async(e,t,n={})=>{let{include:r,useEntityIdFromInclude:i}=n.modelOptions,a={modelType:e,...!i&&{entityId:{[c.Op.in]:t}}};return D.findAll({where:a,transaction:n.transaction,include:r?.(t),raw:!0})},Pe=e=>D.scope(`userScope`).findOne({where:e}),Fe=async(e,t)=>(await D.scope(`userScope`).update(t,{where:{id:e},returning:!0,individualHooks:!0}))[1][0],Ie=async(e,{findAll:t,modelOptions:n={},withDisabled:r=!1,...i}={withDisabled:!1,modelOptions:{}})=>{let{modelType:a}=e[0]?.dataValues??{},o=new Set,s=[],l=new Set;e.forEach(e=>{let{dataValues:{modelId:t,entityId:n,customFields:r}}=e;s.push(t),l.add(n),Object.keys(r??{}).forEach(e=>{o.add(e)})});let u={modelType:a,entityId:{[c.Op.in]:Array.from(l)},name:{[c.Op.in]:Array.from(o)}},d=await(t??O)(u,{withDisabled:r,modelOptions:n,...i}),f=d.filter(e=>o.has(e.name)),p=Object.fromEntries(f.map(e=>[e.name,e]));if(!d?.length||f.length!==o.size){let e=Array.from(o).filter(e=>!p[e]);throw new be(e)}return p};var Le,Re,ze,Be,Ve,He;let k=class extends u.Model{static validateValueAgainstDefinition(e,t){let{validation:n,fieldType:r,name:i}=t;if(!xe(r))throw new ve(r);if(e.value===null)return;let a=Se(e.value,r,n);if(a.error)throw new C(e.value,i,a.error)}static async validateCustomFieldValues(e){let t=e.map(e=>e.customFieldDefinitionId),n=[...new Set(t)],r=await je(n,{withDisabled:!0});if(!r||r.length!==n.length)throw Error(`Definitions not found`);e.forEach(e=>{let t=r.find(t=>t.id===e.customFieldDefinitionId);t&&this.validateValueAgainstDefinition(e,t)})}static async validateCustomFieldValue(e){let{customFieldDefinitionId:t}=e,n=await Me(t,{withDisabled:!0});this.validateValueAgainstDefinition(e,n)}static afterSaveHandler(e,t){t.transaction?t.transaction.afterCommit(()=>S(e[0])):S(e[0])}};T([u.PrimaryKey,(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],k.prototype,`modelId`,void 0),T([u.PrimaryKey,(0,u.ForeignKey)(()=>D),(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],k.prototype,`customFieldDefinitionId`,void 0),T([(0,u.Column)({type:u.DataType.JSONB,allowNull:!0}),w(`design:type`,Object)],k.prototype,`value`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!1}),w(`design:type`,typeof(Le=typeof Date<`u`&&Date)==`function`?Le:Object)],k.prototype,`createdAt`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!0}),w(`design:type`,typeof(Re=typeof Date<`u`&&Date)==`function`?Re:Object)],k.prototype,`updatedAt`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!0}),w(`design:type`,typeof(ze=typeof Date<`u`&&Date)==`function`?ze:Object)],k.prototype,`deletedAt`,void 0),T([(0,u.BelongsTo)(()=>D,{scope:{disabled:!1}}),w(`design:type`,typeof(Be=D!==void 0&&D)==`function`?Be:Object)],k.prototype,`customFieldDefinition`,void 0),T([u.BeforeBulkCreate,u.BeforeBulkUpdate,w(`design:type`,Function),w(`design:paramtypes`,[Array]),w(`design:returntype`,Promise)],k,`validateCustomFieldValues`,null),T([u.BeforeUpdate,u.BeforeCreate,u.BeforeUpsert,w(`design:type`,Function),w(`design:paramtypes`,[typeof(Ve=k!==void 0&&k)==`function`?Ve:Object]),w(`design:returntype`,Promise)],k,`validateCustomFieldValue`,null),T([u.AfterUpsert,w(`design:type`,Function),w(`design:paramtypes`,[typeof(He=k!==void 0&&k)==`function`?He:Object,Object]),w(`design:returntype`,void 0)],k,`afterSaveHandler`,null),k=T([(0,u.Table)({tableName:`custom_field_values`,timestamps:!0})],k);var A=k,Ue;let j=class extends u.Model{};T([u.PrimaryKey,(0,u.Column)({type:u.DataType.UUID,defaultValue:u.DataType.UUIDV4,allowNull:!1}),w(`design:type`,String)],j.prototype,`id`,void 0),T([(0,u.ForeignKey)(()=>N),(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],j.prototype,`testModelId`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],j.prototype,`fleetId`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!0}),w(`design:type`,String)],j.prototype,`businessModelId`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!0}),w(`design:type`,String)],j.prototype,`demandSourceId`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN}),w(`design:type`,Boolean)],j.prototype,`anotherAttribute`,void 0),T([(0,u.BelongsTo)(()=>N),w(`design:type`,typeof(Ue=N!==void 0&&N)==`function`?Ue:Object)],j.prototype,`testModel`,void 0),j=T([(0,u.Table)({schema:`custom-fields`,tableName:`associated_test_models`,createdAt:!1,updatedAt:!1})],j);var We=j;let M=class extends u.Model{};T([u.PrimaryKey,(0,u.Column)({type:u.DataType.UUID,defaultValue:u.DataType.UUIDV4,allowNull:!1}),w(`design:type`,String)],M.prototype,`id`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],M.prototype,`fleetId`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!0}),w(`design:type`,String)],M.prototype,`businessModelId`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!0}),w(`design:type`,String)],M.prototype,`demandSourceId`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN}),w(`design:type`,Boolean)],M.prototype,`coolAttribute`,void 0),T([(0,u.HasMany)(()=>We),w(`design:type`,Array)],M.prototype,`associatedModels`,void 0),T([(0,u.Column)({type:u.DataType.VIRTUAL}),w(`design:type`,Object)],M.prototype,`customFields`,void 0),M=T([(0,u.Table)({schema:`custom-fields`,tableName:`test_models`,createdAt:!1,updatedAt:!1})],M);var N=M,Ge=function(e){return e.BUSINESS_MODEL=`businessModel`,e.CONTEXT=`context`,e.DEMAND_SOURCE=`demandSource`,e.FLEET=`fleet`,e}(Ge||{});let P=class extends u.Model{};T([u.PrimaryKey,(0,u.Column)({defaultValue:u.DataType.UUIDV4,type:u.DataType.UUID}),w(`design:type`,String)],P.prototype,`id`,void 0),T([(0,u.Column)({type:u.DataType.UUID}),w(`design:type`,String)],P.prototype,`entityId`,void 0),T([(0,u.Column)({type:u.DataType.ENUM(...Object.values(Ge))}),w(`design:type`,String)],P.prototype,`entityType`,void 0),P=T([(0,u.Table)({createdAt:!1,updatedAt:!1})],P);var F=P,Ke;let I=class extends u.Model{};T([u.PrimaryKey,(0,u.Column)({type:u.DataType.UUID,defaultValue:u.DataType.UUIDV4,allowNull:!1}),w(`design:type`,String)],I.prototype,`id`,void 0),T([(0,u.ForeignKey)(()=>F),(0,u.Column)({type:u.DataType.UUID}),w(`design:type`,String)],I.prototype,`contextId`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN}),w(`design:type`,Boolean)],I.prototype,`coolAttribute`,void 0),T([(0,u.Column)({type:u.DataType.VIRTUAL}),w(`design:type`,Object)],I.prototype,`customFields`,void 0),T([(0,u.BelongsTo)(()=>F),w(`design:type`,typeof(Ke=F!==void 0&&F)==`function`?Ke:Object)],I.prototype,`context`,void 0),I=T([(0,u.Table)({createdAt:!1,updatedAt:!1})],I);var qe=I,Je,Ye,Xe,Ze;let L=class extends u.Model{static afterSaveHandler(e,t){t.transaction?t.transaction.afterCommit(()=>S(e[0])):S(e[0])}};T([u.PrimaryKey,(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],L.prototype,`modelId`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],L.prototype,`entityId`,void 0),T([(0,u.Column)({type:u.DataType.JSONB,allowNull:!1,defaultValue:{}}),w(`design:type`,typeof(Je=typeof Record<`u`&&Record)==`function`?Je:Object)],L.prototype,`customFields`,void 0),T([(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,String)],L.prototype,`modelType`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!1}),w(`design:type`,typeof(Ye=typeof Date<`u`&&Date)==`function`?Ye:Object)],L.prototype,`createdAt`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!0}),w(`design:type`,typeof(Xe=typeof Date<`u`&&Date)==`function`?Xe:Object)],L.prototype,`updatedAt`,void 0),T([u.AfterUpsert,w(`design:type`,Function),w(`design:paramtypes`,[typeof(Ze=L!==void 0&&L)==`function`?Ze:Object,Object]),w(`design:returntype`,void 0)],L,`afterSaveHandler`,null),L=T([(0,u.Table)({tableName:`custom_field_entries`,timestamps:!0,indexes:[{name:`idx_cfe_custom_fields`,using:`gin`,operator:`jsonb_path_ops`,fields:[`custom_fields`]}],validate:{async validationByType(){if(!Object.keys(this.customFields??{}).length)return;let e=await Ie([this]);Ce(this,e)}}})],L);var R=L,Qe,$e,et;let z=class extends u.Model{static afterSaveHandler(e,t){t.transaction?t.transaction.afterCommit(()=>S(e)):S(e)}};T([u.PrimaryKey,(0,u.Default)(()=>(0,g.randomUUID)()),(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],z.prototype,`id`,void 0),T([(0,u.Column)({type:u.DataType.UUID,allowNull:!1}),w(`design:type`,String)],z.prototype,`entityId`,void 0),T([(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,String)],z.prototype,`entityType`,void 0),T([(0,u.Column)({type:u.DataType.STRING,allowNull:!1}),w(`design:type`,String)],z.prototype,`modelType`,void 0),T([(0,u.Column)({type:u.DataType.JSONB,allowNull:!1}),w(`design:type`,Object)],z.prototype,`schema`,void 0),T([(0,u.Column)({type:u.DataType.BOOLEAN,allowNull:!1,defaultValue:!1}),w(`design:type`,Boolean)],z.prototype,`disabled`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!1}),w(`design:type`,typeof(Qe=typeof Date<`u`&&Date)==`function`?Qe:Object)],z.prototype,`createdAt`,void 0),T([(0,u.Column)({type:u.DataType.DATE,allowNull:!0}),w(`design:type`,typeof($e=typeof Date<`u`&&Date)==`function`?$e:Object)],z.prototype,`updatedAt`,void 0),T([u.AfterUpsert,w(`design:type`,Function),w(`design:paramtypes`,[typeof(et=z!==void 0&&z)==`function`?et:Object,Object]),w(`design:returntype`,void 0)],z,`afterSaveHandler`,null),z=T([(0,u.DefaultScope)(()=>({where:{disabled:!1}})),(0,u.Table)({tableName:`custom_validators`,timestamps:!0})],z);var B=z;const tt=[D,A,B],nt=[N,We,qe,F],rt=`sadot-migration`,it=`49c9dd1d-b1cc-445b-a911-fd349d783110`,at=async(e,t,{schemaPrefix:n=`sadot-migration`,schemaVersion:r=`49c9dd1d-b1cc-445b-a911-fd349d783110`,useCustomFieldsEntries:i=!1}={})=>{let a=`${n}_${r}${i?`_withEntries`:``}`;if(b.info(`custom-fields: initialize custom-fields tables`),!e.addModels)throw Error(`sequelize instance must have addModels function`);i&&tt.push(R),e.addModels(tt),D.addScope(`userScope`,()=>{let e=t();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),B.addScope(`userScope`,()=>{let e=t();return e?.permissions?{where:{entityId:[...Object.keys(e.permissions.fleets),...Object.keys(e.permissions.businessModels),...Object.keys(e.permissions.demandSources)]}}:{}}),b.info(`custom-fields: models added`);let o=e.define(`SequelizeMeta`,{name:{type:c.DataTypes.STRING,allowNull:!1,unique:!0,primaryKey:!0,autoIncrement:!1}},{tableName:`SequelizeMeta`,timestamps:!1,schema:`public`});b.info(`custom-fields: starting migrations`);let s=await o.findAll({where:{name:{[c.Op.like]:`${n}%`}},raw:!0}),l=s.at(-1),u=s.findIndex(e=>e.name===a);if(b.info(`custom-fields: migrations`,{migrations:s,currentSadotSchemaVersion:l,expectedSchemaVersionIndex:u}),(!l||l.name!==a)&&(b.info(`custom-fields: syncing models`),await D.sync({alter:!0}),await A.sync({alter:!0}),i&&await R.sync({alter:!0}),await B.sync({alter:!0}),u===-1&&await o.create({name:a}),b.info(`custom-fields: models synced`),s.length&&u!==-1&&u<s.length-1)){let e=s.slice(u+1);await o.destroy({where:{name:{[c.Op.in]:e.map(e=>e.name)}}})}},ot=async e=>{if(b.info(`custom-fields: initialize custom-fields test models`),!e.addModels)throw Error(`sequelize instance must have addModels function`);e.addModels(nt),await e.dropSchema(`custom-fields`,{logging:!1}),await e.createSchema(`custom-fields`,{logging:!1}),b.info(`custom-fields: test models added`),await N.sync({alter:!0}),await We.sync({alter:!0}),await F.sync({alter:!0}),await qe.sync({alter:!0}),b.info(`custom-fields: test models synced`)};var V=(e,t,n=void 0)=>{let r=e;return[f.ValidationError,c.ValidationError].some(t=>e instanceof t)&&(r=new h.BadRequest([e],null)),(0,h.handleError)(r,t,n)};const st=f.default.object({name:f.default.string().required(),type:f.default.string(),size:f.default.string(),addedBy:f.default.string().uuid()}),ct=f.default.object({value:f.default.string().required(),color:f.default.string().required()}),lt=f.default.when(`fieldType`,{is:x.SELECT,then:f.default.array().required().items(f.default.string()).min(1).unique(),otherwise:f.default.when(`fieldType`,{is:x.STATUS,then:f.default.array().required().items(ct).min(1).unique(`value`),otherwise:f.default.forbidden()})}),ut=f.default.when(`fieldType`,{switch:[{is:x.BOOLEAN,then:f.default.boolean().allow(null)},{is:x.DATE,then:f.default.date().allow(null)},{is:x.DATETIME,then:f.default.date().allow(null)},{is:x.FILE,then:f.default.array().items(st).allow(null)},{is:x.IMAGE,then:f.default.array().items(f.default.string().uri()).allow(null)},{is:x.NUMBER,then:f.default.number().allow(null)},{is:x.SELECT,then:f.default.string().allow(null)},{is:x.STATUS,then:f.default.string().allow(null)},{is:x.TEXT,then:f.default.string().allow(null)}]}),dt=f.default.object({name:f.default.string().required(),displayName:f.default.string().required(),validation:lt,defaultValue:ut,fieldType:f.default.string().valid(...Object.values(x)).required(),entityId:f.default.string().guid().required(),entityType:f.default.string().required(),description:f.default.string(),required:f.default.boolean(),disabled:f.default.boolean(),blockEditingFromUI:f.default.boolean()}).oxor(`required`,`blockEditingFromUI`,{isPresent:e=>e===!0}),ft=f.default.object({displayName:f.default.string(),validation:lt,defaultValue:ut,fieldType:f.default.string().valid(...Object.values(x)),description:f.default.string().allow(null),required:f.default.boolean(),disabled:f.default.boolean(),blockEditingFromUI:f.default.boolean()}).oxor(`required`,`blockEditingFromUI`,{isPresent:e=>e===!0}),pt=e=>dt.validateAsync(e,{abortEarly:!1}),mt=e=>ft.validateAsync(e,{abortEarly:!1}),H=(0,_.Router)({logger:b}),U=`CustomFieldDefinition`,ht=e=>e.replace(/(^\w|-\w)/g,e=>e.replace(/-/,``).toUpperCase());H.post(`/`,async(e,t)=>{let{modelName:n}=e.params,r=ht(n);try{let n=await pt(e.body),i=await Ae({...n,modelType:r});return t.status(201).json(i)}catch(e){return b.error(`Failed to create custom field definition`,e),V(e,t,{logger:b,message:`Error in create ${U} request`})}}),H.get(`/:customFieldDefinitionId`,async(e,t)=>{let{customFieldDefinitionId:n}=e.params;try{let e=await Me(n);if(!e)throw new h.ResourceNotFoundError;return t.json(e)}catch(e){return b.error(`Failed to fetch custom field definition`,e),V(e,t,{logger:b,message:`Error in get ${U} request`})}}),H.get(`/`,async(e,t)=>{let{params:{modelName:n},query:{entityIds:r}}=e,i=ht(n);try{let e={modelType:i,...r?.length>0&&{entityId:r}},n=await O(e,{withDisabled:!0});return t.json(n)}catch(e){return b.error(`Failed to fetch custom field definitions`,e),V(e,t,{logger:b,message:`Error in get all ${U} request`})}}),H.patch(`/:customFieldDefinitionId`,async(e,t)=>{let{customFieldDefinitionId:n,modelName:r}=e.params,i=ht(r);try{let r=await mt(e.body);if(!await Pe({id:n,modelType:i}))throw new h.ResourceNotFoundError;let a=await Fe(n,{...r,modelType:i});return t.status(200).json(a)}catch(e){return b.error(`Failed to patch custom field definition`,e),V(e,t,{logger:b,message:`Error in update ${U} request`})}});var gt=H;const _t=async(e,t={})=>(b.debug(`custom-validator - create validator`),await B.create(e,t)),W=async(e={},t={})=>{b.debug(`custom-validator - find all validators`);let{transaction:n,withDisabled:r,include:i,attributes:a,raw:o}=t,s;return s=r?await B.unscoped().scope(`userScope`).findAll({where:e,transaction:n,include:i,attributes:a,raw:o}):await B.scope([`defaultScope`,`userScope`]).findAll({where:e,transaction:n,include:i,attributes:a,raw:o}),s},vt=async(e,t,n={})=>(b.debug(`custom-validator - find all validators by model type`),W({modelType:e,...!n?.modelOptions?.useEntityIdFromInclude&&{entityId:t}},{...n,include:n?.modelOptions?.include?.(t)})),yt=async(e,t,n)=>(b.debug(`custom-validator - update validator`),B.update(t,{where:{id:e},returning:!0,...n})),bt=async(e,t)=>(b.debug(`custom-validator - disable validator`),yt(e,{disabled:!0},t)),xt=f.default.object().unknown(!0),St=f.default.object({type:f.default.string().valid(`object`),properties:f.default.object({before:xt,after:xt}).required(),required:f.default.array().items(f.default.string()),allOf:f.default.array().items(f.default.object()),anyOf:f.default.array().items(f.default.object()),oneOf:f.default.array().items(f.default.object()),additionalProperties:f.default.alternatives().try(f.default.boolean(),f.default.object()),$id:f.default.string(),$schema:f.default.string(),if:f.default.object(),then:f.default.object(),else:f.default.object()}),Ct={create:f.default.object({entityId:f.default.string().uuid().required(),entityType:f.default.string().required(),schema:St.required()}),update:f.default.object({entityId:f.default.string().uuid(),entityType:f.default.string(),schema:St,disabled:f.default.boolean()}).min(1)};var wt=Ct;const Tt=new ee.default({allErrors:!0,strict:!1,strictTypes:!1,$data:!0});(0,y.default)(Tt);const Et={type:`object`,properties:{type:{type:`string`,enum:[`object`]},properties:{type:`object`,properties:{before:{type:`object`,properties:{type:{type:`string`,enum:[`object`]},properties:{type:`object`}}},after:{type:`object`,properties:{type:{type:`string`,enum:[`object`]},properties:{type:`object`}}}}},required:{type:`array`,items:{type:`string`}},if:{type:`object`},then:{type:`object`},else:{type:`object`}},required:[`type`,`properties`]},Dt=e=>{try{let t=Tt.compile(Et);if(!t(e)){let n=t.errors?.map(e=>`${e.instancePath||``} ${e.message||`Invalid schema structure`}`).join(`, `);throw b.error(`Invalid validator schema structure`,{errors:t.errors,schema:e}),new h.BadRequest([Error(`Invalid validator schema structure: ${n}`)],[`Invalid validator schema structure`])}try{return Tt.compile(e),!0}catch(t){throw b.error(`Failed to compile validator schema`,{error:t,schema:e}),new h.BadRequest([Error(`Failed to compile validator schema: ${t.message}`)],[`Invalid validator schema`])}}catch(t){throw t instanceof h.BadRequest?t:(b.error(`Error validating validator schema`,{error:t,schema:e}),new h.BadRequest([Error(`Error validating validator schema: ${t.message}`)],[`Invalid validator schema`]))}},G=(0,_.Router)({logger:b}),K=`CustomValidator`;G.post(`/`,async(e,t)=>{let{modelName:n}=e.params;try{let r=await wt.create.validateAsync(e.body);Dt(r.schema);let i=await _t({...r,modelType:n});return t.status(v.StatusCodes.CREATED).json(i)}catch(e){return V(e,t,{logger:b,message:`Error in create ${K} request`})}}),G.get(`/`,async(e,t)=>{try{let{modelName:n}=e.params,{entityId:r,entityType:i}=e.query,a={modelType:n,...r&&{entityId:r},...i&&{entityType:i}},o=await W(a);return t.status(v.StatusCodes.OK).json({validators:o})}catch(e){return V(e,t,{logger:b,message:`Error in get all ${K} request`})}}),G.get(`/:validatorId`,async(e,t)=>{try{let{validatorId:n,modelName:r}=e.params,i=await W({id:n,modelType:r},{withDisabled:!0});if(!i.length)throw new h.ResourceNotFoundError(`Validator not found`);return t.status(v.StatusCodes.OK).json(i[0])}catch(e){return V(e,t,{logger:b,message:`Error in get ${K} request`})}}),G.patch(`/:validatorId`,async(e,t)=>{try{let{validatorId:n}=e.params,r=await wt.update.validateAsync(e.body);if(r.schema&&Dt(r.schema),!(await W({id:n},{withDisabled:!0})).length)throw new h.ResourceNotFoundError(`Validator not found`);let[i,a]=await yt(n,r);if(!i)throw new h.ResourceNotFoundError(`Validator not found`);return t.status(v.StatusCodes.OK).json(a[0])}catch(e){return V(e,t,{logger:b,message:`Error in update ${K} request`})}}),G.delete(`/:validatorId`,async(e,t)=>{try{let{validatorId:n}=e.params;if(!(await W({id:n},{withDisabled:!0})).length)throw new h.ResourceNotFoundError(`Validator not found`);let[r]=await bt(n);if(!r)throw new h.ResourceNotFoundError(`Validator failed to be disabled`);return t.status(v.StatusCodes.NO_CONTENT).send()}catch(e){return V(e,t,{logger:b,message:`Error in delete ${K} request`})}});var Ot=G;const kt=(0,_.Router)({logger:b});kt.use(`/custom-field-definitions/:modelName`,gt),kt.use(`/custom-validators/:modelName`,Ot);var At=kt;const jt=(0,_.Router)({logger:b});jt.use(`/v1`,At);var Mt=jt,Nt=e=>{let t=process.env.NODE_ENV||`test`,n=e[t],r;return r=n.use_env_variable?new u.Sequelize(process.env[n.use_env_variable],n):new u.Sequelize(n.database,n.username,n.password,n),r};const Pt={[x.DATE]:e=>{if(e){let t=new Date(e);if(t.toString()===`Invalid Date`)throw Error(`Invalid date value: ${e}`);return t.toISOString()}return null}},Ft=async(e,t)=>{let{transaction:n}=t;return A.findAll({where:{modelId:e},transaction:n,raw:!0,nest:!0})},It=async(e,t,n,r,i={})=>{let a=Object.keys(r);b.debug(`custom-fields: updating values for ${e} ${t}`,{names:a,optionsKeys:i?Object.keys(i):null,valuesToUpdate:r,identifiers:n});let{modelOptions:o,transaction:s}=i,c={modelType:e,name:a,...!i.modelOptions?.useEntityIdFromInclude&&{entityId:n}},l=await O(c,{withDisabled:!0,transaction:s,include:o.include?.(n)})??[],u=l.filter(e=>e.disabled);if(l.length!==a.length){b.warn(`custom-fields: missing definitions for ${e} ${t}`,{names:a,fieldDefinitions:l});let n=a.filter(e=>!l.some(t=>t.name===e));throw new be(n)}let d=u?.map(e=>e.name)||[],f=a.filter(e=>d.includes(e));f?.length>0&&b.warn(`custom-fields: trying to update disabled values: ${f.join(`, `)}`);let p=a.map(e=>{let n=l.find(t=>t.name===e),i=Pt[n.fieldType],a=i?i(r[e]):r[e];return{modelId:t,updatedAt:new Date,customFieldDefinitionId:n.id,value:a===void 0?n.defaultValue:a}});return Promise.all(p.map(async e=>{let[t]=await A.upsert(e,{transaction:i.transaction});return t}))},Lt=async(e,t={})=>{let{transaction:n}=t;return R.findOne({where:{modelId:e},transaction:n})},Rt=async(e,t={})=>{let{transaction:n}=t;return R.findAll({where:{modelId:e},transaction:n})},zt=async(e,t,n,r,i={})=>{let a=Object.keys(n);b.debug(`custom-fields: updating entries for ${t} ${e}`,{customFieldsNames:a,optionsKeys:i?Object.keys(i):null,customFields:n,identifiers:r});let{modelOptions:o,transaction:s}=i,c={modelType:t,name:a,...!i.modelOptions?.useEntityIdFromInclude&&{entityId:r}},l=await O(c,{withDisabled:!0,transaction:s,include:o.include?.(r)})??[],u=l.filter(e=>e.disabled);if(l.length!==a.length){b.warn(`custom-fields: missing definitions for ${t} ${e}`,{names:a,fieldDefinitions:l});let n=a.filter(e=>!l.some(t=>t.name===e));throw new be(n)}let d=u?.map(e=>e.name)||[],f=a.filter(e=>d.includes(e));f?.length>0&&b.warn(`custom-fields: trying to update disabled values: ${f.join(`, `)}`);let p=Object.fromEntries(l.map(e=>[e.name,e]));return Object.entries(n).filter(([e])=>Pt[p[e].fieldType]).forEach(([e,t])=>{let{fieldType:r}=p[e];n[e]=Pt[r](t)}),R.upsert({modelId:e,entityId:l[0].entityId,modelType:t,customFields:n},i)},Bt=(e,t)=>e.map(e=>t[e]),Vt=(e,t)=>{let n=Array.from(new Set(t));return Array.isArray(e)?e.flatMap(e=>Bt(n,e)):Bt(n,e)};var q=Vt;const Ht=[`id`,`name`,`entityId`,`fieldType`,`displayName`,`validation`,`entityType`,`modelType`,`required`,`disabled`,`defaultValue`],Ut=async({instancesIds:e,options:t,sadotOptions:n})=>{if(!n.useCustomFieldsEntries)return{};let r=await Rt(e,t??{}),i=Object.fromEntries(r.map(e=>{let{modelId:t,customFields:n}=e?.dataValues??{};if(t)return[t,n]}).filter(Boolean));return e.forEach(e=>{i[e]??={}}),i},Wt=async({instancesIds:e,options:t,sadotOptions:n})=>n.useCustomFieldsEntries?{}:(await Ft(e,t??{})).reduce((e,t)=>{let{modelId:n}=t;return e[n]??=[],e[n].push(t),e},{}),Gt=(e,t)=>e.reduce((e,n)=>({...e,...t[n.customFieldDefinitionId]&&{[t[n.customFieldDefinitionId].name]:n.value}}),{}),Kt=(e,t,n,r={},i={useCustomFieldsEntries:!1})=>async(a,o)=>{if(o.originalAttributes?.length>0&&!o.originalAttributes?.includes?.(`customFields`))return;let s=Array.isArray(a)?a:[a];s=s.filter(Boolean);let c=q(s,t),l=[...new Set(c)].filter(Boolean),u=l.reduce((e,t)=>({...e,[t]:[]}),{}),d,f;o.transaction&&(o.transaction.definitionCache||=new Map,f=`${e}:${l.slice().sort().join(`,`)}`,d=o.transaction.definitionCache.get(f)),d||(d=Ne(e,l,{transaction:o.transaction,modelOptions:r,attributes:Ht}),o.transaction?.definitionCache?.set(f,d));let p=await d;if(p.length===0){s.forEach(e=>{e.customFields={}});return}r?.include&&r.useEntityIdFromInclude&&r.include(c).forEach(({model:e})=>{p.forEach(t=>{let n=t[`${e.name}.entityId`];u[n]=[]})});let m=p.reduce((e,t)=>({...e,[t.id]:t}),{});p.forEach(e=>{u[e.entityId].push(e)});let h=s.map(e=>e.id),[g,_]=await Promise.all([Wt({instancesIds:h,options:o,sadotOptions:i}),Ut({instancesIds:h,options:o,sadotOptions:i})]);s.forEach(e=>{let{id:r}=e,a=g[r],s=a?Gt(a,m):{},c=i.useCustomFieldsEntries?_[r]:s;t.forEach(t=>{let n=e[t],r=u[n];r?.length>0&&r.forEach(e=>{c[e.name]===void 0&&(c[e.name]=null)})}),e.customFields=c,o.attributesToRemove?.forEach?.(t=>{delete e.dataValues?.[t],delete e?.[t]}),n===`afterFind`&&e?.changed?.(`customFields`,!1)})};var qt=Kt;const Jt=(e,t)=>{let n=e.filter(e=>!t.includes(e));return t.includes?.(`id`)||n.push(`id`),n},Yt=e=>t=>{let{attributes:n}=t;if(n?.includes?.(`customFields`)){let r=Jt(e,n);b.debug(`sadot - before find hook`),r?.length>0&&(n.push(...r),t.attributesToRemove=r)}},Xt=async({modelId:e,modelType:t,identifiers:n,customFields:r,options:i={modelOptions:{},useCustomFieldsEntries:!1}})=>{if(await It(t,e,n,r,{...i,modelOptions:i.modelOptions??{}}),!i?.useCustomFieldsEntries)return;let{dataValues:{customFields:a}}=await Lt(e,i)??{dataValues:{}},o={...a,...r};await zt(e,t,o,n,{...i,modelOptions:i.modelOptions??{}})};var Zt=Xt;const Qt=[`id`,`schema`,`modelType`,`entityId`,`disabled`],J=new ee.default({allErrors:!0,strict:!1,strictTypes:!1,$data:!0});(0,y.default)(J),(0,ne.default)(J);const $t=(e,t)=>({__proto__:null,...e,...t}),en=async(e,t)=>{if(!e.id||!e.customFields||Object.keys(e.customFields).length===0)return e.customFields||{};try{let n=await e.constructor.findOne({where:{id:e.id},attributes:[`customFields`],transaction:t.transaction,raw:!0});if(n?.customFields){let t=$t(n.customFields,e.customFields);return b.debug(`sadot - fetched complete custom fields for validation`,{fieldsCount:Object.keys(t).length,updateFieldsCount:Object.keys(e.customFields).length}),t}}catch(e){b.error(`sadot - error fetching complete model for validation`,{error:e})}return e.customFields||{}},tn=e=>{let t={...e.dataValues};(e.changed?.()||[]).forEach(n=>{let r=e.previous?.(n);r!==void 0&&(t[n]=r)});let n=e.previous?.(`customFields`);return n!==void 0&&(t.customFields=n),t},nn=e=>e.reduce((e,t)=>{let n=(t.instancePath||``).split(`/`).filter(Boolean).join(`.`).replace(/^after\./,``),r=t.keyword===`required`?`.${t.params?.missingProperty}`:``,i=(n+r).replace(/^\./,``)||`root`;return e[i]=t.message||`Invalid value`,e},{}),rn=async(e,t,n,r={},i=!1)=>{let a=e.constructor.name;b.debug(`sadot - validating model`,{isCreate:i,modelType:a});let o=q(e,n);if(b.debug(`sadot - identifiers`,{identifiers:o}),!o||Object.keys(o).length===0){b.debug(`sadot - skipping validation: no identifiers`);return}let s=Object.values(o)[0];if(b.debug(`sadot - entityId`,{entityId:s}),!s){b.debug(`sadot - skipping validation: no entityId`);return}let c,l;t.transaction&&(t.transaction.validationsCache||=new Map,l=`${a}-${s}`,c=t.transaction.validationsCache.get(l)),c||(c=vt(a,s,{transaction:t.transaction,attributes:Qt,modelOptions:r}),t.transaction&&t?.transaction?.validationsCache.set(l,c));let u=await c;if(b.debug(`sadot - validators found`,{count:u.length}),!u.length){b.debug(`sadot - skipping validation: no validators found`);return}let d=null;i||(d=tn(e));let f=i?e.customFields||{}:await en(e,t);for(let t of u){let{schema:n}=t,r=n;if(b.debug(`sadot - validating with schema`,{schema:n,hasAfterProps:!!r.properties?.after,hasBeforeProps:!!r.properties?.before}),i){if(r.properties?.after){let t=J.compile({...n,properties:{after:r.properties.after}});if(!t(JSON.parse(JSON.stringify({after:{...e.dataValues,customFields:f}})))){let e=t.errors?.map(e=>`${e.instancePath||``} ${e.message||`Invalid value`}`).join(`, `),n=nn(t.errors);throw new h.BadRequest([Error(`Validation failed for ${a}: ${e}`)],void 0,{customError:n})}}}else{let t=J.compile(r),n=$t(e.dataValues);n.customFields=f;let i={before:d,after:n},o=t(JSON.parse(JSON.stringify(i)));if(b.debug(`sadot - validation result`,{isValid:o,test:{before:d,after:n}}),!o){let e=t.errors?.map(e=>`${e.instancePath||``} ${e.message||`Invalid value`}`).join(`, `),n=nn(t.errors);throw new h.BadRequest([Error(`Validation failed for ${a}: ${e}`)],void 0,{customError:n})}}}},an=async({modelType:e,modelOptions:t,identifiers:n,options:r})=>{let{include:i,useEntityIdFromInclude:a}=t,o={modelType:e,disabled:!1,...!a&&{entityId:n}};return await O(o,{withDisabled:!1,transaction:r.transaction,include:i?.(n)})},on=(e,t)=>{(e||[]).forEach(e=>{let{fieldType:n,name:r}=e;if([x.DATE,x.DATETIME].includes(n)){let e=t.customFields?.[r];if(e){let{value:n,error:i}=f.default.date().validate(e);if(i)throw new C(e,r,i);t.customFields[r]=n.toISOString()}}})},sn=(e,t={},n={useCustomFieldsEntries:!1})=>async(r,i)=>{b.debug(`sadot - before create hook`);let{fields:a}=i,o=r.constructor.name,s=q(r,e),c=await an({modelType:o,modelOptions:t,identifiers:s,options:i}),l=c.filter(e=>![null,void 0].includes(e.defaultValue));l.length&&(r.customFields||={},l.filter(e=>r.customFields?.[e.name]===void 0).forEach(({name:e,defaultValue:t})=>{r.customFields[e]=t}));let u=Array.from(new Set(c.filter(({required:e})=>e).map(({name:e})=>e))),{customFields:d}=r,f=Object.keys(d??{}),p=u.filter(e=>!f.includes(e));if(p?.length)throw new he(p);await rn(r,i,e,t,!0),on(c,r);let m=a.indexOf(`customFields`);m===-1||!d||!Object.keys(d).length||(await Zt({modelId:r.id,modelType:o,identifiers:s,customFields:d,options:{useCustomFieldsEntries:n.useCustomFieldsEntries,transaction:i.transaction,modelOptions:t}}),a.splice(m,1))},cn=(e,t={},n={useCustomFieldsEntries:!1})=>async(r,i)=>{b.debug(`sadot - before update hook`);let{fields:a}=i,o=r.constructor.name,s=q(r,e),c=await an({modelType:o,modelOptions:t,identifiers:s,options:i});await rn(r,i,e,t,!1),on(c,r);let l=a.indexOf(`customFields`);if(l>-1){let{customFields:e}=r;if(!Object.keys(e).length)return;await Zt({modelId:r.id,modelType:o,identifiers:s,customFields:e,options:{useCustomFieldsEntries:n.useCustomFieldsEntries,transaction:i.transaction,modelOptions:t}}),a.splice(l,1)}},ln=e=>{e.individualHooks=!0},un=e=>{e.individualHooks=!0},dn=(e=5)=>Array.from({length:e},()=>`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.charAt((0,g.randomInt)(52))).join(``),fn=(e,t,n,r=[x.DATETIME,x.DATE])=>{let i=r.map(e=>`'${e}'`).join(`,`),a=`EXISTS ( SELECT 1 FROM "custom_field_values" AS "cv" INNER JOIN custom_field_definitions AS cd ON cd.entity_id = '${n}' AND cv.custom_field_definition_id = cd.id AND cd.model_type = '${t.name}' ${i?`AND cd.field_type NOT IN (${i})`:``} WHERE "cv"."deleted_at" IS NULL AND "cv"."model_id" = "${t.name}"."id" AND CAST("cv"."value" AS TEXT) ILIKE :searchTerm)`;return{where:{[c.Op.or]:[u.Sequelize.where(u.Sequelize.literal(a),!0)]},replacements:{searchTerm:`%${e}%`}}};let Y=function(e){return e.VALUES=`values`,e.ENTRIES=`entries`,e}({});const pn=e=>Array.isArray(e)&&typeof e[0]==`string`,X=e=>[`true`,`false`].includes(e.toString()),mn=e=>e instanceof Date||Object.prototype.toString.call(e)===`[object Date]`,hn=(e,t)=>`to_jsonb(${e}::${t})`,Z=e=>hn(e,`text`),gn=e=>hn(e,`boolean`),_n=e=>hn(e,`numeric`),vn=(e,t)=>mn(t)?hn(e,`timestamp`):e,Q=` AND `,yn=` OR `,bn=`cd`,xn=`cd.name`,Sn=`cv`,$=`cv.value`,Cn=`ce`,wn=(e,t,n,r)=>{let i=`text`;mn(e)?i=`date`:Number.isNaN(Number(e))?X(e)&&(i=`boolean`):i=`numeric`;let a=r.get(e);return`(jsonb_extract_path_text(ce.custom_fields, :${n})::${i}) ${t} :${a}`},Tn=e=>{let t=e;return X(e)?t=e===`true`:Number.isNaN(Number(e))||(t=Number(e)),t},En=(e,t)=>{let n=Tn(e),r=JSON.stringify({[t]:n}),i;return X(e)&&(i=`ce.custom_fields @> '${JSON.stringify({[t]:e})}'`),`
3
+ (
4
+ ${i?`${i} OR`:``}
5
+ ce.custom_fields @> '${r}'
6
+ )
7
+ `},Dn=(e,t,n)=>{switch(e){case Y.VALUES:return`
8
+ SELECT cv.model_id
9
+ FROM custom_field_values AS cv
10
+ INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
11
+ ${Q}cd.model_type = '${t}'
12
+ WHERE ${n.join(yn)}
13
+ ${Q}cv.deleted_at IS NULL${Q}cd.deleted_at IS NULL
14
+ GROUP BY cv.model_id
15
+ HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${n.length}
16
+ `.replace(/\n/g,``);case Y.ENTRIES:return`
17
+ SELECT ce.model_id
18
+ FROM custom_field_entries ce
19
+ JOIN custom_field_definitions cfd
20
+ ON ce.model_type = cfd.model_type
21
+ AND ce.entity_id = cfd.entity_id
22
+ WHERE
23
+ cfd.deleted_at IS NULL AND
24
+ ${n.join(Q)}
25
+ `;default:throw Error(`Invalid query type`)}},On=(e,t,n)=>{switch(e){case Y.VALUES:return`(
26
+ SELECT value
27
+ FROM (SELECT cv.model_id, cv.value
28
+ FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd
29
+ ON cv.custom_field_definition_id = cd.id
30
+ ${Q}cd.model_type = '${t}'
31
+ WHERE cv.model_id = "${t}"."id"
32
+ ${Q}cd.name = :${n}
33
+ ) AS CustomFieldAggregation
34
+ )
35
+ `;case Y.ENTRIES:return`(
36
+ SELECT
37
+ customFields.value
38
+ FROM
39
+ custom_field_entries AS ce,
40
+ jsonb_each_text(custom_fields) AS customFields
41
+ WHERE
42
+ customFields.key = :${n}${Q}
43
+ ce.model_type = '${t}'${Q}
44
+ ce.model_id = "${t}"."id"
45
+ )
46
+ `;default:throw Error(`Invalid query type`)}},kn=(e,t,n)=>{let r=n.get(e);if(!r)return!1;let i=`(cd.name = :${r})`;if(Array.isArray(t)){if(t.length===0)return!1;if(pn(t)){let e=t.flatMap(e=>{let t=n.get(e);return X(e)?[Z(`:${t}`),gn(`:${t}`)]:Number.isNaN(Number(e))?Z(`:${t}`):_n(`:${t}`)}).join(`,`);return`(${i}${Q}${$} IN (${e}))`}return t.map(e=>{let t=n.get(e.value),r=Z(`:${t}`);return`(${i}${Q}${vn($,e.value)} ${e.operator} ${r})`}).join(Q)}if(typeof t==`string`||typeof t==`number`){let e=n.get(t),r=Number.isNaN(Number(t))?Z(`:${e}`):_n(`:${e}`),a=X(t)?`${yn}${$} = ${gn(`:${e}`)}`:``;return`(${i}${Q}(${vn($,t)} = ${r}${a}))`}if(t?.operator){let e=n.get(t.value),r=Z(`:${e}`);return`( ${i}${Q}${vn($,t.value)} ${t.operator} ${r})`}return!1},An=(e,t,n)=>{let r=n.get(e);return r?Array.isArray(t)?t.length===0?!1:pn(t)?`( ${t.map(t=>En(t,e)).join(`${yn}\n`)})`:t.map(e=>wn(e.value,e.operator,r,n)).join(Q):typeof t==`string`||typeof t==`number`?En(t,e):t?.operator?wn(t.value,t.operator,r,n):!1:!1},jn=(e,t)=>({replacementsMap:n,scopeValue:r})=>{if(!r||Object.keys(r).length===0)return{};let i=t?.useCustomFieldsEntries?Y.ENTRIES:Y.VALUES,a=new Map(Object.entries(n).map(([e,t])=>[t,e])),o=Object.entries(r).map(([e,t])=>{switch(i){case Y.ENTRIES:return An(e,t,a);case Y.VALUES:return kn(e,t,a);default:return!1}}).filter(Boolean);if(o.length===0)return{};let s=Dn(i,e,o);return{where:{id:{[c.Op.in]:u.Sequelize.literal(`(${s})`)}},replacements:n}},Mn=d.customFields.CUSTOM_FIELDS_FILTER_SCOPE,Nn=(e,t)=>({replacementsMap:n,scopeValue:r})=>{if(!r||r.length===0)return{};let i=t?.useCustomFieldsEntries?Y.ENTRIES:Y.VALUES,a=dn(),o=Object.entries(r).map(([t])=>{let r=Object.keys(n).find(e=>n[e]===t);return[u.Sequelize.literal(On(i,e,r)),a]}),s=Object.entries(r).map(([,e])=>{let t=typeof e==`string`?e:Object.values(e)[0];return u.Sequelize.literal(`"${a}" ${t||`ASC`}`)});return{attributes:{include:o},order:s,replacements:n}},{CUSTOM_FIELDS_FILTER_SCOPE:Pn}=d.customFields,Fn=(e,t,n={useCustomFieldsEntries:!1})=>{e.forEach(async({name:e,scopeAttributes:r,modelOptions:i})=>{try{let a=t(e);if(!a){b.warn(`sadot - tried to addHooks to a model that does not exist yet`,{name:e,scopeAttributes:r});return}a.rawAttributes.customFields={type:c.DataTypes.VIRTUAL},a.refreshAttributes(),a.addHook(`beforeFind`,`sadot-beforeFind`,Yt(r)),a.addHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`,ln),a.addHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`,un),a.addHook(`beforeCreate`,`sadot-beforeCreate`,sn(r,i,n)),a.addHook(`beforeUpdate`,`sadot-beforeUpdate`,cn(r,i,n)),a.addHook(`afterFind`,`sadot-afterFind`,qt(e,r,`afterFind`,i,n)),a.addHook(`afterUpdate`,`sadot-afterUpdate`,qt(e,r,null,i,n)),a.addHook(`afterCreate`,`sadot-afterCreate`,qt(e,r,null,i,n))}catch(t){b.error(`Could not add custom fields hook to model ${e}. `,t)}})},In=(e,t)=>{e.forEach(async({name:e})=>{try{let n=t(e);if(!n)return;n.rawAttributes.customFields&&(delete n.rawAttributes.customFields,n.refreshAttributes()),n.removeHook(`beforeFind`,`sadot-beforeFind`),n.removeHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`),n.removeHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`),n.removeHook(`beforeCreate`,`sadot-beforeCreate`),n.removeHook(`beforeUpdate`,`sadot-beforeUpdate`),n.removeHook(`afterFind`,`sadot-afterFind`),n.removeHook(`afterUpdate`,`sadot-afterUpdate`)}catch(t){b.error(`Could not add custom fields hook to model ${e}. `,t)}})},Ln=(e,t,n)=>{n?.useCustomFieldsEntries||(e.hasMany(A,{foreignKey:`modelId`,as:`customFieldValue`}),A.belongsTo(e,{foreignKey:`modelId`,as:t}))},Rn=(e,t,n={useCustomFieldsEntries:!1})=>{e.forEach(async({name:e,scopeAttributes:r})=>{try{let i=t(e);if(!i){b.warn(`sadot - tried to addScopes to a model that does not exist yet`,{name:e,scopeAttributes:r});return}Ln(i,e,n),i.addScope(Pn,jn(e,n)),i.addScope(te.CUSTOM_FIELDS_SORT_SCOPE,Nn(e,n))}catch(t){b.error(`Could not add custom fields scopes to model ${e}. `,t)}})},zn=e=>{e.forEach(({modelOptions:e})=>{e?.customAssociation?.(D),e?.customAssociation?.(B)})},Bn=f.default.object().pattern(f.default.string(),f.default.any()),Vn=async(e,t,n)=>{ie().catch(()=>null);let{models:r,useCustomFieldsEntries:i}=n;e&&e.use(`/api`,Mt);let a=n.sequelize??Nt(n.databaseConfig);return process.env.NODE_ENV===`test`&&await ot(a),Fn(r,t,{useCustomFieldsEntries:i}),await at(a,n.getUser,{useCustomFieldsEntries:i}),Rn(r,t,{useCustomFieldsEntries:i}),zn(r),b.debug(`sadot - custom fields finished initializing with models`,r),a};var Hn=Vn;const Un=(e,t)=>{In(e,t)};exports.AssociatedTestModel=We,exports.CUSTOM_FIELDS_FILTER_SCOPE=oe,exports.ContextAwareTestModel=qe,exports.ContextTestModel=F,exports.CustomFieldDefinition=D,exports.CustomFieldDefinitionType=x,exports.CustomFieldEntries=R,exports.CustomFieldValue=A,exports.CustomFieldsSchema=Bn,exports.CustomValidator=B,exports.TestModel=N,exports.customFieldsSortScope=Nn,exports.default=Hn,exports.disableCustomFields=Un,exports.generateCustomFieldSearchQueryPayload=fn,exports.generateRandomString=dn,exports.initTables=at,exports.initTestModels=ot,exports.supportedEntities=ae;
2
47
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["api","initDB","initTestModels","initTables"],"sources":["../src/index.ts"],"sourcesContent":["import type { Application } from 'express';\nimport type { Sequelize } from 'sequelize-typescript';\nimport {\n initTables, initTestModels,\n} from './models';\nimport api from './api';\nimport initDB from './utils/db';\nimport logger, { tryAddingTraceIdMiddleware } from './utils/logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from './types';\nimport {\n addHooks, addScopes, applyCustomAssociation, removeHooks,\n} from './utils/init';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\n\n/**\n * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file\n * @see {@link 'custom-fields/config'} for configurations\n */\nconst useCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n tryAddingTraceIdMiddleware().catch(() => null);\n const { models, useCustomFieldsEntries } = options;\n if (app) {\n app.use('/api', api);\n }\n const sequelize = options.sequelize ?? initDB(options.databaseConfig);\n if (process.env.NODE_ENV === 'test') {\n await initTestModels(sequelize);\n }\n // The order is important\n addHooks(models, getModel, { useCustomFieldsEntries });\n await initTables(sequelize, options.getUser, { useCustomFieldsEntries });\n addScopes(models, getModel, { useCustomFieldsEntries });\n applyCustomAssociation(models);\n\n logger.debug('sadot - custom fields finished initializing with models', models);\n return sequelize;\n};\n\nexport default useCustomFields;\n\nexport const disableCustomFields = (models: Models[], getModel: ModelFetcher): void => {\n removeHooks(models, getModel);\n};\n"],"mappings":"2YAyBM,EAAkB,MACtB,EACA,EACA,IACuB,CACvB,EAAA,4BAA4B,CAAC,UAAY,KAAK,CAC9C,GAAM,CAAE,SAAQ,0BAA2B,EACvC,GACF,EAAI,IAAI,OAAQA,EAAAA,QAAI,CAEtB,IAAM,EAAY,EAAQ,WAAaC,EAAAA,QAAO,EAAQ,eAAe,CAWrE,OAVI,QAAQ,IAAI,WAAa,QAC3B,MAAMC,EAAAA,eAAe,EAAU,CAGjC,EAAA,SAAS,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACtD,MAAMC,EAAAA,WAAW,EAAW,EAAQ,QAAS,CAAE,yBAAwB,CAAC,CACxE,EAAA,UAAU,EAAQ,EAAU,CAAE,yBAAwB,CAAC,CACvD,EAAA,uBAAuB,EAAO,CAE9B,EAAA,QAAO,MAAM,0DAA2D,EAAO,CACxE,GAGT,IAAA,EAAe,EAEf,MAAa,GAAuB,EAAkB,IAAiC,CACrF,EAAA,YAAY,EAAQ,EAAS"}
1
+ {"version":3,"file":"index.cjs","names":["logger: LoggerInstanceManager","CUSTOM_FIELDS_FILTER_SCOPE: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE","customFields","validateSelect: Validator<string, string[]>","Joi","validateStatus: Validator<StatusValue, StatusOption[]>","Joi","CustomValidationTypes: Record<Extract<CustomFieldDefinitionType, 'select' | 'status'>, CustomFieldDefinitionType>","validators: Validators","Joi","events: Events","Events","BadRequest","CustomFieldDefinition","Model","PrimaryKey","DataType","CustomFieldValue","BeforeCreate","AfterSave","create","CustomFieldDefinition","findAll","Op","where: WhereOptions","update","customFields","CustomFieldValue","Model","CustomFieldDefinitionRepo.findByIds","CustomFieldDefinitionRepo.findById","PrimaryKey","DataType","CustomFieldDefinition","BeforeBulkCreate","BeforeBulkUpdate","BeforeUpdate","BeforeCreate","BeforeUpsert","AfterUpsert","AssociatedTestModel","Model","PrimaryKey","DataType","TestModel","TestModel","Model","PrimaryKey","DataType","AssociatedTestModel","ContextTestModel","Model","PrimaryKey","DataType","ContextAwareTestModel","Model","PrimaryKey","DataType","ContextTestModel","CustomFieldEntries","Model","PrimaryKey","DataType","AfterUpsert","CustomFieldDefinitionRepo.getCustomFieldDefinitionsDictionary","CustomValidator","Model","PrimaryKey","DataType","AfterUpsert","productionModels: ProductionModel[]","CustomFieldDefinition","CustomFieldValue","CustomValidator","TestModel","AssociatedTestModel","ContextAwareTestModel","ContextTestModel","sequelize","CustomFieldEntries","getUser","DataTypes","Op","InputValidationError","DatabaseValidationError","BadRequest","Joi","router: ReturnType<typeof Router>","ENTITY","router","validatedPayload: CreateCustomFieldDefinition","DefinitionRepo.create","handleError","DefinitionRepo.findById","ResourceNotFoundError","DefinitionRepo.findAll","validatedPayload: UpdateCustomFieldDefinition","DefinitionRepo.findByWhere","DefinitionRepo.update","CustomValidator","validators","Joi","validationSchemas: ValidationSchemas","Ajv","BadRequest","router: ReturnType<typeof Router>","router","validations","ValidatorRepo.create","StatusCodes","handleError","validators","ValidatorRepo.findAll","ResourceNotFoundError","ValidatorRepo.update","ValidatorRepo.disable","router: ReturnType<typeof Router>","router","definitionRouter","validatorRouter","router: ReturnType<typeof Router>","v1","env: string","sequelize: Sequelize","Sequelize","sequelize","formatFunctions: Partial<Record<CustomFieldDefinitionType, (value: any) => string | null>>","CustomFieldValue","where: WhereOptions","DefinitionRepo.findAll","values: CreateCustomFieldValue[]","CustomFieldEntries","customFields","where: WhereOptions","DefinitionRepo.findAll","EntriesRepo.findEntriesByModelIds","customFields","ValueRepo.findValuesByModelIds","applyScopeToInstance","DefinitionRepo.findByEntityIds","ValueRepo.updateValues","customFields","EntriesRepo.findEntriesByModelId","EntriesRepo.updateEntries","ajv","Ajv","beforeFull: any","applyScopeToInstance","ValidatorRepo.findAllByModelType","validators","BadRequest","where: WhereOptions","DefinitionRepo.findAll","Joi","customFields","updateInstanceValues","Op","Sequelize","CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name`","CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value`","formattedValue: string | number | boolean","Op","Sequelize","scopeName: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE","customFields","customFields","DataTypes","enrichResults","CustomFieldValue","CUSTOM_FIELDS_FILTER_SCOPE","CUSTOM_FIELDS_SORT_SCOPE","CustomFieldDefinition","CustomValidator","CustomFieldsSchema: Joi.ObjectSchema<Record<string, any>>","Joi","api","sequelize","initDB"],"sources":["../src/utils/logger/index.ts","../src/utils/constants/index.ts","../src/utils/validations/validators/select.validator.ts","../src/utils/validations/validators/status.validator.ts","../src/utils/validations/validators/index.ts","../src/events/index.ts","../src/errors/index.ts","../src/utils/validations/index.ts","../src/models/CustomFieldDefinition.ts","../src/repository/definition.ts","../src/models/CustomFieldValue.ts","../src/models/tests/AssociatedTestModel.ts","../src/models/tests/TestModel.ts","../src/models/tests/contextAwareModels/ContextTestModel.ts","../src/models/tests/contextAwareModels/ContextAwareTestModel.ts","../src/models/CustomFieldEntries.ts","../src/models/CustomValidator.ts","../src/models/index.ts","../src/api/v1/errors.ts","../src/api/v1/definition/validations.ts","../src/api/v1/definition/index.ts","../src/repository/validator.ts","../src/api/v1/validator/validations.ts","../src/utils/validations/schema/validator-schema.ts","../src/api/v1/validator/index.ts","../src/api/v1/index.ts","../src/api/index.ts","../src/utils/db/index.ts","../src/repository/utils/formatValues.ts","../src/repository/value.ts","../src/repository/entries.ts","../src/utils/scopeAttributes.ts","../src/hooks/enrich.ts","../src/hooks/find.ts","../src/hooks/utils/updateInstanceValues.ts","../src/hooks/hooks.ts","../src/utils/helpers/index.ts","../src/scopes/helpers/filter.helpers.ts","../src/scopes/filter.ts","../src/utils/init.ts","../src/utils/validations/schema/custom-fields.ts","../src/index.ts"],"sourcesContent":["import Logger, { type LoggerInstanceManager } from '@autofleet/logger';\n\nconst logger: LoggerInstanceManager = Logger();\n\nexport async function tryAddingTraceIdMiddleware(): Promise<void> {\n try {\n const { outbreak } = await import('@autofleet/zehut');\n logger.addContextMiddleware(() => ({ traceId: outbreak.getCurrentContextTraceId() }));\n } catch (err) {\n logger.error('Failed to add traceId middleware', { err });\n }\n}\n\nexport default logger;\n","import { customFields } from '@autofleet/common-types';\n\nexport const supportedEntities = ['businessModelId', 'fleetId', 'demandSourceId'] as const;\n\n/**\n * Supported custom field types\n */\nexport enum CustomFieldDefinitionType {\n NUMBER = 'number',\n BOOLEAN = 'boolean',\n DATE = 'date',\n DATETIME = 'datetime',\n TEXT = 'text',\n IMAGE = 'image',\n SELECT = 'select',\n STATUS = 'status',\n FILE = 'file',\n}\n\n// eslint-disable-next-line prefer-destructuring\nconst CUSTOM_FIELDS_FILTER_SCOPE: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE = customFields.CUSTOM_FIELDS_FILTER_SCOPE;\n\nexport {\n /** @deprecated Use the value from `@autofleet/common-types` instead */\n CUSTOM_FIELDS_FILTER_SCOPE,\n};\n","import Joi from 'joi';\nimport type { Validator } from '../type';\n\n/**\n * Validate that the value is one of the select values\n */\nexport const validateSelect: Validator<string, string[]> = (\n value,\n selectValues,\n) => (\n Joi.string().allow(null).valid(...selectValues).validate(value)\n);\n","import Joi from 'joi';\nimport type { Validator } from '../type';\n\ntype StatusColor = string | null; // TODO: Takes from @autofleet/colors ?\ntype StatusValue = string;\ntype StatusOption = {\n value: StatusValue;\n color: StatusColor;\n}\n\n/**\n* Validate that the value is one of the status values\n*/\nexport const validateStatus: Validator<StatusValue, StatusOption[]> = (\n value,\n statusValues,\n) => (\n Joi.string()\n .allow(null)\n .valid(...statusValues.map((statusValue) => statusValue.value))\n .validate(value)\n);\n","import Joi from 'joi';\nimport { CustomFieldDefinitionType } from '../../constants';\nimport type { Validators } from '../type';\nimport { validateSelect } from './select.validator';\nimport { validateStatus } from './status.validator';\n\ntype CustomValidationTypes = Extract<CustomFieldDefinitionType, 'select' | 'status'>;\n/**\n * Custom field types that must have custom validation.\n * TODO: remove this after moving to schema-based validation\n */\nexport const CustomValidationTypes: Record<Extract<CustomFieldDefinitionType, 'select' | 'status'>, CustomFieldDefinitionType> = {\n [CustomFieldDefinitionType.SELECT]: CustomFieldDefinitionType.SELECT,\n [CustomFieldDefinitionType.STATUS]: CustomFieldDefinitionType.STATUS,\n} as const;\n\n/**\n * Validators for custom fields\n */\nexport const validators: Validators = {\n [CustomFieldDefinitionType.SELECT]: validateSelect,\n [CustomFieldDefinitionType.STATUS]: validateStatus,\n [CustomFieldDefinitionType.TEXT]: (value) => Joi.string().min(0).validate(value),\n [CustomFieldDefinitionType.NUMBER]: (value) => Joi.number().strict(true).validate(value),\n [CustomFieldDefinitionType.BOOLEAN]: (value) => Joi.boolean().strict().validate(value),\n [CustomFieldDefinitionType.DATE]: (value) => Joi.date().validate(value),\n [CustomFieldDefinitionType.DATETIME]: (value) => Joi.date().validate(value),\n [CustomFieldDefinitionType.IMAGE]: (value) => Joi.array().min(1).unique()\n .items(Joi.string().uri())\n .validate(value),\n [CustomFieldDefinitionType.FILE]: (value) => Joi.array().min(1).unique().items(Joi.object({\n name: Joi.string().required(),\n type: Joi.string(),\n size: Joi.string(),\n addedBy: Joi.string().uuid(),\n }))\n .validate(value),\n};\n","import Events from '@autofleet/events';\nimport { getUser } from '@autofleet/zehut';\nimport logger from '../utils/logger';\nimport type {\n CustomFieldDefinition,\n CustomFieldEntries,\n CustomFieldValue,\n CustomValidator,\n} from '../models';\n\nconst events: Events = new Events({\n logger,\n getUserId: (payload) => payload?.user_id ?? getUser()?.id ?? null,\n});\n\nconst KEYS_TO_CONVERT = ['value', 'defaultValue', 'blockEditingFromUI'];\n\nconst stringifyBooleans = (savedObject: any, keysToConvert: string[]) => {\n const savedObjectKeySet = new Set(Object.keys(savedObject));\n if (keysToConvert.every((key) => !savedObjectKeySet.has(key))) {\n return savedObject;\n }\n return {\n ...savedObject,\n ...Object.fromEntries(keysToConvert.map((key) => [key, typeof savedObject[key] === 'boolean' ? savedObject[key].toString() : savedObject[key]])),\n };\n};\n\nconst modelTableMapping = {\n CustomFieldDefinition: {\n tableName: 'dim_custom_field_definition',\n eventVersion: '1',\n },\n CustomFieldValue: {\n tableName: 'dim_custom_field_value',\n eventVersion: '1',\n },\n CustomFieldEntries: {\n tableName: 'dim_custom_field_entries',\n eventVersion: '1',\n },\n};\n\nexport const sendDimEvent = (instance: CustomFieldDefinition | CustomFieldValue | CustomFieldEntries | CustomValidator): void => {\n const mapping = modelTableMapping[instance.constructor.name];\n if (!mapping) {\n return;\n }\n let objectToSend = instance.get();\n try {\n objectToSend = stringifyBooleans(instance.get(), KEYS_TO_CONVERT);\n } catch (err) {\n logger.error('Failed to convert booleans in dim event payload', err);\n }\n\n events.sendObject(\n mapping.tableName,\n mapping.eventVersion,\n objectToSend,\n ).catch(() => {});\n};\n\nexport default events;\n","/* eslint-disable max-classes-per-file */\nimport { BadRequest } from '@autofleet/errors';\nimport type { ValidationError } from 'joi';\nimport type { EntriesValidationError } from '../types/entries';\n\nexport class MissingRequiredCustomFieldError extends BadRequest {\n constructor(missingFields: string[]) {\n const err = new Error(`The following custom fields are required: ${missingFields.join(',')}`);\n super([err], null, missingFields);\n this.message = 'MISSING_REQUIRED_CUSTOM_FIELDS';\n }\n}\n\nexport class UnsupportedCustomFieldTypeError extends BadRequest {\n constructor(fieldType: string) {\n const err = new Error(`Type \"${fieldType}\" is not supported`);\n super([err], null, null);\n this.message = 'UNSUPPORTED_CUSTOM_FIELD_TYPE';\n }\n}\n\nexport class UnsupportedCustomValidationError extends BadRequest {\n constructor(fieldType: string) {\n const err = new Error(`Validation for \"${fieldType}\" is not supported`);\n super([err], null, null);\n this.message = 'UNSUPPORTED_CUSTOM_VALIDATION_TYPE';\n }\n}\n\nexport class InvalidFieldTypeError extends BadRequest {\n constructor(fieldType: string) {\n const err = new Error(`Invalid field type ${fieldType}`);\n super([err], null, null);\n this.message = 'INVALID_FIELD_TYPE';\n }\n}\n\nexport class InvalidValueError extends BadRequest {\n constructor(value: any, fieldDefinitionName: string, joiValidationError: ValidationError) {\n const formattedErrorMessage = joiValidationError.message\n .replace(/\"/g, '')\n .replace('value', `'${fieldDefinitionName}'`);\n\n const formattedValue = typeof value === 'object' ? JSON.stringify(value) : value;\n\n const invalidValueMessage = `Invalid Value on field '${fieldDefinitionName}'. ${formattedErrorMessage}. received: '${formattedValue}'`;\n\n const err = new Error(invalidValueMessage);\n super([err], null, null);\n this.message = invalidValueMessage;\n }\n}\n\nexport class InvalidEntriesError extends BadRequest {\n constructor(modelId: string, validationErrors: EntriesValidationError[]) {\n const errors = validationErrors.map((validationError) => new InvalidValueError(validationError.value, validationError.fieldDefinitionName, validationError.joiValidationError));\n super(errors, null, null);\n this.message = `Invalid entries on ${modelId}\\n${validationErrors.map((validationError) => (\n `${validationError.fieldDefinitionName} - ${validationError.joiValidationError.message}`\n )).join('\\n')}`;\n }\n}\n\nexport class MissingDefinitionError extends BadRequest {\n constructor(fieldNames: string[]) {\n const err = new Error(`Missing custom field definition for field ${fieldNames.join(',')}`);\n super([err], null, null);\n this.message = 'MISSING_DEFINITION';\n }\n}\n","import type Joi from 'joi';\nimport { InvalidEntriesError } from '../../errors';\nimport type { CustomFieldDefinition } from '../../models';\nimport type { CustomFieldEntriesDTO } from '../../types/entries';\nimport type { CustomFieldDefinitionType } from '../constants';\nimport { validators } from './validators';\n\nexport const validateFieldType = (type: CustomFieldDefinitionType): boolean => Object.keys(validators).includes(type);\n\nexport const validateValue = (\n value: unknown,\n valueType: CustomFieldDefinitionType,\n validation?: unknown,\n): Joi.ValidationResult => {\n const validator = validators[valueType];\n return validator(value, validation);\n /** TODO: Add validation for required fields\n * @example\n * if (validations.required && !value) {\n * return false;\n * }\n */\n};\n\nexport const validateInstanceCustomFieldEntries = (\n instance: CustomFieldEntriesDTO,\n definitionsByName: { [defName: string]: CustomFieldDefinition; },\n _validateValue: typeof validateValue = validateValue,\n): void => {\n const validationErrors = Object.entries(instance.customFields)\n .map(([customFieldName, value]) => {\n // Allow NULL values, just like we do in custom_field_values.\n if (value === null) return null;\n\n const { validation, fieldType } = definitionsByName[customFieldName];\n const result = _validateValue(value, fieldType, validation);\n if (result?.error) {\n return {\n joiValidationError: result.error,\n fieldDefinitionName: customFieldName,\n value,\n };\n }\n return null;\n })\n .filter((result) => !!result);\n\n if (validationErrors?.length) {\n throw new InvalidEntriesError(instance.modelId, validationErrors);\n }\n};\n","import {\n Table,\n Column,\n Model,\n DataType,\n HasMany,\n PrimaryKey,\n BeforeCreate,\n DefaultScope,\n AfterSave,\n Is,\n} from 'sequelize-typescript';\nimport type { CreateOptions } from 'sequelize';\nimport { CustomFieldDefinitionType } from '../utils/constants';\nimport { CustomValidationTypes } from '../utils/validations/validators';\nimport { CustomFieldValue } from '.';\nimport { sendDimEvent } from '../events';\nimport { InvalidValueError, UnsupportedCustomFieldTypeError, UnsupportedCustomValidationError } from '../errors';\nimport logger from '../utils/logger';\nimport { validateValue } from '../utils/validations';\n\n@DefaultScope(() => ({ where: { disabled: false } }))\n@Table({\n tableName: 'custom_field_definitions',\n indexes: [\n {\n name: 'unique_name_model_type',\n fields: ['model_type', 'entity_id', 'name'],\n unique: true,\n },\n ],\n timestamps: true,\n validate: {\n validationByType(this: CustomFieldDefinition) {\n // Verify the validation is provided if needed\n if (!this.validation && CustomValidationTypes[this.fieldType]) {\n // TODO: enforce the validation-object schema based on the fieldType\n logger.error(`No custom validation for custom field type ${this.fieldType} found`);\n throw new UnsupportedCustomValidationError(`Validation provided for \"${this.fieldType}\" is not supported`);\n }\n },\n },\n})\nclass CustomFieldDefinition extends Model {\n @PrimaryKey\n @Column({\n type: DataType.UUID,\n defaultValue: DataType.UUIDV4,\n allowNull: false,\n })\n declare id: string;\n\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n name!: string;\n\n @Column({\n type: DataType.STRING,\n })\n displayName?: string; // Defaulted to name with beforeCreate hook\n\n @Is('SupportedType', (value) => {\n if (!Object.values(CustomFieldDefinitionType).includes(value as CustomFieldDefinitionType)) {\n throw new UnsupportedCustomFieldTypeError(`\"${value}\" is not a supported type.`);\n }\n })\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n fieldType!: CustomFieldDefinitionType;\n\n @Column({\n type: DataType.JSONB,\n })\n validation?: any;\n\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n entityId!: string; /** Client association entity id */\n\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n entityType!: string; /** Client association entity type (demand source / fleet / etc.) */\n\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n modelType!: string; /** Model type. e.g. Vehicle / StopPoint / etc. */\n\n @Column({\n type: DataType.TEXT,\n })\n description?: string;\n\n @Column({\n type: DataType.BOOLEAN,\n defaultValue: false,\n })\n required?: boolean;\n\n @Column({\n type: DataType.BOOLEAN,\n defaultValue: false,\n })\n disabled?: boolean;\n\n @Column({\n type: DataType.JSONB,\n allowNull: true,\n })\n defaultValue?: any;\n\n @Column({\n type: DataType.DATE,\n allowNull: false,\n })\n declare createdAt?: Date;\n\n @Column({\n type: DataType.DATE,\n allowNull: true,\n })\n declare updatedAt?: Date;\n\n @Column({\n type: DataType.DATE,\n allowNull: true,\n })\n declare deletedAt?: Date;\n\n @Column({\n type: DataType.BOOLEAN,\n defaultValue: false,\n allowNull: false,\n })\n blockEditingFromUI!: boolean;\n\n @HasMany(() => CustomFieldValue)\n values: CustomFieldValue[];\n\n @BeforeCreate\n static displayNameDefaultValue(instance: CustomFieldDefinition): void {\n if (!instance?.displayName) {\n // eslint-disable-next-line no-param-reassign\n instance.displayName = instance.name;\n }\n if (![null, undefined].includes(instance.defaultValue)) {\n const isValid = validateValue(instance.defaultValue, instance.fieldType, instance.validation);\n if (isValid.error) {\n throw new InvalidValueError(instance.defaultValue, instance.name, isValid.error);\n }\n }\n }\n\n @AfterSave\n static afterSaveHandler(instance: CustomFieldDefinition, options: CreateOptions): void {\n if (options.transaction) {\n options.transaction.afterCommit(() => sendDimEvent(instance));\n } else {\n sendDimEvent(instance);\n }\n }\n}\n\nexport default CustomFieldDefinition;\n","import {\n Op,\n type Includeable, type Transaction, type FindOptions, type WhereOptions, type Transactionable,\n} from 'sequelize';\nimport { CustomFieldDefinition, type CustomFieldEntries } from '../models';\nimport type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../types/definition';\nimport type { ModelOptions } from '../types';\nimport { MissingDefinitionError } from '../errors';\n\nexport const create = (data: CreateCustomFieldDefinition): Promise<CustomFieldDefinition> =>\n CustomFieldDefinition.create(data);\n\ninterface SadotFindOptions {\n withDisabled?: boolean;\n transaction?: Transaction;\n include?: Includeable | Includeable[];\n}\n\ntype SadotGetDefinitionsByEntityIdsOptions = FindOptions & { modelOptions?: ModelOptions; findAll?: typeof findAll; } & Pick<SadotFindOptions, 'withDisabled'>;\n\nexport const findAll = (\n where: WhereOptions,\n options: SadotFindOptions = { withDisabled: false },\n): Promise<CustomFieldDefinition[]> => {\n const queryModel = options.withDisabled\n ? CustomFieldDefinition.unscoped()\n : CustomFieldDefinition;\n\n return queryModel.scope('userScope').findAll({\n where,\n transaction: options.transaction,\n raw: true,\n include: options.include,\n });\n};\n\nexport const findByIds = (\n ids: string[],\n options: SadotFindOptions = { withDisabled: false },\n): Promise<CustomFieldDefinition[]> => findAll({ id: { [Op.in]: ids } }, options);\n\nexport const findById = (\n id: string,\n options: Pick<SadotFindOptions, 'withDisabled'> = { withDisabled: false },\n): Promise<CustomFieldDefinition | null> => {\n const { withDisabled } = options;\n if (withDisabled) {\n return CustomFieldDefinition.unscoped().scope('userScope').findByPk(id);\n }\n return CustomFieldDefinition.scope('userScope').findByPk(id);\n};\n\nexport const findByEntityIds = async (\n modelType: string,\n entityIds: string[],\n options: FindOptions & { modelOptions?: ModelOptions } = {},\n): Promise<CustomFieldDefinition[]> => {\n const { include, useEntityIdFromInclude } = options.modelOptions;\n const where: WhereOptions = {\n modelType,\n ...(!useEntityIdFromInclude && { entityId: { [Op.in]: entityIds } }),\n };\n\n return CustomFieldDefinition.findAll({\n where,\n transaction: options.transaction,\n include: include?.(entityIds),\n raw: true,\n });\n};\n\nexport const findByWhere = (where: WhereOptions<CustomFieldDefinition>): Promise<CustomFieldDefinition | null> =>\n CustomFieldDefinition.scope('userScope').findOne({\n where,\n });\n\nexport const findDefinitionsByModels = async (\n modelTypes: string[],\n options?: Transactionable,\n): Promise<CustomFieldDefinition[]> => {\n const query: WhereOptions<CreateCustomFieldDefinition> = { modelType: { [Op.in]: modelTypes } };\n return CustomFieldDefinition.findAll({\n where: query,\n transaction: options?.transaction,\n });\n};\n\nexport const update = async (\n id: string,\n data: UpdateCustomFieldDefinition,\n): Promise<CustomFieldDefinition> => {\n const updatedDefinition = (await CustomFieldDefinition.scope('userScope').update(data, {\n where: { id },\n returning: true,\n individualHooks: true,\n }))[1][0];\n return updatedDefinition;\n};\n\nexport const disable = (id: string): Promise<[affectedCount: number]> =>\n CustomFieldDefinition.update(\n { disabled: true },\n { where: { id } },\n );\n\nexport const destroy = (id: string): Promise<number> =>\n CustomFieldDefinition.destroy({ where: { id } });\n\n/**\n * Return the names of the required fields for a given model\n */\nexport const getRequiredFields = async (\n modelType: string,\n modelId: string | string[],\n entityId: string | string[],\n modelOptions: ModelOptions = {},\n): Promise<string[]> => {\n const entityIds = Array.isArray(entityId) ? entityId : [entityId];\n const { include, useEntityIdFromInclude } = modelOptions;\n\n const where: WhereOptions = {\n modelType,\n required: true,\n ...(!useEntityIdFromInclude && { entityId: { [Op.in]: entityIds } }),\n };\n\n const requiredFields = await CustomFieldDefinition.findAll({\n where,\n include: include?.(entityIds),\n logging: true,\n });\n const requiredFieldsNames = requiredFields.map((definition) => definition.name);\n return [...new Set(requiredFieldsNames)];\n};\n\n/**\n * @returns A promise resolving with a dictionary of custom field definitions by name.\n * @throws A {@link MissingDefinitionError} if any of the custom fields doesn't have a definition.\n */\nexport const getCustomFieldDefinitionsDictionary = async (\n instances: CustomFieldEntries[],\n {\n findAll: _findAll,\n modelOptions = {},\n withDisabled = false,\n ...options\n }: SadotGetDefinitionsByEntityIdsOptions = { withDisabled: false, modelOptions: {} },\n): Promise<{ [definitionName: string]: CustomFieldDefinition }> => {\n const { modelType } = instances[0]?.dataValues ?? {};\n const customFields = new Set<string>();\n const modelIds = [];\n const entityIds = new Set<string>();\n instances.forEach((instance) => {\n const { dataValues: { modelId, entityId, customFields: instanceCustomFields } } = instance;\n modelIds.push(modelId);\n entityIds.add(entityId);\n\n Object.keys(instanceCustomFields ?? {}).forEach((fieldName) => {\n customFields.add(fieldName);\n });\n });\n\n const where: WhereOptions = {\n modelType,\n entityId: { [Op.in]: Array.from(entityIds) },\n name: { [Op.in]: Array.from(customFields) },\n };\n\n const findAllToUse = _findAll ?? findAll;\n\n // @ts-expect-error findAll doesn't expect modelOptions at all.\n const definitions = await findAllToUse(where, { withDisabled, modelOptions, ...options });\n\n const matchedDefinitions = definitions.filter((def) => customFields.has(def.name));\n const matchedDefinitionsByName = Object.fromEntries(matchedDefinitions.map((definition) => [definition.name, definition]));\n\n if (!definitions?.length || matchedDefinitions.length !== customFields.size) {\n const unmatchedCustomFields = Array.from(customFields).filter((customField) => !matchedDefinitionsByName[customField]);\n throw new MissingDefinitionError(unmatchedCustomFields);\n }\n\n return matchedDefinitionsByName;\n};\n","import {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n BelongsTo,\n ForeignKey,\n BeforeCreate,\n BeforeUpsert,\n AfterUpsert,\n BeforeUpdate,\n BeforeBulkCreate,\n BeforeBulkUpdate,\n} from 'sequelize-typescript';\nimport type { CreateOptions } from 'sequelize';\nimport { sendDimEvent } from '../events';\nimport { CustomFieldDefinition } from '.';\nimport { validateFieldType, validateValue } from '../utils/validations';\nimport * as CustomFieldDefinitionRepo from '../repository/definition';\nimport { InvalidFieldTypeError, InvalidValueError } from '../errors';\n\n@Table({\n tableName: 'custom_field_values',\n timestamps: true,\n})\nclass CustomFieldValue extends Model {\n @PrimaryKey\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n modelId!: string;\n\n @PrimaryKey\n @ForeignKey(() => CustomFieldDefinition)\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n customFieldDefinitionId!: string;\n\n @Column({\n type: DataType.JSONB,\n allowNull: true,\n })\n value!: any;\n\n @Column({\n type: DataType.DATE,\n allowNull: false,\n })\n declare createdAt?: Date;\n\n @Column({\n type: DataType.DATE,\n allowNull: true,\n })\n declare updatedAt?: Date;\n\n @Column({\n type: DataType.DATE,\n allowNull: true,\n })\n declare deletedAt?: Date;\n\n @BelongsTo(() => CustomFieldDefinition, { scope: { disabled: false } })\n customFieldDefinition: CustomFieldDefinition;\n\n private static validateValueAgainstDefinition(\n instance: CustomFieldValue,\n definition: CustomFieldDefinition,\n ): void {\n const { validation, fieldType, name } = definition;\n const isValidFieldType = validateFieldType(fieldType);\n if (!isValidFieldType) {\n throw new InvalidFieldTypeError(fieldType);\n }\n // Always allow null values\n if (instance.value === null) return;\n const validateValueResponse = validateValue(instance.value, fieldType, validation);\n if (validateValueResponse.error) {\n throw new InvalidValueError(instance.value, name, validateValueResponse.error);\n }\n }\n\n @BeforeBulkCreate\n @BeforeBulkUpdate\n static async validateCustomFieldValues(instances: CustomFieldValue[]): Promise<void> {\n const ids = instances.map((instance) => instance.customFieldDefinitionId);\n const uniqueIds = [...new Set(ids)];\n const definitions = await CustomFieldDefinitionRepo.findByIds(\n uniqueIds,\n { withDisabled: true },\n );\n\n if (!definitions || definitions.length !== uniqueIds.length) {\n throw new Error('Definitions not found');\n }\n\n instances.forEach((instance) => {\n const definition = definitions.find((d) => d.id === instance.customFieldDefinitionId);\n if (definition) {\n this.validateValueAgainstDefinition(instance, definition);\n }\n });\n }\n\n @BeforeUpdate\n @BeforeCreate\n @BeforeUpsert\n static async validateCustomFieldValue(instance: CustomFieldValue): Promise<void> {\n const { customFieldDefinitionId } = instance;\n // eslint-disable-next-line max-len\n const cfd = await CustomFieldDefinitionRepo.findById(customFieldDefinitionId, { withDisabled: true });\n this.validateValueAgainstDefinition(instance, cfd);\n }\n\n @AfterUpsert\n static afterSaveHandler(instance: CustomFieldValue, options: CreateOptions): void {\n if (options.transaction) {\n options.transaction.afterCommit(() => sendDimEvent(instance[0]));\n } else {\n sendDimEvent(instance[0]);\n }\n }\n}\n\nexport default CustomFieldValue;\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n ForeignKey,\n BelongsTo,\n} from 'sequelize-typescript';\nimport TestModel from './TestModel';\n\n@Table({\n schema: 'custom-fields', tableName: 'associated_test_models', createdAt: false, updatedAt: false,\n})\nclass AssociatedTestModel extends Model {\n @PrimaryKey\n @Column({\n type: DataType.UUID,\n defaultValue: DataType.UUIDV4,\n allowNull: false,\n })\n declare id: string;\n\n @ForeignKey(() => TestModel)\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n testModelId!: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n fleetId: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: true,\n })\n businessModelId: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: true,\n })\n demandSourceId: string;\n\n @Column({\n type: DataType.BOOLEAN,\n })\n anotherAttribute?: boolean;\n\n @BelongsTo(() => TestModel)\n testModel: TestModel;\n}\n\nexport default AssociatedTestModel;\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n HasMany,\n} from 'sequelize-typescript';\nimport AssociatedTestModel from './AssociatedTestModel';\n\n@Table({\n schema: 'custom-fields', tableName: 'test_models', createdAt: false, updatedAt: false,\n})\nclass TestModel extends Model {\n @PrimaryKey\n @Column({\n type: DataType.UUID,\n defaultValue: DataType.UUIDV4,\n allowNull: false,\n })\n declare id: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n fleetId: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: true,\n })\n businessModelId: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: true,\n })\n demandSourceId: string;\n\n @Column({\n type: DataType.BOOLEAN,\n })\n coolAttribute?: boolean;\n\n @HasMany(() => AssociatedTestModel)\n associatedModels: AssociatedTestModel[];\n\n @Column({\n type: DataType.VIRTUAL,\n })\n customFields?: any;\n}\n\nexport default TestModel;\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n} from 'sequelize-typescript';\n\n// eslint-disable-next-line no-shadow\n enum EEntityTypes {\n BUSINESS_MODEL = 'businessModel',\n CONTEXT = 'context',\n DEMAND_SOURCE = 'demandSource',\n FLEET = 'fleet',\n}\n\n@Table({ createdAt: false, updatedAt: false })\nclass ContextTestModel extends Model {\n @PrimaryKey\n @Column({\n defaultValue: DataType.UUIDV4,\n type: DataType.UUID,\n })\n declare id: string;\n\n @Column({\n type: DataType.UUID,\n })\n entityId: string;\n\n @Column({\n type: DataType.ENUM(...Object.values(EEntityTypes)),\n })\n entityType: EEntityTypes;\n}\n\nexport default ContextTestModel;\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n HasMany,\n BelongsTo,\n ForeignKey,\n} from 'sequelize-typescript';\nimport AssociatedTestModel from '../AssociatedTestModel';\nimport ContextTestModel from './ContextTestModel';\n\n@Table({ createdAt: false, updatedAt: false })\nclass ContextAwareTestModel extends Model {\n @PrimaryKey\n @Column({\n type: DataType.UUID,\n defaultValue: DataType.UUIDV4,\n allowNull: false,\n })\n declare id: string;\n\n @ForeignKey(() => ContextTestModel)\n @Column({ type: DataType.UUID })\n contextId: string;\n\n @Column({\n type: DataType.BOOLEAN,\n })\n coolAttribute?: boolean;\n\n @Column({\n type: DataType.VIRTUAL,\n })\n customFields?: any;\n\n @BelongsTo(() => ContextTestModel)\n context: ContextTestModel;\n}\n\nexport default ContextAwareTestModel;\n","import {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n AfterUpsert,\n} from 'sequelize-typescript';\nimport type { CreateOptions } from 'sequelize';\nimport { sendDimEvent } from '../events';\nimport * as CustomFieldDefinitionRepo from '../repository/definition';\nimport { validateInstanceCustomFieldEntries } from '../utils/validations';\n\n@Table({\n tableName: 'custom_field_entries',\n timestamps: true,\n indexes: [\n {\n name: 'idx_cfe_custom_fields',\n using: 'gin',\n operator: 'jsonb_path_ops',\n fields: ['custom_fields'],\n },\n ],\n validate: {\n async validationByType(this: CustomFieldEntries) {\n if (!Object.keys(this.customFields ?? {}).length) {\n return;\n }\n\n const definitionsByName = await CustomFieldDefinitionRepo.getCustomFieldDefinitionsDictionary([this]);\n validateInstanceCustomFieldEntries(this, definitionsByName);\n },\n },\n})\nclass CustomFieldEntries extends Model {\n @PrimaryKey\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n /** The ID of the model of which this row hold the custom field entries of, e.g. vehicleId / stopPointId / etc. */\n modelId!: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n /** The ID of the entity of which this row hold the custom field entries of, e.g. fleetId / etc. */\n entityId!: string;\n\n @Column({\n type: DataType.JSONB,\n allowNull: false,\n defaultValue: {},\n })\n /** A dictionary of customFields and values with the following structure: `{ customFieldName: 'CustomFieldValue' }` */\n customFields!: Record<string, any>;\n\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n /** The type of model which this custom field entry represents. e.g. Vehicle / StopPoint / etc. */\n modelType!: string;\n\n @Column({\n type: DataType.DATE,\n allowNull: false,\n })\n declare createdAt?: Date;\n\n @Column({\n type: DataType.DATE,\n allowNull: true,\n })\n declare updatedAt?: Date;\n\n @AfterUpsert\n static afterSaveHandler(instance: CustomFieldEntries, options: CreateOptions): void {\n if (options.transaction) {\n options.transaction.afterCommit(() => sendDimEvent(instance[0]));\n } else {\n sendDimEvent(instance[0]);\n }\n }\n}\n\nexport default CustomFieldEntries;\n","import {\n Table,\n Column,\n Model,\n PrimaryKey,\n DataType,\n Default,\n AfterUpsert,\n DefaultScope,\n} from 'sequelize-typescript';\nimport type { CreateOptions } from 'sequelize';\nimport { randomUUID } from 'node:crypto';\nimport { sendDimEvent } from '../events';\nimport type { SchemaObject } from '../api/v1/validator/validations';\n\n@DefaultScope(() => ({ where: { disabled: false } }))\n@Table({\n tableName: 'custom_validators',\n timestamps: true,\n})\nclass CustomValidator extends Model {\n @PrimaryKey\n @Default(() => randomUUID())\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n declare id: string;\n\n @Column({\n type: DataType.UUID,\n allowNull: false,\n })\n /** The ID of the entity for which this validator is defined, e.g. fleetId / etc. */\n entityId!: string;\n\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n /** The type of entity (fleet, businessModel, etc). */\n entityType!: string;\n\n @Column({\n type: DataType.STRING,\n allowNull: false,\n })\n /** The type of model this validator applies to. e.g. Vehicle / StopPoint / etc. */\n modelType!: string;\n\n @Column({\n type: DataType.JSONB,\n allowNull: false,\n })\n /** JSON Schema to validate models against */\n schema!: SchemaObject;\n\n @Column({\n type: DataType.BOOLEAN,\n allowNull: false,\n defaultValue: false,\n })\n disabled!: boolean;\n\n @Column({\n type: DataType.DATE,\n allowNull: false,\n })\n declare createdAt?: Date;\n\n @Column({\n type: DataType.DATE,\n allowNull: true,\n })\n declare updatedAt?: Date;\n\n @AfterUpsert\n static afterSaveHandler(instance: CustomValidator, options: CreateOptions): void {\n if (options.transaction) {\n options.transaction.afterCommit(() => sendDimEvent(instance));\n } else {\n sendDimEvent(instance);\n }\n }\n}\n\nexport default CustomValidator;\n","/* eslint-disable no-param-reassign */\nimport { DataTypes, Op } from 'sequelize';\nimport type { Sequelize } from 'sequelize-typescript';\nimport logger from '../utils/logger';\nimport CustomFieldDefinition from './CustomFieldDefinition';\nimport CustomFieldValue from './CustomFieldValue';\nimport TestModel from './tests/TestModel';\nimport ContextAwareTestModel from './tests/contextAwareModels/ContextAwareTestModel';\nimport ContextTestModel from './tests/contextAwareModels/ContextTestModel';\nimport AssociatedTestModel from './tests/AssociatedTestModel';\nimport type { CustomFieldOptions } from '../types';\nimport CustomFieldEntries from './CustomFieldEntries';\nimport CustomValidator from './CustomValidator';\n\ntype ProductionModel = typeof CustomFieldDefinition | typeof CustomFieldValue | typeof CustomFieldEntries | typeof CustomValidator\ninterface InitTablesOptions {\n schemaPrefix?: string\n schemaVersion?: string\n useCustomFieldsEntries?: boolean\n}\n\nconst productionModels: ProductionModel[] = [CustomFieldDefinition, CustomFieldValue, CustomValidator];\nconst testModels = [TestModel, AssociatedTestModel, ContextAwareTestModel, ContextTestModel];\n\nconst SADOT_MIGRATION_PREFIX = 'sadot-migration';\nconst SCHEMA_VERSION = '49c9dd1d-b1cc-445b-a911-fd349d783110';\n\nconst initTables = async (\n sequelize: Sequelize,\n getUser: CustomFieldOptions['getUser'],\n {\n schemaPrefix = SADOT_MIGRATION_PREFIX,\n schemaVersion = SCHEMA_VERSION,\n useCustomFieldsEntries = false,\n }: InitTablesOptions = {},\n): Promise<void> => {\n const CUSTOM_FIELDS_SCHEMA_VERSION = `${schemaPrefix}_${schemaVersion}${useCustomFieldsEntries ? '_withEntries' : ''}`;\n logger.info('custom-fields: initialize custom-fields tables');\n // Detect models and import them to the orm\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n\n if (useCustomFieldsEntries) {\n productionModels.push(CustomFieldEntries);\n }\n\n sequelize.addModels(productionModels);\n\n CustomFieldDefinition.addScope('userScope', () => {\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n CustomValidator.addScope('userScope', () => {\n const user = getUser();\n if (!user?.permissions) {\n return {};\n }\n return {\n where: {\n entityId: [\n ...Object.keys(user.permissions.fleets),\n ...Object.keys(user.permissions.businessModels),\n ...Object.keys(user.permissions.demandSources),\n ],\n },\n };\n });\n\n logger.info('custom-fields: models added');\n\n const SequelizeMeta = sequelize.define(\n 'SequelizeMeta',\n {\n name: {\n type: DataTypes.STRING,\n allowNull: false,\n unique: true,\n primaryKey: true,\n autoIncrement: false,\n },\n },\n {\n tableName: 'SequelizeMeta',\n timestamps: false,\n schema: 'public',\n },\n );\n\n logger.info('custom-fields: starting migrations');\n const migrations = await SequelizeMeta.findAll({ where: { name: { [Op.like]: `${schemaPrefix}%` } }, raw: true });\n const currentSadotSchemaVersion = migrations.at(-1);\n const expectedSchemaVersionIndex = migrations.findIndex((m) => (m as any).name === CUSTOM_FIELDS_SCHEMA_VERSION);\n\n logger.info('custom-fields: migrations', { migrations, currentSadotSchemaVersion, expectedSchemaVersionIndex });\n if (!currentSadotSchemaVersion || (currentSadotSchemaVersion as any).name !== CUSTOM_FIELDS_SCHEMA_VERSION) {\n logger.info('custom-fields: syncing models');\n await CustomFieldDefinition.sync({ alter: true });\n await CustomFieldValue.sync({ alter: true });\n // T.Y TODO: Remove the if statement once we're ready to add the new entries table for all MS\n if (useCustomFieldsEntries) {\n await CustomFieldEntries.sync({ alter: true });\n }\n\n // Always sync CustomValidator\n await CustomValidator.sync({ alter: true });\n\n if (expectedSchemaVersionIndex === -1) {\n await SequelizeMeta.create({ name: CUSTOM_FIELDS_SCHEMA_VERSION });\n }\n logger.info('custom-fields: models synced');\n if (migrations.length && expectedSchemaVersionIndex !== -1 && expectedSchemaVersionIndex < migrations.length - 1) {\n // We have existing migrations, and we are calling `sync`.\n // This means we are in a `down` migration, and hence we should delete newer migrations to ensure we can reapply them.\n const migrationsToDelete = migrations.slice(expectedSchemaVersionIndex + 1);\n await SequelizeMeta.destroy({ where: { name: { [Op.in]: migrationsToDelete.map((m) => (m as any).name) } } });\n }\n }\n};\n\nconst initTestModels = async (sequelize: Sequelize): Promise<void> => {\n logger.info('custom-fields: initialize custom-fields test models');\n // Detect models and import them to the orm\n // eslint-disable-next-line @typescript-eslint/explicit-function-return-type\n if (!sequelize.addModels) {\n throw new Error('sequelize instance must have addModels function');\n }\n\n sequelize.addModels(testModels);\n await sequelize.dropSchema('custom-fields', { logging: false });\n await sequelize.createSchema('custom-fields', { logging: false });\n\n logger.info('custom-fields: test models added');\n await TestModel.sync({ alter: true });\n await AssociatedTestModel.sync({ alter: true });\n await ContextTestModel.sync({ alter: true });\n await ContextAwareTestModel.sync({ alter: true });\n logger.info('custom-fields: test models synced');\n};\n\n// Export models and functions\nexport { CustomFieldValue };\nexport { CustomFieldDefinition };\nexport { CustomFieldEntries };\nexport { CustomValidator };\nexport { TestModel };\nexport { AssociatedTestModel };\nexport { ContextAwareTestModel };\nexport { ContextTestModel };\nexport { initTables };\nexport { initTestModels };\n","import type { Response } from 'express';\nimport { handleError, BadRequest, type LogPayload } from '@autofleet/errors';\nimport { ValidationError as InputValidationError } from 'joi';\nimport { ValidationError as DatabaseValidationError } from 'sequelize';\n\nexport default (err: Error, res: Response, additionalData: LogPayload = undefined): void => {\n let error = err;\n if ([InputValidationError, DatabaseValidationError].some((ErrClass) => err instanceof ErrClass)) {\n error = new BadRequest([err], null);\n }\n\n return handleError(error, res, additionalData);\n};\n","/* eslint-disable newline-per-chained-call */\nimport Joi from 'joi';\nimport { CustomFieldDefinitionType } from '../../../utils/constants';\nimport type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../../../types/definition';\n\nconst FileValidationSchema = Joi.object({\n name: Joi.string().required(),\n type: Joi.string(),\n size: Joi.string(),\n addedBy: Joi.string().uuid(),\n});\nconst statusValidationObject = Joi.object({\n value: Joi.string().required(),\n color: Joi.string().required(),\n});\n/**\n * Schema for the validation of custom field definition\n * The only custom validation is for\n * {@link CustomFieldDefinitionType.SELECT SELECT}\n * and\n * {@link CustomFieldDefinitionType.STATUS STATUS}\n * field types.\n * The rest of the field types are validated by Joi\n */\nconst ValidationSchema = Joi.when('fieldType', {\n is: CustomFieldDefinitionType.SELECT,\n then: Joi.array().required().items(Joi.string()).min(1).unique(),\n otherwise: Joi.when('fieldType', {\n is: CustomFieldDefinitionType.STATUS,\n then: Joi.array().required().items(statusValidationObject).min(1).unique('value'),\n otherwise: Joi.forbidden(),\n }),\n});\n\nconst DefaultValueSchema = Joi.when('fieldType', {\n switch: [\n { is: CustomFieldDefinitionType.BOOLEAN, then: Joi.boolean().allow(null) },\n { is: CustomFieldDefinitionType.DATE, then: Joi.date().allow(null) },\n { is: CustomFieldDefinitionType.DATETIME, then: Joi.date().allow(null) },\n { is: CustomFieldDefinitionType.FILE, then: Joi.array().items(FileValidationSchema).allow(null) },\n { is: CustomFieldDefinitionType.IMAGE, then: Joi.array().items(Joi.string().uri()).allow(null) },\n { is: CustomFieldDefinitionType.NUMBER, then: Joi.number().allow(null) },\n { is: CustomFieldDefinitionType.SELECT, then: Joi.string().allow(null) },\n { is: CustomFieldDefinitionType.STATUS, then: Joi.string().allow(null) },\n { is: CustomFieldDefinitionType.TEXT, then: Joi.string().allow(null) },\n ],\n});\n\nconst CustomFieldDefinitionCreationSchema = Joi.object({\n name: Joi.string().required(),\n displayName: Joi.string().required(),\n validation: ValidationSchema,\n defaultValue: DefaultValueSchema,\n fieldType: Joi.string().valid(...Object.values(CustomFieldDefinitionType)).required(),\n entityId: Joi.string().guid().required(),\n entityType: Joi.string().required(),\n description: Joi.string(),\n required: Joi.boolean(),\n disabled: Joi.boolean(),\n blockEditingFromUI: Joi.boolean(),\n}).oxor('required', 'blockEditingFromUI', { isPresent: (value) => value === true });\n\nconst CustomFieldDefinitionUpdateSchema = Joi.object({\n displayName: Joi.string(),\n validation: ValidationSchema,\n defaultValue: DefaultValueSchema,\n fieldType: Joi.string().valid(...Object.values(CustomFieldDefinitionType)),\n description: Joi.string().allow(null),\n required: Joi.boolean(),\n disabled: Joi.boolean(),\n blockEditingFromUI: Joi.boolean(),\n}).oxor('required', 'blockEditingFromUI', { isPresent: (value) => value === true });\n\nexport const validateCustomFieldDefinitionCreation = (payload: unknown): Promise<CreateCustomFieldDefinition> =>\n CustomFieldDefinitionCreationSchema.validateAsync(payload, { abortEarly: false });\n\nexport const validateCustomFieldDefinitionUpdate = (payload: unknown): Promise<UpdateCustomFieldDefinition> =>\n CustomFieldDefinitionUpdateSchema.validateAsync(payload, { abortEarly: false });\n","import { ResourceNotFoundError } from '@autofleet/errors';\nimport { Router } from '@autofleet/node-common';\nimport handleError from '../errors';\nimport * as DefinitionRepo from '../../../repository/definition';\nimport type { CreateCustomFieldDefinition, UpdateCustomFieldDefinition } from '../../../types/definition';\nimport { validateCustomFieldDefinitionCreation, validateCustomFieldDefinitionUpdate } from './validations';\nimport logger from '../../../utils/logger';\nimport type { CustomFieldDefinition } from '../../../models';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\nconst ENTITY = 'CustomFieldDefinition';\n\nconst toPascalCase = (str: string): string => str.replace(/(^\\w|-\\w)/g, (subStr) => subStr.replace(/-/, '').toUpperCase());\n\n/**\n * Create\n */\nrouter.post<{ modelName: string; }>('/', async (req, res) => {\n const { modelName } = req.params;\n const modelType = toPascalCase(modelName);\n try {\n const validatedPayload: CreateCustomFieldDefinition = await validateCustomFieldDefinitionCreation(req.body);\n\n const customFieldDefinition = await DefinitionRepo.create({\n ...validatedPayload,\n modelType,\n });\n return res.status(201).json(customFieldDefinition);\n } catch (err) {\n logger.error('Failed to create custom field definition', err);\n return handleError(err, res, { logger, message: `Error in create ${ENTITY} request` });\n }\n});\n\n/**\n * Get by id\n */\nrouter.get<{ modelName: string; customFieldDefinitionId: string; }, CustomFieldDefinition>('/:customFieldDefinitionId', async (req, res) => {\n const { customFieldDefinitionId } = req.params;\n try {\n const customFieldDefinition = await DefinitionRepo.findById(customFieldDefinitionId);\n\n if (!customFieldDefinition) {\n throw new ResourceNotFoundError();\n }\n\n return res.json(customFieldDefinition);\n } catch (err) {\n logger.error('Failed to fetch custom field definition', err);\n return handleError(err, res, { logger, message: `Error in get ${ENTITY} request` });\n }\n});\n\n/**\n * Get all\n */\nrouter.get<{ modelName: string; }, CustomFieldDefinition[], never, { entityIds?: string[]; }>('/', async (req, res) => {\n const { params: { modelName }, query: { entityIds } } = req;\n\n const modelType = toPascalCase(modelName);\n try {\n const where = {\n modelType,\n ...(entityIds?.length > 0 && { entityId: entityIds }),\n };\n const customFieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true });\n return res.json(customFieldDefinitions);\n } catch (err) {\n logger.error('Failed to fetch custom field definitions', err);\n return handleError(err, res, { logger, message: `Error in get all ${ENTITY} request` });\n }\n});\n\n/**\n * Update\n */\nrouter.patch<{ modelName: string; customFieldDefinitionId: string; }, CustomFieldDefinition>('/:customFieldDefinitionId', async (req, res) => {\n const { customFieldDefinitionId, modelName } = req.params;\n const modelType = toPascalCase(modelName);\n try {\n const validatedPayload: UpdateCustomFieldDefinition = await validateCustomFieldDefinitionUpdate(req.body);\n\n const customFieldDefinition = await DefinitionRepo.findByWhere({\n id: customFieldDefinitionId,\n modelType,\n });\n\n if (!customFieldDefinition) {\n throw new ResourceNotFoundError();\n }\n\n const updatedCustomFieldDefinition = await DefinitionRepo.update(\n customFieldDefinitionId,\n { ...validatedPayload, modelType },\n );\n\n return res.status(200).json(updatedCustomFieldDefinition);\n } catch (err) {\n logger.error('Failed to patch custom field definition', err);\n return handleError(err, res, { logger, message: `Error in update ${ENTITY} request` });\n }\n});\n\nexport default router;\n","import type { FindOptions, IncludeOptions, Transactionable } from 'sequelize';\nimport logger from '../utils/logger';\nimport { CustomValidator } from '../models';\nimport type { ModelOptions } from '../types';\n\nexport interface FindValidatorOptions extends Transactionable {\n withDisabled?: boolean;\n attributes?: string[];\n raw?: boolean;\n include?: IncludeOptions[];\n}\n\n// Make sure this interface is compatible with the Sequelize model\nexport interface ValidatorAttributes {\n entityId: string;\n entityType: string;\n modelType: string;\n schema: CustomValidator['schema'];\n disabled?: boolean;\n [key: string]: unknown; // Add index signature for Sequelize compatibility\n}\n\nexport const create = async (\n validatorAttributes: ValidatorAttributes,\n options: Transactionable = {},\n): Promise<CustomValidator> => {\n logger.debug('custom-validator - create validator');\n\n // Use unknown type to bypass TypeScript errors while maintaining compatibility\n const validator = await CustomValidator.create(validatorAttributes as Record<string, unknown>, options);\n\n return validator;\n};\n\nexport const findAll = async (\n where = {},\n options: FindOptions & {\n modelOptions?: ModelOptions,\n withDisabled?: boolean\n } = {},\n): Promise<CustomValidator[]> => {\n logger.debug('custom-validator - find all validators');\n\n const {\n transaction, withDisabled, include, attributes, raw,\n } = options;\n\n let validators;\n if (withDisabled) {\n // If withDisabled is true, use unscoped to ignore the default scope that filters disabled items\n // Apply the userScope separately to maintain permission filtering\n validators = await CustomValidator.unscoped().scope('userScope').findAll({\n where,\n transaction,\n include,\n attributes,\n raw,\n });\n } else {\n // Use defaultScope and userScope to filter both disabled and by permissions\n // The defaultScope keeps only non-disabled validators\n validators = await CustomValidator.scope(['defaultScope', 'userScope']).findAll({\n where,\n transaction,\n include,\n attributes,\n raw,\n });\n }\n\n return validators;\n};\n\nexport const findAllByModelType = async (\n modelType: string,\n entityId: string,\n options: FindOptions & {\n modelOptions?: ModelOptions,\n withDisabled?: boolean\n } = {},\n): Promise<CustomValidator[]> => {\n logger.debug('custom-validator - find all validators by model type');\n return findAll(\n {\n modelType,\n ...(!options?.modelOptions?.useEntityIdFromInclude && { entityId }),\n },\n {\n ...options,\n include: options?.modelOptions?.include?.(entityId),\n },\n );\n};\n\nexport const update = async (\n id: string,\n updates: Partial<ValidatorAttributes>,\n options?: Transactionable,\n): Promise<[number, CustomValidator[]]> => {\n logger.debug('custom-validator - update validator');\n\n return CustomValidator.update(\n updates,\n {\n where: { id },\n returning: true,\n ...options,\n },\n );\n};\n\nexport const disable = async (\n id: string,\n options?: Transactionable,\n): Promise<[number, CustomValidator[]]> => {\n logger.debug('custom-validator - disable validator');\n\n return update(id, { disabled: true }, options);\n};\n","import Joi from 'joi';\n\nconst jsonSchemaValidation = Joi.object().unknown(true);\n\nexport interface SchemaObject {\n type: 'object';\n properties?: {\n before?: object;\n after?: object;\n };\n required?: string[];\n allOf?: object[];\n anyOf?: object[];\n oneOf?: object[];\n additionalProperties?: boolean | object;\n $id?: string;\n $schema?: string;\n if?: object;\n then?: object;\n else?: object;\n}\n\nconst schemaObject = Joi.object<SchemaObject>({\n type: Joi.string().valid('object'),\n properties: Joi.object({\n before: jsonSchemaValidation,\n after: jsonSchemaValidation,\n }).required(),\n required: Joi.array().items(Joi.string()),\n allOf: Joi.array().items(Joi.object()),\n anyOf: Joi.array().items(Joi.object()),\n oneOf: Joi.array().items(Joi.object()),\n additionalProperties: Joi.alternatives().try(Joi.boolean(), Joi.object()),\n $id: Joi.string(),\n $schema: Joi.string(),\n if: Joi.object(),\n then: Joi.object(),\n else: Joi.object(),\n});\n\nexport interface CreateValidatorPayload {\n entityId: string;\n entityType: string;\n schema: SchemaObject;\n}\n\nexport interface UpdateValidatorPayload extends Partial<CreateValidatorPayload> {\n disabled?: boolean;\n}\n\ninterface ValidationSchemas {\n create: Joi.ObjectSchema<CreateValidatorPayload>;\n update: Joi.ObjectSchema<UpdateValidatorPayload>;\n}\n\nconst validationSchemas: ValidationSchemas = {\n create: Joi.object<CreateValidatorPayload>({\n entityId: Joi.string().uuid().required(),\n entityType: Joi.string().required(),\n schema: schemaObject.required(),\n }),\n\n update: Joi.object<UpdateValidatorPayload>({\n entityId: Joi.string().uuid(),\n entityType: Joi.string(),\n schema: schemaObject,\n disabled: Joi.boolean(),\n }).min(1),\n};\n\nexport default validationSchemas;\n","import Ajv from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { BadRequest } from '@autofleet/errors';\nimport logger from '../../logger';\nimport type { SchemaObject } from '../../../api/v1/validator/validations';\n\n// Instantiate Ajv for meta-validation\nconst metaValidator = new Ajv({\n allErrors: true,\n strict: false,\n strictTypes: false,\n $data: true, // Enable $data references\n});\naddFormats(metaValidator);\n\n/**\n * Schema for validating JSON Schema objects in custom validators\n * This is a meta-schema to ensure that custom validator schemas are valid Ajv schemas\n */\nconst validatorMetaSchema = {\n type: 'object',\n properties: {\n type: { type: 'string', enum: ['object'] },\n properties: {\n type: 'object',\n properties: {\n before: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: ['object'] },\n properties: { type: 'object' },\n },\n },\n after: {\n type: 'object',\n properties: {\n type: { type: 'string', enum: ['object'] },\n properties: { type: 'object' },\n },\n },\n },\n },\n required: {\n type: 'array',\n items: { type: 'string' },\n },\n if: { type: 'object' },\n then: { type: 'object' },\n else: { type: 'object' },\n },\n required: ['type', 'properties'],\n};\n\n/**\n * Validates that a given schema is a valid Ajv schema\n * This function is used to validate schemas passed to custom validators\n *\n * @param schema The schema to validate\n * @returns true if valid, throws an error if invalid\n */\nexport const validateValidatorSchema = (schema: SchemaObject): boolean => {\n try {\n // First validate the schema structure\n const validateMetaSchema = metaValidator.compile(validatorMetaSchema);\n const isValidStructure = validateMetaSchema(schema);\n\n if (!isValidStructure) {\n const errorDetails = validateMetaSchema.errors?.map((err) =>\n `${(err as unknown as { instancePath: string }).instancePath || ''} ${(err as unknown as { message: string }).message || 'Invalid schema structure'}`).join(', ');\n\n logger.error('Invalid validator schema structure', {\n errors: validateMetaSchema.errors,\n schema,\n });\n\n throw new BadRequest(\n [new Error(`Invalid validator schema structure: ${errorDetails}`)],\n ['Invalid validator schema structure'],\n );\n }\n\n // Then try to compile the schema with Ajv to verify it's a valid JSON Schema\n try {\n metaValidator.compile(schema);\n return true;\n } catch (compileError) {\n logger.error('Failed to compile validator schema', { error: compileError, schema });\n\n throw new BadRequest(\n [new Error(`Failed to compile validator schema: ${(compileError as Error).message}`)],\n ['Invalid validator schema'],\n );\n }\n } catch (error) {\n if (error instanceof BadRequest) {\n throw error;\n }\n\n logger.error('Error validating validator schema', { error, schema });\n throw new BadRequest(\n [new Error(`Error validating validator schema: ${(error as Error).message}`)],\n ['Invalid validator schema'],\n );\n }\n};\n\nexport default validateValidatorSchema;\n","import { ResourceNotFoundError } from '@autofleet/errors';\nimport { Router } from '@autofleet/node-common';\nimport { StatusCodes } from 'http-status-codes';\nimport handleError from '../errors';\nimport * as ValidatorRepo from '../../../repository/validator';\nimport validations from './validations';\nimport logger from '../../../utils/logger';\nimport { validateValidatorSchema } from '../../../utils/validations/schema/validator-schema';\nimport type { CustomValidator } from '../../../models';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\nconst ENTITY = 'CustomValidator';\n\n/**\n * Create\n */\nrouter.post<{ modelName: string }>('/', async (req, res) => {\n const { modelName } = req.params;\n try {\n // Validate the request body\n const validatedPayload = await validations.create.validateAsync(req.body);\n\n // Validate that the schema is a valid AJV schema\n validateValidatorSchema(validatedPayload.schema);\n\n const validator = await ValidatorRepo.create({\n ...validatedPayload,\n modelType: modelName,\n });\n\n return res.status(StatusCodes.CREATED).json(validator);\n } catch (err) {\n return handleError(err, res, { logger, message: `Error in create ${ENTITY} request` });\n }\n});\n\n/**\n * Get all\n */\nrouter.get<\n { modelName: string },\n { validators: CustomValidator[] },\n never,\n { entityId?: string; entityType?: string }\n>('/', async (req, res) => {\n try {\n const { modelName } = req.params;\n const { entityId, entityType } = req.query;\n\n const where = {\n modelType: modelName,\n ...(entityId && { entityId }),\n ...(entityType && { entityType }),\n };\n\n const validators = await ValidatorRepo.findAll(where);\n\n return res.status(StatusCodes.OK).json({ validators });\n } catch (err) {\n return handleError(err, res, { logger, message: `Error in get all ${ENTITY} request` });\n }\n});\n\n/**\n * Get by id\n */\nrouter.get<{ modelName: string; validatorId: string }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId, modelName } = req.params;\n // Include disabled validators when fetching by ID\n const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });\n\n if (!validators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err, res, { logger, message: `Error in get ${ENTITY} request` });\n }\n});\n\n/**\n * Update\n */\nrouter.patch<{ modelName: string; validatorId: string }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // Validate the request body\n const validatedPayload = await validations.update.validateAsync(req.body);\n\n // If schema is included in the update, validate that it's a valid AJV schema\n if (validatedPayload.schema) {\n validateValidatorSchema(validatedPayload.schema);\n }\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload as any);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err, res, { logger, message: `Error in update ${ENTITY} request` });\n }\n});\n\n/**\n * Delete (disable)\n */\nrouter.delete<{ modelName: string; validatorId: string }>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count] = await ValidatorRepo.disable(validatorId);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator failed to be disabled');\n }\n\n return res.status(StatusCodes.NO_CONTENT).send();\n } catch (err) {\n return handleError(err, res, { logger, message: `Error in delete ${ENTITY} request` });\n }\n});\n\nexport default router;\n","import { Router } from '@autofleet/node-common';\nimport logger from '../../utils/logger';\nimport definitionRouter from './definition';\nimport validatorRouter from './validator';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\n\nrouter.use('/custom-field-definitions/:modelName', definitionRouter);\nrouter.use('/custom-validators/:modelName', validatorRouter);\n\nexport default router;\n","// export the api object\nimport { Router } from '@autofleet/node-common';\nimport v1 from './v1';\nimport logger from '../utils/logger';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\n\nrouter.use('/v1', v1);\n\nexport default router;\n","import { Sequelize } from 'sequelize-typescript';\nimport { QueryTypes } from 'sequelize';\n\nexport default (databaseConfig: any): Sequelize => {\n const ENV_DEV = 'test';\n const env: string = process.env.NODE_ENV || ENV_DEV;\n const config = databaseConfig[env];\n let sequelize: Sequelize;\n if (config.use_env_variable) {\n sequelize = new Sequelize(process.env[config.use_env_variable], config);\n } else {\n sequelize = new Sequelize(config.database, config.username, config.password, config);\n }\n return sequelize;\n};\n\nexport const createSequelizeMeta = (sequelize: Sequelize): Promise<{ name: string; }[]> => sequelize.query(`\nCREATE TABLE IF NOT EXISTS \"SequelizeMeta\" (\n name character varying(255) PRIMARY KEY\n);\n`, { type: QueryTypes.SELECT });\n","import { CustomFieldDefinitionType } from '../../utils/constants';\n\nexport const formatFunctions: Partial<Record<CustomFieldDefinitionType, (value: any) => string | null>> = {\n [CustomFieldDefinitionType.DATE]: (value) => {\n if (value) {\n const date = new Date(value);\n if (date.toString() === 'Invalid Date') {\n throw new Error(`Invalid date value: ${value}`);\n }\n return date.toISOString();\n }\n return null;\n },\n};\n","import type { FindOptions, Transactionable, WhereOptions } from 'sequelize';\nimport { CustomFieldValue, CustomFieldDefinition } from '../models';\nimport * as DefinitionRepo from './definition';\nimport type { CreateCustomFieldValue, ValuesToUpdate } from '../types/value';\nimport logger from '../utils/logger';\nimport { MissingDefinitionError } from '../errors';\nimport type { ModelOptions } from '../types';\nimport { formatFunctions } from './utils/formatValues';\n\nexport const findByModelIdAndDefinition = async (modelId: string, customFieldDefinitionId: string): Promise<CustomFieldValue[]> =>\n CustomFieldValue.findAll({ where: { modelId, customFieldDefinitionId }, include: [CustomFieldDefinition] });\n\nexport const create = async (data: CreateCustomFieldValue, withAssociations = false): Promise<CustomFieldValue> => {\n const created = await CustomFieldValue.create(data);\n if (withAssociations) {\n const createdWithAssociations = await findByModelIdAndDefinition(created.modelId, created.customFieldDefinitionId);\n return createdWithAssociations?.[0];\n }\n return created;\n};\n\nexport const findAllValues = async (): Promise<CustomFieldValue[]> => CustomFieldValue.findAll({ include: [CustomFieldDefinition] });\n/**\n * Get all values for model instance id (with their definitions)\n * @param modelId\n * @returns CustomFieldValue[]\n */\nexport const findValuesByModelId = async (modelId: string): Promise<CustomFieldValue[]> => CustomFieldValue.findAll({ where: { modelId }, include: [CustomFieldDefinition] });\n\n/**\n* Retrieves custom field values for given model IDs\n* @param modelIds - An array of model IDs to query custom field values for.\n* @param options - Optional configuration object.\n*/\nexport const findValuesByModelIds = async (modelIds: string[], options?: Transactionable): Promise<CustomFieldValue[]> => {\n const { transaction } = options;\n return CustomFieldValue.findAll({\n where: { modelId: modelIds },\n transaction,\n raw: true,\n nest: true,\n });\n};\n\n/**\n * Try to update custom field values for a model instance.\n * Create new value record if not exists, but fails if value's definition not exist.\n * Return the updated values\n */\nexport const updateValues = async (\n modelType: string,\n modelId: string,\n identifiers: string[],\n valuesToUpdate: ValuesToUpdate,\n options: FindOptions & { modelOptions?: ModelOptions } = {},\n): Promise<CustomFieldValue[]> => {\n const names = Object.keys(valuesToUpdate);\n logger.debug(`custom-fields: updating values for ${modelType} ${modelId}`, {\n names,\n optionsKeys: options ? Object.keys(options) : null,\n valuesToUpdate,\n identifiers,\n });\n const { modelOptions, transaction } = options;\n\n const where: WhereOptions = {\n modelType,\n name: names,\n ...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),\n };\n\n const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) ?? [];\n\n const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);\n if (fieldDefinitions.length !== names.length) {\n logger.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names, fieldDefinitions });\n const missingDefinitions = names.filter((name) => !fieldDefinitions.some((def) => def.name === name));\n throw new MissingDefinitionError(missingDefinitions);\n }\n\n const disabledNames = disabledDefinitions?.map((def) => def.name) || [];\n const valuesWithDisabledDefinitions = names.filter((name) => disabledNames.includes(name));\n if (valuesWithDisabledDefinitions?.length > 0) {\n logger.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);\n }\n\n const values: CreateCustomFieldValue[] = names.map((name) => {\n const fieldDefinition = fieldDefinitions.find((def) => def.name === name);\n const formatFunction = formatFunctions[fieldDefinition.fieldType];\n const value = formatFunction ? formatFunction(valuesToUpdate[name]) : valuesToUpdate[name];\n return {\n modelId,\n updatedAt: new Date(),\n customFieldDefinitionId: fieldDefinition.id,\n value: value !== undefined ? value : fieldDefinition.defaultValue,\n };\n });\n\n return Promise.all(values.map(async (value) => {\n const [cfv] = await CustomFieldValue.upsert(value, {\n transaction: options.transaction,\n });\n return cfv;\n }));\n};\n\nexport const deleteValue = (\n id: string,\n options: any = {},\n): Promise<any> => CustomFieldValue.update(\n { deletedAt: new Date() },\n {\n where: { id },\n transaction: options.transaction,\n },\n);\n","/* eslint-disable no-param-reassign */\nimport type {\n FindOptions,\n Includeable,\n Transaction,\n WhereOptions,\n} from 'sequelize';\nimport { CustomFieldEntries } from '../models';\nimport type { ModelOptions } from '../types';\nimport logger from '../utils/logger';\nimport { MissingDefinitionError } from '../errors';\nimport * as DefinitionRepo from './definition';\nimport { formatFunctions } from './utils/formatValues';\n\ntype CustomFieldEntriesModelOptions = ModelOptions & { include?: Includeable, transaction?: Transaction };\n\nexport const findEntriesByModelId = async (modelId: string, options: CustomFieldEntriesModelOptions = {}): Promise<CustomFieldEntries | null> => {\n const { transaction } = options;\n return CustomFieldEntries.findOne({\n where: { modelId },\n transaction,\n });\n};\n\nexport const findEntriesByModelIds = async (modelIds: string[], options: CustomFieldEntriesModelOptions = {}): Promise<CustomFieldEntries[]> => {\n const { transaction } = options;\n return CustomFieldEntries.findAll({\n where: { modelId: modelIds },\n transaction,\n });\n};\n\nexport const updateEntries = async (\n modelId: string,\n modelType: string,\n customFields: Record<string, any>,\n identifiers: string[],\n options: FindOptions & { modelOptions?: ModelOptions } = {},\n): Promise<[CustomFieldEntries, boolean | null]> => {\n const customFieldsNames = Object.keys(customFields);\n logger.debug(`custom-fields: updating entries for ${modelType} ${modelId}`, {\n customFieldsNames,\n optionsKeys: options ? Object.keys(options) : null,\n customFields,\n identifiers,\n });\n const { modelOptions, transaction } = options;\n\n const where: WhereOptions = {\n modelType,\n name: customFieldsNames,\n ...(!options.modelOptions?.useEntityIdFromInclude && { entityId: identifiers }),\n };\n\n const fieldDefinitions = await DefinitionRepo.findAll(where, { withDisabled: true, transaction, include: modelOptions.include?.(identifiers) }) ?? [];\n\n const disabledDefinitions = fieldDefinitions.filter((def) => def.disabled);\n if (fieldDefinitions.length !== customFieldsNames.length) {\n logger.warn(`custom-fields: missing definitions for ${modelType} ${modelId}`, { names: customFieldsNames, fieldDefinitions });\n const missingDefinitions = customFieldsNames.filter((name) => !fieldDefinitions.some((def) => def.name === name));\n throw new MissingDefinitionError(missingDefinitions);\n }\n\n const disabledNames = disabledDefinitions?.map((def) => def.name) || [];\n const valuesWithDisabledDefinitions = customFieldsNames.filter((name) => disabledNames.includes(name));\n if (valuesWithDisabledDefinitions?.length > 0) {\n logger.warn(`custom-fields: trying to update disabled values: ${valuesWithDisabledDefinitions.join(', ')}`);\n }\n\n const definitionsByName = Object.fromEntries(fieldDefinitions.map((definition) => [definition.name, definition]));\n // If we need to format the value before we save it\n Object.entries(customFields)\n .filter(([definitionName]) => formatFunctions[definitionsByName[definitionName].fieldType])\n .forEach(([definitionName, value]) => {\n const { fieldType } = definitionsByName[definitionName];\n customFields[definitionName] = formatFunctions[fieldType](value);\n });\n\n return CustomFieldEntries.upsert(\n {\n modelId,\n entityId: fieldDefinitions[0].entityId,\n modelType,\n customFields,\n },\n options,\n );\n};\n","const mapAttributeToInstance = (scopeAttributes: string[], instance: any) =>\n scopeAttributes.map((attr) => instance[attr]);\n\nconst applyScopeToInstance = (instance: any, scopeAttributes: string[]): any[] => {\n const uniqueAttributes = Array.from(new Set(scopeAttributes));\n if (Array.isArray(instance)) {\n return instance.flatMap((ins) => mapAttributeToInstance(uniqueAttributes, ins));\n }\n return mapAttributeToInstance(uniqueAttributes, instance);\n};\n\nexport default applyScopeToInstance;\n","/* eslint-disable no-param-reassign */\nimport * as ValueRepo from '../repository/value';\nimport * as DefinitionRepo from '../repository/definition';\nimport * as EntriesRepo from '../repository/entries';\nimport type CustomFieldValue from '../models/CustomFieldValue';\nimport type CustomFieldDefinition from '../models/CustomFieldDefinition';\nimport type { SerializedCustomFields } from '../types/definition';\nimport type { CustomFieldOptions, ModelOptions, TransactionOptions } from '../types';\nimport applyScopeToInstance from '../utils/scopeAttributes';\n\n// Include all required fields for proper functioning\nconst CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL = [\n 'id',\n 'name',\n 'entityId',\n 'fieldType',\n 'displayName',\n 'validation',\n 'entityType',\n 'modelType',\n 'required',\n 'disabled',\n 'defaultValue',\n];\n\ntype SupportedHookTypes = 'afterFind' | 'afterCreate' | 'afterUpdate';\n\ntype CustomFieldEntries = Record<string, any>;\n\ninterface GetValuesGroupByInstanceResponse {\n [modelId: string]: CustomFieldValue[];\n}\n\ninterface GetCustomFieldEntriesByInstanceIdResponse {\n [modelId: string]: CustomFieldEntries;\n}\n\nexport const getCustomFieldEntriesByInstanceId = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[],\n options?: TransactionOptions,\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,\n}): Promise<GetCustomFieldEntriesByInstanceIdResponse> => {\n if (!sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldEntries = await EntriesRepo.findEntriesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n const customFieldEntriesByInstanceId = Object.fromEntries(customFieldEntries.map((instanceEntries) => {\n const { modelId, customFields } = instanceEntries?.dataValues ?? {};\n if (!modelId) {\n return undefined;\n }\n return [modelId, customFields];\n }).filter(Boolean));\n\n instancesIds.forEach((instanceId) => {\n customFieldEntriesByInstanceId[instanceId] ??= {};\n });\n\n return customFieldEntriesByInstanceId;\n};\n\nexport const getValuesGroupByInstance = async ({\n instancesIds,\n options,\n sadotOptions,\n}: {\n instancesIds: string[],\n options?: TransactionOptions,\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,\n}): Promise<GetValuesGroupByInstanceResponse> => {\n if (sadotOptions.useCustomFieldsEntries) {\n return {};\n }\n\n const customFieldValues = await ValueRepo.findValuesByModelIds(\n instancesIds,\n options ?? {},\n );\n\n // Group fields by modelId\n return customFieldValues.reduce((acc, v) => {\n const { modelId } = v;\n acc[modelId] ??= [];\n acc[modelId].push(v);\n return acc;\n }, {});\n};\n\n/**\n * Serialize custom fields value into the format of {[name] -> [fieldData]}\n */\nconst serializeCustomFields = (\n customFieldValues: CustomFieldValue[],\n customFieldDefinitionsHash: Record<string, CustomFieldDefinition>,\n): SerializedCustomFields => {\n const customFields = customFieldValues.reduce((acc, cfv) => ({\n ...acc,\n ...(\n customFieldDefinitionsHash[cfv.customFieldDefinitionId]\n && { [customFieldDefinitionsHash[cfv.customFieldDefinitionId].name]: cfv.value }\n ),\n }), {});\n return customFields;\n};\n/**\n * A hook to attach the custom fields when fetching a model instances.\n */\nconst enrichResults = (\n modelType: string,\n scopeAttributes: string[],\n hookType?: SupportedHookTypes,\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false },\n) => async (\n instancesOrInstance: any | any[],\n options: TransactionOptions,\n): Promise<void> => {\n if (\n options.originalAttributes?.length > 0\n && !options.originalAttributes?.includes?.('customFields')\n ) {\n return;\n }\n\n const primaryKey = 'id';\n let instances = Array.isArray(instancesOrInstance)\n ? instancesOrInstance\n : [instancesOrInstance];\n\n instances = instances.filter(Boolean);\n\n const identifiers = applyScopeToInstance(instances, scopeAttributes);\n\n const uniqueIdentifiers = [...new Set(identifiers)].filter(Boolean);\n\n const identifierCustomFieldDefinitionsMapping = uniqueIdentifiers.reduce((map, identifier) => ({\n ...map,\n [identifier]: [],\n }), {});\n\n // Cache for definitions by model type and transaction to avoid redundant DB queries\n let customFieldDefinitionsPromise;\n let cacheKey;\n\n if (options.transaction) {\n // Initialize definition cache Map if not already present directly on the transaction object\n options.transaction.definitionCache ||= new Map();\n cacheKey = `${modelType}:${uniqueIdentifiers.slice().sort().join(',')}`;\n customFieldDefinitionsPromise = options.transaction.definitionCache.get(cacheKey);\n }\n\n if (!customFieldDefinitionsPromise) {\n // Fetch from database (either first time in this transaction or no transaction)\n customFieldDefinitionsPromise = DefinitionRepo.findByEntityIds(\n modelType,\n uniqueIdentifiers,\n { transaction: options.transaction, modelOptions, attributes: CUSTOM_FIELD_DEFINITION_ATTRIBUTES_TO_PULL },\n );\n\n options.transaction?.definitionCache?.set(cacheKey, customFieldDefinitionsPromise);\n }\n const customFieldDefinitions = await customFieldDefinitionsPromise;\n\n if (customFieldDefinitions.length === 0) {\n // if no custom fields, we can return\n instances.forEach((instance) => {\n instance.customFields = {};\n });\n return;\n }\n\n if (modelOptions?.include && modelOptions.useEntityIdFromInclude) {\n // if we pass useEntityIdFromInclude,\n // map the entity from the options to the identifierCustomFieldDefinitionsMapping\n modelOptions.include(identifiers).forEach(({ model }) => {\n customFieldDefinitions.forEach((cfd) => {\n const entityId = cfd[`${model.name}.entityId`];\n identifierCustomFieldDefinitionsMapping[entityId] = [];\n });\n });\n }\n\n const definitionsMap = customFieldDefinitions.reduce((map, definition) => ({\n ...map,\n [definition.id]: definition,\n }), {});\n\n customFieldDefinitions.forEach((cfd) => {\n identifierCustomFieldDefinitionsMapping[cfd.entityId].push(cfd);\n });\n\n // Get the values per instates ids:\n const instancesIds = instances.map((i) => i[primaryKey]);\n\n // Group fields by modelId\n const [valuesGroupByInstance, customFieldEntriesByInstanceId] = await Promise.all([\n getValuesGroupByInstance({\n instancesIds,\n options,\n sadotOptions,\n }),\n getCustomFieldEntriesByInstanceId({\n instancesIds,\n options,\n sadotOptions,\n }),\n ]);\n\n // Attach custom fields to the instances\n instances.forEach((instance) => {\n const { id } = instance;\n\n const instanceValues = valuesGroupByInstance[id];\n const serializedCustomFieldsValues = instanceValues ? serializeCustomFields(instanceValues, definitionsMap) : {};\n\n const customFields = sadotOptions.useCustomFieldsEntries\n ? customFieldEntriesByInstanceId[id]\n : serializedCustomFieldsValues;\n\n scopeAttributes.forEach((attribute) => {\n const identifier = instance[attribute];\n\n const entityCustomFieldDefinitions = identifierCustomFieldDefinitionsMapping[identifier];\n if (entityCustomFieldDefinitions?.length > 0) {\n entityCustomFieldDefinitions.forEach((customFieldDefinition) => {\n if (customFields[customFieldDefinition.name] === undefined) {\n customFields[customFieldDefinition.name] = null;\n }\n });\n }\n });\n instance.customFields = customFields;\n options.attributesToRemove?.forEach?.((attribute) => {\n delete instance.dataValues?.[attribute];\n // if raw:\n delete instance?.[attribute];\n });\n // sequelize will think customFields changed also in 'find', so we need to mark it as unchanged\n if (hookType === 'afterFind') {\n // changed() could be undefined, i.e in raw: true\n instance?.changed?.('customFields', false);\n }\n });\n};\n\nexport default enrichResults;\n","/* eslint-disable no-param-reassign */\nimport type { FindOptions } from 'sequelize';\nimport logger from '../utils/logger';\n\nconst doScopeAttributesMissing = (\n scopeAttributes: string[],\n queryAttributes: (string | string[])[],\n): string[] => {\n const attributes = scopeAttributes\n .filter((attribute) => !queryAttributes.includes(attribute));\n if (!queryAttributes.includes?.('id')) {\n attributes.push('id');\n }\n return attributes;\n};\n\n// eslint-disable-next-line import/prefer-default-export\nexport const beforeFind = (scopeAttributes: string[]) => (options: FindOptions): void => {\n const { attributes: queryAttributes } = options;\n if ((queryAttributes as string[])?.includes?.('customFields')) {\n const missingScopeAttributes = doScopeAttributesMissing(scopeAttributes, queryAttributes as string[]);\n logger.debug('sadot - before find hook');\n if (missingScopeAttributes?.length > 0) {\n (queryAttributes as string[]).push(...missingScopeAttributes);\n (options as any).attributesToRemove = missingScopeAttributes;\n }\n }\n};\n","import type { Transaction } from 'sequelize';\nimport * as ValueRepo from '../../repository/value';\nimport * as EntriesRepo from '../../repository/entries';\nimport type { ModelOptions } from '../../types';\n\ninterface UpdateInstanceValuesParams {\n modelId: string;\n modelType: string;\n identifiers: string[];\n customFields: Record<string, any>;\n options?: {\n transaction?: Transaction;\n modelOptions?: ModelOptions;\n useCustomFieldsEntries?: boolean;\n };\n}\n\nconst updateInstanceValues = async ({\n modelId,\n modelType,\n identifiers,\n customFields,\n options = {\n modelOptions: {},\n useCustomFieldsEntries: false,\n },\n}: UpdateInstanceValuesParams): Promise<void> => {\n await ValueRepo.updateValues(\n modelType,\n modelId,\n identifiers,\n customFields,\n {\n ...options,\n modelOptions: options.modelOptions ?? {},\n },\n );\n\n /*\n T.Y TODO - Once we're ready to switch from custom_field_values to custom_field_entries, we should remove the ValueRepo.updateValues call.\n Currently, We're updating both tables to keep the data in sync, but not all microservices are using the new table yet.\n */\n\n if (!options?.useCustomFieldsEntries) {\n return;\n }\n\n const { dataValues: { customFields: oldCustomFields } } = await EntriesRepo.findEntriesByModelId(modelId, options) ?? { dataValues: {} };\n const newCustomFields = { ...oldCustomFields, ...customFields };\n\n await EntriesRepo.updateEntries(\n modelId,\n modelType,\n newCustomFields,\n identifiers,\n {\n ...options,\n modelOptions: options.modelOptions ?? {},\n },\n );\n};\n\nexport default updateInstanceValues;\n","import type {\n BulkCreateOptions, CreateOptions, UpdateOptions, WhereOptions,\n} from 'sequelize';\nimport Ajv from 'ajv';\nimport Joi from 'joi';\nimport addFormats from 'ajv-formats';\nimport { BadRequest } from '@autofleet/errors';\nimport ajvErrors from 'ajv-errors';\nimport logger from '../utils/logger';\nimport * as ValidatorRepo from '../repository/validator';\nimport * as DefinitionRepo from '../repository/definition';\nimport { InvalidValueError, MissingRequiredCustomFieldError } from '../errors';\nimport type { CustomFieldOptions, ModelOptions } from '../types';\nimport applyScopeToInstance from '../utils/scopeAttributes';\nimport updateInstanceValues from './utils/updateInstanceValues';\nimport { CustomFieldDefinitionType } from '../utils/constants';\nimport type { CustomFieldDefinition } from '../models';\n\n// Include all required fields for proper validation\nconst CUSTOM_VALIDATOR_ATTRIBUTES_TO_PULL = ['id', 'schema', 'modelType', 'entityId', 'disabled'];\n\n// Initialize Ajv with relaxed settings to avoid warnings\nconst ajv = new Ajv({\n allErrors: true,\n strict: false, // Disable strict mode to avoid warnings\n strictTypes: false, // Disable strict type checking\n $data: true, // Enable $data references\n});\n\naddFormats(ajv);\najvErrors(ajv);\n\n/**\n * Helper function to manually copy object properties\n * This is more efficient for large objects and avoids excessive object creation\n */\n// eslint-disable-next-line prefer-object-spread\nconst manualObjectCopy = (sourceObj: Record<string, any>, additionalProps?: Record<string, any>): Record<string, any> =>\n ({ __proto__: null, ...sourceObj, ...additionalProps });\n\n/**\n * Fetches complete custom fields for an instance by merging DB values with update values\n * This is needed for partial updates to ensure all related fields are available for validation\n */\nconst getCompleteCustomFields = async (instance, options): Promise<Record<string, any>> => {\n // If we don't have an instance id or no custom fields being updated, return original fields\n if (!instance.id || !instance.customFields || Object.keys(instance.customFields).length === 0) {\n return instance.customFields || {};\n }\n\n try {\n const ModelClass = instance.constructor;\n // Only select the customFields column to minimize data transfer\n const currentCustomFields = await ModelClass.findOne({\n where: { id: instance.id },\n attributes: ['customFields'],\n transaction: options.transaction,\n raw: true, // Get plain object instead of model instance for better performance\n });\n\n if (currentCustomFields?.customFields) {\n // Merge existing fields with update fields using our helper function\n const completeFields = manualObjectCopy(\n currentCustomFields.customFields,\n instance.customFields,\n );\n\n logger.debug('sadot - fetched complete custom fields for validation', {\n fieldsCount: Object.keys(completeFields).length,\n updateFieldsCount: Object.keys(instance.customFields).length,\n });\n\n return completeFields;\n }\n } catch (error) {\n logger.error('sadot - error fetching complete model for validation', { error });\n // Continue with partial data if we can't fetch the complete model\n }\n\n return instance.customFields || {};\n};\n\nconst buildPreChangeState = (instance: any) => {\n const beforeFull: any = { ...instance.dataValues };\n\n const changedKeys: string[] = instance.changed?.() || [];\n changedKeys.forEach((key) => {\n const prevVal = instance.previous?.(key);\n if (prevVal !== undefined) {\n beforeFull[key] = prevVal;\n }\n });\n\n const prevCF = instance.previous?.('customFields');\n if (prevCF !== undefined) {\n beforeFull.customFields = prevCF;\n }\n\n return beforeFull;\n};\n\nconst formatAjvErrors = (\n errors: {\n instancePath?: string;\n keyword: string;\n message?: string;\n params?: Record<string, any>;\n}[],\n): Record<string, string> => errors.reduce((acc, err) => {\n const basePath = (err.instancePath || '')\n .split('/')\n .filter(Boolean)\n .join('.')\n .replace(/^after\\./, '');\n\n const missingProp = err.keyword === 'required' ? `.${err.params?.missingProperty}` : '';\n const key = (basePath + missingProp).replace(/^\\./, '') || 'root';\n\n const message = err.message || 'Invalid value';\n acc[key] = message;\n\n return acc;\n}, {} as Record<string, string>);\n\n/**\n * Validates the model using custom validators\n */\nconst validateModel = async (\n instance,\n options,\n scopeAttributes: string[],\n modelOptions: ModelOptions = {},\n isCreate = false,\n): Promise<void> => {\n const modelType = instance.constructor.name;\n\n logger.debug('sadot - validating model', { isCreate, modelType });\n const identifiers = applyScopeToInstance(instance, scopeAttributes);\n\n logger.debug('sadot - identifiers', { identifiers });\n\n // Skip if no identifiers\n if (!identifiers || Object.keys(identifiers).length === 0) {\n logger.debug('sadot - skipping validation: no identifiers');\n return;\n }\n\n // Find the entityId from identifiers (fleetId, businessModelId, etc.)\n const entityId = Object.values(identifiers)[0]; // Get the first value as entityId\n\n logger.debug('sadot - entityId', { entityId });\n\n if (!entityId) {\n logger.debug('sadot - skipping validation: no entityId');\n return;\n }\n\n let validatorsPromise;\n let cacheKey;\n if (options.transaction) {\n // eslint-disable-next-line no-param-reassign\n options.transaction.validationsCache ||= new Map();\n cacheKey = `${modelType}-${entityId}`;\n validatorsPromise = options.transaction.validationsCache.get(cacheKey);\n }\n\n if (!validatorsPromise) {\n validatorsPromise = ValidatorRepo.findAllByModelType(\n modelType,\n entityId,\n {\n transaction: options.transaction,\n attributes: CUSTOM_VALIDATOR_ATTRIBUTES_TO_PULL,\n modelOptions,\n },\n );\n if (options.transaction) {\n options?.transaction?.validationsCache.set(cacheKey, validatorsPromise);\n }\n }\n const validators = await validatorsPromise;\n\n logger.debug('sadot - validators found', { count: validators.length });\n\n if (!validators.length) {\n logger.debug('sadot - skipping validation: no validators found');\n return;\n }\n\n // For updates, get the previous values\n let originalValues = null;\n if (!isCreate) {\n originalValues = buildPreChangeState(instance);\n }\n\n // Get complete custom fields by merging DB values with update values\n // This is especially important for partial updates to ensure all related fields are available\n const completeCustomFields = !isCreate\n ? await getCompleteCustomFields(instance, options)\n : instance.customFields || {};\n\n // eslint-disable-next-line no-restricted-syntax\n for (const validator of validators) {\n const { schema } = validator;\n const typedSchema = schema as Record<string, any>;\n\n logger.debug('sadot - validating with schema', {\n schema,\n hasAfterProps: !!typedSchema.properties?.after,\n hasBeforeProps: !!typedSchema.properties?.before,\n });\n\n if (isCreate) {\n // For create operations, we only need the 'after' state\n if (typedSchema.properties?.after) {\n const validateSchema = ajv.compile({\n ...schema,\n // Focus only on the 'after' validation part for create\n properties: {\n after: typedSchema.properties.after,\n },\n });\n\n const isValid = validateSchema(JSON.parse(JSON.stringify({\n after: {\n ...instance.dataValues,\n customFields: completeCustomFields,\n },\n })));\n\n if (!isValid) {\n const errorDetails = validateSchema.errors?.map((err) =>\n `${(err as any).instancePath || ''} ${(err as any).message || 'Invalid value'}`).join(', ');\n\n const formattedErrors = formatAjvErrors(validateSchema.errors);\n throw new BadRequest(\n [new Error(`Validation failed for ${modelType}: ${errorDetails}`)],\n undefined,\n {\n customError: formattedErrors,\n },\n );\n }\n }\n } else {\n // For update operations, we need both before and after\n const validateSchema = ajv.compile(typedSchema);\n\n // Create after object with our helper function\n const afterObj = manualObjectCopy(instance.dataValues);\n\n // Add complete custom fields\n afterObj.customFields = completeCustomFields;\n\n // Create validation payload\n const payload = {\n before: originalValues,\n after: afterObj,\n };\n\n // Validate\n const isValid = validateSchema(JSON.parse(JSON.stringify(payload)));\n\n logger.debug('sadot - validation result', {\n isValid,\n test: {\n before: originalValues,\n after: afterObj,\n },\n });\n\n if (!isValid) {\n const errorDetails = validateSchema\n .errors\n ?.map((err) => `${(err as any).instancePath || ''} ${(err as any).message || 'Invalid value'}`).join(', ');\n\n const formattedErrors = formatAjvErrors(validateSchema.errors);\n throw new BadRequest(\n [new Error(`Validation failed for ${modelType}: ${errorDetails}`)],\n undefined,\n {\n customError: formattedErrors,\n },\n );\n }\n }\n }\n};\n\nconst getFieldDefinitions = async ({\n modelType,\n modelOptions,\n identifiers,\n options,\n}: {\n modelType: any,\n modelOptions: ModelOptions,\n identifiers: any[],\n options: any\n}) => {\n const { include, useEntityIdFromInclude } = modelOptions;\n const where: WhereOptions = {\n modelType,\n disabled: false,\n ...(!useEntityIdFromInclude && { entityId: identifiers }),\n };\n\n const fieldDefinitions = await DefinitionRepo.findAll(where, {\n withDisabled: false,\n transaction: options.transaction,\n include: include?.(identifiers),\n });\n return fieldDefinitions;\n};\n\nconst formatDates = (fieldDefinitions: CustomFieldDefinition[], instance: any) => {\n (fieldDefinitions || []).forEach((fieldDefinition) => {\n const { fieldType, name } = fieldDefinition;\n if ([CustomFieldDefinitionType.DATE, CustomFieldDefinitionType.DATETIME].includes(fieldType)) {\n const value = instance.customFields?.[name];\n if (value) {\n const { value: joiValue, error: validationError } = Joi.date().validate(value);\n if (validationError) {\n throw new InvalidValueError(value, name, validationError);\n }\n // eslint-disable-next-line no-param-reassign\n instance.customFields[name] = joiValue.toISOString();\n }\n }\n });\n};\n\n/**\n * Hook to handle validation and custom fields during creation\n */\nexport const beforeCreate = (\n scopeAttributes: string[],\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false },\n) => async (\n instance: any,\n options: CreateOptions,\n): Promise<void> => {\n logger.debug('sadot - before create hook');\n const { fields } = options;\n const modelType = instance.constructor.name;\n\n const identifiers = applyScopeToInstance(instance, scopeAttributes);\n\n // Step 1: Handle custom fields default values and required fields\n\n const fieldDefinitions = await getFieldDefinitions({\n modelType, modelOptions, identifiers, options,\n });\n\n // Apply default values\n const fieldsWithDefaultValue = fieldDefinitions.filter((def) => ![null, undefined].includes(def.defaultValue));\n if (fieldsWithDefaultValue.length) {\n // eslint-disable-next-line no-param-reassign\n instance.customFields ||= {};\n fieldsWithDefaultValue\n .filter((def) => (instance.customFields?.[def.name] === undefined))\n .forEach(({ name, defaultValue }) => {\n // eslint-disable-next-line no-param-reassign\n instance.customFields[name] = defaultValue;\n });\n }\n\n // Check for required fields\n const requiredFieldsNames = Array.from(\n new Set(fieldDefinitions.filter(({ required }) => required).map(({ name }) => name)),\n );\n const { customFields } = instance;\n const fieldsNames = Object.keys(customFields ?? {});\n const missingFields = requiredFieldsNames.filter((name) => !fieldsNames.includes(name));\n if (missingFields?.length) {\n throw new MissingRequiredCustomFieldError(missingFields);\n }\n\n // Step 2: Validate the model data (including custom fields)\n await validateModel(instance, options, scopeAttributes, modelOptions, true);\n\n // format date and datetime fields\n formatDates(fieldDefinitions, instance);\n\n // Step 3: Save custom field values if they exist\n const customFieldsIdx = fields.indexOf('customFields');\n if (customFieldsIdx === -1 || !customFields || !Object.keys(customFields).length) {\n // No custom fields to update\n return;\n }\n\n // Save custom field values\n await updateInstanceValues({\n modelId: instance.id,\n modelType,\n identifiers,\n customFields,\n options: {\n useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,\n transaction: options.transaction,\n modelOptions,\n },\n });\n\n // Remove customFields from fields array after handling\n // eslint-disable-next-line no-param-reassign\n fields.splice(customFieldsIdx, 1);\n};\n\n/**\n * Hook to handle validation and custom fields during update\n */\nexport const beforeUpdate = (\n scopeAttributes: string[],\n modelOptions: ModelOptions = {},\n sadotOptions: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false },\n) => async (\n instance: any,\n options: UpdateOptions,\n): Promise<void> => {\n logger.debug('sadot - before update hook');\n const { fields } = options;\n const modelType = instance.constructor.name;\n const identifiers = applyScopeToInstance(instance, scopeAttributes);\n\n const fieldDefinitions = await getFieldDefinitions({\n modelType, modelOptions, identifiers, options,\n });\n\n // Step 1: Validate the model data (including custom fields)\n await validateModel(instance, options, scopeAttributes, modelOptions, false);\n\n // format date and datetime fields\n formatDates(fieldDefinitions, instance);\n\n // Step 2: Update custom field values if they exist\n const customFieldsIdx = fields.indexOf('customFields');\n if (customFieldsIdx > -1) {\n const { customFields } = instance;\n\n if (!Object.keys(customFields).length) {\n return;\n }\n\n // Save custom field values\n await updateInstanceValues({\n modelId: instance.id,\n modelType,\n identifiers,\n customFields,\n options: {\n useCustomFieldsEntries: sadotOptions.useCustomFieldsEntries,\n transaction: options.transaction,\n modelOptions,\n },\n });\n\n // Remove customFields from fields array after handling\n // eslint-disable-next-line no-param-reassign\n fields.splice(customFieldsIdx, 1);\n }\n};\n\n/**\n * Hook to enable individual hooks for bulk create operations\n */\nexport const beforeBulkCreate = (options: BulkCreateOptions): void => {\n // This will activate the beforeCreate hook on each instance\n // eslint-disable-next-line no-param-reassign\n options.individualHooks = true;\n};\n\n/**\n * Hook to enable individual hooks for bulk update operations\n */\nexport const beforeBulkUpdate = (options: UpdateOptions): void => {\n // This will activate the beforeUpdate hook on each instance\n // eslint-disable-next-line no-param-reassign\n options.individualHooks = true;\n};\n","/* eslint-disable import/prefer-default-export */\nimport { type WhereOptions, Op, type BindOrReplacements } from 'sequelize';\nimport { type ModelStatic, Sequelize } from 'sequelize-typescript';\nimport { randomInt } from 'node:crypto';\nimport { CustomFieldDefinitionType } from '../constants';\n\n/**\n * Builds a WHERE clause and replacements for free-text search by custom fields.\n *\n * This function constructs a WHERE clause and replacement bindings that allow searching\n * for a given term within custom fields associated with a specific model type and entity ID.\n * The WHERE clause and replacements are designed to be added to the main query.\n *\n * @param {string} searchTerm - The term to search for within custom fields.\n * @param {ModelStatic} model - The Sequelize model representing the entity type to search for.\n * @param {string} entityId - The entity ID to filter the custom fields by.\n * @param {CustomFieldDefinitionType[]} excludedCustomFieldsTypes - An array of custom field types\n * to exclude from the search\n *\n * @returns {CustomFieldsSearchPayload} - An object containing the WHERE clause and replacements\n * for Sequelize.\n */\n\ninterface CustomFieldsSearchPayload {\n where: WhereOptions;\n replacements: BindOrReplacements;\n}\n\nexport const generateRandomString = (length = 5): string => {\n const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n return Array.from({ length }, () => characters.charAt(randomInt(characters.length))).join('');\n};\n\nexport const generateCustomFieldSearchQueryPayload = (\n searchTerm: string,\n model: ModelStatic,\n entityId: string,\n customFieldsTypesToExclude: CustomFieldDefinitionType[] = [\n CustomFieldDefinitionType.DATETIME,\n CustomFieldDefinitionType.DATE,\n ],\n): CustomFieldsSearchPayload => {\n const excludedTypesString = customFieldsTypesToExclude.map((type) => `'${type}'`).join(',');\n\n const subQuery = 'EXISTS ('\n + ' SELECT 1'\n + ' FROM \"custom_field_values\" AS \"cv\"'\n + ' INNER JOIN custom_field_definitions AS cd '\n + ` ON cd.entity_id = '${entityId}'`\n + ' AND cv.custom_field_definition_id = cd.id'\n + ` AND cd.model_type = '${model.name}'`\n + ` ${excludedTypesString ? `AND cd.field_type NOT IN (${excludedTypesString})` : ''}`\n + ' WHERE'\n + ' \"cv\".\"deleted_at\" IS NULL'\n + ` AND \"cv\".\"model_id\" = \"${model.name}\".\"id\"`\n + ' AND CAST(\"cv\".\"value\" AS TEXT) ILIKE :searchTerm)';\n\n return {\n where: {\n [Op.or]: [\n Sequelize.where(Sequelize.literal(subQuery), true),\n ],\n },\n replacements: { searchTerm: `%${searchTerm}%` },\n };\n};\n","import type { WhereOptions } from 'sequelize';\n\n/**\n * Type representing possible condition values.\n * Currently supporting strings and arrays of strings.\n * More types to be added (TBA).\n */\nexport type ConditionWithOperator = {\n operator: string;\n value: string;\n};\nexport type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];\n\nexport type CustomFieldSort = {\n field: string;\n direction: 'ASC' | 'DESC';\n}\n\nexport type CustomFieldFilterOptions = {\n where?: WhereOptions;\n replacements?: Record<string, string>;\n}\n\nexport enum SubQueryType {\n VALUES = 'values',\n ENTRIES = 'entries',\n}\n\nexport const isConditionStringArray = (input: any): input is string[] => Array.isArray(input) && typeof input[0] === 'string';\nexport const isBooleanString = (input: string): boolean => ['true', 'false'].includes(input.toString());\nexport const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n\nexport const castValueToJsonb = (value: string, type: string) => `to_jsonb(${value}::${type})`;\nexport const castValueToJsonbText = (value: string): string => castValueToJsonb(value, 'text');\nexport const castValueToJsonbBoolean = (value: string): string => castValueToJsonb(value, 'boolean');\nexport const castValueToJsonbNumeric = (value: string): string => castValueToJsonb(value, 'numeric');\nexport const castIfNeeded = (columnName: string, conditionValue: string): string => {\n if (isDate(conditionValue)) {\n return castValueToJsonb(columnName, 'timestamp');\n }\n return columnName;\n};\n\nexport const AND_DELIMITER = ' AND ';\nexport const OR_DELIMITER = ' OR ';\nexport const CD_TABLE_ALIAS = 'cd';\nexport const CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name` = `${CD_TABLE_ALIAS}.name`;\nexport const CV_TABLE_ALIAS = 'cv';\nexport const CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value` = `${CV_TABLE_ALIAS}.value`;\nexport const CE_TABLE_ALIAS = 'ce';\n\nconst getSingleConditionWithOperator = (value: any, operator: string, replacementKey: string, reverseReplacementsMap: Map<string, string>) => {\n let type = 'text';\n if (isDate(value)) {\n type = 'date';\n } else if (!Number.isNaN(Number(value))) {\n type = 'numeric';\n } else if (isBooleanString(value)) {\n type = 'boolean';\n }\n const replacedValue = reverseReplacementsMap.get(value);\n\n return `(jsonb_extract_path_text(${CE_TABLE_ALIAS}.custom_fields, :${replacementKey})::${type}) ${operator} :${replacedValue}`;\n};\n\nconst getFormattedValue = (value: string) => {\n let formattedValue: string | number | boolean = value;\n if (isBooleanString(value)) {\n formattedValue = value === 'true';\n } else if (!Number.isNaN(Number(value))) {\n formattedValue = Number(value);\n }\n\n return formattedValue;\n};\n\nconst getJSONSubQuery = (value: string, key: string) => {\n const formattedValue = getFormattedValue(value);\n const jsonQuery = JSON.stringify({ [key]: formattedValue });\n let jsonQueryWithStringBoolean;\n if (isBooleanString(value)) {\n jsonQueryWithStringBoolean = `${CE_TABLE_ALIAS}.custom_fields @> '${JSON.stringify({ [key]: value })}'`;\n }\n return `\n (\n ${jsonQueryWithStringBoolean ? `${jsonQueryWithStringBoolean} OR` : ''}\n ${CE_TABLE_ALIAS}.custom_fields @> '${jsonQuery}'\n )\n `;\n};\n\nexport const getFilterCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, conditionsStrings: Array<string | boolean>): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `\n SELECT ${CV_TABLE_ALIAS}.model_id\n FROM custom_field_values AS ${CV_TABLE_ALIAS}\n INNER JOIN custom_field_definitions AS ${CD_TABLE_ALIAS} ON ${CV_TABLE_ALIAS}.custom_field_definition_id = ${CD_TABLE_ALIAS}.id\n ${AND_DELIMITER}${CD_TABLE_ALIAS}.model_type = '${modelType}'\n WHERE ${conditionsStrings.join(OR_DELIMITER)}\n ${AND_DELIMITER}${CV_TABLE_ALIAS}.deleted_at IS NULL${AND_DELIMITER}${CD_TABLE_ALIAS}.deleted_at IS NULL\n GROUP BY ${CV_TABLE_ALIAS}.model_id\n HAVING COUNT(DISTINCT ${CV_TABLE_ALIAS}.custom_field_definition_id) = ${conditionsStrings.length}\n `.replace(/\\n/g, '');\n case SubQueryType.ENTRIES:\n return `\n SELECT ce.model_id\n FROM custom_field_entries ce\n JOIN custom_field_definitions cfd\n ON ce.model_type = cfd.model_type\n AND ce.entity_id = cfd.entity_id\n WHERE\n cfd.deleted_at IS NULL AND\n ${conditionsStrings.join(AND_DELIMITER)}\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const getSortCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, replacementKey: string): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `(\n SELECT value\n FROM (SELECT cv.model_id, cv.value\n FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd\n ON cv.custom_field_definition_id = cd.id\n ${AND_DELIMITER}cd.model_type = '${modelType}'\n WHERE cv.model_id = \"${modelType}\".\"id\"\n ${AND_DELIMITER}cd.name = :${replacementKey}\n ) AS CustomFieldAggregation\n )\n `;\n case SubQueryType.ENTRIES:\n return `(\n SELECT\n customFields.value\n FROM\n custom_field_entries AS ${CE_TABLE_ALIAS},\n jsonb_each_text(custom_fields) AS customFields\n WHERE\n customFields.key = :${replacementKey}${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_type = '${modelType}'${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_id = \"${modelType}\".\"id\"\n )\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const formatConditionsForValues = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n const columnCondition = `(${CD_NAME_COLUMN} = :${replacementKey})`;\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.flatMap((v) => {\n const valRandom = reverseReplacementsMap.get(v);\n if (isBooleanString(v)) {\n return [castValueToJsonbText(`:${valRandom}`), castValueToJsonbBoolean(`:${valRandom}`)];\n }\n if (!Number.isNaN(Number(v))) {\n return castValueToJsonbNumeric(`:${valRandom}`);\n }\n return castValueToJsonbText(`:${valRandom}`);\n }).join(',');\n return `(${columnCondition}${AND_DELIMITER}${CV_VALUE_COLUMN} IN (${values}))`;\n }\n return condition.map((c) => {\n const valRep = reverseReplacementsMap.get(c.value);\n const valueAsJsonb = castValueToJsonbText(`:${valRep}`);\n\n return `(${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, c.value)} ${c.operator} ${valueAsJsonb})`;\n }).join(AND_DELIMITER);\n }\n if (typeof condition === 'string' || typeof condition === 'number') {\n const conditionRep = reverseReplacementsMap.get(condition);\n const valueAsJsonb = !Number.isNaN(Number(condition)) ? castValueToJsonbNumeric(`:${conditionRep}`) : castValueToJsonbText(`:${conditionRep}`);\n const valueAsJsonbBoolean = isBooleanString(condition) ? `${OR_DELIMITER}${CV_VALUE_COLUMN} = ${castValueToJsonbBoolean(`:${conditionRep}`)}` : '';\n return `(${columnCondition}${AND_DELIMITER}(${castIfNeeded(CV_VALUE_COLUMN, condition)} = ${valueAsJsonb}${valueAsJsonbBoolean}))`;\n }\n if (condition?.operator) {\n const valueRep = reverseReplacementsMap.get(condition.value);\n const valueAsJsonb = castValueToJsonbText(`:${valueRep}`);\n return `( ${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, condition.value)} ${condition.operator} ${valueAsJsonb})`;\n }\n return false;\n};\n\nexport const formatConditionsForEntries = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.map((value) => getJSONSubQuery(value, key)).join(`${OR_DELIMITER}\\n`);\n return `( ${values})`;\n }\n return condition.map((c) => getSingleConditionWithOperator(c.value, c.operator, replacementKey, reverseReplacementsMap)).join(AND_DELIMITER);\n }\n\n if (typeof condition === 'string' || typeof condition === 'number') {\n return getJSONSubQuery(condition, key);\n }\n\n if (condition?.operator) {\n return getSingleConditionWithOperator(condition.value, condition.operator, replacementKey, reverseReplacementsMap);\n }\n return false;\n};\n","/* eslint-disable import/prefer-default-export */\nimport { Op } from 'sequelize';\nimport type { Literal } from 'sequelize/types/utils';\nimport { Sequelize } from 'sequelize-typescript';\nimport { customFields } from '@autofleet/common-types';\nimport { generateRandomString } from '../utils/helpers';\nimport type { CustomFieldOptions } from '../types';\nimport {\n formatConditionsForEntries,\n formatConditionsForValues,\n getFilterCustomFieldsSubQuery,\n getSortCustomFieldsSubQuery,\n SubQueryType,\n type ConditionValue,\n type CustomFieldFilterOptions,\n} from './helpers/filter.helpers';\n\ntype customFieldsFilterScopeParams = {\n replacementsMap: Record<string, string>;\n scopeValue: Record<string, ConditionValue>;\n}\n\n/**\n * A Sequelize scope for filtering models by custom fields.\n * This scope builds a WHERE clause to be applied on the main query.\n *\n * @param name - The model type name used to join custom_field_definitions.\n * @returns A function that takes conditions and returns the Sequelize options object.\n */\nexport const customFieldsFilterScope = (\n name: string,\n options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,\n) => ({ replacementsMap: replacements, scopeValue: conditions }: customFieldsFilterScopeParams): CustomFieldFilterOptions => {\n if (!conditions || Object.keys(conditions).length === 0) {\n return {};\n }\n\n const queryType = options?.useCustomFieldsEntries ? SubQueryType.ENTRIES : SubQueryType.VALUES;\n const reverseReplacementsMap = new Map(Object.entries(replacements).map(([key, value]) => [value, key]));\n // Build the WHERE clause for custom field filtering\n const conditionsStrings = Object.entries(conditions).map(([key, condition]) => {\n switch (queryType) {\n case SubQueryType.ENTRIES:\n return formatConditionsForEntries(key, condition, reverseReplacementsMap);\n case SubQueryType.VALUES:\n return formatConditionsForValues(key, condition, reverseReplacementsMap);\n default:\n return false;\n }\n }).filter(Boolean);\n if (conditionsStrings.length === 0) {\n return {};\n }\n const subQuery = getFilterCustomFieldsSubQuery(queryType, name, conditionsStrings);\n\n return {\n where: {\n id: {\n [Op.in]: Sequelize.literal(`(${subQuery})`),\n },\n },\n replacements,\n };\n};\n\nexport const scopeName: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE = customFields.CUSTOM_FIELDS_FILTER_SCOPE;\n\nexport const customFieldsSortScope = (\n name: string,\n options?: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>,\n) => ({ replacementsMap, scopeValue: sort }: { replacementsMap: Record<string, string>; scopeValue: Record<string, ConditionValue>; }): {\n attributes: { include: (string | Literal)[][]; };\n order: Literal[];\n replacements: Record<string, string>;\n} | Record<string, never> => {\n if (!sort || (sort as unknown as any[]).length === 0) {\n return {};\n }\n\n const queryType = options?.useCustomFieldsEntries ? SubQueryType.ENTRIES : SubQueryType.VALUES;\n const randomStr = generateRandomString();\n const includes = Object.entries(sort).map(([key]) => {\n const replacementKey = Object.keys(replacementsMap).find(\n (randomString) => replacementsMap[randomString] === key,\n );\n return ([\n Sequelize.literal(getSortCustomFieldsSubQuery(queryType, name, replacementKey)),\n randomStr,\n ]);\n });\n\n const orders = Object.entries(sort).map(([, sortObject]) => {\n const direction = typeof sortObject === 'string' ? sortObject : Object.values(sortObject)[0];\n return Sequelize.literal(`\"${randomStr}\" ${direction || 'ASC'}`);\n });\n return {\n attributes: {\n include: includes,\n },\n order: orders,\n replacements: replacementsMap,\n };\n};\n","import { DataTypes } from 'sequelize';\nimport type { ModelCtor } from 'sequelize-typescript';\nimport { customFields } from '@autofleet/common-types';\nimport { CUSTOM_FIELDS_SORT_SCOPE } from '@autofleet/common-types/lib/custom-fields';\nimport {\n CustomFieldDefinition,\n CustomFieldValue,\n CustomValidator,\n} from '../models';\nimport {\n beforeFind,\n enrichResults,\n beforeBulkUpdate,\n beforeUpdate,\n beforeCreate,\n beforeBulkCreate,\n} from '../hooks';\nimport { customFieldsFilterScope } from '../scopes';\nimport logger from './logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: { useCustomFieldsEntries: boolean } = { useCustomFieldsEntries: false },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions,\n }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addHooks to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n model.rawAttributes.customFields = {\n type: DataTypes.VIRTUAL,\n };\n model.refreshAttributes();\n // TODO: Uncomment after tests are passed\n // model.addHook('afterFind', workaround);\n model.addHook('beforeFind', 'sadot-beforeFind', beforeFind(scopeAttributes));\n model.addHook('beforeBulkCreate', 'sadot-beforeBulkCreate', beforeBulkCreate);\n model.addHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate', beforeBulkUpdate);\n model.addHook('beforeCreate', 'sadot-beforeCreate', beforeCreate(scopeAttributes, modelOptions, sadotOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, sadotOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, sadotOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, null, modelOptions, sadotOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, null, modelOptions, sadotOptions));\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\nexport const removeHooks = (models: Models[], getModel: ModelFetcher): void => {\n models.forEach(async ({ name }) => {\n try {\n const model = getModel(name);\n if (!model) return;\n if (model.rawAttributes.customFields) {\n delete model.rawAttributes.customFields;\n model.refreshAttributes();\n }\n // model.removeHook('afterFind', 'sadot-workaround');\n model.removeHook('beforeFind', 'sadot-beforeFind');\n model.removeHook('beforeBulkCreate', 'sadot-beforeBulkCreate');\n model.removeHook('beforeBulkUpdate', 'sadot-beforeBulkUpdate');\n model.removeHook('beforeCreate', 'sadot-beforeCreate');\n model.removeHook('beforeUpdate', 'sadot-beforeUpdate');\n model.removeHook('afterFind', 'sadot-afterFind');\n model.removeHook('afterUpdate', 'sadot-afterUpdate');\n } catch (e) {\n logger.error(`Could not add custom fields hook to model ${name}. `, e);\n }\n });\n};\n\n/**\n * Necessary associations for the {@link customFieldsFilterScope} scope\n */\nconst addAssociations = (model: ModelCtor, modelName: string, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'>): void => {\n if (options?.useCustomFieldsEntries) return;\n model.hasMany(CustomFieldValue, { foreignKey: 'modelId', as: 'customFieldValue' });\n // TBC: maybe can be removed\n CustomFieldValue.belongsTo(model, { foreignKey: 'modelId', as: modelName });\n};\n\nexport const addScopes = (models: Models[], getModel: ModelFetcher, options: Pick<CustomFieldOptions, 'useCustomFieldsEntries'> = { useCustomFieldsEntries: false }): void => {\n models.forEach(async ({ name, scopeAttributes }) => {\n try {\n const model = getModel(name);\n if (!model) {\n logger.warn('sadot - tried to addScopes to a model that does not exist yet', {\n name,\n scopeAttributes,\n });\n return;\n }\n // Necessary associations for the filtering scope\n addAssociations(model, name, options);\n // Add filter scope\n model.addScope(CUSTOM_FIELDS_FILTER_SCOPE, customFieldsFilterScope(name, options));\n model.addScope(CUSTOM_FIELDS_SORT_SCOPE, customFieldsSortScope(name, options));\n } catch (e) {\n logger.error(`Could not add custom fields scopes to model ${name}. `, e);\n }\n });\n};\n\nexport const applyCustomAssociation = (models: Models[]): void => {\n models.forEach(({ modelOptions }) => {\n modelOptions?.customAssociation?.(CustomFieldDefinition);\n modelOptions?.customAssociation?.(CustomValidator);\n });\n};\n","import Joi from 'joi';\n\nconst CustomFieldsSchema: Joi.ObjectSchema<Record<string, any>> = Joi.object().pattern(\n Joi.string(),\n Joi.any(),\n);\n\nexport { CustomFieldsSchema };\n","import type { Application } from 'express';\nimport type { Sequelize } from 'sequelize-typescript';\nimport {\n initTables, initTestModels,\n} from './models';\nimport api from './api';\nimport initDB from './utils/db';\nimport logger, { tryAddingTraceIdMiddleware } from './utils/logger';\nimport type { CustomFieldOptions, ModelFetcher, Models } from './types';\nimport {\n addHooks, addScopes, applyCustomAssociation, removeHooks,\n} from './utils/init';\n\nexport * from './utils/validations/schema/custom-fields';\n\nexport * from './utils/constants';\n\nexport * from './utils/helpers';\n\nexport { customFieldsSortScope } from './scopes/filter';\n\n// Export models for external use\nexport * from './models';\n\n/**\n * Adding custom fields enrichment to the models inside the MODELS_FILE_NAME json file\n * @see {@link 'custom-fields/config'} for configurations\n */\nconst useCustomFields = async (\n app: Pick<Application, 'use'> | null,\n getModel: ModelFetcher,\n options: CustomFieldOptions,\n): Promise<Sequelize> => {\n tryAddingTraceIdMiddleware().catch(() => null);\n const { models, useCustomFieldsEntries } = options;\n if (app) {\n app.use('/api', api);\n }\n const sequelize = options.sequelize ?? initDB(options.databaseConfig);\n if (process.env.NODE_ENV === 'test') {\n await initTestModels(sequelize);\n }\n // The order is important\n addHooks(models, getModel, { useCustomFieldsEntries });\n await initTables(sequelize, options.getUser, { useCustomFieldsEntries });\n addScopes(models, getModel, { useCustomFieldsEntries });\n applyCustomAssociation(models);\n\n logger.debug('sadot - custom fields finished initializing with models', models);\n return sequelize;\n};\n\nexport default useCustomFields;\n\nexport const disableCustomFields = (models: Models[], getModel: ModelFetcher): void => {\n removeHooks(models, getModel);\n};\n"],"mappings":"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"}