@autofleet/sadot 1.9.0 → 1.10.0

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 (56) hide show
  1. package/dist/hooks/enrich.cjs +1 -1
  2. package/dist/hooks/enrich.cjs.map +1 -1
  3. package/dist/hooks/enrich.js +1 -1
  4. package/dist/hooks/enrich.js.map +1 -1
  5. package/dist/hooks/hooks.cjs +1 -1
  6. package/dist/hooks/hooks.cjs.map +1 -1
  7. package/dist/hooks/hooks.js +1 -1
  8. package/dist/hooks/hooks.js.map +1 -1
  9. package/dist/hooks/utils/updateInstanceValues.cjs +1 -1
  10. package/dist/hooks/utils/updateInstanceValues.cjs.map +1 -1
  11. package/dist/hooks/utils/updateInstanceValues.js +1 -1
  12. package/dist/hooks/utils/updateInstanceValues.js.map +1 -1
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +3 -1
  16. package/dist/index.d.ts +3 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/migrations/index.cjs +1 -1
  20. package/dist/migrations/index.cjs.map +1 -1
  21. package/dist/migrations/index.d.cts +2 -2
  22. package/dist/migrations/index.d.ts +2 -2
  23. package/dist/migrations/index.js +1 -1
  24. package/dist/migrations/index.js.map +1 -1
  25. package/dist/models/index.cjs +1 -1
  26. package/dist/models/index.cjs.map +1 -1
  27. package/dist/models/index.js +1 -1
  28. package/dist/models/index.js.map +1 -1
  29. package/dist/repository/backfill.cjs +34 -0
  30. package/dist/repository/backfill.cjs.map +1 -0
  31. package/dist/repository/backfill.d.cts +32 -0
  32. package/dist/repository/backfill.d.ts +32 -0
  33. package/dist/repository/backfill.js +34 -0
  34. package/dist/repository/backfill.js.map +1 -0
  35. package/dist/scopes/filter.cjs +1 -1
  36. package/dist/scopes/filter.cjs.map +1 -1
  37. package/dist/scopes/filter.d.cts +1 -1
  38. package/dist/scopes/filter.d.ts +1 -1
  39. package/dist/scopes/filter.js +1 -1
  40. package/dist/scopes/filter.js.map +1 -1
  41. package/dist/types/index.d.cts +12 -1
  42. package/dist/types/index.d.ts +14 -3
  43. package/dist/utils/custom-fields-mode.cjs +2 -0
  44. package/dist/utils/custom-fields-mode.cjs.map +1 -0
  45. package/dist/utils/custom-fields-mode.d.cts +27 -0
  46. package/dist/utils/custom-fields-mode.d.ts +27 -0
  47. package/dist/utils/custom-fields-mode.js +2 -0
  48. package/dist/utils/custom-fields-mode.js.map +1 -0
  49. package/dist/utils/db/index.js +1 -1
  50. package/dist/utils/db/index.js.map +1 -1
  51. package/dist/utils/helpers/index.js.map +1 -1
  52. package/dist/utils/init.cjs +1 -1
  53. package/dist/utils/init.cjs.map +1 -1
  54. package/dist/utils/init.js +1 -1
  55. package/dist/utils/init.js.map +1 -1
  56. package/package.json +4 -4
@@ -0,0 +1,34 @@
1
+ import e from"../utils/logger/index.js";import{QueryTypes as t}from"sequelize";const n=async(n,{modelType:r,tableName:i,scopeColumn:a,primaryKeyColumn:o=`id`,transaction:s})=>{let[c]=await n.query(`SELECT to_regclass('custom_field_entries') AS entries_table,
2
+ to_regclass('custom_field_values') AS values_table`,{type:t.SELECT,transaction:s});if(!c.entries_table&&c.values_table)throw Error(`custom-fields backfill: custom_field_entries is missing while custom_field_values exists — run the sadot migrations that create it (useCustomFieldsEntries) before backfilling`);if(!c.entries_table)return e.info(`custom-fields: sadot tables absent, nothing to backfill for ${r}`),0;if(!c.values_table)return e.info(`custom-fields: custom_field_values absent, nothing to backfill for ${r}`),0;let l=n.getQueryInterface().quoteIdentifier.bind(n.getQueryInterface()),u=l(i),d=l(o),f=l(a),[,p]=await n.query(`
3
+ INSERT INTO custom_field_entries (model_id, entity_id, model_type, custom_fields, created_at, updated_at)
4
+ SELECT
5
+ t.${d},
6
+ agg.entity_id,
7
+ :modelType,
8
+ agg.custom_fields,
9
+ COALESCE(t.created_at, now()),
10
+ now()
11
+ FROM (
12
+ SELECT
13
+ cfv.model_id,
14
+ cfd.entity_id,
15
+ jsonb_object_agg(cfd.name, cfv.value) AS custom_fields
16
+ FROM custom_field_values cfv
17
+ INNER JOIN custom_field_definitions cfd
18
+ ON cfd.id = cfv.custom_field_definition_id
19
+ AND cfd.deleted_at IS NULL
20
+ AND cfd.model_type = :modelType
21
+ WHERE cfv.deleted_at IS NULL
22
+ AND cfv.value IS NOT NULL
23
+ GROUP BY cfv.model_id, cfd.entity_id
24
+ ) agg
25
+ INNER JOIN ${u} t
26
+ ON t.${d} = agg.model_id
27
+ AND t.${f} = agg.entity_id
28
+ AND t.deleted_at IS NULL
29
+ ON CONFLICT (model_id) DO UPDATE
30
+ SET custom_fields = EXCLUDED.custom_fields,
31
+ entity_id = EXCLUDED.entity_id,
32
+ updated_at = now()
33
+ `,{replacements:{modelType:r},type:t.INSERT,transaction:s}),m=typeof p==`number`?p:p?.rowCount??0;return e.info(`custom-fields: backfilled ${m} ${r} rows into custom_field_entries`),m};export{n as backfillCustomFieldEntries};
34
+ //# sourceMappingURL=backfill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backfill.js","names":[],"sources":["../../src/repository/backfill.ts"],"sourcesContent":["import { QueryTypes, type Sequelize, type Transaction } from 'sequelize';\nimport logger from '../utils/logger';\n\ninterface BackfillParams {\n /** custom_field_definitions.model_type value (e.g. 'Vehicle'). */\n modelType: string;\n /** Table to backfill from (e.g. 'vehicles'). */\n tableName: string;\n /** DB column matching custom_field_definitions.entity_id (e.g. 'fleet_id'), so backfilled rows stay filterable. */\n scopeColumn: string;\n /** Defaults to 'id'. */\n primaryKeyColumn?: string;\n transaction?: Transaction;\n}\n\n/**\n * Backfills custom_field_entries from custom_field_values for every live row of the table.\n * Idempotent — safe to re-run to complete rows partially written during WRITE_ONLY.\n *\n * Call after dual-write is deployed, before reads switch to entries.\n * Assumes the table has created_at and deleted_at columns.\n * Returns the number of rows inserted or updated.\n */\nexport const backfillCustomFieldEntries = async (\n sequelize: Sequelize,\n {\n modelType, tableName, scopeColumn, primaryKeyColumn = 'id', transaction,\n }: BackfillParams,\n): Promise<number> => {\n // Sadot's migrations may not have run yet — check rather than assume.\n const [tables] = await sequelize.query(\n `SELECT to_regclass('custom_field_entries') AS entries_table,\n to_regclass('custom_field_values') AS values_table`,\n { type: QueryTypes.SELECT, transaction },\n ) as [{ entries_table: string | null; values_table: string | null; }];\n\n // Values exist but entries doesn't — backfilling before the table was created.\n // Skipping silently would let the later migration record as applied with no data moved.\n if (!tables.entries_table && tables.values_table) {\n throw new Error(\n 'custom-fields backfill: custom_field_entries is missing while custom_field_values exists — '\n + 'run the sadot migrations that create it (useCustomFieldsEntries) before backfilling',\n );\n }\n\n // No sadot tables at all — nothing to backfill.\n if (!tables.entries_table) {\n logger.info(`custom-fields: sadot tables absent, nothing to backfill for ${modelType}`);\n return 0;\n }\n\n // Entries exists but values doesn't (e.g. after a later cleanup phase drops it) —\n // nothing to backfill from.\n if (!tables.values_table) {\n logger.info(`custom-fields: custom_field_values absent, nothing to backfill for ${modelType}`);\n return 0;\n }\n\n const quote = sequelize.getQueryInterface().quoteIdentifier.bind(sequelize.getQueryInterface());\n const table = quote(tableName);\n const pk = quote(primaryKeyColumn);\n const scope = quote(scopeColumn);\n\n const [, meta] = await sequelize.query(\n `\n INSERT INTO custom_field_entries (model_id, entity_id, model_type, custom_fields, created_at, updated_at)\n SELECT\n t.${pk},\n agg.entity_id,\n :modelType,\n agg.custom_fields,\n COALESCE(t.created_at, now()),\n now()\n FROM (\n SELECT\n cfv.model_id,\n cfd.entity_id,\n jsonb_object_agg(cfd.name, cfv.value) AS custom_fields\n FROM custom_field_values cfv\n INNER JOIN custom_field_definitions cfd\n ON cfd.id = cfv.custom_field_definition_id\n AND cfd.deleted_at IS NULL\n AND cfd.model_type = :modelType\n WHERE cfv.deleted_at IS NULL\n AND cfv.value IS NOT NULL\n GROUP BY cfv.model_id, cfd.entity_id\n ) agg\n INNER JOIN ${table} t\n ON t.${pk} = agg.model_id\n AND t.${scope} = agg.entity_id\n AND t.deleted_at IS NULL\n ON CONFLICT (model_id) DO UPDATE\n SET custom_fields = EXCLUDED.custom_fields,\n entity_id = EXCLUDED.entity_id,\n updated_at = now()\n `,\n {\n replacements: { modelType },\n type: QueryTypes.INSERT,\n transaction,\n },\n );\n\n const backfilledCount = typeof meta === 'number' ? meta : ((meta as any)?.rowCount ?? 0);\n logger.info(`custom-fields: backfilled ${backfilledCount} ${modelType} rows into custom_field_entries`);\n return backfilledCount;\n};\n"],"mappings":"+EAuBA,MAAa,EAA6B,MACxC,EACA,CACE,YAAW,YAAW,cAAa,mBAAmB,KAAM,iBAE1C,CAEpB,GAAM,CAAC,GAAU,MAAM,EAAU,MAC/B;iEAEA,CAAE,KAAM,EAAW,OAAQ,cAAa,CACzC,CAID,GAAI,CAAC,EAAO,eAAiB,EAAO,aAClC,MAAU,MACR,iLAED,CAIH,GAAI,CAAC,EAAO,cAEV,OADA,EAAO,KAAK,+DAA+D,IAAY,CAChF,EAKT,GAAI,CAAC,EAAO,aAEV,OADA,EAAO,KAAK,sEAAsE,IAAY,CACvF,EAGT,IAAM,EAAQ,EAAU,mBAAmB,CAAC,gBAAgB,KAAK,EAAU,mBAAmB,CAAC,CACzF,EAAQ,EAAM,EAAU,CACxB,EAAK,EAAM,EAAiB,CAC5B,EAAQ,EAAM,EAAY,CAE1B,EAAG,GAAQ,MAAM,EAAU,MAC/B;;;UAGM,EAAG;;;;;;;;;;;;;;;;;;;;iBAoBI,EAAM;aACV,EAAG;aACH,EAAM;;;;;;MAOf,CACE,aAAc,CAAE,YAAW,CAC3B,KAAM,EAAW,OACjB,cACD,CACF,CAEK,EAAkB,OAAO,GAAS,SAAW,EAAS,GAAc,UAAY,EAEtF,OADA,EAAO,KAAK,6BAA6B,EAAgB,GAAG,EAAU,iCAAiC,CAChG"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/helpers/index.cjs`),n=require(`./helpers/filter.helpers.cjs`);let r=require(`sequelize`),i=require(`sequelize-typescript`),a=require(`@autofleet/common-types`);const o=(e,t)=>({replacementsMap:a,scopeValue:o})=>{if(!o||Object.keys(o).length===0)return{};let s=t?.useCustomFieldsEntries?n.SubQueryType.ENTRIES:n.SubQueryType.VALUES,c=new Map(Object.entries(a).map(([e,t])=>[t,e])),l=Object.entries(o).map(([e,t])=>{switch(s){case n.SubQueryType.ENTRIES:return n.formatConditionsForEntries(e,t,c);case n.SubQueryType.VALUES:return n.formatConditionsForValues(e,t,c);default:return!1}}).filter(Boolean);if(l.length===0)return{};let u=n.getFilterCustomFieldsSubQuery(s,e,l);return{where:{id:{[r.Op.in]:i.Sequelize.literal(`(${u})`)}},replacements:a}},s=a.customFields.CUSTOM_FIELDS_FILTER_SCOPE,c=(e,r)=>({replacementsMap:a,scopeValue:o})=>{if(!o||o.length===0)return{};let s=r?.useCustomFieldsEntries?n.SubQueryType.ENTRIES:n.SubQueryType.VALUES,c=t.generateRandomString(),l=Object.entries(o).map(([t])=>{let r=Object.keys(a).find(e=>a[e]===t);return[i.Sequelize.literal(n.getSortCustomFieldsSubQuery(s,e,r)),c]}),u=Object.entries(o).map(([,e])=>{let t=typeof e==`string`?e:Object.values(e)[0];return i.Sequelize.literal(`"${c}" ${t||`ASC`}`)});return{attributes:{include:l},order:u,replacements:a}};exports.customFieldsFilterScope=o,exports.customFieldsSortScope=c;
1
+ const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`../utils/custom-fields-mode.cjs`),n=require(`../utils/helpers/index.cjs`),r=require(`./helpers/filter.helpers.cjs`);let i=require(`sequelize`),a=require(`sequelize-typescript`),o=require(`@autofleet/common-types`);const s=(e,n)=>({replacementsMap:o,scopeValue:s})=>{if(!s||Object.keys(s).length===0)return{};let c=t.readsEntries(n?.customFieldsEntriesMode)?r.SubQueryType.ENTRIES:r.SubQueryType.VALUES,l=new Map(Object.entries(o).map(([e,t])=>[t,e])),u=Object.entries(s).map(([e,t])=>{switch(c){case r.SubQueryType.ENTRIES:return r.formatConditionsForEntries(e,t,l);case r.SubQueryType.VALUES:return r.formatConditionsForValues(e,t,l);default:return!1}}).filter(Boolean);if(u.length===0)return{};let d=r.getFilterCustomFieldsSubQuery(c,e,u);return{where:{id:{[i.Op.in]:a.Sequelize.literal(`(${d})`)}},replacements:o}},c=o.customFields.CUSTOM_FIELDS_FILTER_SCOPE,l=(e,i)=>({replacementsMap:o,scopeValue:s})=>{if(!s||s.length===0)return{};let c=t.readsEntries(i?.customFieldsEntriesMode)?r.SubQueryType.ENTRIES:r.SubQueryType.VALUES,l=n.generateRandomString(),u=Object.entries(s).map(([t])=>{let n=Object.keys(o).find(e=>o[e]===t);return[a.Sequelize.literal(r.getSortCustomFieldsSubQuery(c,e,n)),l]}),d=Object.entries(s).map(([,e])=>{let t=typeof e==`string`?e:Object.values(e)[0];return a.Sequelize.literal(`"${l}" ${t||`ASC`}`)});return{attributes:{include:u},order:d,replacements:o}};exports.customFieldsFilterScope=s,exports.customFieldsSortScope=l;
2
2
  //# sourceMappingURL=filter.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter.cjs","names":["SubQueryType","formatConditionsForEntries","formatConditionsForValues","getFilterCustomFieldsSubQuery","Op","Sequelize","scopeName: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE","customFields","generateRandomString","getSortCustomFieldsSubQuery"],"sources":["../../src/scopes/filter.ts"],"sourcesContent":["import { 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\ninterface 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"],"mappings":"wOA4BA,MAAa,GACX,EACA,KACI,CAAE,gBAAiB,EAAc,WAAY,KAA0E,CAC3H,GAAI,CAAC,GAAc,OAAO,KAAK,EAAW,CAAC,SAAW,EACpD,MAAO,EAAE,CAGX,IAAM,EAAY,GAAS,uBAAyBA,EAAAA,aAAa,QAAUA,EAAAA,aAAa,OAClF,EAAyB,IAAI,IAAI,OAAO,QAAQ,EAAa,CAAC,KAAK,CAAC,EAAK,KAAW,CAAC,EAAO,EAAI,CAAC,CAAC,CAElG,EAAoB,OAAO,QAAQ,EAAW,CAAC,KAAK,CAAC,EAAK,KAAe,CAC7E,OAAQ,EAAR,CACE,KAAKA,EAAAA,aAAa,QAChB,OAAOC,EAAAA,2BAA2B,EAAK,EAAW,EAAuB,CAC3E,KAAKD,EAAAA,aAAa,OAChB,OAAOE,EAAAA,0BAA0B,EAAK,EAAW,EAAuB,CAC1E,QACE,MAAO,KAEX,CAAC,OAAO,QAAQ,CAClB,GAAI,EAAkB,SAAW,EAC/B,MAAO,EAAE,CAEX,IAAM,EAAWC,EAAAA,8BAA8B,EAAW,EAAM,EAAkB,CAElF,MAAO,CACL,MAAO,CACL,GAAI,EACDC,EAAAA,GAAG,IAAKC,EAAAA,UAAU,QAAQ,IAAI,EAAS,GAAG,CAC5C,CACF,CACD,eACD,EAGUC,EAA4DC,EAAAA,aAAa,2BAEzE,GACX,EACA,KACI,CAAE,kBAAiB,WAAY,KAIR,CAC3B,GAAI,CAAC,GAAS,EAA0B,SAAW,EACjD,MAAO,EAAE,CAGX,IAAM,EAAY,GAAS,uBAAyBP,EAAAA,aAAa,QAAUA,EAAAA,aAAa,OAClF,EAAYQ,EAAAA,sBAAsB,CAClC,EAAW,OAAO,QAAQ,EAAK,CAAC,KAAK,CAAC,KAAS,CACnD,IAAM,EAAiB,OAAO,KAAK,EAAgB,CAAC,KAClD,GAAgB,EAAgB,KAAkB,EACnD,CACD,MAAQ,CACNH,EAAAA,UAAU,QAAQI,EAAAA,4BAA4B,EAAW,EAAM,EAAgB,CAAC,CAChF,EACD,EACD,CAEI,EAAS,OAAO,QAAQ,EAAK,CAAC,KAAK,EAAG,KAAgB,CAC1D,IAAM,EAAY,OAAO,GAAe,SAAW,EAAa,OAAO,OAAO,EAAW,CAAC,GAC1F,OAAOJ,EAAAA,UAAU,QAAQ,IAAI,EAAU,IAAI,GAAa,QAAQ,EAChE,CACF,MAAO,CACL,WAAY,CACV,QAAS,EACV,CACD,MAAO,EACP,aAAc,EACf"}
1
+ {"version":3,"file":"filter.cjs","names":["readsEntries","SubQueryType","formatConditionsForEntries","formatConditionsForValues","getFilterCustomFieldsSubQuery","Op","Sequelize","scopeName: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE","customFields","generateRandomString","getSortCustomFieldsSubQuery"],"sources":["../../src/scopes/filter.ts"],"sourcesContent":["import { 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 { readsEntries } from '../utils/custom-fields-mode';\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\ninterface 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, 'customFieldsEntriesMode'>,\n) => ({ replacementsMap: replacements, scopeValue: conditions }: customFieldsFilterScopeParams): CustomFieldFilterOptions => {\n if (!conditions || Object.keys(conditions).length === 0) {\n return {};\n }\n\n const queryType = readsEntries(options?.customFieldsEntriesMode) ? 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, 'customFieldsEntriesMode'>,\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 = readsEntries(options?.customFieldsEntriesMode) ? 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"],"mappings":"qRA6BA,MAAa,GACX,EACA,KACI,CAAE,gBAAiB,EAAc,WAAY,KAA0E,CAC3H,GAAI,CAAC,GAAc,OAAO,KAAK,EAAW,CAAC,SAAW,EACpD,MAAO,EAAE,CAGX,IAAM,EAAYA,EAAAA,aAAa,GAAS,wBAAwB,CAAGC,EAAAA,aAAa,QAAUA,EAAAA,aAAa,OACjG,EAAyB,IAAI,IAAI,OAAO,QAAQ,EAAa,CAAC,KAAK,CAAC,EAAK,KAAW,CAAC,EAAO,EAAI,CAAC,CAAC,CAElG,EAAoB,OAAO,QAAQ,EAAW,CAAC,KAAK,CAAC,EAAK,KAAe,CAC7E,OAAQ,EAAR,CACE,KAAKA,EAAAA,aAAa,QAChB,OAAOC,EAAAA,2BAA2B,EAAK,EAAW,EAAuB,CAC3E,KAAKD,EAAAA,aAAa,OAChB,OAAOE,EAAAA,0BAA0B,EAAK,EAAW,EAAuB,CAC1E,QACE,MAAO,KAEX,CAAC,OAAO,QAAQ,CAClB,GAAI,EAAkB,SAAW,EAC/B,MAAO,EAAE,CAEX,IAAM,EAAWC,EAAAA,8BAA8B,EAAW,EAAM,EAAkB,CAElF,MAAO,CACL,MAAO,CACL,GAAI,EACDC,EAAAA,GAAG,IAAKC,EAAAA,UAAU,QAAQ,IAAI,EAAS,GAAG,CAC5C,CACF,CACD,eACD,EAGUC,EAA4DC,EAAAA,aAAa,2BAEzE,GACX,EACA,KACI,CAAE,kBAAiB,WAAY,KAIR,CAC3B,GAAI,CAAC,GAAS,EAA0B,SAAW,EACjD,MAAO,EAAE,CAGX,IAAM,EAAYR,EAAAA,aAAa,GAAS,wBAAwB,CAAGC,EAAAA,aAAa,QAAUA,EAAAA,aAAa,OACjG,EAAYQ,EAAAA,sBAAsB,CAClC,EAAW,OAAO,QAAQ,EAAK,CAAC,KAAK,CAAC,KAAS,CACnD,IAAM,EAAiB,OAAO,KAAK,EAAgB,CAAC,KAClD,GAAgB,EAAgB,KAAkB,EACnD,CACD,MAAQ,CACNH,EAAAA,UAAU,QAAQI,EAAAA,4BAA4B,EAAW,EAAM,EAAgB,CAAC,CAChF,EACD,EACD,CAEI,EAAS,OAAO,QAAQ,EAAK,CAAC,KAAK,EAAG,KAAgB,CAC1D,IAAM,EAAY,OAAO,GAAe,SAAW,EAAa,OAAO,OAAO,EAAW,CAAC,GAC1F,OAAOJ,EAAAA,UAAU,QAAQ,IAAI,EAAU,IAAI,GAAa,QAAQ,EAChE,CACF,MAAO,CACL,WAAY,CACV,QAAS,EACV,CACD,MAAO,EACP,aAAc,EACf"}
@@ -5,7 +5,7 @@ import { Literal } from "sequelize/types/utils";
5
5
 
6
6
  //#region src/scopes/filter.d.ts
7
7
 
8
- declare const customFieldsSortScope: (name: string, options?: Pick<CustomFieldOptions, "useCustomFieldsEntries">) => ({
8
+ declare const customFieldsSortScope: (name: string, options?: Pick<CustomFieldOptions, "customFieldsEntriesMode">) => ({
9
9
  replacementsMap,
10
10
  scopeValue: sort
11
11
  }: {
@@ -5,7 +5,7 @@ import { Literal } from "sequelize/types/utils";
5
5
 
6
6
  //#region src/scopes/filter.d.ts
7
7
 
8
- declare const customFieldsSortScope: (name: string, options?: Pick<CustomFieldOptions, "useCustomFieldsEntries">) => ({
8
+ declare const customFieldsSortScope: (name: string, options?: Pick<CustomFieldOptions, "customFieldsEntriesMode">) => ({
9
9
  replacementsMap,
10
10
  scopeValue: sort
11
11
  }: {
@@ -1,2 +1,2 @@
1
- import{generateRandomString as e}from"../utils/helpers/index.js";import{SubQueryType as t,formatConditionsForEntries as n,formatConditionsForValues as r,getFilterCustomFieldsSubQuery as i,getSortCustomFieldsSubQuery as a}from"./helpers/filter.helpers.js";import{Op as o}from"sequelize";import{Sequelize as s}from"sequelize-typescript";import{customFields as c}from"@autofleet/common-types";const l=(e,a)=>({replacementsMap:c,scopeValue:l})=>{if(!l||Object.keys(l).length===0)return{};let u=a?.useCustomFieldsEntries?t.ENTRIES:t.VALUES,d=new Map(Object.entries(c).map(([e,t])=>[t,e])),f=Object.entries(l).map(([e,i])=>{switch(u){case t.ENTRIES:return n(e,i,d);case t.VALUES:return r(e,i,d);default:return!1}}).filter(Boolean);if(f.length===0)return{};let p=i(u,e,f);return{where:{id:{[o.in]:s.literal(`(${p})`)}},replacements:c}};c.CUSTOM_FIELDS_FILTER_SCOPE;const u=(n,r)=>({replacementsMap:i,scopeValue:o})=>{if(!o||o.length===0)return{};let c=r?.useCustomFieldsEntries?t.ENTRIES:t.VALUES,l=e(),u=Object.entries(o).map(([e])=>{let t=Object.keys(i).find(t=>i[t]===e);return[s.literal(a(c,n,t)),l]}),d=Object.entries(o).map(([,e])=>{let t=typeof e==`string`?e:Object.values(e)[0];return s.literal(`"${l}" ${t||`ASC`}`)});return{attributes:{include:u},order:d,replacements:i}};export{l as customFieldsFilterScope,u as customFieldsSortScope};
1
+ import{readsEntries as e}from"../utils/custom-fields-mode.js";import{generateRandomString as t}from"../utils/helpers/index.js";import{SubQueryType as n,formatConditionsForEntries as r,formatConditionsForValues as i,getFilterCustomFieldsSubQuery as a,getSortCustomFieldsSubQuery as o}from"./helpers/filter.helpers.js";import{Op as s}from"sequelize";import{Sequelize as c}from"sequelize-typescript";import{customFields as l}from"@autofleet/common-types";const u=(t,o)=>({replacementsMap:l,scopeValue:u})=>{if(!u||Object.keys(u).length===0)return{};let d=e(o?.customFieldsEntriesMode)?n.ENTRIES:n.VALUES,f=new Map(Object.entries(l).map(([e,t])=>[t,e])),p=Object.entries(u).map(([e,t])=>{switch(d){case n.ENTRIES:return r(e,t,f);case n.VALUES:return i(e,t,f);default:return!1}}).filter(Boolean);if(p.length===0)return{};let m=a(d,t,p);return{where:{id:{[s.in]:c.literal(`(${m})`)}},replacements:l}};l.CUSTOM_FIELDS_FILTER_SCOPE;const d=(r,i)=>({replacementsMap:a,scopeValue:s})=>{if(!s||s.length===0)return{};let l=e(i?.customFieldsEntriesMode)?n.ENTRIES:n.VALUES,u=t(),d=Object.entries(s).map(([e])=>{let t=Object.keys(a).find(t=>a[t]===e);return[c.literal(o(l,r,t)),u]}),f=Object.entries(s).map(([,e])=>{let t=typeof e==`string`?e:Object.values(e)[0];return c.literal(`"${u}" ${t||`ASC`}`)});return{attributes:{include:d},order:f,replacements:a}};export{u as customFieldsFilterScope,d as customFieldsSortScope};
2
2
  //# sourceMappingURL=filter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","names":["scopeName: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE"],"sources":["../../src/scopes/filter.ts"],"sourcesContent":["import { 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\ninterface 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"],"mappings":"sYA4BA,MAAa,GACX,EACA,KACI,CAAE,gBAAiB,EAAc,WAAY,KAA0E,CAC3H,GAAI,CAAC,GAAc,OAAO,KAAK,EAAW,CAAC,SAAW,EACpD,MAAO,EAAE,CAGX,IAAM,EAAY,GAAS,uBAAyB,EAAa,QAAU,EAAa,OAClF,EAAyB,IAAI,IAAI,OAAO,QAAQ,EAAa,CAAC,KAAK,CAAC,EAAK,KAAW,CAAC,EAAO,EAAI,CAAC,CAAC,CAElG,EAAoB,OAAO,QAAQ,EAAW,CAAC,KAAK,CAAC,EAAK,KAAe,CAC7E,OAAQ,EAAR,CACE,KAAK,EAAa,QAChB,OAAO,EAA2B,EAAK,EAAW,EAAuB,CAC3E,KAAK,EAAa,OAChB,OAAO,EAA0B,EAAK,EAAW,EAAuB,CAC1E,QACE,MAAO,KAEX,CAAC,OAAO,QAAQ,CAClB,GAAI,EAAkB,SAAW,EAC/B,MAAO,EAAE,CAEX,IAAM,EAAW,EAA8B,EAAW,EAAM,EAAkB,CAElF,MAAO,CACL,MAAO,CACL,GAAI,EACD,EAAG,IAAK,EAAU,QAAQ,IAAI,EAAS,GAAG,CAC5C,CACF,CACD,eACD,EAGsE,EAAa,2BAEtF,MAAa,GACX,EACA,KACI,CAAE,kBAAiB,WAAY,KAIR,CAC3B,GAAI,CAAC,GAAS,EAA0B,SAAW,EACjD,MAAO,EAAE,CAGX,IAAM,EAAY,GAAS,uBAAyB,EAAa,QAAU,EAAa,OAClF,EAAY,GAAsB,CAClC,EAAW,OAAO,QAAQ,EAAK,CAAC,KAAK,CAAC,KAAS,CACnD,IAAM,EAAiB,OAAO,KAAK,EAAgB,CAAC,KAClD,GAAgB,EAAgB,KAAkB,EACnD,CACD,MAAQ,CACN,EAAU,QAAQ,EAA4B,EAAW,EAAM,EAAgB,CAAC,CAChF,EACD,EACD,CAEI,EAAS,OAAO,QAAQ,EAAK,CAAC,KAAK,EAAG,KAAgB,CAC1D,IAAM,EAAY,OAAO,GAAe,SAAW,EAAa,OAAO,OAAO,EAAW,CAAC,GAC1F,OAAO,EAAU,QAAQ,IAAI,EAAU,IAAI,GAAa,QAAQ,EAChE,CACF,MAAO,CACL,WAAY,CACV,QAAS,EACV,CACD,MAAO,EACP,aAAc,EACf"}
1
+ {"version":3,"file":"filter.js","names":["Sequelize","scopeName: typeof customFields.CUSTOM_FIELDS_FILTER_SCOPE"],"sources":["../../src/scopes/filter.ts"],"sourcesContent":["import { 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 { readsEntries } from '../utils/custom-fields-mode';\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\ninterface 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, 'customFieldsEntriesMode'>,\n) => ({ replacementsMap: replacements, scopeValue: conditions }: customFieldsFilterScopeParams): CustomFieldFilterOptions => {\n if (!conditions || Object.keys(conditions).length === 0) {\n return {};\n }\n\n const queryType = readsEntries(options?.customFieldsEntriesMode) ? 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, 'customFieldsEntriesMode'>,\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 = readsEntries(options?.customFieldsEntriesMode) ? 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"],"mappings":"ocA6BA,MAAa,GACX,EACA,KACI,CAAE,gBAAiB,EAAc,WAAY,KAA0E,CAC3H,GAAI,CAAC,GAAc,OAAO,KAAK,EAAW,CAAC,SAAW,EACpD,MAAO,EAAE,CAGX,IAAM,EAAY,EAAa,GAAS,wBAAwB,CAAG,EAAa,QAAU,EAAa,OACjG,EAAyB,IAAI,IAAI,OAAO,QAAQ,EAAa,CAAC,KAAK,CAAC,EAAK,KAAW,CAAC,EAAO,EAAI,CAAC,CAAC,CAElG,EAAoB,OAAO,QAAQ,EAAW,CAAC,KAAK,CAAC,EAAK,KAAe,CAC7E,OAAQ,EAAR,CACE,KAAK,EAAa,QAChB,OAAO,EAA2B,EAAK,EAAW,EAAuB,CAC3E,KAAK,EAAa,OAChB,OAAO,EAA0B,EAAK,EAAW,EAAuB,CAC1E,QACE,MAAO,KAEX,CAAC,OAAO,QAAQ,CAClB,GAAI,EAAkB,SAAW,EAC/B,MAAO,EAAE,CAEX,IAAM,EAAW,EAA8B,EAAW,EAAM,EAAkB,CAElF,MAAO,CACL,MAAO,CACL,GAAI,EACD,EAAG,IAAKA,EAAU,QAAQ,IAAI,EAAS,GAAG,CAC5C,CACF,CACD,eACD,EAGsE,EAAa,2BAEtF,MAAa,GACX,EACA,KACI,CAAE,kBAAiB,WAAY,KAIR,CAC3B,GAAI,CAAC,GAAS,EAA0B,SAAW,EACjD,MAAO,EAAE,CAGX,IAAM,EAAY,EAAa,GAAS,wBAAwB,CAAG,EAAa,QAAU,EAAa,OACjG,EAAY,GAAsB,CAClC,EAAW,OAAO,QAAQ,EAAK,CAAC,KAAK,CAAC,KAAS,CACnD,IAAM,EAAiB,OAAO,KAAK,EAAgB,CAAC,KAClD,GAAgB,EAAgB,KAAkB,EACnD,CACD,MAAQ,CACNA,EAAU,QAAQ,EAA4B,EAAW,EAAM,EAAgB,CAAC,CAChF,EACD,EACD,CAEI,EAAS,OAAO,QAAQ,EAAK,CAAC,KAAK,EAAG,KAAgB,CAC1D,IAAM,EAAY,OAAO,GAAe,SAAW,EAAa,OAAO,OAAO,EAAW,CAAC,GAC1F,OAAOA,EAAU,QAAQ,IAAI,EAAU,IAAI,GAAa,QAAQ,EAChE,CACF,MAAO,CACL,WAAY,CACV,QAAS,EACV,CACD,MAAO,EACP,aAAc,EACf"}
@@ -1,6 +1,7 @@
1
1
  import { CustomFieldDefinition } from "../models/CustomFieldDefinition.cjs";
2
+ import { CustomFieldsEntriesMode } from "../utils/custom-fields-mode.cjs";
2
3
  import { ModelCtor, Sequelize } from "sequelize-typescript";
3
- import { IncludeOptions } from "sequelize";
4
+ import { IncludeOptions, Transaction } from "sequelize";
4
5
  import { getUser } from "@autofleet/zehut";
5
6
 
6
7
  //#region src/types/index.d.ts
@@ -48,6 +49,16 @@ interface CustomFieldOptions {
48
49
  databaseConfig: any;
49
50
  getUser: typeof getUser;
50
51
  sequelize?: Sequelize;
52
+ /**
53
+ * Which custom-field table this service reads from and writes to.
54
+ * Defaults to `'disabled'` (values only) when omitted.
55
+ * @see {@link CustomFieldsEntriesMode}
56
+ */
57
+ customFieldsEntriesMode?: CustomFieldsEntriesMode;
58
+ /**
59
+ * @deprecated Use {@link CustomFieldOptions.customFieldsEntriesMode} instead.
60
+ * `true` maps to `'read-and-write'`, `false` to `'disabled'`.
61
+ */
51
62
  useCustomFieldsEntries?: boolean;
52
63
  useValidators?: boolean;
53
64
  useModelTypeMapping?: boolean;
@@ -1,8 +1,9 @@
1
1
  import { CustomFieldDefinition } from "../models/CustomFieldDefinition.js";
2
2
  import "../models/CustomValidator.js";
3
- import { IncludeOptions } from "sequelize";
3
+ import { CustomFieldsEntriesMode } from "../utils/custom-fields-mode.js";
4
+ import { IncludeOptions, Transaction } from "sequelize";
4
5
  import { getUser } from "@autofleet/zehut";
5
- import { ModelCtor, Sequelize } from "sequelize-typescript";
6
+ import { ModelCtor, Sequelize as Sequelize$1 } from "sequelize-typescript";
6
7
 
7
8
  //#region src/types/index.d.ts
8
9
  type ModelFetcher = (name: string) => any;
@@ -48,7 +49,17 @@ interface CustomFieldOptions {
48
49
  hasTypeId?: boolean;
49
50
  databaseConfig: any;
50
51
  getUser: typeof getUser;
51
- sequelize?: Sequelize;
52
+ sequelize?: Sequelize$1;
53
+ /**
54
+ * Which custom-field table this service reads from and writes to.
55
+ * Defaults to `'disabled'` (values only) when omitted.
56
+ * @see {@link CustomFieldsEntriesMode}
57
+ */
58
+ customFieldsEntriesMode?: CustomFieldsEntriesMode;
59
+ /**
60
+ * @deprecated Use {@link CustomFieldOptions.customFieldsEntriesMode} instead.
61
+ * `true` maps to `'read-and-write'`, `false` to `'disabled'`.
62
+ */
52
63
  useCustomFieldsEntries?: boolean;
53
64
  useValidators?: boolean;
54
65
  useModelTypeMapping?: boolean;
@@ -0,0 +1,2 @@
1
+ const e=require(`./logger/index.cjs`),t={DISABLED:`disabled`,WRITE_ONLY:`write-only`,READ_AND_WRITE:`read-and-write`},n=Object.values(t),r=e=>n.includes(e),i=`sadot: \`useCustomFieldsEntries\` is deprecated, use \`customFieldsEntriesMode\` with one of ${Object.values(t).map(e=>`'${e}'`).join(` | `)}`,a=[void 0,null,``,!1],o=(o={})=>{let{useCustomFieldsEntries:s}=o,c=o.customFieldsEntriesMode,l=a.includes(c)?void 0:c;if(l!==void 0){if(!r(l))throw Error(`sadot: unknown customFieldsEntriesMode ${JSON.stringify(l)}. Expected one of ${n.map(e=>`'${e}'`).join(` | `)}`);return s!==void 0&&e.default.warn(`${i}. Both were passed; \`useCustomFieldsEntries\` is ignored`),l}return s===void 0?t.DISABLED:(e.default.warn(i),s?t.READ_AND_WRITE:t.DISABLED)},s=[t.WRITE_ONLY,t.READ_AND_WRITE],c=[t.READ_AND_WRITE],l=e=>s.includes(e),u=e=>c.includes(e);exports.CUSTOM_FIELDS_ENTRIES_MODE=t,exports.readsEntries=u,exports.resolveCustomFieldsEntriesMode=o,exports.writesEntries=l;
2
+ //# sourceMappingURL=custom-fields-mode.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-fields-mode.cjs","names":["CUSTOM_FIELDS_ENTRIES_MODES: readonly CustomFieldsEntriesMode[]","UNSET_MODE_VALUES: readonly unknown[]","ENTRIES_WRITING_MODES: readonly CustomFieldsEntriesMode[]","ENTRIES_READING_MODES: readonly CustomFieldsEntriesMode[]"],"sources":["../../src/utils/custom-fields-mode.ts"],"sourcesContent":["import logger from './logger';\n\n/**\n * How a service uses `custom_field_entries`.\n *\n * - `DISABLED` — values only. The default when the option is omitted.\n * - `WRITE_ONLY` — write both tables, still read from `custom_field_values`.\n * The safe middle stage: entries fills up and stays current while reads are\n * unaffected, so a backfill only has to cover history.\n * - `READ_AND_WRITE` — write both tables, read from `custom_field_entries`.\n *\n * `custom_field_values` is written in every mode, which is what makes moving\n * between stages reversible.\n */\nexport const CUSTOM_FIELDS_ENTRIES_MODE = {\n DISABLED: 'disabled',\n WRITE_ONLY: 'write-only',\n READ_AND_WRITE: 'read-and-write',\n} as const;\n\nexport type CustomFieldsEntriesMode = typeof CUSTOM_FIELDS_ENTRIES_MODE[keyof typeof CUSTOM_FIELDS_ENTRIES_MODE];\n\nconst CUSTOM_FIELDS_ENTRIES_MODES: readonly CustomFieldsEntriesMode[] = Object.values(CUSTOM_FIELDS_ENTRIES_MODE);\n\nconst isCustomFieldsEntriesMode = (value: unknown): value is CustomFieldsEntriesMode =>\n CUSTOM_FIELDS_ENTRIES_MODES.includes(value as CustomFieldsEntriesMode);\n\nexport interface CustomFieldsEntriesModeOptions {\n customFieldsEntriesMode?: CustomFieldsEntriesMode;\n /** @deprecated Use `customFieldsEntriesMode` instead. */\n useCustomFieldsEntries?: boolean;\n}\n\nconst DEPRECATION_MESSAGE = 'sadot: `useCustomFieldsEntries` is deprecated, use `customFieldsEntriesMode`'\n + ` with one of ${Object.values(CUSTOM_FIELDS_ENTRIES_MODE).map(mode => `'${mode}'`).join(' | ')}`;\n\n/**\n * Resolves the effective mode from the new option and the deprecated boolean.\n *\n * The legacy boolean keeps working so services can bump the package before they\n * rename the option, but an unrecognised mode is a typo and throws rather than\n * silently degrading to `DISABLED` — which would stop entries being written.\n */\n// `null` and an empty string mean \"not configured\" rather than \"typo\" — a settings\n// lookup or an env var that came back empty. The public option type does not admit\n// them, but a JS caller can still pass them.\nconst UNSET_MODE_VALUES: readonly unknown[] = [undefined, null, '', false];\n\nexport const resolveCustomFieldsEntriesMode = (options: CustomFieldsEntriesModeOptions = {}): CustomFieldsEntriesMode => {\n const { useCustomFieldsEntries } = options;\n\n const rawMode = options.customFieldsEntriesMode as unknown;\n const customFieldsEntriesMode = UNSET_MODE_VALUES.includes(rawMode) ? undefined : rawMode;\n\n if (customFieldsEntriesMode !== undefined) {\n if (!isCustomFieldsEntriesMode(customFieldsEntriesMode)) {\n throw new Error(\n `sadot: unknown customFieldsEntriesMode ${JSON.stringify(customFieldsEntriesMode)}.`\n + ` Expected one of ${CUSTOM_FIELDS_ENTRIES_MODES.map(mode => `'${mode}'`).join(' | ')}`,\n );\n }\n if (useCustomFieldsEntries !== undefined) {\n logger.warn(`${DEPRECATION_MESSAGE}. Both were passed; \\`useCustomFieldsEntries\\` is ignored`);\n }\n return customFieldsEntriesMode;\n }\n\n if (useCustomFieldsEntries !== undefined) {\n logger.warn(DEPRECATION_MESSAGE);\n return useCustomFieldsEntries\n ? CUSTOM_FIELDS_ENTRIES_MODE.READ_AND_WRITE\n : CUSTOM_FIELDS_ENTRIES_MODE.DISABLED;\n }\n\n return CUSTOM_FIELDS_ENTRIES_MODE.DISABLED;\n};\n\n// Both predicates accept `undefined` so the \"no mode means DISABLED\" rule lives here\n// rather than being repeated at every call site. Publicly exported scopes can be\n// invoked with no options at all.\n\nconst ENTRIES_WRITING_MODES: readonly CustomFieldsEntriesMode[] = [\n CUSTOM_FIELDS_ENTRIES_MODE.WRITE_ONLY,\n CUSTOM_FIELDS_ENTRIES_MODE.READ_AND_WRITE,\n];\nconst ENTRIES_READING_MODES: readonly CustomFieldsEntriesMode[] = [CUSTOM_FIELDS_ENTRIES_MODE.READ_AND_WRITE];\n\n/** True when `custom_field_entries` should be written alongside `custom_field_values`. */\nexport const writesEntries = (mode: CustomFieldsEntriesMode | undefined): boolean =>\n ENTRIES_WRITING_MODES.includes(mode as CustomFieldsEntriesMode);\n\n/** True when reads, filtering and sorting should go to `custom_field_entries`. */\nexport const readsEntries = (mode: CustomFieldsEntriesMode | undefined): boolean =>\n ENTRIES_READING_MODES.includes(mode as CustomFieldsEntriesMode);\n"],"mappings":"sCAca,EAA6B,CACxC,SAAU,WACV,WAAY,aACZ,eAAgB,iBACjB,CAIKA,EAAkE,OAAO,OAAO,EAA2B,CAE3G,EAA6B,GACjC,EAA4B,SAAS,EAAiC,CAQlE,EAAsB,gGACR,OAAO,OAAO,EAA2B,CAAC,IAAI,GAAQ,IAAI,EAAK,GAAG,CAAC,KAAK,MAAM,GAY5FC,EAAwC,CAAC,IAAA,GAAW,KAAM,GAAI,GAAM,CAE7D,GAAkC,EAA0C,EAAE,GAA8B,CACvH,GAAM,CAAE,0BAA2B,EAE7B,EAAU,EAAQ,wBAClB,EAA0B,EAAkB,SAAS,EAAQ,CAAG,IAAA,GAAY,EAElF,GAAI,IAA4B,IAAA,GAAW,CACzC,GAAI,CAAC,EAA0B,EAAwB,CACrD,MAAU,MACR,0CAA0C,KAAK,UAAU,EAAwB,CAAC,oBAC5D,EAA4B,IAAI,GAAQ,IAAI,EAAK,GAAG,CAAC,KAAK,MAAM,GACvF,CAKH,OAHI,IAA2B,IAAA,IAC7B,EAAA,QAAO,KAAK,GAAG,EAAoB,2DAA2D,CAEzF,EAUT,OAPI,IAA2B,IAAA,GAOxB,EAA2B,UANhC,EAAA,QAAO,KAAK,EAAoB,CACzB,EACH,EAA2B,eAC3B,EAA2B,WAU7BC,EAA4D,CAChE,EAA2B,WAC3B,EAA2B,eAC5B,CACKC,EAA4D,CAAC,EAA2B,eAAe,CAGhG,EAAiB,GAC5B,EAAsB,SAAS,EAAgC,CAGpD,EAAgB,GAC3B,EAAsB,SAAS,EAAgC"}
@@ -0,0 +1,27 @@
1
+ //#region src/utils/custom-fields-mode.d.ts
2
+ /**
3
+ * How a service uses `custom_field_entries`.
4
+ *
5
+ * - `DISABLED` — values only. The default when the option is omitted.
6
+ * - `WRITE_ONLY` — write both tables, still read from `custom_field_values`.
7
+ * The safe middle stage: entries fills up and stays current while reads are
8
+ * unaffected, so a backfill only has to cover history.
9
+ * - `READ_AND_WRITE` — write both tables, read from `custom_field_entries`.
10
+ *
11
+ * `custom_field_values` is written in every mode, which is what makes moving
12
+ * between stages reversible.
13
+ */
14
+ declare const CUSTOM_FIELDS_ENTRIES_MODE: {
15
+ readonly DISABLED: "disabled";
16
+ readonly WRITE_ONLY: "write-only";
17
+ readonly READ_AND_WRITE: "read-and-write";
18
+ };
19
+ type CustomFieldsEntriesMode = typeof CUSTOM_FIELDS_ENTRIES_MODE[keyof typeof CUSTOM_FIELDS_ENTRIES_MODE];
20
+ interface CustomFieldsEntriesModeOptions {
21
+ customFieldsEntriesMode?: CustomFieldsEntriesMode;
22
+ /** @deprecated Use `customFieldsEntriesMode` instead. */
23
+ useCustomFieldsEntries?: boolean;
24
+ }
25
+ //#endregion
26
+ export { CUSTOM_FIELDS_ENTRIES_MODE, CustomFieldsEntriesMode, CustomFieldsEntriesModeOptions };
27
+ //# sourceMappingURL=custom-fields-mode.d.cts.map
@@ -0,0 +1,27 @@
1
+ //#region src/utils/custom-fields-mode.d.ts
2
+ /**
3
+ * How a service uses `custom_field_entries`.
4
+ *
5
+ * - `DISABLED` — values only. The default when the option is omitted.
6
+ * - `WRITE_ONLY` — write both tables, still read from `custom_field_values`.
7
+ * The safe middle stage: entries fills up and stays current while reads are
8
+ * unaffected, so a backfill only has to cover history.
9
+ * - `READ_AND_WRITE` — write both tables, read from `custom_field_entries`.
10
+ *
11
+ * `custom_field_values` is written in every mode, which is what makes moving
12
+ * between stages reversible.
13
+ */
14
+ declare const CUSTOM_FIELDS_ENTRIES_MODE: {
15
+ readonly DISABLED: "disabled";
16
+ readonly WRITE_ONLY: "write-only";
17
+ readonly READ_AND_WRITE: "read-and-write";
18
+ };
19
+ type CustomFieldsEntriesMode = typeof CUSTOM_FIELDS_ENTRIES_MODE[keyof typeof CUSTOM_FIELDS_ENTRIES_MODE];
20
+ interface CustomFieldsEntriesModeOptions {
21
+ customFieldsEntriesMode?: CustomFieldsEntriesMode;
22
+ /** @deprecated Use `customFieldsEntriesMode` instead. */
23
+ useCustomFieldsEntries?: boolean;
24
+ }
25
+ //#endregion
26
+ export { CUSTOM_FIELDS_ENTRIES_MODE, CustomFieldsEntriesMode, CustomFieldsEntriesModeOptions };
27
+ //# sourceMappingURL=custom-fields-mode.d.ts.map
@@ -0,0 +1,2 @@
1
+ import e from"./logger/index.js";const t={DISABLED:`disabled`,WRITE_ONLY:`write-only`,READ_AND_WRITE:`read-and-write`},n=Object.values(t),r=e=>n.includes(e),i=`sadot: \`useCustomFieldsEntries\` is deprecated, use \`customFieldsEntriesMode\` with one of ${Object.values(t).map(e=>`'${e}'`).join(` | `)}`,a=[void 0,null,``,!1],o=(o={})=>{let{useCustomFieldsEntries:s}=o,c=o.customFieldsEntriesMode,l=a.includes(c)?void 0:c;if(l!==void 0){if(!r(l))throw Error(`sadot: unknown customFieldsEntriesMode ${JSON.stringify(l)}. Expected one of ${n.map(e=>`'${e}'`).join(` | `)}`);return s!==void 0&&e.warn(`${i}. Both were passed; \`useCustomFieldsEntries\` is ignored`),l}return s===void 0?t.DISABLED:(e.warn(i),s?t.READ_AND_WRITE:t.DISABLED)},s=[t.WRITE_ONLY,t.READ_AND_WRITE],c=[t.READ_AND_WRITE],l=e=>s.includes(e),u=e=>c.includes(e);export{t as CUSTOM_FIELDS_ENTRIES_MODE,u as readsEntries,o as resolveCustomFieldsEntriesMode,l as writesEntries};
2
+ //# sourceMappingURL=custom-fields-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-fields-mode.js","names":["CUSTOM_FIELDS_ENTRIES_MODES: readonly CustomFieldsEntriesMode[]","UNSET_MODE_VALUES: readonly unknown[]","ENTRIES_WRITING_MODES: readonly CustomFieldsEntriesMode[]","ENTRIES_READING_MODES: readonly CustomFieldsEntriesMode[]"],"sources":["../../src/utils/custom-fields-mode.ts"],"sourcesContent":["import logger from './logger';\n\n/**\n * How a service uses `custom_field_entries`.\n *\n * - `DISABLED` — values only. The default when the option is omitted.\n * - `WRITE_ONLY` — write both tables, still read from `custom_field_values`.\n * The safe middle stage: entries fills up and stays current while reads are\n * unaffected, so a backfill only has to cover history.\n * - `READ_AND_WRITE` — write both tables, read from `custom_field_entries`.\n *\n * `custom_field_values` is written in every mode, which is what makes moving\n * between stages reversible.\n */\nexport const CUSTOM_FIELDS_ENTRIES_MODE = {\n DISABLED: 'disabled',\n WRITE_ONLY: 'write-only',\n READ_AND_WRITE: 'read-and-write',\n} as const;\n\nexport type CustomFieldsEntriesMode = typeof CUSTOM_FIELDS_ENTRIES_MODE[keyof typeof CUSTOM_FIELDS_ENTRIES_MODE];\n\nconst CUSTOM_FIELDS_ENTRIES_MODES: readonly CustomFieldsEntriesMode[] = Object.values(CUSTOM_FIELDS_ENTRIES_MODE);\n\nconst isCustomFieldsEntriesMode = (value: unknown): value is CustomFieldsEntriesMode =>\n CUSTOM_FIELDS_ENTRIES_MODES.includes(value as CustomFieldsEntriesMode);\n\nexport interface CustomFieldsEntriesModeOptions {\n customFieldsEntriesMode?: CustomFieldsEntriesMode;\n /** @deprecated Use `customFieldsEntriesMode` instead. */\n useCustomFieldsEntries?: boolean;\n}\n\nconst DEPRECATION_MESSAGE = 'sadot: `useCustomFieldsEntries` is deprecated, use `customFieldsEntriesMode`'\n + ` with one of ${Object.values(CUSTOM_FIELDS_ENTRIES_MODE).map(mode => `'${mode}'`).join(' | ')}`;\n\n/**\n * Resolves the effective mode from the new option and the deprecated boolean.\n *\n * The legacy boolean keeps working so services can bump the package before they\n * rename the option, but an unrecognised mode is a typo and throws rather than\n * silently degrading to `DISABLED` — which would stop entries being written.\n */\n// `null` and an empty string mean \"not configured\" rather than \"typo\" — a settings\n// lookup or an env var that came back empty. The public option type does not admit\n// them, but a JS caller can still pass them.\nconst UNSET_MODE_VALUES: readonly unknown[] = [undefined, null, '', false];\n\nexport const resolveCustomFieldsEntriesMode = (options: CustomFieldsEntriesModeOptions = {}): CustomFieldsEntriesMode => {\n const { useCustomFieldsEntries } = options;\n\n const rawMode = options.customFieldsEntriesMode as unknown;\n const customFieldsEntriesMode = UNSET_MODE_VALUES.includes(rawMode) ? undefined : rawMode;\n\n if (customFieldsEntriesMode !== undefined) {\n if (!isCustomFieldsEntriesMode(customFieldsEntriesMode)) {\n throw new Error(\n `sadot: unknown customFieldsEntriesMode ${JSON.stringify(customFieldsEntriesMode)}.`\n + ` Expected one of ${CUSTOM_FIELDS_ENTRIES_MODES.map(mode => `'${mode}'`).join(' | ')}`,\n );\n }\n if (useCustomFieldsEntries !== undefined) {\n logger.warn(`${DEPRECATION_MESSAGE}. Both were passed; \\`useCustomFieldsEntries\\` is ignored`);\n }\n return customFieldsEntriesMode;\n }\n\n if (useCustomFieldsEntries !== undefined) {\n logger.warn(DEPRECATION_MESSAGE);\n return useCustomFieldsEntries\n ? CUSTOM_FIELDS_ENTRIES_MODE.READ_AND_WRITE\n : CUSTOM_FIELDS_ENTRIES_MODE.DISABLED;\n }\n\n return CUSTOM_FIELDS_ENTRIES_MODE.DISABLED;\n};\n\n// Both predicates accept `undefined` so the \"no mode means DISABLED\" rule lives here\n// rather than being repeated at every call site. Publicly exported scopes can be\n// invoked with no options at all.\n\nconst ENTRIES_WRITING_MODES: readonly CustomFieldsEntriesMode[] = [\n CUSTOM_FIELDS_ENTRIES_MODE.WRITE_ONLY,\n CUSTOM_FIELDS_ENTRIES_MODE.READ_AND_WRITE,\n];\nconst ENTRIES_READING_MODES: readonly CustomFieldsEntriesMode[] = [CUSTOM_FIELDS_ENTRIES_MODE.READ_AND_WRITE];\n\n/** True when `custom_field_entries` should be written alongside `custom_field_values`. */\nexport const writesEntries = (mode: CustomFieldsEntriesMode | undefined): boolean =>\n ENTRIES_WRITING_MODES.includes(mode as CustomFieldsEntriesMode);\n\n/** True when reads, filtering and sorting should go to `custom_field_entries`. */\nexport const readsEntries = (mode: CustomFieldsEntriesMode | undefined): boolean =>\n ENTRIES_READING_MODES.includes(mode as CustomFieldsEntriesMode);\n"],"mappings":"iCAcA,MAAa,EAA6B,CACxC,SAAU,WACV,WAAY,aACZ,eAAgB,iBACjB,CAIKA,EAAkE,OAAO,OAAO,EAA2B,CAE3G,EAA6B,GACjC,EAA4B,SAAS,EAAiC,CAQlE,EAAsB,gGACR,OAAO,OAAO,EAA2B,CAAC,IAAI,GAAQ,IAAI,EAAK,GAAG,CAAC,KAAK,MAAM,GAY5FC,EAAwC,CAAC,IAAA,GAAW,KAAM,GAAI,GAAM,CAE7D,GAAkC,EAA0C,EAAE,GAA8B,CACvH,GAAM,CAAE,0BAA2B,EAE7B,EAAU,EAAQ,wBAClB,EAA0B,EAAkB,SAAS,EAAQ,CAAG,IAAA,GAAY,EAElF,GAAI,IAA4B,IAAA,GAAW,CACzC,GAAI,CAAC,EAA0B,EAAwB,CACrD,MAAU,MACR,0CAA0C,KAAK,UAAU,EAAwB,CAAC,oBAC5D,EAA4B,IAAI,GAAQ,IAAI,EAAK,GAAG,CAAC,KAAK,MAAM,GACvF,CAKH,OAHI,IAA2B,IAAA,IAC7B,EAAO,KAAK,GAAG,EAAoB,2DAA2D,CAEzF,EAUT,OAPI,IAA2B,IAAA,GAOxB,EAA2B,UANhC,EAAO,KAAK,EAAoB,CACzB,EACH,EAA2B,eAC3B,EAA2B,WAU7BC,EAA4D,CAChE,EAA2B,WAC3B,EAA2B,eAC5B,CACKC,EAA4D,CAAC,EAA2B,eAAe,CAGhG,EAAiB,GAC5B,EAAsB,SAAS,EAAgC,CAGpD,EAAgB,GAC3B,EAAsB,SAAS,EAAgC"}
@@ -1,2 +1,2 @@
1
- import"sequelize";import{Sequelize as e}from"sequelize-typescript";var t=t=>{let n=t[process.env.NODE_ENV||`test`],r;return r=n.use_env_variable?new e(process.env[n.use_env_variable],n):new e(n.database,n.username,n.password,n),r};export{t as default};
1
+ import{QueryTypes as e}from"sequelize";import{Sequelize as t}from"sequelize-typescript";var n=e=>{let n=e[process.env.NODE_ENV||`test`],r;return r=n.use_env_variable?new t(process.env[n.use_env_variable],n):new t(n.database,n.username,n.password,n),r};export{n as default};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["sequelize: Sequelize"],"sources":["../../../src/utils/db/index.ts"],"sourcesContent":["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"],"mappings":"mEAGA,IAAA,EAAgB,GAAmC,CAGjD,IAAM,EAAS,EADK,QAAQ,IAAI,UADhB,QAGZA,EAMJ,MALA,CAGE,EAHE,EAAO,iBACG,IAAI,EAAU,QAAQ,IAAI,EAAO,kBAAoB,EAAO,CAE5D,IAAI,EAAU,EAAO,SAAU,EAAO,SAAU,EAAO,SAAU,EAAO,CAE/E"}
1
+ {"version":3,"file":"index.js","names":["sequelize: Sequelize","Sequelize"],"sources":["../../../src/utils/db/index.ts"],"sourcesContent":["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"],"mappings":"wFAGA,IAAA,EAAgB,GAAmC,CAGjD,IAAM,EAAS,EADK,QAAQ,IAAI,UADhB,QAGZA,EAMJ,MALA,CAGE,EAHE,EAAO,iBACG,IAAIC,EAAU,QAAQ,IAAI,EAAO,kBAAoB,EAAO,CAE5D,IAAIA,EAAU,EAAO,SAAU,EAAO,SAAU,EAAO,SAAU,EAAO,CAE/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/utils/helpers/index.ts"],"sourcesContent":["import { 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 = 'SELECT cv.model_id'\n + ' FROM \"custom_field_values\" AS cv'\n + ' INNER JOIN custom_field_definitions AS cd'\n + ' ON cv.custom_field_definition_id = cd.id'\n + ` AND cd.entity_id = '${entityId}'`\n + ` AND cd.model_type = '${model.name}'`\n + ` AND cd.deleted_at IS NULL`\n + (excludedTypesString ? ` AND cd.field_type NOT IN (${excludedTypesString})` : '')\n + ' WHERE cv.deleted_at IS NULL'\n + ' AND CAST(cv.value AS TEXT) ILIKE :searchTerm';\n\n return {\n where: {\n id: {\n [Op.in]: Sequelize.literal(`(${subQuery})`),\n },\n },\n replacements: { searchTerm: `%${searchTerm}%` },\n };\n};\n"],"mappings":"0LA2BA,MAAa,GAAwB,EAAS,IAErC,MAAM,KAAK,CAAE,SAAQ,KAAQ,uDAAW,OAAO,EAAU,GAAkB,CAAC,CAAC,CAAC,KAAK,GAAG,CAGlF,GACX,EACA,EACA,EACA,EAA0D,CACxD,EAA0B,SAC1B,EAA0B,KAC3B,GAC6B,CAC9B,IAAM,EAAsB,EAA2B,IAAI,GAAQ,IAAI,EAAK,GAAG,CAAC,KAAK,IAAI,CAEnF,EAAW,8JAIW,EAAS,yBACR,EAAM,KAAK,8BAEnC,EAAsB,8BAA8B,EAAoB,GAAK,IAC9E,4EAGJ,MAAO,CACL,MAAO,CACL,GAAI,EACD,EAAG,IAAK,EAAU,QAAQ,IAAI,EAAS,GAAG,CAC5C,CACF,CACD,aAAc,CAAE,WAAY,IAAI,EAAW,GAAI,CAChD"}
1
+ {"version":3,"file":"index.js","names":["Sequelize"],"sources":["../../../src/utils/helpers/index.ts"],"sourcesContent":["import { 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 = 'SELECT cv.model_id'\n + ' FROM \"custom_field_values\" AS cv'\n + ' INNER JOIN custom_field_definitions AS cd'\n + ' ON cv.custom_field_definition_id = cd.id'\n + ` AND cd.entity_id = '${entityId}'`\n + ` AND cd.model_type = '${model.name}'`\n + ` AND cd.deleted_at IS NULL`\n + (excludedTypesString ? ` AND cd.field_type NOT IN (${excludedTypesString})` : '')\n + ' WHERE cv.deleted_at IS NULL'\n + ' AND CAST(cv.value AS TEXT) ILIKE :searchTerm';\n\n return {\n where: {\n id: {\n [Op.in]: Sequelize.literal(`(${subQuery})`),\n },\n },\n replacements: { searchTerm: `%${searchTerm}%` },\n };\n};\n"],"mappings":"0LA2BA,MAAa,GAAwB,EAAS,IAErC,MAAM,KAAK,CAAE,SAAQ,KAAQ,uDAAW,OAAO,EAAU,GAAkB,CAAC,CAAC,CAAC,KAAK,GAAG,CAGlF,GACX,EACA,EACA,EACA,EAA0D,CACxD,EAA0B,SAC1B,EAA0B,KAC3B,GAC6B,CAC9B,IAAM,EAAsB,EAA2B,IAAI,GAAQ,IAAI,EAAK,GAAG,CAAC,KAAK,IAAI,CAEnF,EAAW,8JAIW,EAAS,yBACR,EAAM,KAAK,8BAEnC,EAAsB,8BAA8B,EAAoB,GAAK,IAC9E,4EAGJ,MAAO,CACL,MAAO,CACL,GAAI,EACD,EAAG,IAAKA,EAAU,QAAQ,IAAI,EAAS,GAAG,CAC5C,CACF,CACD,aAAc,CAAE,WAAY,IAAI,EAAW,GAAI,CAChD"}
@@ -1,2 +1,2 @@
1
- const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`./logger/index.cjs`),n=require(`../models/CustomFieldValue.cjs`),r=require(`../models/CustomFieldDefinition.cjs`),i=require(`../models/CustomValidator.cjs`);require(`../models/index.cjs`);const a=require(`../hooks/enrich.cjs`),o=require(`../hooks/find.cjs`),s=require(`../hooks/hooks.cjs`);require(`../hooks/index.cjs`);const c=require(`../scopes/filter.cjs`);require(`../scopes/index.cjs`);let l=require(`sequelize`),u=require(`@autofleet/common-types`),d=require(`@autofleet/common-types/lib/custom-fields`);const{CUSTOM_FIELDS_FILTER_SCOPE:f}=u.customFields,p=(e,n,r={useCustomFieldsEntries:!1})=>{e.forEach(async({name:e,scopeAttributes:i,modelOptions:c,hasTypeId:u,getRequiredCustomFields:d})=>{try{let f=n(e);if(!f){t.default.warn(`sadot - tried to addHooks to a model that does not exist yet`,{name:e,scopeAttributes:i});return}f.rawAttributes.customFields={type:l.DataTypes.VIRTUAL},f.refreshAttributes();let p={...r,hasTypeId:u??!1,getRequiredCustomFields:d};f.addHook(`beforeFind`,`sadot-beforeFind`,o.beforeFind(i)),f.addHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`,s.beforeBulkCreate),f.addHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`,s.beforeBulkUpdate),f.addHook(`beforeCreate`,`sadot-beforeCreate`,s.beforeCreate(i,c,p)),f.addHook(`beforeUpdate`,`sadot-beforeUpdate`,s.beforeUpdate(i,c,p)),f.addHook(`afterFind`,`sadot-afterFind`,a.default(e,i,`afterFind`,c,p)),f.addHook(`afterUpdate`,`sadot-afterUpdate`,a.default(e,i,void 0,c,p)),f.addHook(`afterCreate`,`sadot-afterCreate`,a.default(e,i,void 0,c,p))}catch(n){t.default.error(`Could not add custom fields hook to model ${e}. `,n)}})},m=(e,n)=>{e.forEach(async({name:e})=>{try{let t=n(e);if(!t)return;t.rawAttributes.customFields&&(delete t.rawAttributes.customFields,t.refreshAttributes()),t.removeHook(`beforeFind`,`sadot-beforeFind`),t.removeHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`),t.removeHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`),t.removeHook(`beforeCreate`,`sadot-beforeCreate`),t.removeHook(`beforeUpdate`,`sadot-beforeUpdate`),t.removeHook(`afterFind`,`sadot-afterFind`),t.removeHook(`afterUpdate`,`sadot-afterUpdate`)}catch(n){t.default.error(`Could not add custom fields hook to model ${e}. `,n)}})},h=(e,t,r)=>{r?.useCustomFieldsEntries||(e.hasMany(n.default,{foreignKey:`modelId`,as:`customFieldValue`}),n.default.belongsTo(e,{foreignKey:`modelId`,as:t}))},g=(e,n,r={useCustomFieldsEntries:!1})=>{e.forEach(async({name:e,scopeAttributes:i})=>{try{let a=n(e);if(!a){t.default.warn(`sadot - tried to addScopes to a model that does not exist yet`,{name:e,scopeAttributes:i});return}h(a,e,r),a.addScope(f,c.customFieldsFilterScope(e,r)),a.addScope(d.CUSTOM_FIELDS_SORT_SCOPE,c.customFieldsSortScope(e,r))}catch(n){t.default.error(`Could not add custom fields scopes to model ${e}. `,n)}})},_=e=>{e.forEach(({modelOptions:e})=>{e?.customAssociation?.(r.default),e?.customAssociation?.(i.default)})};exports.addHooks=p,exports.addScopes=g,exports.applyCustomAssociation=_,exports.removeHooks=m;
1
+ const e=require(`../_virtual/rolldown_runtime.cjs`),t=require(`./logger/index.cjs`),n=require(`../models/CustomFieldValue.cjs`),r=require(`../models/CustomFieldDefinition.cjs`),i=require(`../models/CustomValidator.cjs`),a=require(`./custom-fields-mode.cjs`);require(`../models/index.cjs`);const o=require(`../hooks/enrich.cjs`),s=require(`../hooks/find.cjs`),c=require(`../hooks/hooks.cjs`);require(`../hooks/index.cjs`);const l=require(`../scopes/filter.cjs`);require(`../scopes/index.cjs`);let u=require(`sequelize`),d=require(`@autofleet/common-types`),f=require(`@autofleet/common-types/lib/custom-fields`);const{CUSTOM_FIELDS_FILTER_SCOPE:p}=d.customFields,m=(e,n,r)=>{e.forEach(async({name:e,scopeAttributes:i,modelOptions:a,hasTypeId:l,getRequiredCustomFields:d})=>{try{let f=n(e);if(!f){t.default.warn(`sadot - tried to addHooks to a model that does not exist yet`,{name:e,scopeAttributes:i});return}f.rawAttributes.customFields={type:u.DataTypes.VIRTUAL},f.refreshAttributes();let p={...r,hasTypeId:l??!1,getRequiredCustomFields:d};f.addHook(`beforeFind`,`sadot-beforeFind`,s.beforeFind(i)),f.addHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`,c.beforeBulkCreate),f.addHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`,c.beforeBulkUpdate),f.addHook(`beforeCreate`,`sadot-beforeCreate`,c.beforeCreate(i,a,p)),f.addHook(`beforeUpdate`,`sadot-beforeUpdate`,c.beforeUpdate(i,a,p)),f.addHook(`afterFind`,`sadot-afterFind`,o.default(e,i,`afterFind`,a,p)),f.addHook(`afterUpdate`,`sadot-afterUpdate`,o.default(e,i,void 0,a,p)),f.addHook(`afterCreate`,`sadot-afterCreate`,o.default(e,i,void 0,a,p))}catch(n){t.default.error(`Could not add custom fields hook to model ${e}. `,n)}})},h=(e,n)=>{e.forEach(async({name:e})=>{try{let t=n(e);if(!t)return;t.rawAttributes.customFields&&(delete t.rawAttributes.customFields,t.refreshAttributes()),t.removeHook(`beforeFind`,`sadot-beforeFind`),t.removeHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`),t.removeHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`),t.removeHook(`beforeCreate`,`sadot-beforeCreate`),t.removeHook(`beforeUpdate`,`sadot-beforeUpdate`),t.removeHook(`afterFind`,`sadot-afterFind`),t.removeHook(`afterUpdate`,`sadot-afterUpdate`)}catch(n){t.default.error(`Could not add custom fields hook to model ${e}. `,n)}})},g=(e,t,r)=>{a.readsEntries(r.customFieldsEntriesMode)||(e.hasMany(n.default,{foreignKey:`modelId`,as:`customFieldValue`}),n.default.belongsTo(e,{foreignKey:`modelId`,as:t}))},_=(e,n,r)=>{e.forEach(async({name:e,scopeAttributes:i})=>{try{let a=n(e);if(!a){t.default.warn(`sadot - tried to addScopes to a model that does not exist yet`,{name:e,scopeAttributes:i});return}g(a,e,r),a.addScope(p,l.customFieldsFilterScope(e,r)),a.addScope(f.CUSTOM_FIELDS_SORT_SCOPE,l.customFieldsSortScope(e,r))}catch(n){t.default.error(`Could not add custom fields scopes to model ${e}. `,n)}})},v=e=>{e.forEach(({modelOptions:e})=>{e?.customAssociation?.(r.default),e?.customAssociation?.(i.default)})};exports.addHooks=m,exports.addScopes=_,exports.applyCustomAssociation=v,exports.removeHooks=h;
2
2
  //# sourceMappingURL=init.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.cjs","names":["customFields","DataTypes","beforeFind","beforeBulkCreate","beforeBulkUpdate","beforeCreate","beforeUpdate","enrichResults","CustomFieldValue","customFieldsFilterScope","CUSTOM_FIELDS_SORT_SCOPE","customFieldsSortScope","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["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, hasTypeId, getRequiredCustomFields,\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\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\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, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\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"],"mappings":"6jBAsBA,KAAM,CAAE,8BAA+BA,EAAAA,aAE1B,GACX,EACA,EACA,EAAsD,CAAE,uBAAwB,GAAO,GAC9E,CACT,EAAO,QAAQ,MAAO,CACpB,OAAM,kBAAiB,eAAc,YAAW,6BAC5C,CACJ,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAA,QAAO,KAAK,+DAAgE,CAC1E,OACA,kBACD,CAAC,CACF,OAEF,EAAM,cAAc,aAAe,CACjC,KAAMC,EAAAA,UAAU,QACjB,CACD,EAAM,mBAAmB,CAEzB,IAAM,EAAgB,CACpB,GAAG,EACH,UAAW,GAAa,GACxB,0BACD,CAID,EAAM,QAAQ,aAAc,mBAAoBC,EAAAA,WAAW,EAAgB,CAAC,CAC5E,EAAM,QAAQ,mBAAoB,yBAA0BC,EAAAA,iBAAiB,CAC7E,EAAM,QAAQ,mBAAoB,yBAA0BC,EAAAA,iBAAiB,CAC7E,EAAM,QAAQ,eAAgB,qBAAsBC,EAAAA,aAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,eAAgB,qBAAsBC,EAAAA,aAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,YAAa,kBAAmBC,EAAAA,QAAc,EAAM,EAAiB,YAAa,EAAc,EAAc,CAAC,CAC7H,EAAM,QAAQ,cAAe,oBAAqBA,EAAAA,QAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,CAC/H,EAAM,QAAQ,cAAe,oBAAqBA,EAAAA,QAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,OACxH,EAAG,CACV,EAAA,QAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAGS,GAAe,EAAkB,IAAiC,CAC7E,EAAO,QAAQ,MAAO,CAAE,UAAW,CACjC,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,OACR,EAAM,cAAc,eACtB,OAAO,EAAM,cAAc,aAC3B,EAAM,mBAAmB,EAG3B,EAAM,WAAW,aAAc,mBAAmB,CAClD,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,YAAa,kBAAkB,CAChD,EAAM,WAAW,cAAe,oBAAoB,OAC7C,EAAG,CACV,EAAA,QAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAME,GAAmB,EAAkB,EAAmB,IAAsE,CAC9H,GAAS,yBACb,EAAM,QAAQC,EAAAA,QAAkB,CAAE,WAAY,UAAW,GAAI,mBAAoB,CAAC,CAElF,EAAA,QAAiB,UAAU,EAAO,CAAE,WAAY,UAAW,GAAI,EAAW,CAAC,GAGhE,GAAa,EAAkB,EAAwB,EAA8D,CAAE,uBAAwB,GAAO,GAAW,CAC5K,EAAO,QAAQ,MAAO,CAAE,OAAM,qBAAsB,CAClD,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAA,QAAO,KAAK,gEAAiE,CAC3E,OACA,kBACD,CAAC,CACF,OAGF,EAAgB,EAAO,EAAM,EAAQ,CAErC,EAAM,SAAS,EAA4BC,EAAAA,wBAAwB,EAAM,EAAQ,CAAC,CAClF,EAAM,SAASC,EAAAA,yBAA0BC,EAAAA,sBAAsB,EAAM,EAAQ,CAAC,OACvE,EAAG,CACV,EAAA,QAAO,MAAM,+CAA+C,EAAK,IAAK,EAAE,GAE1E,EAGS,EAA0B,GAA2B,CAChE,EAAO,SAAS,CAAE,kBAAmB,CACnC,GAAc,oBAAoBC,EAAAA,QAAsB,CACxD,GAAc,oBAAoBC,EAAAA,QAAgB,EAClD"}
1
+ {"version":3,"file":"init.cjs","names":["customFields","DataTypes","beforeFind","beforeBulkCreate","beforeBulkUpdate","beforeCreate","beforeUpdate","enrichResults","readsEntries","CustomFieldValue","customFieldsFilterScope","CUSTOM_FIELDS_SORT_SCOPE","customFieldsSortScope","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["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 { ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\nimport { type CustomFieldsEntriesMode, readsEntries } from './custom-fields-mode';\n\n/** The mode is resolved once in `useCustomFields`, so it is always concrete here. */\ninterface SadotScopeOptions {\n customFieldsEntriesMode: CustomFieldsEntriesMode;\n}\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: { customFieldsEntriesMode: CustomFieldsEntriesMode; },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions, hasTypeId, getRequiredCustomFields,\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\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\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, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\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: SadotScopeOptions): void => {\n // Inverted polarity: these associations serve the values read path, so they are\n // skipped only once reads move to entries. 'write-only' still reads values.\n if (readsEntries(options.customFieldsEntriesMode)) 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: SadotScopeOptions): 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"],"mappings":"mmBA4BA,KAAM,CAAE,8BAA+BA,EAAAA,aAE1B,GACX,EACA,EACA,IACS,CACT,EAAO,QAAQ,MAAO,CACpB,OAAM,kBAAiB,eAAc,YAAW,6BAC5C,CACJ,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAA,QAAO,KAAK,+DAAgE,CAC1E,OACA,kBACD,CAAC,CACF,OAEF,EAAM,cAAc,aAAe,CACjC,KAAMC,EAAAA,UAAU,QACjB,CACD,EAAM,mBAAmB,CAEzB,IAAM,EAAgB,CACpB,GAAG,EACH,UAAW,GAAa,GACxB,0BACD,CAID,EAAM,QAAQ,aAAc,mBAAoBC,EAAAA,WAAW,EAAgB,CAAC,CAC5E,EAAM,QAAQ,mBAAoB,yBAA0BC,EAAAA,iBAAiB,CAC7E,EAAM,QAAQ,mBAAoB,yBAA0BC,EAAAA,iBAAiB,CAC7E,EAAM,QAAQ,eAAgB,qBAAsBC,EAAAA,aAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,eAAgB,qBAAsBC,EAAAA,aAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,YAAa,kBAAmBC,EAAAA,QAAc,EAAM,EAAiB,YAAa,EAAc,EAAc,CAAC,CAC7H,EAAM,QAAQ,cAAe,oBAAqBA,EAAAA,QAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,CAC/H,EAAM,QAAQ,cAAe,oBAAqBA,EAAAA,QAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,OACxH,EAAG,CACV,EAAA,QAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAGS,GAAe,EAAkB,IAAiC,CAC7E,EAAO,QAAQ,MAAO,CAAE,UAAW,CACjC,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,OACR,EAAM,cAAc,eACtB,OAAO,EAAM,cAAc,aAC3B,EAAM,mBAAmB,EAG3B,EAAM,WAAW,aAAc,mBAAmB,CAClD,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,YAAa,kBAAkB,CAChD,EAAM,WAAW,cAAe,oBAAoB,OAC7C,EAAG,CACV,EAAA,QAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAME,GAAmB,EAAkB,EAAmB,IAAqC,CAG7FC,EAAAA,aAAa,EAAQ,wBAAwB,GACjD,EAAM,QAAQC,EAAAA,QAAkB,CAAE,WAAY,UAAW,GAAI,mBAAoB,CAAC,CAElF,EAAA,QAAiB,UAAU,EAAO,CAAE,WAAY,UAAW,GAAI,EAAW,CAAC,GAGhE,GAAa,EAAkB,EAAwB,IAAqC,CACvG,EAAO,QAAQ,MAAO,CAAE,OAAM,qBAAsB,CAClD,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAA,QAAO,KAAK,gEAAiE,CAC3E,OACA,kBACD,CAAC,CACF,OAGF,EAAgB,EAAO,EAAM,EAAQ,CAErC,EAAM,SAAS,EAA4BC,EAAAA,wBAAwB,EAAM,EAAQ,CAAC,CAClF,EAAM,SAASC,EAAAA,yBAA0BC,EAAAA,sBAAsB,EAAM,EAAQ,CAAC,OACvE,EAAG,CACV,EAAA,QAAO,MAAM,+CAA+C,EAAK,IAAK,EAAE,GAE1E,EAGS,EAA0B,GAA2B,CAChE,EAAO,SAAS,CAAE,kBAAmB,CACnC,GAAc,oBAAoBC,EAAAA,QAAsB,CACxD,GAAc,oBAAoBC,EAAAA,QAAgB,EAClD"}
@@ -1,2 +1,2 @@
1
- import e from"./logger/index.js";import t from"../models/CustomFieldValue.js";import n from"../models/CustomFieldDefinition.js";import r from"../models/CustomValidator.js";import"../models/index.js";import i from"../hooks/enrich.js";import{beforeFind as a}from"../hooks/find.js";import{beforeBulkCreate as o,beforeBulkUpdate as s,beforeCreate as c,beforeUpdate as l}from"../hooks/hooks.js";import"../hooks/index.js";import{customFieldsFilterScope as u,customFieldsSortScope as d}from"../scopes/filter.js";import"../scopes/index.js";import{DataTypes as f}from"sequelize";import{customFields as p}from"@autofleet/common-types";import{CUSTOM_FIELDS_SORT_SCOPE as m}from"@autofleet/common-types/lib/custom-fields";const{CUSTOM_FIELDS_FILTER_SCOPE:h}=p,g=(t,n,r={useCustomFieldsEntries:!1})=>{t.forEach(async({name:t,scopeAttributes:u,modelOptions:d,hasTypeId:p,getRequiredCustomFields:m})=>{try{let h=n(t);if(!h){e.warn(`sadot - tried to addHooks to a model that does not exist yet`,{name:t,scopeAttributes:u});return}h.rawAttributes.customFields={type:f.VIRTUAL},h.refreshAttributes();let g={...r,hasTypeId:p??!1,getRequiredCustomFields:m};h.addHook(`beforeFind`,`sadot-beforeFind`,a(u)),h.addHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`,o),h.addHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`,s),h.addHook(`beforeCreate`,`sadot-beforeCreate`,c(u,d,g)),h.addHook(`beforeUpdate`,`sadot-beforeUpdate`,l(u,d,g)),h.addHook(`afterFind`,`sadot-afterFind`,i(t,u,`afterFind`,d,g)),h.addHook(`afterUpdate`,`sadot-afterUpdate`,i(t,u,void 0,d,g)),h.addHook(`afterCreate`,`sadot-afterCreate`,i(t,u,void 0,d,g))}catch(n){e.error(`Could not add custom fields hook to model ${t}. `,n)}})},_=(t,n)=>{t.forEach(async({name:t})=>{try{let e=n(t);if(!e)return;e.rawAttributes.customFields&&(delete e.rawAttributes.customFields,e.refreshAttributes()),e.removeHook(`beforeFind`,`sadot-beforeFind`),e.removeHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`),e.removeHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`),e.removeHook(`beforeCreate`,`sadot-beforeCreate`),e.removeHook(`beforeUpdate`,`sadot-beforeUpdate`),e.removeHook(`afterFind`,`sadot-afterFind`),e.removeHook(`afterUpdate`,`sadot-afterUpdate`)}catch(n){e.error(`Could not add custom fields hook to model ${t}. `,n)}})},v=(e,n,r)=>{r?.useCustomFieldsEntries||(e.hasMany(t,{foreignKey:`modelId`,as:`customFieldValue`}),t.belongsTo(e,{foreignKey:`modelId`,as:n}))},y=(t,n,r={useCustomFieldsEntries:!1})=>{t.forEach(async({name:t,scopeAttributes:i})=>{try{let a=n(t);if(!a){e.warn(`sadot - tried to addScopes to a model that does not exist yet`,{name:t,scopeAttributes:i});return}v(a,t,r),a.addScope(h,u(t,r)),a.addScope(m,d(t,r))}catch(n){e.error(`Could not add custom fields scopes to model ${t}. `,n)}})},b=e=>{e.forEach(({modelOptions:e})=>{e?.customAssociation?.(n),e?.customAssociation?.(r)})};export{g as addHooks,y as addScopes,b as applyCustomAssociation,_ as removeHooks};
1
+ import e from"./logger/index.js";import t from"../models/CustomFieldValue.js";import n from"../models/CustomFieldDefinition.js";import r from"../models/CustomValidator.js";import{readsEntries as i}from"./custom-fields-mode.js";import"../models/index.js";import a from"../hooks/enrich.js";import{beforeFind as o}from"../hooks/find.js";import{beforeBulkCreate as s,beforeBulkUpdate as c,beforeCreate as l,beforeUpdate as u}from"../hooks/hooks.js";import"../hooks/index.js";import{customFieldsFilterScope as d,customFieldsSortScope as f}from"../scopes/filter.js";import"../scopes/index.js";import{DataTypes as p}from"sequelize";import{customFields as m}from"@autofleet/common-types";import{CUSTOM_FIELDS_SORT_SCOPE as h}from"@autofleet/common-types/lib/custom-fields";const{CUSTOM_FIELDS_FILTER_SCOPE:g}=m,_=(t,n,r)=>{t.forEach(async({name:t,scopeAttributes:i,modelOptions:d,hasTypeId:f,getRequiredCustomFields:m})=>{try{let h=n(t);if(!h){e.warn(`sadot - tried to addHooks to a model that does not exist yet`,{name:t,scopeAttributes:i});return}h.rawAttributes.customFields={type:p.VIRTUAL},h.refreshAttributes();let g={...r,hasTypeId:f??!1,getRequiredCustomFields:m};h.addHook(`beforeFind`,`sadot-beforeFind`,o(i)),h.addHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`,s),h.addHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`,c),h.addHook(`beforeCreate`,`sadot-beforeCreate`,l(i,d,g)),h.addHook(`beforeUpdate`,`sadot-beforeUpdate`,u(i,d,g)),h.addHook(`afterFind`,`sadot-afterFind`,a(t,i,`afterFind`,d,g)),h.addHook(`afterUpdate`,`sadot-afterUpdate`,a(t,i,void 0,d,g)),h.addHook(`afterCreate`,`sadot-afterCreate`,a(t,i,void 0,d,g))}catch(n){e.error(`Could not add custom fields hook to model ${t}. `,n)}})},v=(t,n)=>{t.forEach(async({name:t})=>{try{let e=n(t);if(!e)return;e.rawAttributes.customFields&&(delete e.rawAttributes.customFields,e.refreshAttributes()),e.removeHook(`beforeFind`,`sadot-beforeFind`),e.removeHook(`beforeBulkCreate`,`sadot-beforeBulkCreate`),e.removeHook(`beforeBulkUpdate`,`sadot-beforeBulkUpdate`),e.removeHook(`beforeCreate`,`sadot-beforeCreate`),e.removeHook(`beforeUpdate`,`sadot-beforeUpdate`),e.removeHook(`afterFind`,`sadot-afterFind`),e.removeHook(`afterUpdate`,`sadot-afterUpdate`)}catch(n){e.error(`Could not add custom fields hook to model ${t}. `,n)}})},y=(e,n,r)=>{i(r.customFieldsEntriesMode)||(e.hasMany(t,{foreignKey:`modelId`,as:`customFieldValue`}),t.belongsTo(e,{foreignKey:`modelId`,as:n}))},b=(t,n,r)=>{t.forEach(async({name:t,scopeAttributes:i})=>{try{let a=n(t);if(!a){e.warn(`sadot - tried to addScopes to a model that does not exist yet`,{name:t,scopeAttributes:i});return}y(a,t,r),a.addScope(g,d(t,r)),a.addScope(h,f(t,r))}catch(n){e.error(`Could not add custom fields scopes to model ${t}. `,n)}})},x=e=>{e.forEach(({modelOptions:e})=>{e?.customAssociation?.(n),e?.customAssociation?.(r)})};export{_ as addHooks,b as addScopes,x as applyCustomAssociation,v as removeHooks};
2
2
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","names":["enrichResults","CustomFieldValue","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["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, hasTypeId, getRequiredCustomFields,\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\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\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, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\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"],"mappings":"ssBAsBA,KAAM,CAAE,8BAA+B,EAE1B,GACX,EACA,EACA,EAAsD,CAAE,uBAAwB,GAAO,GAC9E,CACT,EAAO,QAAQ,MAAO,CACpB,OAAM,kBAAiB,eAAc,YAAW,6BAC5C,CACJ,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,+DAAgE,CAC1E,OACA,kBACD,CAAC,CACF,OAEF,EAAM,cAAc,aAAe,CACjC,KAAM,EAAU,QACjB,CACD,EAAM,mBAAmB,CAEzB,IAAM,EAAgB,CACpB,GAAG,EACH,UAAW,GAAa,GACxB,0BACD,CAID,EAAM,QAAQ,aAAc,mBAAoB,EAAW,EAAgB,CAAC,CAC5E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,YAAa,kBAAmBA,EAAc,EAAM,EAAiB,YAAa,EAAc,EAAc,CAAC,CAC7H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,CAC/H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,OACxH,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAGS,GAAe,EAAkB,IAAiC,CAC7E,EAAO,QAAQ,MAAO,CAAE,UAAW,CACjC,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,OACR,EAAM,cAAc,eACtB,OAAO,EAAM,cAAc,aAC3B,EAAM,mBAAmB,EAG3B,EAAM,WAAW,aAAc,mBAAmB,CAClD,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,YAAa,kBAAkB,CAChD,EAAM,WAAW,cAAe,oBAAoB,OAC7C,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAME,GAAmB,EAAkB,EAAmB,IAAsE,CAC9H,GAAS,yBACb,EAAM,QAAQC,EAAkB,CAAE,WAAY,UAAW,GAAI,mBAAoB,CAAC,CAElF,EAAiB,UAAU,EAAO,CAAE,WAAY,UAAW,GAAI,EAAW,CAAC,GAGhE,GAAa,EAAkB,EAAwB,EAA8D,CAAE,uBAAwB,GAAO,GAAW,CAC5K,EAAO,QAAQ,MAAO,CAAE,OAAM,qBAAsB,CAClD,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,gEAAiE,CAC3E,OACA,kBACD,CAAC,CACF,OAGF,EAAgB,EAAO,EAAM,EAAQ,CAErC,EAAM,SAAS,EAA4B,EAAwB,EAAM,EAAQ,CAAC,CAClF,EAAM,SAAS,EAA0B,EAAsB,EAAM,EAAQ,CAAC,OACvE,EAAG,CACV,EAAO,MAAM,+CAA+C,EAAK,IAAK,EAAE,GAE1E,EAGS,EAA0B,GAA2B,CAChE,EAAO,SAAS,CAAE,kBAAmB,CACnC,GAAc,oBAAoBC,EAAsB,CACxD,GAAc,oBAAoBC,EAAgB,EAClD"}
1
+ {"version":3,"file":"init.js","names":["enrichResults","CustomFieldValue","CustomFieldDefinition","CustomValidator"],"sources":["../../src/utils/init.ts"],"sourcesContent":["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 { ModelFetcher, Models } from '../types';\nimport { customFieldsSortScope } from '../scopes/filter';\nimport { type CustomFieldsEntriesMode, readsEntries } from './custom-fields-mode';\n\n/** The mode is resolved once in `useCustomFields`, so it is always concrete here. */\ninterface SadotScopeOptions {\n customFieldsEntriesMode: CustomFieldsEntriesMode;\n}\n\nconst { CUSTOM_FIELDS_FILTER_SCOPE } = customFields;\n\nexport const addHooks = (\n models: Models[],\n getModel: ModelFetcher,\n sadotOptions: { customFieldsEntriesMode: CustomFieldsEntriesMode; },\n): void => {\n models.forEach(async ({\n name, scopeAttributes, modelOptions, hasTypeId, getRequiredCustomFields,\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\n const enrichOptions = {\n ...sadotOptions,\n hasTypeId: hasTypeId ?? false,\n getRequiredCustomFields,\n };\n\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, enrichOptions));\n model.addHook('beforeUpdate', 'sadot-beforeUpdate', beforeUpdate(scopeAttributes, modelOptions, enrichOptions));\n model.addHook('afterFind', 'sadot-afterFind', enrichResults(name, scopeAttributes, 'afterFind', modelOptions, enrichOptions));\n model.addHook('afterUpdate', 'sadot-afterUpdate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\n model.addHook('afterCreate', 'sadot-afterCreate', enrichResults(name, scopeAttributes, undefined, modelOptions, enrichOptions));\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: SadotScopeOptions): void => {\n // Inverted polarity: these associations serve the values read path, so they are\n // skipped only once reads move to entries. 'write-only' still reads values.\n if (readsEntries(options.customFieldsEntriesMode)) 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: SadotScopeOptions): 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"],"mappings":"6vBA4BA,KAAM,CAAE,8BAA+B,EAE1B,GACX,EACA,EACA,IACS,CACT,EAAO,QAAQ,MAAO,CACpB,OAAM,kBAAiB,eAAc,YAAW,6BAC5C,CACJ,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,+DAAgE,CAC1E,OACA,kBACD,CAAC,CACF,OAEF,EAAM,cAAc,aAAe,CACjC,KAAM,EAAU,QACjB,CACD,EAAM,mBAAmB,CAEzB,IAAM,EAAgB,CACpB,GAAG,EACH,UAAW,GAAa,GACxB,0BACD,CAID,EAAM,QAAQ,aAAc,mBAAoB,EAAW,EAAgB,CAAC,CAC5E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,mBAAoB,yBAA0B,EAAiB,CAC7E,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,eAAgB,qBAAsB,EAAa,EAAiB,EAAc,EAAc,CAAC,CAC/G,EAAM,QAAQ,YAAa,kBAAmBA,EAAc,EAAM,EAAiB,YAAa,EAAc,EAAc,CAAC,CAC7H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,CAC/H,EAAM,QAAQ,cAAe,oBAAqBA,EAAc,EAAM,EAAiB,IAAA,GAAW,EAAc,EAAc,CAAC,OACxH,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAGS,GAAe,EAAkB,IAAiC,CAC7E,EAAO,QAAQ,MAAO,CAAE,UAAW,CACjC,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,OACR,EAAM,cAAc,eACtB,OAAO,EAAM,cAAc,aAC3B,EAAM,mBAAmB,EAG3B,EAAM,WAAW,aAAc,mBAAmB,CAClD,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,mBAAoB,yBAAyB,CAC9D,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,eAAgB,qBAAqB,CACtD,EAAM,WAAW,YAAa,kBAAkB,CAChD,EAAM,WAAW,cAAe,oBAAoB,OAC7C,EAAG,CACV,EAAO,MAAM,6CAA6C,EAAK,IAAK,EAAE,GAExE,EAME,GAAmB,EAAkB,EAAmB,IAAqC,CAG7F,EAAa,EAAQ,wBAAwB,GACjD,EAAM,QAAQC,EAAkB,CAAE,WAAY,UAAW,GAAI,mBAAoB,CAAC,CAElF,EAAiB,UAAU,EAAO,CAAE,WAAY,UAAW,GAAI,EAAW,CAAC,GAGhE,GAAa,EAAkB,EAAwB,IAAqC,CACvG,EAAO,QAAQ,MAAO,CAAE,OAAM,qBAAsB,CAClD,GAAI,CACF,IAAM,EAAQ,EAAS,EAAK,CAC5B,GAAI,CAAC,EAAO,CACV,EAAO,KAAK,gEAAiE,CAC3E,OACA,kBACD,CAAC,CACF,OAGF,EAAgB,EAAO,EAAM,EAAQ,CAErC,EAAM,SAAS,EAA4B,EAAwB,EAAM,EAAQ,CAAC,CAClF,EAAM,SAAS,EAA0B,EAAsB,EAAM,EAAQ,CAAC,OACvE,EAAG,CACV,EAAO,MAAM,+CAA+C,EAAK,IAAK,EAAE,GAE1E,EAGS,EAA0B,GAA2B,CAChE,EAAO,SAAS,CAAE,kBAAmB,CACnC,GAAc,oBAAoBC,EAAsB,CACxD,GAAc,oBAAoBC,EAAgB,EAClD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autofleet/sadot",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,10 +53,10 @@
53
53
  "express": "^4.21.2",
54
54
  "npm-watch": "^0.11.0",
55
55
  "supertest": "^7.0.0",
56
- "@autofleet/logger": "^4.7.8",
57
- "@autofleet/zehut": "^4.15.1",
58
56
  "@autofleet/errors": "^3.3.15",
59
- "@autofleet/node-common": "^4.4.3"
57
+ "@autofleet/node-common": "^4.4.3",
58
+ "@autofleet/zehut": "^4.15.1",
59
+ "@autofleet/logger": "^4.7.8"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@autofleet/errors": "^3",