@autofleet/sequelize-utils 6.0.0 → 6.0.2

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.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=s(require(`@autofleet/events`)),l=s(require(`@autofleet/logger`)),u=s(require(`sequelize`)),d=s(require(`debug`));var f=(0,l.default)(),p=new c.default({logger:f});const m=async(e,t)=>{t.transaction?t.transaction.afterCommit(()=>e()):await e()};var h=m;const g=e=>e instanceof Date||Object.prototype.toString.call(e)===`[object Date]`,_=e=>{let t={...e};return Object.entries(t).filter(([,e])=>g(e)).forEach(([e,n])=>{t[e]=n.getTime()/1e3}),t},v=(e,t)=>{let n=(e,n=!1)=>{try{let r=e.get();n&&Object.assign(r,{deletedAt:new Date});let i=t[e.constructor.name]?.tableName,a=`1`,o=_(r);if(!i)return;p.sendObject(i,a,o,Object.keys(e.rawAttributes)).catch(e=>{f.error(`sendObject error`,{tableName:i,eventVersion:a,e})})}catch(e){f.error(`dimTables error`,{e})}};e.addHook(`afterSave`,(e,t)=>h(()=>n(e),t)),e.addHook(`afterDestroy`,(e,t)=>h(()=>n(e,!0),t))};var y=v;const b=(0,d.default)(`sequelize-utils`),x=async(e,t,n=2,r={})=>{if(typeof t!=`function`)throw Error(`funcToRun must be a function`);if(typeof n!=`number`)throw Error(`if defined, retriesCount must be a number`);if(n<0)throw Error(`retriesCount must be a positive number`);try{let n=await e.transaction(r,async e=>{let n=await t(e);return n});return n}catch(i){if((i instanceof u.DatabaseError||i?.constructor?.name===`DatabaseError`)&&--n>=0)return b(`error inside transactionWithRetry - will retry times ${n}`,i),x(e,t,n,r);throw n===-1&&b(`error inside transactionWithRetry - will stop retry`,i),i}},S=`rollback has been called on this transaction`,C=`Transaction cancelled due to request cancellation`,w=(e,t,n,r)=>{let i=!1;if(t.socket.destroyed)throw b(C),Error(C);return e.transaction(async e=>{let a=async()=>{b(C),!i&&(i=!0,await e.rollback())},o=async()=>{let t=!n.writableFinished;if(t){if(b(C),i)return;i=!0,await e.rollback()}};t.socket.once(`close`,a),n.once(`close`,o);let s=()=>{t.socket.removeListener(`close`,a),n.removeListener(`close`,o)};try{let t=await r(e);return s(),t}catch(e){throw s(),e.message.includes(S)?Error(C):e}})};var T=e=>{let t=(t,n,r)=>x(e,t,n,r),n=(t,n,r)=>w(e,t,n,r),r=t=>y(e,t),i=(e,n)=>e?n(e):t(n,0);return{httpBasedTransaction:n,transactionWithRetry:t,registerModelEventHooks:r,runAfterTransactionCommits:h,useOrCreateTransaction:i}};module.exports=T;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["Events","cb: () => unknown","options: Transactionable","input: unknown","obj: object","sequelize: Sequelize","modelTableMapping: ModelMapping","object: Model","events","logger","sequelize","runAfterTransactionCommits","sequelize: Sequelize","funcToRun: (transaction: Transaction) => Promise<T>","options: TransactionOptions","sequelize","DatabaseError","sequelize: Sequelize","req: IncomingMessage","res: ServerResponse","cb: (transaction: Transaction) => Promise<T>","sequelize","transaction: Transaction","sequelize: Sequelize","transactionWithRetry","funcToRun: (transaction: Transaction) => Promise<T>","retriesCount?: number","options?: TransactionOptions","_transactionWithRetry","sequelize","httpBasedTransaction","req: IncomingMessage","res: ServerResponse","cb: (transaction: Transaction) => Promise<T>","_httpBasedTransaction","modelTableMapping: ModelMapping","addModelEventHooks","transaction: Transaction","cb: (t: Transaction) => Promise<T>"],"sources":["../src/logger.ts","../src/events/index.ts","../src/runAfterTransactionCommits.ts","../src/model-event-hooks.ts","../src/common.ts","../src/transaction-with-retry.ts","../src/http-based-transaction.ts","../src/index.ts"],"sourcesContent":["import Logger from '@autofleet/logger';\n\nexport default Logger();\n","import Events from '@autofleet/events';\nimport logger from '../logger';\n\nexport default new Events({ logger });\n","import { Transactionable } from 'sequelize';\n\nconst runAfterTransactionCommits = async (cb: () => unknown, options: Transactionable): Promise<void> => {\n if (options.transaction) {\n options.transaction.afterCommit(() => cb());\n } else {\n await cb();\n }\n};\nexport default runAfterTransactionCommits;\n","import type { Model, Sequelize } from 'sequelize';\nimport events from './events';\nimport logger from './logger';\nimport runAfterTransactionCommits from './runAfterTransactionCommits';\n\nexport interface ModelMapping {\n [ModelName: string]: {\n tableName: string\n };\n}\nconst isDate = (input: unknown): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n// eslint-disable-next-line @typescript-eslint/ban-types\nconst formatDatesInObject = (obj: object) => {\n const newObj = { ...obj };\n Object.entries(newObj).filter(([, value]) => isDate(value)).forEach(([key, value]) => {\n newObj[key] = (value as Date).getTime() / 1000;\n });\n return newObj;\n};\n\nconst addModelEventHooks = (sequelize: Sequelize, modelTableMapping: ModelMapping): void => {\n const updateEventToDimTable = (object: Model, isDelete = false) => {\n try {\n const objectToSend = object.get();\n if (isDelete) {\n Object.assign(objectToSend, { deletedAt: new Date() });\n }\n const tableName = modelTableMapping[object.constructor.name]?.tableName;\n const eventVersion = '1';\n const objectToSendFormatted = formatDatesInObject(objectToSend);\n if (!tableName) {\n return;\n }\n events.sendObject(\n tableName,\n eventVersion,\n objectToSendFormatted,\n // @ts-expect-error the rawAttributes is typed as static, while it actually is on the instance level.\n Object.keys(object.rawAttributes),\n ).catch((e) => {\n logger.error('sendObject error', { tableName, eventVersion, e });\n });\n } catch (e) {\n logger.error('dimTables error', { e });\n }\n };\n\n sequelize.addHook('afterSave', (savedObject, options) => runAfterTransactionCommits(() => updateEventToDimTable(savedObject), options));\n sequelize.addHook('afterDestroy', (savedObject, options) => runAfterTransactionCommits(() => updateEventToDimTable(savedObject, true), options));\n};\n\nexport default addModelEventHooks;\n","import debug from 'debug';\n\nexport const debugLog = debug('sequelize-utils');\n","import {\n DatabaseError, type Sequelize, type Transaction, type TransactionOptions,\n} from 'sequelize';\nimport { debugLog } from './common';\n\nexport const transactionWithRetry = async <T>(sequelize: Sequelize, funcToRun: (transaction: Transaction) => Promise<T>, retriesCount = 2, options: TransactionOptions = {}): Promise<T> => {\n if (typeof funcToRun !== 'function') {\n throw new Error('funcToRun must be a function');\n }\n if (typeof retriesCount !== 'number') {\n throw new Error('if defined, retriesCount must be a number');\n }\n if (retriesCount < 0) {\n throw new Error('retriesCount must be a positive number');\n }\n try {\n const transValue = await sequelize.transaction(options, async (transaction) => {\n const funcValue = await funcToRun(transaction);\n return funcValue;\n });\n return transValue;\n } catch (e) {\n if ((e instanceof DatabaseError || e?.constructor?.name === 'DatabaseError') && --retriesCount >= 0) {\n debugLog(`error inside transactionWithRetry - will retry times ${retriesCount}`, e);\n return transactionWithRetry(sequelize, funcToRun, retriesCount, options);\n }\n if (retriesCount === -1) {\n debugLog('error inside transactionWithRetry - will stop retry', e);\n }\n throw e;\n }\n};\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Sequelize, Transaction } from 'sequelize';\nimport { debugLog } from './common';\n\nconst rollbackErrorText = 'rollback has been called on this transaction';\nconst abortErrorText = 'Transaction cancelled due to request cancellation';\n\nexport const httpBasedTransaction = <T>(sequelize: Sequelize, req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>): Promise<T> => {\n let aborted = false;\n if (req.socket.destroyed) {\n debugLog(abortErrorText);\n throw new Error(abortErrorText);\n }\n return sequelize.transaction(async (transaction: Transaction) => {\n // https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/test/parallel/test-http-aborted.js#L9\n\n // 2023-04-13: Node.js 16.0.0\n // Added also the `res.writableFinished` check, because it seems that the socket is not destroyed when the request is aborted, but the response is not finished.\n // https://github.com/Jimbly/http-proxy-node16/commit/ba0c414cd03799e357c5d867c11dea06a9c34ec8#diff-b2d1e3b7c5f3b424a0af7971c582c822fd25a5ea279040ef6dc93fc4b2cf619dR151\n\n const rollback = async () => {\n debugLog(abortErrorText);\n if (aborted) return;\n aborted = true;\n await transaction.rollback();\n };\n const resRollback = async () => {\n const didNotFinishWrite = !res.writableFinished;\n if (didNotFinishWrite) {\n debugLog(abortErrorText);\n if (aborted) return;\n aborted = true;\n await transaction.rollback();\n }\n };\n req.socket.once('close', rollback);\n res.once('close', resRollback);\n\n const removeListeners = () => {\n req.socket.removeListener('close', rollback);\n res.removeListener('close', resRollback);\n };\n\n try {\n const response = await cb(transaction);\n removeListeners();\n return response;\n } catch (e) {\n removeListeners();\n if (e.message.includes(rollbackErrorText)) {\n throw new Error(abortErrorText);\n }\n throw e;\n }\n });\n};\n","/* eslint-disable import/prefer-default-export */\nimport type {\n Sequelize,\n Transaction,\n TransactionOptions,\n} from 'sequelize';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport addModelEventHooks, { ModelMapping } from './model-event-hooks';\nimport { transactionWithRetry as _transactionWithRetry } from './transaction-with-retry';\nimport { httpBasedTransaction as _httpBasedTransaction } from './http-based-transaction';\nimport runAfterTransactionCommits from './runAfterTransactionCommits';\n\ntype ArgsWithoutSequelize<T> = T extends (arg1: Sequelize, ...args: infer U) => unknown ? U : never;\n\nexport default (sequelize: Sequelize): {\n transactionWithRetry: <T>(...args: ArgsWithoutSequelize<typeof _transactionWithRetry<T>>) => Promise<T>;\n httpBasedTransaction: <T>(...args: ArgsWithoutSequelize<typeof _httpBasedTransaction<T>>) => Promise<T>;\n registerModelEventHooks: (...args: ArgsWithoutSequelize<typeof addModelEventHooks>) => void;\n runAfterTransactionCommits: typeof runAfterTransactionCommits;\n useOrCreateTransaction: <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => Promise<T>;\n} => {\n const transactionWithRetry = <T>(funcToRun: (transaction: Transaction) => Promise<T>, retriesCount?: number, options?: TransactionOptions): Promise<T> => _transactionWithRetry(sequelize, funcToRun, retriesCount, options);\n const httpBasedTransaction = <T>(req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>): Promise<T> => _httpBasedTransaction(sequelize, req, res, cb);\n const registerModelEventHooks = (modelTableMapping: ModelMapping) => addModelEventHooks(sequelize, modelTableMapping);\n const useOrCreateTransaction = <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => {\n if (transaction) {\n return cb(transaction);\n }\n return transactionWithRetry(cb, 0);\n };\n\n return {\n httpBasedTransaction,\n transactionWithRetry,\n registerModelEventHooks,\n runAfterTransactionCommits,\n useOrCreateTransaction,\n };\n};\n"],"mappings":"wlBAEA,IAAA,GAAA,EAAA,EAAA,UAAuB,CCCvB,EAAe,IAAIA,EAAAA,QAAO,CAAE,OAAA,CAAQ,GCDpC,MAAM,EAA6B,MAAOC,EAAmBC,IAA4C,CACnG,EAAQ,YACV,EAAQ,YAAY,YAAY,IAAM,GAAI,CAAC,CAE3C,MAAM,GAAI,AAEb,EACD,IAAA,EAAe,ECCf,MAAM,EAAS,AAACC,GAAkC,aAAiB,MAAQ,OAAO,UAAU,SAAS,KAAK,EAAM,GAAK,gBAE/G,EAAsB,AAACC,GAAgB,CAC3C,IAAM,EAAS,CAAE,GAAG,CAAK,EAIzB,OAHA,OAAO,QAAQ,EAAO,CAAC,OAAO,CAAC,EAAG,EAAM,GAAK,EAAO,EAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAK,EAAM,GAAK,CACpF,EAAO,GAAQ,EAAe,SAAS,CAAG,GAC3C,EAAC,CACK,CACR,EAEK,EAAqB,CAACmB,EAAsBY,IAA0C,CAC1F,IAAM,EAAwB,CAAC5B,EAAe,EAAW,KAAU,CACjE,GAAI,CACF,IAAM,EAAe,EAAO,KAAK,CAC7B,GACF,OAAO,OAAO,EAAc,CAAE,UAAW,IAAI,IAAQ,EAAC,CAExD,IAAM,EAAY,EAAkB,EAAO,YAAY,OAAO,UACxD,EAAe,IACf,EAAwB,EAAoB,EAAa,CAC/D,GAAI,CAAC,EACH,OAEFC,EAAO,WACL,EACA,EACA,EAEA,OAAO,KAAK,EAAO,cAAc,CAClC,CAAC,MAAM,AAAC,GAAM,CACbC,EAAO,MAAM,mBAAoB,CAAE,YAAW,eAAc,CAAG,EAAC,AACjE,EAAC,AACH,OAAQ,EAAG,CACVA,EAAO,MAAM,kBAAmB,CAAE,CAAG,EAAC,AACvC,CACF,EAEDoB,EAAU,QAAQ,YAAa,CAAC,EAAa,IAAYlB,EAA2B,IAAM,EAAsB,EAAY,CAAE,EAAQ,CAAC,CACvIkB,EAAU,QAAQ,eAAgB,CAAC,EAAa,IAAYlB,EAA2B,IAAM,EAAsB,EAAa,GAAK,CAAE,EAAQ,CAAC,AACjJ,EAED,IAAA,EAAe,ECjDf,MAAa,GAAA,EAAA,EAAA,SAAiB,kBAAkB,CCGnC,EAAuB,MAAUY,EAAsBE,EAAqD,EAAe,EAAGX,EAA8B,CAAE,IAAiB,CAC1L,GAAI,OAAO,GAAc,WACvB,MAAU,MAAM,+BAAA,CAElB,GAAI,OAAO,GAAiB,SAC1B,MAAU,MAAM,4CAAA,CAElB,GAAI,EAAe,EACjB,MAAU,MAAM,yCAAA,CAElB,GAAI,CACF,IAAM,EAAa,MAAMe,EAAU,YAAY,EAAS,MAAO,GAAgB,CAC7E,IAAM,EAAY,MAAM,EAAU,EAAY,CAC9C,OAAO,CACR,EAAC,CACF,OAAO,CACR,OAAQ,EAAG,CACV,IAAK,aAAab,EAAAA,eAAiB,GAAG,aAAa,OAAS,kBAAoB,EAAE,GAAgB,EAEhG,OADA,EAAS,CAAC,qDAAqD,EAAE,GAAc,CAAE,EAAE,CAC5E,EAAqBa,EAAW,EAAW,EAAc,EAAQ,CAK1E,MAHI,IAAiB,IACnB,EAAS,sDAAuD,EAAE,CAE9D,CACP,CACF,EC3BK,EAAoB,+CACpB,EAAiB,oDAEV,EAAuB,CAAIN,EAAsBQ,EAAsBC,EAAqBC,IAA6D,CACpK,IAAI,EAAU,GACd,GAAI,EAAI,OAAO,UAEb,MADA,EAAS,EAAe,CACd,MAAM,EAAA,CAElB,OAAOJ,EAAU,YAAY,MAAOQ,GAA6B,CAO/D,IAAM,EAAW,SAAY,CAC3B,EAAS,EAAe,CACpB,KACJ,EAAU,GACV,MAAM,EAAY,UAAU,CAC7B,EACK,EAAc,SAAY,CAC9B,IAAM,EAAoB,CAAC,EAAI,iBAC/B,GAAI,EAAmB,CAErB,GADA,EAAS,EAAe,CACpB,EAAS,OACb,EAAU,GACV,MAAM,EAAY,UAAU,AAC7B,CACF,EACD,EAAI,OAAO,KAAK,QAAS,EAAS,CAClC,EAAI,KAAK,QAAS,EAAY,CAE9B,IAAM,EAAkB,IAAM,CAC5B,EAAI,OAAO,eAAe,QAAS,EAAS,CAC5C,EAAI,eAAe,QAAS,EAAY,AACzC,EAED,GAAI,CACF,IAAM,EAAW,MAAM,EAAG,EAAY,CAEtC,OADA,GAAiB,CACV,CACR,OAAQ,EAAG,CAKV,MAJA,GAAiB,CACb,EAAE,QAAQ,SAAS,EAAkB,CAC7B,MAAM,EAAA,CAEZ,CACP,CACF,EAAC,AACH,ECzCD,IAAA,EAAe,AAACd,GAMX,CACH,IAAMC,EAAuB,CAAIC,EAAqDC,EAAuBC,IAA6CC,EAAsBC,EAAW,EAAW,EAAc,EAAQ,CACtNC,EAAuB,CAAIC,EAAsBC,EAAqBC,IAA6DC,EAAsBL,EAAW,EAAK,EAAK,EAAG,CACjL,EAA0B,AAACM,GAAoCC,EAAmBP,EAAW,EAAkB,CAC/G,EAAyB,CAAIQ,EAA0BC,IACvD,EACK,EAAG,EAAY,CAEjBd,EAAqB,EAAI,EAAE,CAGpC,MAAO,CACL,qBAAA,EACA,qBAAA,EACA,0BACA,2BAAA,EACA,wBACD,CACF"}
@@ -0,0 +1,32 @@
1
+ import { Sequelize, Transaction, TransactionOptions, Transactionable } from "sequelize";
2
+ import { IncomingMessage, ServerResponse } from "node:http";
3
+
4
+ //#region src/model-event-hooks.d.ts
5
+ interface ModelMapping {
6
+ [ModelName: string]: {
7
+ tableName: string;
8
+ };
9
+ }
10
+ declare const addModelEventHooks: (sequelize: Sequelize, modelTableMapping: ModelMapping) => void;
11
+ //#endregion
12
+ //#region src/transaction-with-retry.d.ts
13
+ declare const transactionWithRetry: <T>(sequelize: Sequelize, funcToRun: (transaction: Transaction) => Promise<T>, retriesCount?: number, options?: TransactionOptions) => Promise<T>;
14
+ //#endregion
15
+ //#region src/http-based-transaction.d.ts
16
+ declare const httpBasedTransaction: <T>(sequelize: Sequelize, req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>) => Promise<T>;
17
+ //#endregion
18
+ //#region src/runAfterTransactionCommits.d.ts
19
+ declare const runAfterTransactionCommits: (cb: () => unknown, options: Transactionable) => Promise<void>;
20
+ //#endregion
21
+ //#region src/index.d.ts
22
+ type ArgsWithoutSequelize<T> = T extends ((arg1: Sequelize, ...args: infer U) => unknown) ? U : never;
23
+ declare const _default: (sequelize: Sequelize) => {
24
+ transactionWithRetry: <T>(...args: ArgsWithoutSequelize<typeof transactionWithRetry<T>>) => Promise<T>;
25
+ httpBasedTransaction: <T>(...args: ArgsWithoutSequelize<typeof httpBasedTransaction<T>>) => Promise<T>;
26
+ registerModelEventHooks: (...args: ArgsWithoutSequelize<typeof addModelEventHooks>) => void;
27
+ runAfterTransactionCommits: typeof runAfterTransactionCommits;
28
+ useOrCreateTransaction: <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => Promise<T>;
29
+ };
30
+ //#endregion
31
+ export { _default as default };
32
+ //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,14 +1,32 @@
1
- import type { Sequelize, Transaction } from 'sequelize';
2
- import addModelEventHooks from './model-event-hooks';
3
- import { transactionWithRetry as _transactionWithRetry } from './transaction-with-retry';
4
- import { httpBasedTransaction as _httpBasedTransaction } from './http-based-transaction';
5
- import runAfterTransactionCommits from './runAfterTransactionCommits';
6
- type ArgsWithoutSequelize<T> = T extends (arg1: Sequelize, ...args: infer U) => unknown ? U : never;
1
+ import { Sequelize, Transaction, TransactionOptions, Transactionable } from "sequelize";
2
+ import { IncomingMessage, ServerResponse } from "node:http";
3
+
4
+ //#region src/model-event-hooks.d.ts
5
+ interface ModelMapping {
6
+ [ModelName: string]: {
7
+ tableName: string;
8
+ };
9
+ }
10
+ declare const addModelEventHooks: (sequelize: Sequelize, modelTableMapping: ModelMapping) => void;
11
+ //#endregion
12
+ //#region src/transaction-with-retry.d.ts
13
+ declare const transactionWithRetry: <T>(sequelize: Sequelize, funcToRun: (transaction: Transaction) => Promise<T>, retriesCount?: number, options?: TransactionOptions) => Promise<T>;
14
+ //#endregion
15
+ //#region src/http-based-transaction.d.ts
16
+ declare const httpBasedTransaction: <T>(sequelize: Sequelize, req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>) => Promise<T>;
17
+ //#endregion
18
+ //#region src/runAfterTransactionCommits.d.ts
19
+ declare const runAfterTransactionCommits: (cb: () => unknown, options: Transactionable) => Promise<void>;
20
+ //#endregion
21
+ //#region src/index.d.ts
22
+ type ArgsWithoutSequelize<T> = T extends ((arg1: Sequelize, ...args: infer U) => unknown) ? U : never;
7
23
  declare const _default: (sequelize: Sequelize) => {
8
- transactionWithRetry: <T>(...args: ArgsWithoutSequelize<typeof _transactionWithRetry<T>>) => Promise<T>;
9
- httpBasedTransaction: <T>(...args: ArgsWithoutSequelize<typeof _httpBasedTransaction<T>>) => Promise<T>;
10
- registerModelEventHooks: (...args: ArgsWithoutSequelize<typeof addModelEventHooks>) => void;
11
- runAfterTransactionCommits: typeof runAfterTransactionCommits;
12
- useOrCreateTransaction: <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => Promise<T>;
24
+ transactionWithRetry: <T>(...args: ArgsWithoutSequelize<typeof transactionWithRetry<T>>) => Promise<T>;
25
+ httpBasedTransaction: <T>(...args: ArgsWithoutSequelize<typeof httpBasedTransaction<T>>) => Promise<T>;
26
+ registerModelEventHooks: (...args: ArgsWithoutSequelize<typeof addModelEventHooks>) => void;
27
+ runAfterTransactionCommits: typeof runAfterTransactionCommits;
28
+ useOrCreateTransaction: <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => Promise<T>;
13
29
  };
14
- export default _default;
30
+ //#endregion
31
+ export { _default as default };
32
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,27 +1,2 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const model_event_hooks_1 = __importDefault(require("./model-event-hooks"));
7
- const transaction_with_retry_1 = require("./transaction-with-retry");
8
- const http_based_transaction_1 = require("./http-based-transaction");
9
- const runAfterTransactionCommits_1 = __importDefault(require("./runAfterTransactionCommits"));
10
- exports.default = (sequelize) => {
11
- const transactionWithRetry = (funcToRun, retriesCount, options) => (0, transaction_with_retry_1.transactionWithRetry)(sequelize, funcToRun, retriesCount, options);
12
- const httpBasedTransaction = (req, res, cb) => (0, http_based_transaction_1.httpBasedTransaction)(sequelize, req, res, cb);
13
- const registerModelEventHooks = (modelTableMapping) => (0, model_event_hooks_1.default)(sequelize, modelTableMapping);
14
- const useOrCreateTransaction = (transaction, cb) => {
15
- if (transaction) {
16
- return cb(transaction);
17
- }
18
- return transactionWithRetry(cb, 0);
19
- };
20
- return {
21
- httpBasedTransaction,
22
- transactionWithRetry,
23
- registerModelEventHooks,
24
- runAfterTransactionCommits: runAfterTransactionCommits_1.default,
25
- useOrCreateTransaction,
26
- };
27
- };
1
+ import e from"@autofleet/events";import t from"@autofleet/logger";import{DatabaseError as n}from"sequelize";import r from"debug";var i=t(),a=new e({logger:i});const o=async(e,t)=>{t.transaction?t.transaction.afterCommit(()=>e()):await e()};var s=o;const c=e=>e instanceof Date||Object.prototype.toString.call(e)===`[object Date]`,l=e=>{let t={...e};return Object.entries(t).filter(([,e])=>c(e)).forEach(([e,n])=>{t[e]=n.getTime()/1e3}),t},u=(e,t)=>{let n=(e,n=!1)=>{try{let r=e.get();n&&Object.assign(r,{deletedAt:new Date});let o=t[e.constructor.name]?.tableName,s=`1`,c=l(r);if(!o)return;a.sendObject(o,s,c,Object.keys(e.rawAttributes)).catch(e=>{i.error(`sendObject error`,{tableName:o,eventVersion:s,e})})}catch(e){i.error(`dimTables error`,{e})}};e.addHook(`afterSave`,(e,t)=>s(()=>n(e),t)),e.addHook(`afterDestroy`,(e,t)=>s(()=>n(e,!0),t))};var d=u;const f=r(`sequelize-utils`),p=async(e,t,r=2,i={})=>{if(typeof t!=`function`)throw Error(`funcToRun must be a function`);if(typeof r!=`number`)throw Error(`if defined, retriesCount must be a number`);if(r<0)throw Error(`retriesCount must be a positive number`);try{let n=await e.transaction(i,async e=>{let n=await t(e);return n});return n}catch(a){if((a instanceof n||a?.constructor?.name===`DatabaseError`)&&--r>=0)return f(`error inside transactionWithRetry - will retry times ${r}`,a),p(e,t,r,i);throw r===-1&&f(`error inside transactionWithRetry - will stop retry`,a),a}},m=`rollback has been called on this transaction`,h=`Transaction cancelled due to request cancellation`,g=(e,t,n,r)=>{let i=!1;if(t.socket.destroyed)throw f(h),Error(h);return e.transaction(async e=>{let a=async()=>{f(h),!i&&(i=!0,await e.rollback())},o=async()=>{let t=!n.writableFinished;if(t){if(f(h),i)return;i=!0,await e.rollback()}};t.socket.once(`close`,a),n.once(`close`,o);let s=()=>{t.socket.removeListener(`close`,a),n.removeListener(`close`,o)};try{let t=await r(e);return s(),t}catch(e){throw s(),e.message.includes(m)?Error(h):e}})};var _=e=>{let t=(t,n,r)=>p(e,t,n,r),n=(t,n,r)=>g(e,t,n,r),r=t=>d(e,t),i=(e,n)=>e?n(e):t(n,0);return{httpBasedTransaction:n,transactionWithRetry:t,registerModelEventHooks:r,runAfterTransactionCommits:s,useOrCreateTransaction:i}};export{_ as default};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["cb: () => unknown","options: Transactionable","input: unknown","obj: object","sequelize: Sequelize","modelTableMapping: ModelMapping","object: Model","events","logger","runAfterTransactionCommits","sequelize: Sequelize","funcToRun: (transaction: Transaction) => Promise<T>","options: TransactionOptions","sequelize: Sequelize","req: IncomingMessage","res: ServerResponse","cb: (transaction: Transaction) => Promise<T>","transaction: Transaction","sequelize: Sequelize","transactionWithRetry","funcToRun: (transaction: Transaction) => Promise<T>","retriesCount?: number","options?: TransactionOptions","_transactionWithRetry","httpBasedTransaction","req: IncomingMessage","res: ServerResponse","cb: (transaction: Transaction) => Promise<T>","_httpBasedTransaction","modelTableMapping: ModelMapping","addModelEventHooks","transaction: Transaction","cb: (t: Transaction) => Promise<T>"],"sources":["../src/logger.ts","../src/events/index.ts","../src/runAfterTransactionCommits.ts","../src/model-event-hooks.ts","../src/common.ts","../src/transaction-with-retry.ts","../src/http-based-transaction.ts","../src/index.ts"],"sourcesContent":["import Logger from '@autofleet/logger';\n\nexport default Logger();\n","import Events from '@autofleet/events';\nimport logger from '../logger';\n\nexport default new Events({ logger });\n","import { Transactionable } from 'sequelize';\n\nconst runAfterTransactionCommits = async (cb: () => unknown, options: Transactionable): Promise<void> => {\n if (options.transaction) {\n options.transaction.afterCommit(() => cb());\n } else {\n await cb();\n }\n};\nexport default runAfterTransactionCommits;\n","import type { Model, Sequelize } from 'sequelize';\nimport events from './events';\nimport logger from './logger';\nimport runAfterTransactionCommits from './runAfterTransactionCommits';\n\nexport interface ModelMapping {\n [ModelName: string]: {\n tableName: string\n };\n}\nconst isDate = (input: unknown): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n// eslint-disable-next-line @typescript-eslint/ban-types\nconst formatDatesInObject = (obj: object) => {\n const newObj = { ...obj };\n Object.entries(newObj).filter(([, value]) => isDate(value)).forEach(([key, value]) => {\n newObj[key] = (value as Date).getTime() / 1000;\n });\n return newObj;\n};\n\nconst addModelEventHooks = (sequelize: Sequelize, modelTableMapping: ModelMapping): void => {\n const updateEventToDimTable = (object: Model, isDelete = false) => {\n try {\n const objectToSend = object.get();\n if (isDelete) {\n Object.assign(objectToSend, { deletedAt: new Date() });\n }\n const tableName = modelTableMapping[object.constructor.name]?.tableName;\n const eventVersion = '1';\n const objectToSendFormatted = formatDatesInObject(objectToSend);\n if (!tableName) {\n return;\n }\n events.sendObject(\n tableName,\n eventVersion,\n objectToSendFormatted,\n // @ts-expect-error the rawAttributes is typed as static, while it actually is on the instance level.\n Object.keys(object.rawAttributes),\n ).catch((e) => {\n logger.error('sendObject error', { tableName, eventVersion, e });\n });\n } catch (e) {\n logger.error('dimTables error', { e });\n }\n };\n\n sequelize.addHook('afterSave', (savedObject, options) => runAfterTransactionCommits(() => updateEventToDimTable(savedObject), options));\n sequelize.addHook('afterDestroy', (savedObject, options) => runAfterTransactionCommits(() => updateEventToDimTable(savedObject, true), options));\n};\n\nexport default addModelEventHooks;\n","import debug from 'debug';\n\nexport const debugLog = debug('sequelize-utils');\n","import {\n DatabaseError, type Sequelize, type Transaction, type TransactionOptions,\n} from 'sequelize';\nimport { debugLog } from './common';\n\nexport const transactionWithRetry = async <T>(sequelize: Sequelize, funcToRun: (transaction: Transaction) => Promise<T>, retriesCount = 2, options: TransactionOptions = {}): Promise<T> => {\n if (typeof funcToRun !== 'function') {\n throw new Error('funcToRun must be a function');\n }\n if (typeof retriesCount !== 'number') {\n throw new Error('if defined, retriesCount must be a number');\n }\n if (retriesCount < 0) {\n throw new Error('retriesCount must be a positive number');\n }\n try {\n const transValue = await sequelize.transaction(options, async (transaction) => {\n const funcValue = await funcToRun(transaction);\n return funcValue;\n });\n return transValue;\n } catch (e) {\n if ((e instanceof DatabaseError || e?.constructor?.name === 'DatabaseError') && --retriesCount >= 0) {\n debugLog(`error inside transactionWithRetry - will retry times ${retriesCount}`, e);\n return transactionWithRetry(sequelize, funcToRun, retriesCount, options);\n }\n if (retriesCount === -1) {\n debugLog('error inside transactionWithRetry - will stop retry', e);\n }\n throw e;\n }\n};\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Sequelize, Transaction } from 'sequelize';\nimport { debugLog } from './common';\n\nconst rollbackErrorText = 'rollback has been called on this transaction';\nconst abortErrorText = 'Transaction cancelled due to request cancellation';\n\nexport const httpBasedTransaction = <T>(sequelize: Sequelize, req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>): Promise<T> => {\n let aborted = false;\n if (req.socket.destroyed) {\n debugLog(abortErrorText);\n throw new Error(abortErrorText);\n }\n return sequelize.transaction(async (transaction: Transaction) => {\n // https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/test/parallel/test-http-aborted.js#L9\n\n // 2023-04-13: Node.js 16.0.0\n // Added also the `res.writableFinished` check, because it seems that the socket is not destroyed when the request is aborted, but the response is not finished.\n // https://github.com/Jimbly/http-proxy-node16/commit/ba0c414cd03799e357c5d867c11dea06a9c34ec8#diff-b2d1e3b7c5f3b424a0af7971c582c822fd25a5ea279040ef6dc93fc4b2cf619dR151\n\n const rollback = async () => {\n debugLog(abortErrorText);\n if (aborted) return;\n aborted = true;\n await transaction.rollback();\n };\n const resRollback = async () => {\n const didNotFinishWrite = !res.writableFinished;\n if (didNotFinishWrite) {\n debugLog(abortErrorText);\n if (aborted) return;\n aborted = true;\n await transaction.rollback();\n }\n };\n req.socket.once('close', rollback);\n res.once('close', resRollback);\n\n const removeListeners = () => {\n req.socket.removeListener('close', rollback);\n res.removeListener('close', resRollback);\n };\n\n try {\n const response = await cb(transaction);\n removeListeners();\n return response;\n } catch (e) {\n removeListeners();\n if (e.message.includes(rollbackErrorText)) {\n throw new Error(abortErrorText);\n }\n throw e;\n }\n });\n};\n","/* eslint-disable import/prefer-default-export */\nimport type {\n Sequelize,\n Transaction,\n TransactionOptions,\n} from 'sequelize';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport addModelEventHooks, { ModelMapping } from './model-event-hooks';\nimport { transactionWithRetry as _transactionWithRetry } from './transaction-with-retry';\nimport { httpBasedTransaction as _httpBasedTransaction } from './http-based-transaction';\nimport runAfterTransactionCommits from './runAfterTransactionCommits';\n\ntype ArgsWithoutSequelize<T> = T extends (arg1: Sequelize, ...args: infer U) => unknown ? U : never;\n\nexport default (sequelize: Sequelize): {\n transactionWithRetry: <T>(...args: ArgsWithoutSequelize<typeof _transactionWithRetry<T>>) => Promise<T>;\n httpBasedTransaction: <T>(...args: ArgsWithoutSequelize<typeof _httpBasedTransaction<T>>) => Promise<T>;\n registerModelEventHooks: (...args: ArgsWithoutSequelize<typeof addModelEventHooks>) => void;\n runAfterTransactionCommits: typeof runAfterTransactionCommits;\n useOrCreateTransaction: <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => Promise<T>;\n} => {\n const transactionWithRetry = <T>(funcToRun: (transaction: Transaction) => Promise<T>, retriesCount?: number, options?: TransactionOptions): Promise<T> => _transactionWithRetry(sequelize, funcToRun, retriesCount, options);\n const httpBasedTransaction = <T>(req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>): Promise<T> => _httpBasedTransaction(sequelize, req, res, cb);\n const registerModelEventHooks = (modelTableMapping: ModelMapping) => addModelEventHooks(sequelize, modelTableMapping);\n const useOrCreateTransaction = <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => {\n if (transaction) {\n return cb(transaction);\n }\n return transactionWithRetry(cb, 0);\n };\n\n return {\n httpBasedTransaction,\n transactionWithRetry,\n registerModelEventHooks,\n runAfterTransactionCommits,\n useOrCreateTransaction,\n };\n};\n"],"mappings":"iIAEA,IAAA,EAAe,GAAQ,CCCvB,EAAe,IAAI,EAAO,CAAE,OAAA,CAAQ,GCDpC,MAAM,EAA6B,MAAOA,EAAmBC,IAA4C,CACnG,EAAQ,YACV,EAAQ,YAAY,YAAY,IAAM,GAAI,CAAC,CAE3C,MAAM,GAAI,AAEb,EACD,IAAA,EAAe,ECCf,MAAM,EAAS,AAACC,GAAkC,aAAiB,MAAQ,OAAO,UAAU,SAAS,KAAK,EAAM,GAAK,gBAE/G,EAAsB,AAACC,GAAgB,CAC3C,IAAM,EAAS,CAAE,GAAG,CAAK,EAIzB,OAHA,OAAO,QAAQ,EAAO,CAAC,OAAO,CAAC,EAAG,EAAM,GAAK,EAAO,EAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAK,EAAM,GAAK,CACpF,EAAO,GAAQ,EAAe,SAAS,CAAG,GAC3C,EAAC,CACK,CACR,EAEK,EAAqB,CAACe,EAAsBW,IAA0C,CAC1F,IAAM,EAAwB,CAACvB,EAAe,EAAW,KAAU,CACjE,GAAI,CACF,IAAM,EAAe,EAAO,KAAK,CAC7B,GACF,OAAO,OAAO,EAAc,CAAE,UAAW,IAAI,IAAQ,EAAC,CAExD,IAAM,EAAY,EAAkB,EAAO,YAAY,OAAO,UACxD,EAAe,IACf,EAAwB,EAAoB,EAAa,CAC/D,GAAI,CAAC,EACH,OAEFC,EAAO,WACL,EACA,EACA,EAEA,OAAO,KAAK,EAAO,cAAc,CAClC,CAAC,MAAM,AAAC,GAAM,CACbC,EAAO,MAAM,mBAAoB,CAAE,YAAW,eAAc,CAAG,EAAC,AACjE,EAAC,AACH,OAAQ,EAAG,CACVA,EAAO,MAAM,kBAAmB,CAAE,CAAG,EAAC,AACvC,CACF,EAED,EAAU,QAAQ,YAAa,CAAC,EAAa,IAAYC,EAA2B,IAAM,EAAsB,EAAY,CAAE,EAAQ,CAAC,CACvI,EAAU,QAAQ,eAAgB,CAAC,EAAa,IAAYA,EAA2B,IAAM,EAAsB,EAAa,GAAK,CAAE,EAAQ,CAAC,AACjJ,EAED,IAAA,EAAe,ECjDf,MAAa,EAAW,EAAM,kBAAkB,CCGnC,EAAuB,MAAUS,EAAsBE,EAAqD,EAAe,EAAGR,EAA8B,CAAE,IAAiB,CAC1L,GAAI,OAAO,GAAc,WACvB,MAAU,MAAM,+BAAA,CAElB,GAAI,OAAO,GAAiB,SAC1B,MAAU,MAAM,4CAAA,CAElB,GAAI,EAAe,EACjB,MAAU,MAAM,yCAAA,CAElB,GAAI,CACF,IAAM,EAAa,MAAM,EAAU,YAAY,EAAS,MAAO,GAAgB,CAC7E,IAAM,EAAY,MAAM,EAAU,EAAY,CAC9C,OAAO,CACR,EAAC,CACF,OAAO,CACR,OAAQ,EAAG,CACV,IAAK,aAAa,GAAiB,GAAG,aAAa,OAAS,kBAAoB,EAAE,GAAgB,EAEhG,OADA,EAAS,CAAC,qDAAqD,EAAE,GAAc,CAAE,EAAE,CAC5E,EAAqB,EAAW,EAAW,EAAc,EAAQ,CAK1E,MAHI,IAAiB,IACnB,EAAS,sDAAuD,EAAE,CAE9D,CACP,CACF,EC3BK,EAAoB,+CACpB,EAAiB,oDAEV,EAAuB,CAAIM,EAAsBO,EAAsBC,EAAqBC,IAA6D,CACpK,IAAI,EAAU,GACd,GAAI,EAAI,OAAO,UAEb,MADA,EAAS,EAAe,CACd,MAAM,EAAA,CAElB,OAAO,EAAU,YAAY,MAAOI,GAA6B,CAO/D,IAAM,EAAW,SAAY,CAC3B,EAAS,EAAe,CACpB,KACJ,EAAU,GACV,MAAM,EAAY,UAAU,CAC7B,EACK,EAAc,SAAY,CAC9B,IAAM,EAAoB,CAAC,EAAI,iBAC/B,GAAI,EAAmB,CAErB,GADA,EAAS,EAAe,CACpB,EAAS,OACb,EAAU,GACV,MAAM,EAAY,UAAU,AAC7B,CACF,EACD,EAAI,OAAO,KAAK,QAAS,EAAS,CAClC,EAAI,KAAK,QAAS,EAAY,CAE9B,IAAM,EAAkB,IAAM,CAC5B,EAAI,OAAO,eAAe,QAAS,EAAS,CAC5C,EAAI,eAAe,QAAS,EAAY,AACzC,EAED,GAAI,CACF,IAAM,EAAW,MAAM,EAAG,EAAY,CAEtC,OADA,GAAiB,CACV,CACR,OAAQ,EAAG,CAKV,MAJA,GAAiB,CACb,EAAE,QAAQ,SAAS,EAAkB,CAC7B,MAAM,EAAA,CAEZ,CACP,CACF,EAAC,AACH,ECzCD,IAAA,EAAe,AAACb,GAMX,CACH,IAAMC,EAAuB,CAAIC,EAAqDC,EAAuBC,IAA6CC,EAAsB,EAAW,EAAW,EAAc,EAAQ,CACtNC,EAAuB,CAAIC,EAAsBC,EAAqBC,IAA6DC,EAAsB,EAAW,EAAK,EAAK,EAAG,CACjL,EAA0B,AAACC,GAAoCC,EAAmB,EAAW,EAAkB,CAC/G,EAAyB,CAAIC,EAA0BC,IACvD,EACK,EAAG,EAAY,CAEjBb,EAAqB,EAAI,EAAE,CAGpC,MAAO,CACL,qBAAA,EACA,qBAAA,EACA,0BACA,2BAAA,EACA,wBACD,CACF"}
package/package.json CHANGED
@@ -1,16 +1,33 @@
1
1
  {
2
2
  "name": "@autofleet/sequelize-utils",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist/"
22
+ ],
6
23
  "scripts": {
7
24
  "start": "ts-node src/index.ts",
8
- "prepublish": "tsc -p tsconfig.build.json",
9
- "build": "tsc -p tsconfig.build.json",
25
+ "prepublish": "tsdown",
26
+ "build": "tsdown",
10
27
  "lint": "eslint .",
11
- "test": "jest",
12
- "test-local": "jest",
13
- "coverage": "jest --coverage --runInBand"
28
+ "test": "vitest",
29
+ "test-local": "vitest",
30
+ "coverage": "vitest --coverage"
14
31
  },
15
32
  "author": "",
16
33
  "license": "Proprietary",
@@ -30,19 +47,20 @@
30
47
  "@autofleet/network": "^1.8.1",
31
48
  "@types/debug": "^4.1.6",
32
49
  "@types/express": "^4.17.13",
33
- "@types/jest": "^29.5.14",
34
- "@types/node": "^22.10.6",
50
+ "@types/node": "^22.16.5",
35
51
  "@typescript-eslint/eslint-plugin": "^7.18.0",
36
52
  "@typescript-eslint/parser": "^7.18.0",
53
+ "@vitest/coverage-v8": "^3.2.4",
54
+ "axios": "^0.30.0",
37
55
  "eslint": "^8.57.0",
38
56
  "eslint-config-airbnb-base": "^15.0.0",
39
57
  "eslint-plugin-import": "^2.31.0",
40
- "express": "^4.17.3",
41
- "jest": "^29.7.0",
58
+ "express": "^4.21.2",
42
59
  "pg": "^8.13.1",
43
60
  "sequelize": "^5.22.3",
44
- "ts-jest": "^29.2.5",
45
61
  "ts-node": "^10.1.0",
46
- "typescript": "^5.5.4"
62
+ "tsdown": "^0.13.0",
63
+ "typescript": "^5.5.4",
64
+ "vitest": "^3.2.4"
47
65
  }
48
- }
66
+ }
package/dist/common.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import debug from 'debug';
2
- export declare const debugLog: debug.Debugger;
package/dist/common.js DELETED
@@ -1,8 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.debugLog = void 0;
7
- const debug_1 = __importDefault(require("debug"));
8
- exports.debugLog = (0, debug_1.default)('sequelize-utils');
@@ -1,3 +0,0 @@
1
- import Events from '@autofleet/events';
2
- declare const _default: Events;
3
- export default _default;
@@ -1,8 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const events_1 = __importDefault(require("@autofleet/events"));
7
- const logger_1 = __importDefault(require("../logger"));
8
- exports.default = new events_1.default({ logger: logger_1.default });
@@ -1,3 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import type { Sequelize, Transaction } from 'sequelize';
3
- export declare const httpBasedTransaction: <T>(sequelize: Sequelize, req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>) => Promise<T>;
@@ -1,51 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.httpBasedTransaction = void 0;
4
- const common_1 = require("./common");
5
- const rollbackErrorText = 'rollback has been called on this transaction';
6
- const abortErrorText = 'Transaction cancelled due to request cancellation';
7
- const httpBasedTransaction = (sequelize, req, res, cb) => {
8
- let aborted = false;
9
- if (req.socket.destroyed) {
10
- (0, common_1.debugLog)(abortErrorText);
11
- throw new Error(abortErrorText);
12
- }
13
- return sequelize.transaction(async (transaction) => {
14
- const rollback = async () => {
15
- (0, common_1.debugLog)(abortErrorText);
16
- if (aborted)
17
- return;
18
- aborted = true;
19
- await transaction.rollback();
20
- };
21
- const resRollback = async () => {
22
- const didNotFinishWrite = !res.writableFinished;
23
- if (didNotFinishWrite) {
24
- (0, common_1.debugLog)(abortErrorText);
25
- if (aborted)
26
- return;
27
- aborted = true;
28
- await transaction.rollback();
29
- }
30
- };
31
- req.socket.once('close', rollback);
32
- res.once('close', resRollback);
33
- const removeListeners = () => {
34
- req.socket.removeListener('close', rollback);
35
- res.removeListener('close', resRollback);
36
- };
37
- try {
38
- const response = await cb(transaction);
39
- removeListeners();
40
- return response;
41
- }
42
- catch (e) {
43
- removeListeners();
44
- if (e.message.includes(rollbackErrorText)) {
45
- throw new Error(abortErrorText);
46
- }
47
- throw e;
48
- }
49
- });
50
- };
51
- exports.httpBasedTransaction = httpBasedTransaction;
package/dist/logger.d.ts DELETED
@@ -1,2 +0,0 @@
1
- declare const _default: import("@autofleet/logger").LoggerInstanceManager;
2
- export default _default;
package/dist/logger.js DELETED
@@ -1,7 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const logger_1 = __importDefault(require("@autofleet/logger"));
7
- exports.default = (0, logger_1.default)();
@@ -1,8 +0,0 @@
1
- import type { Sequelize } from 'sequelize';
2
- export interface ModelMapping {
3
- [ModelName: string]: {
4
- tableName: string;
5
- };
6
- }
7
- declare const addModelEventHooks: (sequelize: Sequelize, modelTableMapping: ModelMapping) => void;
8
- export default addModelEventHooks;
@@ -1,41 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const events_1 = __importDefault(require("./events"));
7
- const logger_1 = __importDefault(require("./logger"));
8
- const runAfterTransactionCommits_1 = __importDefault(require("./runAfterTransactionCommits"));
9
- const isDate = (input) => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
10
- const formatDatesInObject = (obj) => {
11
- const newObj = { ...obj };
12
- Object.entries(newObj).filter(([, value]) => isDate(value)).forEach(([key, value]) => {
13
- newObj[key] = value.getTime() / 1000;
14
- });
15
- return newObj;
16
- };
17
- const addModelEventHooks = (sequelize, modelTableMapping) => {
18
- const updateEventToDimTable = (object, isDelete = false) => {
19
- try {
20
- const objectToSend = object.get();
21
- if (isDelete) {
22
- Object.assign(objectToSend, { deletedAt: new Date() });
23
- }
24
- const tableName = modelTableMapping[object.constructor.name]?.tableName;
25
- const eventVersion = '1';
26
- const objectToSendFormatted = formatDatesInObject(objectToSend);
27
- if (!tableName) {
28
- return;
29
- }
30
- events_1.default.sendObject(tableName, eventVersion, objectToSendFormatted, Object.keys(object.rawAttributes)).catch((e) => {
31
- logger_1.default.error('sendObject error', { tableName, eventVersion, e });
32
- });
33
- }
34
- catch (e) {
35
- logger_1.default.error('dimTables error', { e });
36
- }
37
- };
38
- sequelize.addHook('afterSave', (savedObject, options) => (0, runAfterTransactionCommits_1.default)(() => updateEventToDimTable(savedObject), options));
39
- sequelize.addHook('afterDestroy', (savedObject, options) => (0, runAfterTransactionCommits_1.default)(() => updateEventToDimTable(savedObject, true), options));
40
- };
41
- exports.default = addModelEventHooks;
@@ -1,3 +0,0 @@
1
- import { Transactionable } from 'sequelize';
2
- declare const runAfterTransactionCommits: (cb: () => unknown, options: Transactionable) => Promise<void>;
3
- export default runAfterTransactionCommits;
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const runAfterTransactionCommits = async (cb, options) => {
4
- if (options.transaction) {
5
- options.transaction.afterCommit(() => cb());
6
- }
7
- else {
8
- await cb();
9
- }
10
- };
11
- exports.default = runAfterTransactionCommits;
@@ -1,2 +0,0 @@
1
- import { Sequelize } from 'sequelize';
2
- export declare function createSequelizeInstance(): Sequelize;
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSequelizeInstance = createSequelizeInstance;
4
- const node_process_1 = require("node:process");
5
- const sequelize_1 = require("sequelize");
6
- function createSequelizeInstance() {
7
- return new sequelize_1.Sequelize(node_process_1.env.DB_NAME || 'test_service_development', node_process_1.env.DB_USERNAME || '', node_process_1.env.DB_PASSWORD, {
8
- host: node_process_1.env.DB_HOST || '127.0.0.1',
9
- dialect: 'postgres',
10
- operatorsAliases: sequelize_1.Op,
11
- define: {
12
- underscored: true,
13
- },
14
- pool: {
15
- max: 10,
16
- min: 1,
17
- },
18
- });
19
- }
@@ -1,2 +0,0 @@
1
- import { type Sequelize, type Transaction, type TransactionOptions } from 'sequelize';
2
- export declare const transactionWithRetry: <T>(sequelize: Sequelize, funcToRun: (transaction: Transaction) => Promise<T>, retriesCount?: number, options?: TransactionOptions) => Promise<T>;
@@ -1,34 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.transactionWithRetry = void 0;
4
- const sequelize_1 = require("sequelize");
5
- const common_1 = require("./common");
6
- const transactionWithRetry = async (sequelize, funcToRun, retriesCount = 2, options = {}) => {
7
- if (typeof funcToRun !== 'function') {
8
- throw new Error('funcToRun must be a function');
9
- }
10
- if (typeof retriesCount !== 'number') {
11
- throw new Error('if defined, retriesCount must be a number');
12
- }
13
- if (retriesCount < 0) {
14
- throw new Error('retriesCount must be a positive number');
15
- }
16
- try {
17
- const transValue = await sequelize.transaction(options, async (transaction) => {
18
- const funcValue = await funcToRun(transaction);
19
- return funcValue;
20
- });
21
- return transValue;
22
- }
23
- catch (e) {
24
- if ((e instanceof sequelize_1.DatabaseError || e?.constructor?.name === 'DatabaseError') && --retriesCount >= 0) {
25
- (0, common_1.debugLog)(`error inside transactionWithRetry - will retry times ${retriesCount}`, e);
26
- return (0, exports.transactionWithRetry)(sequelize, funcToRun, retriesCount, options);
27
- }
28
- if (retriesCount === -1) {
29
- (0, common_1.debugLog)('error inside transactionWithRetry - will stop retry', e);
30
- }
31
- throw e;
32
- }
33
- };
34
- exports.transactionWithRetry = transactionWithRetry;
package/src/common.ts DELETED
@@ -1,3 +0,0 @@
1
- import debug from 'debug';
2
-
3
- export const debugLog = debug('sequelize-utils');
@@ -1,4 +0,0 @@
1
- import Events from '@autofleet/events';
2
- import logger from '../logger';
3
-
4
- export default new Events({ logger });
@@ -1,56 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import type { Sequelize, Transaction } from 'sequelize';
3
- import { debugLog } from './common';
4
-
5
- const rollbackErrorText = 'rollback has been called on this transaction';
6
- const abortErrorText = 'Transaction cancelled due to request cancellation';
7
-
8
- export const httpBasedTransaction = <T>(sequelize: Sequelize, req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>): Promise<T> => {
9
- let aborted = false;
10
- if (req.socket.destroyed) {
11
- debugLog(abortErrorText);
12
- throw new Error(abortErrorText);
13
- }
14
- return sequelize.transaction(async (transaction: Transaction) => {
15
- // https://github.com/nodejs/node/blob/e46c680bf2b211bbd52cf959ca17ee98c7f657f5/test/parallel/test-http-aborted.js#L9
16
-
17
- // 2023-04-13: Node.js 16.0.0
18
- // Added also the `res.writableFinished` check, because it seems that the socket is not destroyed when the request is aborted, but the response is not finished.
19
- // https://github.com/Jimbly/http-proxy-node16/commit/ba0c414cd03799e357c5d867c11dea06a9c34ec8#diff-b2d1e3b7c5f3b424a0af7971c582c822fd25a5ea279040ef6dc93fc4b2cf619dR151
20
-
21
- const rollback = async () => {
22
- debugLog(abortErrorText);
23
- if (aborted) return;
24
- aborted = true;
25
- await transaction.rollback();
26
- };
27
- const resRollback = async () => {
28
- const didNotFinishWrite = !res.writableFinished;
29
- if (didNotFinishWrite) {
30
- debugLog(abortErrorText);
31
- if (aborted) return;
32
- aborted = true;
33
- await transaction.rollback();
34
- }
35
- };
36
- req.socket.once('close', rollback);
37
- res.once('close', resRollback);
38
-
39
- const removeListeners = () => {
40
- req.socket.removeListener('close', rollback);
41
- res.removeListener('close', resRollback);
42
- };
43
-
44
- try {
45
- const response = await cb(transaction);
46
- removeListeners();
47
- return response;
48
- } catch (e) {
49
- removeListeners();
50
- if (e.message.includes(rollbackErrorText)) {
51
- throw new Error(abortErrorText);
52
- }
53
- throw e;
54
- }
55
- });
56
- };
package/src/index.ts DELETED
@@ -1,39 +0,0 @@
1
- /* eslint-disable import/prefer-default-export */
2
- import type {
3
- Sequelize,
4
- Transaction,
5
- TransactionOptions,
6
- } from 'sequelize';
7
- import type { IncomingMessage, ServerResponse } from 'http';
8
- import addModelEventHooks, { ModelMapping } from './model-event-hooks';
9
- import { transactionWithRetry as _transactionWithRetry } from './transaction-with-retry';
10
- import { httpBasedTransaction as _httpBasedTransaction } from './http-based-transaction';
11
- import runAfterTransactionCommits from './runAfterTransactionCommits';
12
-
13
- type ArgsWithoutSequelize<T> = T extends (arg1: Sequelize, ...args: infer U) => unknown ? U : never;
14
-
15
- export default (sequelize: Sequelize): {
16
- transactionWithRetry: <T>(...args: ArgsWithoutSequelize<typeof _transactionWithRetry<T>>) => Promise<T>;
17
- httpBasedTransaction: <T>(...args: ArgsWithoutSequelize<typeof _httpBasedTransaction<T>>) => Promise<T>;
18
- registerModelEventHooks: (...args: ArgsWithoutSequelize<typeof addModelEventHooks>) => void;
19
- runAfterTransactionCommits: typeof runAfterTransactionCommits;
20
- useOrCreateTransaction: <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => Promise<T>;
21
- } => {
22
- const transactionWithRetry = <T>(funcToRun: (transaction: Transaction) => Promise<T>, retriesCount?: number, options?: TransactionOptions): Promise<T> => _transactionWithRetry(sequelize, funcToRun, retriesCount, options);
23
- const httpBasedTransaction = <T>(req: IncomingMessage, res: ServerResponse, cb: (transaction: Transaction) => Promise<T>): Promise<T> => _httpBasedTransaction(sequelize, req, res, cb);
24
- const registerModelEventHooks = (modelTableMapping: ModelMapping) => addModelEventHooks(sequelize, modelTableMapping);
25
- const useOrCreateTransaction = <T>(transaction: Transaction, cb: (t: Transaction) => Promise<T>) => {
26
- if (transaction) {
27
- return cb(transaction);
28
- }
29
- return transactionWithRetry(cb, 0);
30
- };
31
-
32
- return {
33
- httpBasedTransaction,
34
- transactionWithRetry,
35
- registerModelEventHooks,
36
- runAfterTransactionCommits,
37
- useOrCreateTransaction,
38
- };
39
- };
package/src/logger.ts DELETED
@@ -1,3 +0,0 @@
1
- import Logger from '@autofleet/logger';
2
-
3
- export default Logger();
@@ -1,52 +0,0 @@
1
- import type { Model, Sequelize } from 'sequelize';
2
- import events from './events';
3
- import logger from './logger';
4
- import runAfterTransactionCommits from './runAfterTransactionCommits';
5
-
6
- export interface ModelMapping {
7
- [ModelName: string]: {
8
- tableName: string
9
- };
10
- }
11
- const isDate = (input: unknown): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
12
- // eslint-disable-next-line @typescript-eslint/ban-types
13
- const formatDatesInObject = (obj: object) => {
14
- const newObj = { ...obj };
15
- Object.entries(newObj).filter(([, value]) => isDate(value)).forEach(([key, value]) => {
16
- newObj[key] = (value as Date).getTime() / 1000;
17
- });
18
- return newObj;
19
- };
20
-
21
- const addModelEventHooks = (sequelize: Sequelize, modelTableMapping: ModelMapping): void => {
22
- const updateEventToDimTable = (object: Model, isDelete = false) => {
23
- try {
24
- const objectToSend = object.get();
25
- if (isDelete) {
26
- Object.assign(objectToSend, { deletedAt: new Date() });
27
- }
28
- const tableName = modelTableMapping[object.constructor.name]?.tableName;
29
- const eventVersion = '1';
30
- const objectToSendFormatted = formatDatesInObject(objectToSend);
31
- if (!tableName) {
32
- return;
33
- }
34
- events.sendObject(
35
- tableName,
36
- eventVersion,
37
- objectToSendFormatted,
38
- // @ts-expect-error the rawAttributes is typed as static, while it actually is on the instance level.
39
- Object.keys(object.rawAttributes),
40
- ).catch((e) => {
41
- logger.error('sendObject error', { tableName, eventVersion, e });
42
- });
43
- } catch (e) {
44
- logger.error('dimTables error', { e });
45
- }
46
- };
47
-
48
- sequelize.addHook('afterSave', (savedObject, options) => runAfterTransactionCommits(() => updateEventToDimTable(savedObject), options));
49
- sequelize.addHook('afterDestroy', (savedObject, options) => runAfterTransactionCommits(() => updateEventToDimTable(savedObject, true), options));
50
- };
51
-
52
- export default addModelEventHooks;
@@ -1,10 +0,0 @@
1
- import { Transactionable } from 'sequelize';
2
-
3
- const runAfterTransactionCommits = async (cb: () => unknown, options: Transactionable): Promise<void> => {
4
- if (options.transaction) {
5
- options.transaction.afterCommit(() => cb());
6
- } else {
7
- await cb();
8
- }
9
- };
10
- export default runAfterTransactionCommits;
@@ -1,22 +0,0 @@
1
- import { env } from 'node:process';
2
- import { Sequelize, Op } from 'sequelize';
3
-
4
- export function createSequelizeInstance(): Sequelize {
5
- return new Sequelize(
6
- env.DB_NAME || 'test_service_development',
7
- env.DB_USERNAME || '',
8
- env.DB_PASSWORD,
9
- {
10
- host: env.DB_HOST || '127.0.0.1',
11
- dialect: 'postgres',
12
- operatorsAliases: Op,
13
- define: {
14
- underscored: true,
15
- },
16
- pool: {
17
- max: 10,
18
- min: 1,
19
- },
20
- },
21
- );
22
- }
@@ -1,32 +0,0 @@
1
- import {
2
- DatabaseError, type Sequelize, type Transaction, type TransactionOptions,
3
- } from 'sequelize';
4
- import { debugLog } from './common';
5
-
6
- export const transactionWithRetry = async <T>(sequelize: Sequelize, funcToRun: (transaction: Transaction) => Promise<T>, retriesCount = 2, options: TransactionOptions = {}): Promise<T> => {
7
- if (typeof funcToRun !== 'function') {
8
- throw new Error('funcToRun must be a function');
9
- }
10
- if (typeof retriesCount !== 'number') {
11
- throw new Error('if defined, retriesCount must be a number');
12
- }
13
- if (retriesCount < 0) {
14
- throw new Error('retriesCount must be a positive number');
15
- }
16
- try {
17
- const transValue = await sequelize.transaction(options, async (transaction) => {
18
- const funcValue = await funcToRun(transaction);
19
- return funcValue;
20
- });
21
- return transValue;
22
- } catch (e) {
23
- if ((e instanceof DatabaseError || e?.constructor?.name === 'DatabaseError') && --retriesCount >= 0) {
24
- debugLog(`error inside transactionWithRetry - will retry times ${retriesCount}`, e);
25
- return transactionWithRetry(sequelize, funcToRun, retriesCount, options);
26
- }
27
- if (retriesCount === -1) {
28
- debugLog('error inside transactionWithRetry - will stop retry', e);
29
- }
30
- throw e;
31
- }
32
- };
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "exclude": [
4
- "node_modules",
5
- "dist/**/*",
6
- "test-utils/**/*",
7
- "**/*.test.*"
8
- ]
9
- }
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2020",
4
- "module": "commonjs",
5
- "declaration": true,
6
- "outDir": "./dist",
7
- "strict": false,
8
- "esModuleInterop": true,
9
- "skipLibCheck": true,
10
- "removeComments": true,
11
- },
12
- "include": ["src/**/*"],
13
- "exclude": [
14
- "node_modules",
15
- "dist/**/*"
16
- ]
17
- }