@scpxl/nodejs-framework 1.0.46 → 1.0.48
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/database/instance.d.ts +29 -0
- package/dist/database/instance.d.ts.map +1 -1
- package/dist/database/instance.js +45 -0
- package/dist/database/instance.js.map +2 -2
- package/dist/queue/manager.d.ts.map +1 -1
- package/dist/queue/manager.js +19 -5
- package/dist/queue/manager.js.map +3 -3
- package/dist/queue/processor/base.d.ts +46 -0
- package/dist/queue/processor/base.d.ts.map +1 -1
- package/dist/queue/processor/base.js +50 -0
- package/dist/queue/processor/base.js.map +2 -2
- package/dist/webserver/controller/entity.d.ts +7 -3
- package/dist/webserver/controller/entity.d.ts.map +1 -1
- package/dist/webserver/controller/entity.js +31 -20
- package/dist/webserver/controller/entity.js.map +2 -2
- package/dist/webserver/webserver.d.ts.map +1 -1
- package/dist/webserver/webserver.js +5 -0
- package/dist/webserver/webserver.js.map +2 -2
- package/dist/websocket/controller/server/base.d.ts +32 -0
- package/dist/websocket/controller/server/base.d.ts.map +1 -1
- package/dist/websocket/controller/server/base.js.map +2 -2
- package/dist/websocket/websocket-server.js +13 -12
- package/dist/websocket/websocket-server.js.map +2 -2
- package/package.json +1 -1
|
@@ -26,8 +26,37 @@ export default class DatabaseInstance {
|
|
|
26
26
|
isConnected(): Promise<boolean>;
|
|
27
27
|
/**
|
|
28
28
|
* Get EntityManager
|
|
29
|
+
*
|
|
30
|
+
* Fork and return a new EntityManager instance
|
|
31
|
+
* WARNING: You MUST call em.clear() when done to prevent memory leaks
|
|
32
|
+
* Consider using withEntityManager() instead for automatic cleanup
|
|
33
|
+
*
|
|
34
|
+
* @deprecated Use withEntityManager() for automatic cleanup
|
|
29
35
|
*/
|
|
30
36
|
getEntityManager(): EntityManager;
|
|
37
|
+
/**
|
|
38
|
+
* Execute a function with a fresh EntityManager that is automatically cleaned up
|
|
39
|
+
* This is the recommended pattern for short-lived operations (HTTP requests, queue jobs, etc.)
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* await databaseInstance.withEntityManager(async (em) => {
|
|
43
|
+
* const user = await em.findOne('User', { id: 1 });
|
|
44
|
+
* return user;
|
|
45
|
+
* });
|
|
46
|
+
*/
|
|
47
|
+
withEntityManager<T>(callback: (em: EntityManager) => Promise<T>): Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Execute a function with a fresh EntityManager that supports transactions
|
|
50
|
+
* The EntityManager is automatically cleaned up after the transaction
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* await databaseInstance.withTransaction(async (em) => {
|
|
54
|
+
* const user = em.create('User', { name: 'John' });
|
|
55
|
+
* await em.persistAndFlush(user);
|
|
56
|
+
* return user;
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
withTransaction<T>(callback: (em: EntityManager) => Promise<T>): Promise<T>;
|
|
31
60
|
/**
|
|
32
61
|
* Disconnect
|
|
33
62
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/database/instance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,KAAK,eAAe,MAAM,cAAc,CAAC;AAEhD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,uBAAuB;IACvB,OAAO,CAAC,eAAe,CAAkB;IAEzC,yBAAyB;IACzB,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,wBAAwB;IACxB,OAAO,CAAC,GAAG,CAAW;IAEtB;;;OAGG;gBACS,EACV,eAAe,EACf,iBAAiB,EACjB,GAAG,GACJ,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,iBAAiB,EAAE,iBAAiB,CAAC;QACrC,GAAG,EAAE,QAAQ,CAAC;KACf;IAMD;;OAEG;IACI,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAItC
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/database/instance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAC;AACtF,OAAO,KAAK,eAAe,MAAM,cAAc,CAAC;AAEhD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,uBAAuB;IACvB,OAAO,CAAC,eAAe,CAAkB;IAEzC,yBAAyB;IACzB,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,wBAAwB;IACxB,OAAO,CAAC,GAAG,CAAW;IAEtB;;;OAGG;gBACS,EACV,eAAe,EACf,iBAAiB,EACjB,GAAG,GACJ,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,iBAAiB,EAAE,iBAAiB,CAAC;QACrC,GAAG,EAAE,QAAQ,CAAC;KACf;IAMD;;OAEG;IACI,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAItC;;;;;;;;OAQG;IACI,gBAAgB,IAAI,aAAa;IAIxC;;;;;;;;;OASG;IACU,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAS1F;;;;;;;;;;OAUG;IACU,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAWxF;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAKzC"}
|
|
@@ -31,10 +31,55 @@ class DatabaseInstance {
|
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Get EntityManager
|
|
34
|
+
*
|
|
35
|
+
* Fork and return a new EntityManager instance
|
|
36
|
+
* WARNING: You MUST call em.clear() when done to prevent memory leaks
|
|
37
|
+
* Consider using withEntityManager() instead for automatic cleanup
|
|
38
|
+
*
|
|
39
|
+
* @deprecated Use withEntityManager() for automatic cleanup
|
|
34
40
|
*/
|
|
35
41
|
getEntityManager() {
|
|
36
42
|
return this.orm.em.fork();
|
|
37
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Execute a function with a fresh EntityManager that is automatically cleaned up
|
|
46
|
+
* This is the recommended pattern for short-lived operations (HTTP requests, queue jobs, etc.)
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* await databaseInstance.withEntityManager(async (em) => {
|
|
50
|
+
* const user = await em.findOne('User', { id: 1 });
|
|
51
|
+
* return user;
|
|
52
|
+
* });
|
|
53
|
+
*/
|
|
54
|
+
async withEntityManager(callback) {
|
|
55
|
+
const em = this.orm.em.fork();
|
|
56
|
+
try {
|
|
57
|
+
return await callback(em);
|
|
58
|
+
} finally {
|
|
59
|
+
em.clear();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Execute a function with a fresh EntityManager that supports transactions
|
|
64
|
+
* The EntityManager is automatically cleaned up after the transaction
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* await databaseInstance.withTransaction(async (em) => {
|
|
68
|
+
* const user = em.create('User', { name: 'John' });
|
|
69
|
+
* await em.persistAndFlush(user);
|
|
70
|
+
* return user;
|
|
71
|
+
* });
|
|
72
|
+
*/
|
|
73
|
+
async withTransaction(callback) {
|
|
74
|
+
const em = this.orm.em.fork();
|
|
75
|
+
try {
|
|
76
|
+
return await em.transactional(async (transactionalEm) => {
|
|
77
|
+
return await callback(transactionalEm);
|
|
78
|
+
});
|
|
79
|
+
} finally {
|
|
80
|
+
em.clear();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
38
83
|
/**
|
|
39
84
|
* Disconnect
|
|
40
85
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/database/instance.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager, MikroORM } from '@mikro-orm/postgresql';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type DatabaseManager from './manager.js';\n\n/**\n * Database Instance\n */\nexport default class DatabaseInstance {\n /** Database manager */\n private databaseManager: DatabaseManager;\n\n /** Application config */\n private applicationConfig: ApplicationConfig;\n\n /** MikroORM instance */\n private orm: MikroORM;\n\n /**\n * Database Instance constructor\n * @param orm MikroORM instance\n */\n constructor({\n databaseManager,\n applicationConfig,\n orm,\n }: {\n databaseManager: DatabaseManager;\n applicationConfig: ApplicationConfig;\n orm: MikroORM;\n }) {\n this.databaseManager = databaseManager;\n this.applicationConfig = applicationConfig;\n this.orm = orm;\n }\n\n /**\n * Check if database is connected\n */\n public isConnected(): Promise<boolean> {\n return this.orm.isConnected();\n }\n\n /**\n * Get EntityManager\n */\n public getEntityManager(): EntityManager {\n return this.orm.em.fork();\n }\n\n /**\n * Disconnect\n */\n public async disconnect(): Promise<void> {\n await this.orm.close();\n\n this.databaseManager.log('Disconnected');\n }\n}\n"],
|
|
5
|
-
"mappings": ";;AAOA,MAAO,iBAA+B;AAAA,EAPtC,OAOsC;AAAA;AAAA;AAAA;AAAA,EAE5B;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,SAAK,kBAAkB;AACvB,SAAK,oBAAoB;AACzB,SAAK,MAAM;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKO,cAAgC;AACrC,WAAO,KAAK,IAAI,YAAY;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { EntityManager, MikroORM } from '@mikro-orm/postgresql';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type DatabaseManager from './manager.js';\n\n/**\n * Database Instance\n */\nexport default class DatabaseInstance {\n /** Database manager */\n private databaseManager: DatabaseManager;\n\n /** Application config */\n private applicationConfig: ApplicationConfig;\n\n /** MikroORM instance */\n private orm: MikroORM;\n\n /**\n * Database Instance constructor\n * @param orm MikroORM instance\n */\n constructor({\n databaseManager,\n applicationConfig,\n orm,\n }: {\n databaseManager: DatabaseManager;\n applicationConfig: ApplicationConfig;\n orm: MikroORM;\n }) {\n this.databaseManager = databaseManager;\n this.applicationConfig = applicationConfig;\n this.orm = orm;\n }\n\n /**\n * Check if database is connected\n */\n public isConnected(): Promise<boolean> {\n return this.orm.isConnected();\n }\n\n /**\n * Get EntityManager\n *\n * Fork and return a new EntityManager instance\n * WARNING: You MUST call em.clear() when done to prevent memory leaks\n * Consider using withEntityManager() instead for automatic cleanup\n *\n * @deprecated Use withEntityManager() for automatic cleanup\n */\n public getEntityManager(): EntityManager {\n return this.orm.em.fork();\n }\n\n /**\n * Execute a function with a fresh EntityManager that is automatically cleaned up\n * This is the recommended pattern for short-lived operations (HTTP requests, queue jobs, etc.)\n *\n * @example\n * await databaseInstance.withEntityManager(async (em) => {\n * const user = await em.findOne('User', { id: 1 });\n * return user;\n * });\n */\n public async withEntityManager<T>(callback: (em: EntityManager) => Promise<T>): Promise<T> {\n const em = this.orm.em.fork();\n try {\n return await callback(em);\n } finally {\n em.clear();\n }\n }\n\n /**\n * Execute a function with a fresh EntityManager that supports transactions\n * The EntityManager is automatically cleaned up after the transaction\n *\n * @example\n * await databaseInstance.withTransaction(async (em) => {\n * const user = em.create('User', { name: 'John' });\n * await em.persistAndFlush(user);\n * return user;\n * });\n */\n public async withTransaction<T>(callback: (em: EntityManager) => Promise<T>): Promise<T> {\n const em = this.orm.em.fork();\n try {\n return await em.transactional(async transactionalEm => {\n return await callback(transactionalEm);\n });\n } finally {\n em.clear();\n }\n }\n\n /**\n * Disconnect\n */\n public async disconnect(): Promise<void> {\n await this.orm.close();\n\n this.databaseManager.log('Disconnected');\n }\n}\n"],
|
|
5
|
+
"mappings": ";;AAOA,MAAO,iBAA+B;AAAA,EAPtC,OAOsC;AAAA;AAAA;AAAA;AAAA,EAE5B;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,SAAK,kBAAkB;AACvB,SAAK,oBAAoB;AACzB,SAAK,MAAM;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKO,cAAgC;AACrC,WAAO,KAAK,IAAI,YAAY;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWO,mBAAkC;AACvC,WAAO,KAAK,IAAI,GAAG,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAa,kBAAqB,UAAyD;AACzF,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK;AAC5B,QAAI;AACF,aAAO,MAAM,SAAS,EAAE;AAAA,IAC1B,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAa,gBAAmB,UAAyD;AACvF,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK;AAC5B,QAAI;AACF,aAAO,MAAM,GAAG,cAAc,OAAM,oBAAmB;AACrD,eAAO,MAAM,SAAS,eAAe;AAAA,MACvC,CAAC;AAAA,IACH,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,aAA4B;AACvC,UAAM,KAAK,IAAI,MAAM;AAErB,SAAK,gBAAgB,IAAI,cAAc;AAAA,EACzC;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/queue/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAgD,MAAM,QAAQ,CAAC;AAEhF,OAAO,KAAK,EAAE,6BAA6B,EAAuB,MAAM,wBAAwB,CAAC;AAOjG,OAAO,KAAK,EAAY,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,OAAO,CAAC,MAAM,CAAyB;IAEvC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,OAAO,CAAsB;IAErC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,aAAa,CAAyC;gBAElD,EACV,iBAAiB,EACjB,OAAO,EACP,MAAM,EAAE,OAAO,EACf,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,EAAE,6BAA6B;IAgBnB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC/E,OAAO,CAAC,aAAa;IAsErB,OAAO,CAAC,qBAAqB;IA0C7B,OAAO,CAAC,YAAY,CAElB;IAEF,OAAO,CAAC,cAAc,CAIpB;IAEF,OAAO,CAAC,eAAe,CAKrB;IAEF,OAAO,CAAC,cAAc,CAEpB;IAEK,aAAa,GAClB,QAAQ,SAAS,eAAe,GAAG,eAAe,EAClD,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,OAAO,GAAG,OAAO,EACjB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,2BAIC;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;KACzC,KAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC,CA0B7E;IAEF,OAAO,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/queue/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAgD,MAAM,QAAQ,CAAC;AAEhF,OAAO,KAAK,EAAE,6BAA6B,EAAuB,MAAM,wBAAwB,CAAC;AAOjG,OAAO,KAAK,EAAY,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,OAAO,CAAC,MAAM,CAAyB;IAEvC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,OAAO,CAAsB;IAErC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,aAAa,CAAyC;gBAElD,EACV,iBAAiB,EACjB,OAAO,EACP,MAAM,EAAE,OAAO,EACf,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,EAAE,6BAA6B;IAgBnB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC/E,OAAO,CAAC,aAAa;IAsErB,OAAO,CAAC,qBAAqB;IA0C7B,OAAO,CAAC,YAAY,CAElB;IAEF,OAAO,CAAC,cAAc,CAIpB;IAEF,OAAO,CAAC,eAAe,CAKrB;IAEF,OAAO,CAAC,cAAc,CAEpB;IAEK,aAAa,GAClB,QAAQ,SAAS,eAAe,GAAG,eAAe,EAClD,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,OAAO,GAAG,OAAO,EACjB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,2BAIC;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;KACzC,KAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC,CA0B7E;IAEF,OAAO,CAAC,eAAe,CA2ErB;IAEW,qBAAqB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IA6B3D;;OAEG;IACI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlE"}
|
package/dist/queue/manager.js
CHANGED
|
@@ -193,14 +193,14 @@ class QueueManager {
|
|
|
193
193
|
if (typeof job.updateData === "function") {
|
|
194
194
|
try {
|
|
195
195
|
await job.updateData({ ...job.data, startTime });
|
|
196
|
-
} catch (
|
|
196
|
+
} catch (error2) {
|
|
197
197
|
Logger.warn({
|
|
198
198
|
message: "Failed to persist job metadata before processing",
|
|
199
199
|
meta: {
|
|
200
200
|
Queue: job.queueName,
|
|
201
201
|
"Job Name": job.name,
|
|
202
202
|
"Job ID": job.id,
|
|
203
|
-
Error:
|
|
203
|
+
Error: error2 instanceof Error ? error2.message : String(error2)
|
|
204
204
|
}
|
|
205
205
|
});
|
|
206
206
|
}
|
|
@@ -214,10 +214,14 @@ class QueueManager {
|
|
|
214
214
|
if (!processor) {
|
|
215
215
|
throw new Error(`No processor registered for job (Name: ${job.name})`);
|
|
216
216
|
}
|
|
217
|
+
let result;
|
|
218
|
+
let error;
|
|
217
219
|
try {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
await processor.beforeProcess({ job });
|
|
221
|
+
result = await processor.process({ job });
|
|
222
|
+
return result;
|
|
223
|
+
} catch (err) {
|
|
224
|
+
error = err;
|
|
221
225
|
Logger.warn({
|
|
222
226
|
message: "Queue worker processing error",
|
|
223
227
|
meta: {
|
|
@@ -228,6 +232,16 @@ class QueueManager {
|
|
|
228
232
|
}
|
|
229
233
|
});
|
|
230
234
|
Logger.error({ error });
|
|
235
|
+
throw error;
|
|
236
|
+
} finally {
|
|
237
|
+
try {
|
|
238
|
+
await processor.afterProcess({ job, result, error });
|
|
239
|
+
} catch (cleanupError) {
|
|
240
|
+
Logger.error({
|
|
241
|
+
error: cleanupError,
|
|
242
|
+
message: "Error in processor afterProcess cleanup"
|
|
243
|
+
});
|
|
244
|
+
}
|
|
231
245
|
}
|
|
232
246
|
}, "workerProcessor");
|
|
233
247
|
async listAllJobsWithStatus() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/queue/manager.ts"],
|
|
4
|
-
"sourcesContent": ["import { type Job, Queue, type QueueOptions, type WorkerOptions } from 'bullmq';\nimport path from 'path';\nimport type { QueueManagerConstructorParams, QueueManagerOptions } from './manager.interface.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport { Logger } from '../logger/index.js';\nimport QueueWorker from './worker.js';\nimport type BaseProcessor from './processor/base.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport type { QueueJob, QueueJobData, QueueJobPayload } from './job.interface.js';\nimport type { ProcessorConstructor } from './processor/processor.interface.js';\nimport type { QueueItem } from './index.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\n\nexport interface JobSummary {\n id: string;\n name: string;\n queueName: string;\n state: 'active' | 'waiting' | 'completed' | 'failed' | 'delayed' | 'paused';\n attemptsMade: number;\n failedReason?: string;\n}\n\nexport default class QueueManager {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: QueueManagerOptions;\n\n private redisInstance: RedisInstance;\n private databaseInstance: DatabaseInstance | null;\n private eventManager?: EventManager;\n\n private queues: Map<string, Queue> = new Map();\n\n private jobProcessors: Map<string, BaseProcessor> = new Map();\n\n constructor({\n applicationConfig,\n options,\n queues: _queues,\n redisInstance,\n databaseInstance,\n eventManager,\n }: QueueManagerConstructorParams) {\n // Merge options with defaults if provided\n if (options) {\n this.options = options;\n } else {\n // This shouldn't happen, but handle the edge case\n this.options = { processorsDirectory: '' };\n }\n\n this.applicationConfig = applicationConfig;\n\n this.redisInstance = redisInstance;\n this.databaseInstance = databaseInstance;\n this.eventManager = eventManager;\n }\n\n public async registerQueues({ queues }: { queues: QueueItem[] }): Promise<void> {\n if (!queues) {\n return;\n }\n\n // Check if processors directory exists\n const processorsDirectoryExists = await File.pathExists(this.options.processorsDirectory);\n\n if (!processorsDirectoryExists) {\n return;\n }\n\n try {\n const jobProcessorClasses = await Loader.loadModulesInDirectory<ProcessorConstructor>({\n directory: this.options.processorsDirectory,\n extensions: ['.ts', '.js'],\n });\n\n for (const queue of queues) {\n this.registerQueue({ queue, jobProcessorClasses });\n }\n\n if (this.applicationConfig.queue.log?.queuesRegistered) {\n this.log('Registered queue', {\n 'Queue Count': queues.length,\n 'Job Count': this.jobProcessors.size,\n });\n }\n } catch (error) {\n Logger.error({ error });\n }\n }\n\n private registerQueue({\n queue,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!queue.jobs) {\n Logger.warn({\n message: 'No jobs found for queue, skip register',\n meta: {\n Name: queue.name,\n },\n });\n\n return;\n }\n\n // Merge framework defaults with queue-specific default job options\n const queueOptions: QueueOptions = {\n connection: this.redisInstance.client,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true,\n ...(queue.defaultJobOptions ?? {}),\n },\n };\n\n const queueInstance = new Queue(queue.name, queueOptions);\n\n queueInstance.on('error', this.onQueueError);\n queueInstance.on('waiting', this.onQueueWaiting);\n queueInstance.on('progress', this.onQueueProgress);\n queueInstance.on('removed', this.onQueueRemoved);\n\n if (!queue.isExternal) {\n // Build worker options, applying per-queue runtime settings\n const workerOptions: WorkerOptions = {\n connection: this.redisInstance.client,\n autorun: true,\n ...(queue.settings ?? {}),\n };\n\n new QueueWorker({\n applicationConfig: this.applicationConfig,\n queueManager: this,\n name: queue.name,\n processor: this.workerProcessor,\n options: workerOptions,\n redisInstance: this.redisInstance,\n });\n }\n\n this.queues.set(queue.name, queueInstance);\n\n if (this.applicationConfig.queue.log?.queueRegistered) {\n this.log('Registered queue', {\n Name: queue.name,\n Settings: queue.settings ? JSON.stringify(queue.settings) : 'default',\n });\n }\n\n // Register job processors\n this.registerJobProcessors({\n queue,\n jobs: queue.jobs,\n jobProcessorClasses,\n });\n }\n\n private registerJobProcessors({\n queue,\n jobs,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobs: QueueJob[];\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!jobs) {\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n for (const job of jobs) {\n if (!queue.isExternal) {\n const ProcessorClass = jobProcessorClasses[job.id];\n\n if (!ProcessorClass) {\n const jobPath = path.join(this.options.processorsDirectory, `${job.id}.${scriptFileExtension}`);\n\n throw new Error(`Processor class not found (Job ID: ${job.id} | Path: ${jobPath})`);\n }\n\n const processorInstance = new ProcessorClass(\n this,\n this.applicationConfig,\n this.redisInstance,\n this.databaseInstance,\n this.eventManager,\n );\n\n this.jobProcessors.set(job.id, processorInstance);\n }\n\n if (this.applicationConfig.queue.log?.jobRegistered) {\n this.log('Job registered', { ID: job.id });\n }\n }\n }\n\n private onQueueError = (error: Error): void => {\n Logger.error({ error });\n };\n\n private onQueueWaiting = (job: Job): void => {\n if (this.applicationConfig.queue.log?.queueWaiting) {\n this.log('Waiting...', { Queue: job.queueName, Job: job.id });\n }\n };\n\n private onQueueProgress = (jobId: string, progress: unknown): void => {\n this.log('Progress update', {\n 'Job ID': jobId,\n Progress: progress,\n });\n };\n\n private onQueueRemoved = (jobId: string): void => {\n this.log('Removed queue', { Job: jobId });\n };\n\n public addJobToQueue = async <\n TPayload extends QueueJobPayload = QueueJobPayload,\n TMetadata extends Record<string, unknown> = Record<string, unknown>,\n TResult = unknown,\n TName extends string = string,\n >({\n queueId,\n jobId,\n data,\n }: {\n queueId: string;\n jobId: TName;\n data: QueueJobData<TPayload, TMetadata>;\n }): Promise<Job<QueueJobData<TPayload, TMetadata>, TResult, TName> | undefined> => {\n const queue = this.queues.get(queueId);\n\n if (!queue) {\n this.log('Queue not found', { 'Queue ID': queueId });\n\n return;\n }\n\n const job = (await queue.add(jobId, data)) as Job<QueueJobData<TPayload, TMetadata>, TResult, TName>;\n\n const dataStr = JSON.stringify(data);\n\n const maxLogDataStrLength = 50;\n const truncatedLogDataStr =\n dataStr.length > maxLogDataStrLength ? `${dataStr.substring(0, maxLogDataStrLength)}...` : dataStr;\n\n if (this.applicationConfig.queue.log?.jobAdded) {\n this.log('Job added', {\n Queue: queueId,\n 'Job ID': jobId,\n Data: truncatedLogDataStr,\n });\n }\n\n return job;\n };\n\n private workerProcessor = async (job: Job): Promise<unknown> => {\n if (!job) {\n return;\n }\n\n const startTime = Time.now();\n\n // Add start time to job data\n if (typeof job.updateData === 'function') {\n try {\n await job.updateData({ ...job.data, startTime });\n } catch (error) {\n Logger.warn({\n message: 'Failed to persist job metadata before processing',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: error instanceof Error ? error.message : String(error),\n },\n });\n }\n }\n\n this.log('Worker processing...', {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n });\n\n const processor = this.jobProcessors.get(job.name);\n\n if (!processor) {\n throw new Error(`No processor registered for job (Name: ${job.name})`);\n }\n\n try {\n const jobResult = await processor.process({ job });\n\n return jobResult;\n } catch (error) {\n Logger.warn({\n message: 'Queue worker processing error',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: (error as Error).message,\n },\n });\n\n Logger.error({ error });\n }\n };\n\n public async listAllJobsWithStatus(): Promise<JobSummary[]> {\n const jobsSummary: JobSummary[] = [];\n\n for (const [queueName, queue] of this.queues) {\n const jobStates = ['active', 'waiting', 'completed', 'failed', 'delayed', 'paused'] as const;\n\n const jobsDetailsPromises = jobStates.map(async state => {\n const jobs = await queue.getJobs([state]);\n return jobs.map(\n (job): JobSummary => ({\n id: job.id ?? 'unknown',\n name: job.name ?? 'unknown',\n queueName,\n state,\n attemptsMade: job.attemptsMade,\n failedReason: job.failedReason,\n }),\n );\n });\n\n const results = await Promise.all(jobsDetailsPromises);\n const flattenedResults = results.flat();\n\n jobsSummary.push(...flattenedResults);\n }\n\n return jobsSummary;\n }\n\n /**\n * Log queue message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'queue', message, meta });\n }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import { type Job, Queue, type QueueOptions, type WorkerOptions } from 'bullmq';\nimport path from 'path';\nimport type { QueueManagerConstructorParams, QueueManagerOptions } from './manager.interface.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport { Logger } from '../logger/index.js';\nimport QueueWorker from './worker.js';\nimport type BaseProcessor from './processor/base.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport type { QueueJob, QueueJobData, QueueJobPayload } from './job.interface.js';\nimport type { ProcessorConstructor } from './processor/processor.interface.js';\nimport type { QueueItem } from './index.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\n\nexport interface JobSummary {\n id: string;\n name: string;\n queueName: string;\n state: 'active' | 'waiting' | 'completed' | 'failed' | 'delayed' | 'paused';\n attemptsMade: number;\n failedReason?: string;\n}\n\nexport default class QueueManager {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: QueueManagerOptions;\n\n private redisInstance: RedisInstance;\n private databaseInstance: DatabaseInstance | null;\n private eventManager?: EventManager;\n\n private queues: Map<string, Queue> = new Map();\n\n private jobProcessors: Map<string, BaseProcessor> = new Map();\n\n constructor({\n applicationConfig,\n options,\n queues: _queues,\n redisInstance,\n databaseInstance,\n eventManager,\n }: QueueManagerConstructorParams) {\n // Merge options with defaults if provided\n if (options) {\n this.options = options;\n } else {\n // This shouldn't happen, but handle the edge case\n this.options = { processorsDirectory: '' };\n }\n\n this.applicationConfig = applicationConfig;\n\n this.redisInstance = redisInstance;\n this.databaseInstance = databaseInstance;\n this.eventManager = eventManager;\n }\n\n public async registerQueues({ queues }: { queues: QueueItem[] }): Promise<void> {\n if (!queues) {\n return;\n }\n\n // Check if processors directory exists\n const processorsDirectoryExists = await File.pathExists(this.options.processorsDirectory);\n\n if (!processorsDirectoryExists) {\n return;\n }\n\n try {\n const jobProcessorClasses = await Loader.loadModulesInDirectory<ProcessorConstructor>({\n directory: this.options.processorsDirectory,\n extensions: ['.ts', '.js'],\n });\n\n for (const queue of queues) {\n this.registerQueue({ queue, jobProcessorClasses });\n }\n\n if (this.applicationConfig.queue.log?.queuesRegistered) {\n this.log('Registered queue', {\n 'Queue Count': queues.length,\n 'Job Count': this.jobProcessors.size,\n });\n }\n } catch (error) {\n Logger.error({ error });\n }\n }\n\n private registerQueue({\n queue,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!queue.jobs) {\n Logger.warn({\n message: 'No jobs found for queue, skip register',\n meta: {\n Name: queue.name,\n },\n });\n\n return;\n }\n\n // Merge framework defaults with queue-specific default job options\n const queueOptions: QueueOptions = {\n connection: this.redisInstance.client,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true,\n ...(queue.defaultJobOptions ?? {}),\n },\n };\n\n const queueInstance = new Queue(queue.name, queueOptions);\n\n queueInstance.on('error', this.onQueueError);\n queueInstance.on('waiting', this.onQueueWaiting);\n queueInstance.on('progress', this.onQueueProgress);\n queueInstance.on('removed', this.onQueueRemoved);\n\n if (!queue.isExternal) {\n // Build worker options, applying per-queue runtime settings\n const workerOptions: WorkerOptions = {\n connection: this.redisInstance.client,\n autorun: true,\n ...(queue.settings ?? {}),\n };\n\n new QueueWorker({\n applicationConfig: this.applicationConfig,\n queueManager: this,\n name: queue.name,\n processor: this.workerProcessor,\n options: workerOptions,\n redisInstance: this.redisInstance,\n });\n }\n\n this.queues.set(queue.name, queueInstance);\n\n if (this.applicationConfig.queue.log?.queueRegistered) {\n this.log('Registered queue', {\n Name: queue.name,\n Settings: queue.settings ? JSON.stringify(queue.settings) : 'default',\n });\n }\n\n // Register job processors\n this.registerJobProcessors({\n queue,\n jobs: queue.jobs,\n jobProcessorClasses,\n });\n }\n\n private registerJobProcessors({\n queue,\n jobs,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobs: QueueJob[];\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!jobs) {\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n for (const job of jobs) {\n if (!queue.isExternal) {\n const ProcessorClass = jobProcessorClasses[job.id];\n\n if (!ProcessorClass) {\n const jobPath = path.join(this.options.processorsDirectory, `${job.id}.${scriptFileExtension}`);\n\n throw new Error(`Processor class not found (Job ID: ${job.id} | Path: ${jobPath})`);\n }\n\n const processorInstance = new ProcessorClass(\n this,\n this.applicationConfig,\n this.redisInstance,\n this.databaseInstance,\n this.eventManager,\n );\n\n this.jobProcessors.set(job.id, processorInstance);\n }\n\n if (this.applicationConfig.queue.log?.jobRegistered) {\n this.log('Job registered', { ID: job.id });\n }\n }\n }\n\n private onQueueError = (error: Error): void => {\n Logger.error({ error });\n };\n\n private onQueueWaiting = (job: Job): void => {\n if (this.applicationConfig.queue.log?.queueWaiting) {\n this.log('Waiting...', { Queue: job.queueName, Job: job.id });\n }\n };\n\n private onQueueProgress = (jobId: string, progress: unknown): void => {\n this.log('Progress update', {\n 'Job ID': jobId,\n Progress: progress,\n });\n };\n\n private onQueueRemoved = (jobId: string): void => {\n this.log('Removed queue', { Job: jobId });\n };\n\n public addJobToQueue = async <\n TPayload extends QueueJobPayload = QueueJobPayload,\n TMetadata extends Record<string, unknown> = Record<string, unknown>,\n TResult = unknown,\n TName extends string = string,\n >({\n queueId,\n jobId,\n data,\n }: {\n queueId: string;\n jobId: TName;\n data: QueueJobData<TPayload, TMetadata>;\n }): Promise<Job<QueueJobData<TPayload, TMetadata>, TResult, TName> | undefined> => {\n const queue = this.queues.get(queueId);\n\n if (!queue) {\n this.log('Queue not found', { 'Queue ID': queueId });\n\n return;\n }\n\n const job = (await queue.add(jobId, data)) as Job<QueueJobData<TPayload, TMetadata>, TResult, TName>;\n\n const dataStr = JSON.stringify(data);\n\n const maxLogDataStrLength = 50;\n const truncatedLogDataStr =\n dataStr.length > maxLogDataStrLength ? `${dataStr.substring(0, maxLogDataStrLength)}...` : dataStr;\n\n if (this.applicationConfig.queue.log?.jobAdded) {\n this.log('Job added', {\n Queue: queueId,\n 'Job ID': jobId,\n Data: truncatedLogDataStr,\n });\n }\n\n return job;\n };\n\n private workerProcessor = async (job: Job): Promise<unknown> => {\n if (!job) {\n return;\n }\n\n const startTime = Time.now();\n\n // Add start time to job data\n if (typeof job.updateData === 'function') {\n try {\n await job.updateData({ ...job.data, startTime });\n } catch (error) {\n Logger.warn({\n message: 'Failed to persist job metadata before processing',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: error instanceof Error ? error.message : String(error),\n },\n });\n }\n }\n\n this.log('Worker processing...', {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n });\n\n const processor = this.jobProcessors.get(job.name);\n\n if (!processor) {\n throw new Error(`No processor registered for job (Name: ${job.name})`);\n }\n\n let result: unknown;\n let error: Error | undefined;\n\n try {\n // Call beforeProcess hook\n await processor.beforeProcess({ job });\n\n // Execute main processing\n result = await processor.process({ job });\n\n return result;\n } catch (err) {\n error = err as Error;\n\n Logger.warn({\n message: 'Queue worker processing error',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: error.message,\n },\n });\n\n Logger.error({ error });\n\n throw error; // Re-throw to mark job as failed\n } finally {\n // ALWAYS call afterProcess for cleanup (even on error)\n try {\n await processor.afterProcess({ job, result, error });\n } catch (cleanupError) {\n // Log but don't throw - cleanup errors shouldn't fail the job\n Logger.error({\n error: cleanupError,\n message: 'Error in processor afterProcess cleanup',\n });\n }\n }\n };\n\n public async listAllJobsWithStatus(): Promise<JobSummary[]> {\n const jobsSummary: JobSummary[] = [];\n\n for (const [queueName, queue] of this.queues) {\n const jobStates = ['active', 'waiting', 'completed', 'failed', 'delayed', 'paused'] as const;\n\n const jobsDetailsPromises = jobStates.map(async state => {\n const jobs = await queue.getJobs([state]);\n return jobs.map(\n (job): JobSummary => ({\n id: job.id ?? 'unknown',\n name: job.name ?? 'unknown',\n queueName,\n state,\n attemptsMade: job.attemptsMade,\n failedReason: job.failedReason,\n }),\n );\n });\n\n const results = await Promise.all(jobsDetailsPromises);\n const flattenedResults = results.flat();\n\n jobsSummary.push(...flattenedResults);\n }\n\n return jobsSummary;\n }\n\n /**\n * Log queue message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'queue', message, meta });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["error"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Job } from 'bullmq';
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/core';
|
|
2
3
|
import type { QueueManager } from '../../queue/index.js';
|
|
3
4
|
import type { DatabaseInstance } from '../../database/index.js';
|
|
4
5
|
import type { ApplicationConfig } from '../../application/base-application.interface.js';
|
|
@@ -16,6 +17,51 @@ export default abstract class BaseProcessor<TQueueManager extends QueueManager =
|
|
|
16
17
|
abstract process({ job }: {
|
|
17
18
|
job: Job<TJobData, TResult>;
|
|
18
19
|
}): Promise<TResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Called before process() - override for setup logic
|
|
22
|
+
* Perfect place to fork EntityManager, open connections, etc.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* async beforeProcess({ job }) {
|
|
26
|
+
* this.jobEntityManager = this.databaseInstance.getEntityManager();
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
beforeProcess({ job }: {
|
|
30
|
+
job: Job<TJobData, TResult>;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Called after process() completes - override for cleanup
|
|
34
|
+
* Perfect place to clear EntityManager, close connections, etc.
|
|
35
|
+
* ALWAYS called even if process() throws an error
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* async afterProcess({ job }) {
|
|
39
|
+
* if (this.jobEntityManager) {
|
|
40
|
+
* this.jobEntityManager.clear();
|
|
41
|
+
* delete this.jobEntityManager;
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
*/
|
|
45
|
+
afterProcess({ job, result, error, }: {
|
|
46
|
+
job: Job<TJobData, TResult>;
|
|
47
|
+
result?: TResult;
|
|
48
|
+
error?: Error;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Convenience method: Execute callback with automatic EntityManager lifecycle
|
|
52
|
+
* Creates fork before, cleans up after (even on error)
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* class MyProcessor extends BaseProcessor {
|
|
56
|
+
* async process({ job }) {
|
|
57
|
+
* return this.withEntityManager(async (em) => {
|
|
58
|
+
* const user = await em.findOne('User', { id: job.data.userId });
|
|
59
|
+
* return user;
|
|
60
|
+
* });
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
*/
|
|
64
|
+
protected withEntityManager<T>(callback: (em: EntityManager) => Promise<T>): Promise<T>;
|
|
19
65
|
/**
|
|
20
66
|
* Enhanced logger with structured methods
|
|
21
67
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/queue/processor/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAEzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,YAAY,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa,CACzC,aAAa,SAAS,YAAY,GAAG,YAAY,EACjD,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,GAAG,OAAO;IAKf,SAAS,CAAC,YAAY,EAAE,aAAa;IACrC,SAAS,CAAC,iBAAiB,EAAE,iBAAiB;IAC9C,SAAS,CAAC,aAAa,EAAE,aAAa;IACtC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI;IACnD,SAAS,CAAC,YAAY,CAAC,EAAE,YAAY;IAPvC,OAAO,CAAC,MAAM,CAAyB;gBAG3B,YAAY,EAAE,aAAa,EAC3B,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,EACzC,YAAY,CAAC,EAAE,YAAY,YAAA;aAGvB,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE;QAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAEnF;;OAEG;IACI,GAAG;uBACO,KAAK,GAAG,OAAO,YAAY,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;wBAavE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;wBAI7C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;yBAI5C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;MAG9D;CACH"}
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/queue/processor/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAEzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,YAAY,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa,CACzC,aAAa,SAAS,YAAY,GAAG,YAAY,EACjD,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,GAAG,OAAO;IAKf,SAAS,CAAC,YAAY,EAAE,aAAa;IACrC,SAAS,CAAC,iBAAiB,EAAE,iBAAiB;IAC9C,SAAS,CAAC,aAAa,EAAE,aAAa;IACtC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI;IACnD,SAAS,CAAC,YAAY,CAAC,EAAE,YAAY;IAPvC,OAAO,CAAC,MAAM,CAAyB;gBAG3B,YAAY,EAAE,aAAa,EAC3B,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,aAAa,EAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,EACzC,YAAY,CAAC,EAAE,YAAY,YAAA;aAGvB,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE;QAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAEnF;;;;;;;;OAQG;IACU,aAAa,CAAC,EAAE,GAAG,EAAE,EAAE;QAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAInF;;;;;;;;;;;;OAYG;IACU,YAAY,CAAC,EACxB,GAAG,EACH,MAAM,EACN,KAAK,GACN,EAAE;QACD,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,KAAK,CAAC;KACf,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjB;;;;;;;;;;;;;OAaG;cACa,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAO7F;;OAEG;IACI,GAAG;uBACO,KAAK,GAAG,OAAO,YAAY,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;wBAavE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;wBAI7C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;yBAI5C,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,IAAI;MAG9D;CACH"}
|
|
@@ -14,6 +14,56 @@ class BaseProcessor {
|
|
|
14
14
|
__name(this, "BaseProcessor");
|
|
15
15
|
}
|
|
16
16
|
logger = Logger;
|
|
17
|
+
/**
|
|
18
|
+
* Called before process() - override for setup logic
|
|
19
|
+
* Perfect place to fork EntityManager, open connections, etc.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* async beforeProcess({ job }) {
|
|
23
|
+
* this.jobEntityManager = this.databaseInstance.getEntityManager();
|
|
24
|
+
* }
|
|
25
|
+
*/
|
|
26
|
+
async beforeProcess({ job }) {
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Called after process() completes - override for cleanup
|
|
30
|
+
* Perfect place to clear EntityManager, close connections, etc.
|
|
31
|
+
* ALWAYS called even if process() throws an error
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* async afterProcess({ job }) {
|
|
35
|
+
* if (this.jobEntityManager) {
|
|
36
|
+
* this.jobEntityManager.clear();
|
|
37
|
+
* delete this.jobEntityManager;
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
*/
|
|
41
|
+
async afterProcess({
|
|
42
|
+
job,
|
|
43
|
+
result,
|
|
44
|
+
error
|
|
45
|
+
}) {
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Convenience method: Execute callback with automatic EntityManager lifecycle
|
|
49
|
+
* Creates fork before, cleans up after (even on error)
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* class MyProcessor extends BaseProcessor {
|
|
53
|
+
* async process({ job }) {
|
|
54
|
+
* return this.withEntityManager(async (em) => {
|
|
55
|
+
* const user = await em.findOne('User', { id: job.data.userId });
|
|
56
|
+
* return user;
|
|
57
|
+
* });
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
*/
|
|
61
|
+
async withEntityManager(callback) {
|
|
62
|
+
if (!this.databaseInstance) {
|
|
63
|
+
throw new Error("Database not available");
|
|
64
|
+
}
|
|
65
|
+
return this.databaseInstance.withEntityManager(callback);
|
|
66
|
+
}
|
|
17
67
|
/**
|
|
18
68
|
* Enhanced logger with structured methods
|
|
19
69
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/queue/processor/base.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Job } from 'bullmq';\nimport type { QueueManager } from '../../queue/index.js';\nimport type { DatabaseInstance } from '../../database/index.js';\nimport type { ApplicationConfig } from '../../application/base-application.interface.js';\nimport { Logger } from '../../logger/index.js';\nimport type { RedisInstance } from '../../redis/index.js';\nimport type EventManager from '../../event/manager.js';\nimport type { QueueJobData } from '../job.interface.js';\nimport { safeSerializeError } from '../../error/error-reporter.js';\n\nexport default abstract class BaseProcessor<\n TQueueManager extends QueueManager = QueueManager,\n TJobData extends QueueJobData = QueueJobData,\n TResult = unknown,\n> {\n private logger: typeof Logger = Logger;\n\n constructor(\n protected queueManager: TQueueManager,\n protected applicationConfig: ApplicationConfig,\n protected redisInstance: RedisInstance,\n protected databaseInstance: DatabaseInstance | null,\n protected eventManager?: EventManager,\n ) {}\n\n public abstract process({ job }: { job: Job<TJobData, TResult> }): Promise<TResult>;\n\n /**\n * Enhanced logger with structured methods\n */\n public log = {\n error: (error: Error | unknown, message?: string, meta?: Record<string, unknown>): void => {\n if (message) {\n const errorMeta = {\n ...(meta ?? {}),\n error: error instanceof Error ? error.message : safeSerializeError(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n this.logger.custom({ level: 'queueJob', message, meta: errorMeta });\n } else {\n this.logger.custom({ level: 'queueJob', message: error });\n }\n },\n\n info: (message: string, meta?: Record<string, unknown>): void => {\n this.logger.custom({ level: 'queueJob', message, meta });\n },\n\n warn: (message: string, meta?: Record<string, unknown>): void => {\n this.logger.custom({ level: 'queueJob', message, meta });\n },\n\n debug: (message: string, meta?: Record<string, unknown>): void => {\n this.logger.custom({ level: 'queueJob', message, meta });\n },\n };\n}\n"],
|
|
5
|
-
"mappings": ";;
|
|
4
|
+
"sourcesContent": ["import type { Job } from 'bullmq';\nimport type { EntityManager } from '@mikro-orm/core';\nimport type { QueueManager } from '../../queue/index.js';\nimport type { DatabaseInstance } from '../../database/index.js';\nimport type { ApplicationConfig } from '../../application/base-application.interface.js';\nimport { Logger } from '../../logger/index.js';\nimport type { RedisInstance } from '../../redis/index.js';\nimport type EventManager from '../../event/manager.js';\nimport type { QueueJobData } from '../job.interface.js';\nimport { safeSerializeError } from '../../error/error-reporter.js';\n\nexport default abstract class BaseProcessor<\n TQueueManager extends QueueManager = QueueManager,\n TJobData extends QueueJobData = QueueJobData,\n TResult = unknown,\n> {\n private logger: typeof Logger = Logger;\n\n constructor(\n protected queueManager: TQueueManager,\n protected applicationConfig: ApplicationConfig,\n protected redisInstance: RedisInstance,\n protected databaseInstance: DatabaseInstance | null,\n protected eventManager?: EventManager,\n ) {}\n\n public abstract process({ job }: { job: Job<TJobData, TResult> }): Promise<TResult>;\n\n /**\n * Called before process() - override for setup logic\n * Perfect place to fork EntityManager, open connections, etc.\n *\n * @example\n * async beforeProcess({ job }) {\n * this.jobEntityManager = this.databaseInstance.getEntityManager();\n * }\n */\n public async beforeProcess({ job }: { job: Job<TJobData, TResult> }): Promise<void> {\n // Default: no-op\n }\n\n /**\n * Called after process() completes - override for cleanup\n * Perfect place to clear EntityManager, close connections, etc.\n * ALWAYS called even if process() throws an error\n *\n * @example\n * async afterProcess({ job }) {\n * if (this.jobEntityManager) {\n * this.jobEntityManager.clear();\n * delete this.jobEntityManager;\n * }\n * }\n */\n public async afterProcess({\n job,\n result,\n error,\n }: {\n job: Job<TJobData, TResult>;\n result?: TResult;\n error?: Error;\n }): Promise<void> {\n // Default: no-op\n }\n\n /**\n * Convenience method: Execute callback with automatic EntityManager lifecycle\n * Creates fork before, cleans up after (even on error)\n *\n * @example\n * class MyProcessor extends BaseProcessor {\n * async process({ job }) {\n * return this.withEntityManager(async (em) => {\n * const user = await em.findOne('User', { id: job.data.userId });\n * return user;\n * });\n * }\n * }\n */\n protected async withEntityManager<T>(callback: (em: EntityManager) => Promise<T>): Promise<T> {\n if (!this.databaseInstance) {\n throw new Error('Database not available');\n }\n return this.databaseInstance.withEntityManager(callback);\n }\n\n /**\n * Enhanced logger with structured methods\n */\n public log = {\n error: (error: Error | unknown, message?: string, meta?: Record<string, unknown>): void => {\n if (message) {\n const errorMeta = {\n ...(meta ?? {}),\n error: error instanceof Error ? error.message : safeSerializeError(error),\n stack: error instanceof Error ? error.stack : undefined,\n };\n this.logger.custom({ level: 'queueJob', message, meta: errorMeta });\n } else {\n this.logger.custom({ level: 'queueJob', message: error });\n }\n },\n\n info: (message: string, meta?: Record<string, unknown>): void => {\n this.logger.custom({ level: 'queueJob', message, meta });\n },\n\n warn: (message: string, meta?: Record<string, unknown>): void => {\n this.logger.custom({ level: 'queueJob', message, meta });\n },\n\n debug: (message: string, meta?: Record<string, unknown>): void => {\n this.logger.custom({ level: 'queueJob', message, meta });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": ";;AAKA,SAAS,cAAc;AAIvB,SAAS,0BAA0B;AAEnC,MAAO,cAIL;AAAA,EAGA,YACY,cACA,mBACA,eACA,kBACA,cACV;AALU;AACA;AACA;AACA;AACA;AAAA,EACT;AAAA,EAxBL,OAeE;AAAA;AAAA;AAAA,EACQ,SAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBhC,MAAa,cAAc,EAAE,IAAI,GAAmD;AAAA,EAEpF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAa,aAAa;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIkB;AAAA,EAElB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAgB,kBAAqB,UAAyD;AAC5F,QAAI,CAAC,KAAK,kBAAkB;AAC1B,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AACA,WAAO,KAAK,iBAAiB,kBAAkB,QAAQ;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKO,MAAM;AAAA,IACX,OAAO,wBAAC,OAAwB,SAAkB,SAAyC;AACzF,UAAI,SAAS;AACX,cAAM,YAAY;AAAA,UAChB,GAAI,QAAQ,CAAC;AAAA,UACb,OAAO,iBAAiB,QAAQ,MAAM,UAAU,mBAAmB,KAAK;AAAA,UACxE,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,QAChD;AACA,aAAK,OAAO,OAAO,EAAE,OAAO,YAAY,SAAS,MAAM,UAAU,CAAC;AAAA,MACpE,OAAO;AACL,aAAK,OAAO,OAAO,EAAE,OAAO,YAAY,SAAS,MAAM,CAAC;AAAA,MAC1D;AAAA,IACF,GAXO;AAAA,IAaP,MAAM,wBAAC,SAAiB,SAAyC;AAC/D,WAAK,OAAO,OAAO,EAAE,OAAO,YAAY,SAAS,KAAK,CAAC;AAAA,IACzD,GAFM;AAAA,IAIN,MAAM,wBAAC,SAAiB,SAAyC;AAC/D,WAAK,OAAO,OAAO,EAAE,OAAO,YAAY,SAAS,KAAK,CAAC;AAAA,IACzD,GAFM;AAAA,IAIN,OAAO,wBAAC,SAAiB,SAAyC;AAChE,WAAK,OAAO,OAAO,EAAE,OAAO,YAAY,SAAS,KAAK,CAAC;AAAA,IACzD,GAFO;AAAA,EAGT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,12 +3,16 @@ import type { EntityManager } from '@mikro-orm/core';
|
|
|
3
3
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
|
4
4
|
import BaseController from './base.js';
|
|
5
5
|
import type { DynamicEntity } from '../../database/dynamic-entity.js';
|
|
6
|
-
import type { WebServerBaseControllerConstructorParams } from './base.interface.js';
|
|
7
6
|
export default abstract class EntityController extends BaseController {
|
|
8
7
|
protected abstract entityName: string;
|
|
9
|
-
protected entityManager: EntityManager;
|
|
10
8
|
private static entityCache;
|
|
11
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Get request-scoped EntityManager with automatic cleanup
|
|
11
|
+
* Creates a new EM fork per request, cleaned up after response
|
|
12
|
+
*
|
|
13
|
+
* @internal Used by route handlers, do not call directly
|
|
14
|
+
*/
|
|
15
|
+
private getRequestEntityManager;
|
|
12
16
|
protected getEntity: () => Promise<typeof DynamicEntity | undefined>;
|
|
13
17
|
private getEntityProperties;
|
|
14
18
|
options: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/webserver/controller/entity.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAyB,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE5D,OAAO,cAAc,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/webserver/controller/entity.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,13 +10,19 @@ class EntityController extends BaseController {
|
|
|
10
10
|
static {
|
|
11
11
|
__name(this, "EntityController");
|
|
12
12
|
}
|
|
13
|
-
entityManager;
|
|
14
13
|
// Cache for entity modules to avoid repeated dynamic imports
|
|
15
14
|
static entityCache = /* @__PURE__ */ new Map();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Get request-scoped EntityManager with automatic cleanup
|
|
17
|
+
* Creates a new EM fork per request, cleaned up after response
|
|
18
|
+
*
|
|
19
|
+
* @internal Used by route handlers, do not call directly
|
|
20
|
+
*/
|
|
21
|
+
getRequestEntityManager(request) {
|
|
22
|
+
if (!request.__entityManager) {
|
|
23
|
+
request.__entityManager = this.databaseInstance.getEntityManager();
|
|
24
|
+
}
|
|
25
|
+
return request.__entityManager;
|
|
20
26
|
}
|
|
21
27
|
getEntity = /* @__PURE__ */ __name(async () => {
|
|
22
28
|
if (this.applicationConfig.database?.enabled !== true) {
|
|
@@ -96,8 +102,9 @@ class EntityController extends BaseController {
|
|
|
96
102
|
}
|
|
97
103
|
getMany = /* @__PURE__ */ __name(async (request, reply) => {
|
|
98
104
|
try {
|
|
105
|
+
const em = this.getRequestEntityManager(request);
|
|
99
106
|
await this.preGetMany({
|
|
100
|
-
entityManager:
|
|
107
|
+
entityManager: em,
|
|
101
108
|
request,
|
|
102
109
|
reply
|
|
103
110
|
});
|
|
@@ -198,7 +205,7 @@ class EntityController extends BaseController {
|
|
|
198
205
|
});
|
|
199
206
|
}
|
|
200
207
|
const populate = request.query.populate ? request.query.populate.split(",") : [];
|
|
201
|
-
const [items, total] = await
|
|
208
|
+
const [items, total] = await em.findAndCount(this.entityName, options.filters, {
|
|
202
209
|
limit: options.limit,
|
|
203
210
|
offset: options.offset,
|
|
204
211
|
orderBy: options.orderBy,
|
|
@@ -213,7 +220,7 @@ class EntityController extends BaseController {
|
|
|
213
220
|
limit: limit > 0 ? limit : total
|
|
214
221
|
};
|
|
215
222
|
await this.postGetMany({
|
|
216
|
-
entityManager:
|
|
223
|
+
entityManager: em,
|
|
217
224
|
request,
|
|
218
225
|
reply,
|
|
219
226
|
data
|
|
@@ -235,8 +242,9 @@ class EntityController extends BaseController {
|
|
|
235
242
|
}
|
|
236
243
|
getOne = /* @__PURE__ */ __name(async (request, reply) => {
|
|
237
244
|
try {
|
|
245
|
+
const em = this.getRequestEntityManager(request);
|
|
238
246
|
await this.preGetOne({
|
|
239
|
-
entityManager:
|
|
247
|
+
entityManager: em,
|
|
240
248
|
request,
|
|
241
249
|
reply
|
|
242
250
|
});
|
|
@@ -249,12 +257,12 @@ class EntityController extends BaseController {
|
|
|
249
257
|
return;
|
|
250
258
|
}
|
|
251
259
|
const id = request.params.id;
|
|
252
|
-
const item = await
|
|
260
|
+
const item = await em.findOne(this.entityName, { id }, { populate });
|
|
253
261
|
if (!item) {
|
|
254
262
|
return this.sendNotFoundResponse(reply, `${EntityClass.singularNameCapitalized} not found`);
|
|
255
263
|
}
|
|
256
264
|
await this.postGetOne({
|
|
257
|
-
entityManager:
|
|
265
|
+
entityManager: em,
|
|
258
266
|
request,
|
|
259
267
|
reply,
|
|
260
268
|
item
|
|
@@ -274,6 +282,7 @@ class EntityController extends BaseController {
|
|
|
274
282
|
}
|
|
275
283
|
createOne = /* @__PURE__ */ __name(async (request, reply) => {
|
|
276
284
|
try {
|
|
285
|
+
const em = this.getRequestEntityManager(request);
|
|
277
286
|
const EntityClass = await this.getEntity();
|
|
278
287
|
if (!EntityClass) {
|
|
279
288
|
this.sendErrorResponse({ reply, error: "Entity not found" });
|
|
@@ -292,10 +301,10 @@ class EntityController extends BaseController {
|
|
|
292
301
|
if (error) {
|
|
293
302
|
return this.sendErrorResponse({ reply, error: error.message });
|
|
294
303
|
}
|
|
295
|
-
const item =
|
|
296
|
-
await
|
|
304
|
+
const item = em.create(this.entityName, value);
|
|
305
|
+
await em.persistAndFlush(item);
|
|
297
306
|
await this.postCreateOne({
|
|
298
|
-
entityManager:
|
|
307
|
+
entityManager: em,
|
|
299
308
|
request,
|
|
300
309
|
reply,
|
|
301
310
|
item
|
|
@@ -309,6 +318,7 @@ class EntityController extends BaseController {
|
|
|
309
318
|
}
|
|
310
319
|
updateOne = /* @__PURE__ */ __name(async (request, reply) => {
|
|
311
320
|
try {
|
|
321
|
+
const em = this.getRequestEntityManager(request);
|
|
312
322
|
const EntityClass = await this.getEntity();
|
|
313
323
|
if (!EntityClass) {
|
|
314
324
|
this.sendErrorResponse({ reply, error: "Entity not found" });
|
|
@@ -319,14 +329,14 @@ class EntityController extends BaseController {
|
|
|
319
329
|
if (error) {
|
|
320
330
|
return this.sendErrorResponse({ reply, error: error.message });
|
|
321
331
|
}
|
|
322
|
-
const item = await
|
|
332
|
+
const item = await em.findOne(this.entityName, { id });
|
|
323
333
|
if (!item) {
|
|
324
334
|
return this.sendNotFoundResponse(reply, `${EntityClass.singularNameCapitalized} not found`);
|
|
325
335
|
}
|
|
326
|
-
|
|
327
|
-
await
|
|
336
|
+
em.assign(item, value);
|
|
337
|
+
await em.persistAndFlush(item);
|
|
328
338
|
await this.postUpdateOne({
|
|
329
|
-
entityManager:
|
|
339
|
+
entityManager: em,
|
|
330
340
|
request,
|
|
331
341
|
reply,
|
|
332
342
|
item
|
|
@@ -338,17 +348,18 @@ class EntityController extends BaseController {
|
|
|
338
348
|
}, "updateOne");
|
|
339
349
|
deleteOne = /* @__PURE__ */ __name(async (request, reply) => {
|
|
340
350
|
try {
|
|
351
|
+
const em = this.getRequestEntityManager(request);
|
|
341
352
|
const EntityClass = await this.getEntity();
|
|
342
353
|
if (!EntityClass) {
|
|
343
354
|
this.sendErrorResponse({ reply, error: "Entity not found" });
|
|
344
355
|
return;
|
|
345
356
|
}
|
|
346
357
|
const id = request.params.id;
|
|
347
|
-
const item = await
|
|
358
|
+
const item = await em.findOne(this.entityName, { id });
|
|
348
359
|
if (!item) {
|
|
349
360
|
return this.sendNotFoundResponse(reply, `${EntityClass.singularNameCapitalized} not found`);
|
|
350
361
|
}
|
|
351
|
-
await
|
|
362
|
+
await em.removeAndFlush(item);
|
|
352
363
|
reply.status(StatusCodes.NO_CONTENT).send();
|
|
353
364
|
} catch (error) {
|
|
354
365
|
this.sendErrorResponse({ reply, error });
|