@common-stack/store-mongo 7.2.1-alpha.5 → 7.2.1-alpha.63

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.
@@ -1,7 +1,40 @@
1
1
  import DataLoader from 'dataloader';
2
2
  import { IBaseService, IDataLoader, AsDomainType } from 'common/server';
3
+ /**
4
+ * BulkDataLoader2 with Dual ID System Support
5
+ *
6
+ * Supports both ObjectId and UUID lookups:
7
+ * - ObjectId: MongoDB's native `_id` field
8
+ * - UUID: External identifier stored as `<collection>Id` (e.g., projectId, organizationId)
9
+ *
10
+ * The loader automatically detects the ID format and queries appropriately:
11
+ * - UUIDs contain hyphens (e.g., "550e8400-e29b-41d4-a957-446655440000")
12
+ * - ObjectIds are 24-character hex strings (e.g., "507f1f77bcf86cd799439011")
13
+ */
3
14
  export declare class BulkDataLoader2<SchemaType> extends DataLoader<string, AsDomainType<SchemaType> | null> implements IDataLoader<SchemaType> {
4
15
  private readonly service;
5
- constructor(service: IBaseService<SchemaType>);
16
+ /**
17
+ * Optional UUID field name for this collection (e.g., 'projectId', 'organizationId')
18
+ * If not provided, the loader will only support ObjectId lookups
19
+ */
20
+ private readonly uuidFieldName?;
21
+ constructor(service: IBaseService<SchemaType>, uuidFieldName?: string);
22
+ /**
23
+ * Detects if an ID is a UUID (contains hyphens) or ObjectId (24-char hex)
24
+ */
25
+ private isUUID;
26
+ /**
27
+ * Detects if an ID is a valid ObjectId
28
+ */
29
+ private isObjectId;
30
+ /**
31
+ * Loads records by IDs, supporting both UUID and ObjectId formats
32
+ * Performs a single query with $or conditions for efficient lookup
33
+ */
34
+ private loadByIds;
35
+ /**
36
+ * Finds a record by ID, checking both ObjectId and UUID fields
37
+ */
38
+ private findRecordById;
6
39
  withOptions: DataLoader<DataLoaderOptions<SchemaType>, AsDomainType<SchemaType>[], DataLoaderOptions<SchemaType>>;
7
40
  }
@@ -1,12 +1,95 @@
1
- import {__decorate,__param,__metadata}from'tslib';import DataLoader from'dataloader';import {injectable,unmanaged}from'inversify';import {IBaseService}from'common/server';var _a;
1
+ import {__decorate,__param,__metadata}from'tslib';import DataLoader from'dataloader';import {injectable,unmanaged}from'inversify';import {Types}from'mongoose';import {IBaseService}from'common/server';var _a;
2
+ /**
3
+ * BulkDataLoader2 with Dual ID System Support
4
+ *
5
+ * Supports both ObjectId and UUID lookups:
6
+ * - ObjectId: MongoDB's native `_id` field
7
+ * - UUID: External identifier stored as `<collection>Id` (e.g., projectId, organizationId)
8
+ *
9
+ * The loader automatically detects the ID format and queries appropriately:
10
+ * - UUIDs contain hyphens (e.g., "550e8400-e29b-41d4-a957-446655440000")
11
+ * - ObjectIds are 24-character hex strings (e.g., "507f1f77bcf86cd799439011")
12
+ */
2
13
  let BulkDataLoader2 = class BulkDataLoader2 extends DataLoader {
3
14
  service;
4
- constructor(service) {
15
+ /**
16
+ * Optional UUID field name for this collection (e.g., 'projectId', 'organizationId')
17
+ * If not provided, the loader will only support ObjectId lookups
18
+ */
19
+ uuidFieldName;
20
+ constructor(service, uuidFieldName) {
5
21
  super(async (ids) => {
6
- const data = await this.service.getByIds(ids);
7
- return ids.map((id) => data.find((record) => record.id === id) || null);
22
+ const data = await this.loadByIds(ids);
23
+ return ids.map((id) => this.findRecordById(data, id));
8
24
  });
9
25
  this.service = service;
26
+ this.uuidFieldName = uuidFieldName;
27
+ }
28
+ /**
29
+ * Detects if an ID is a UUID (contains hyphens) or ObjectId (24-char hex)
30
+ */
31
+ isUUID(id) {
32
+ return id.includes('-');
33
+ }
34
+ /**
35
+ * Detects if an ID is a valid ObjectId
36
+ */
37
+ isObjectId(id) {
38
+ return Types.ObjectId.isValid(id) && !this.isUUID(id);
39
+ }
40
+ /**
41
+ * Loads records by IDs, supporting both UUID and ObjectId formats
42
+ * Performs a single query with $or conditions for efficient lookup
43
+ */
44
+ async loadByIds(ids) {
45
+ // Separate UUIDs and ObjectIds for optimized querying
46
+ const uuidIds = [];
47
+ const objectIds = [];
48
+ ids.forEach((id) => {
49
+ if (this.isUUID(id)) {
50
+ uuidIds.push(id);
51
+ }
52
+ else if (this.isObjectId(id)) {
53
+ objectIds.push(id);
54
+ }
55
+ });
56
+ // If no UUID field is configured, only support ObjectId lookups
57
+ if (!this.uuidFieldName && uuidIds.length > 0) {
58
+ console.warn(`[BulkDataLoader2] UUID IDs detected but no uuidFieldName configured. UUIDs will not be resolved: ${uuidIds.join(', ')}`);
59
+ }
60
+ // Build query criteria using $or for mixed ID types
61
+ const criteria = [];
62
+ if (objectIds.length > 0) {
63
+ // Query by _id (ObjectId)
64
+ criteria.push({ _id: { $in: objectIds } });
65
+ }
66
+ if (uuidIds.length > 0 && this.uuidFieldName) {
67
+ // Query by UUID field (e.g., projectId, organizationId)
68
+ criteria.push({ [this.uuidFieldName]: { $in: uuidIds } });
69
+ }
70
+ // If no valid IDs, return empty array
71
+ if (criteria.length === 0) {
72
+ return [];
73
+ }
74
+ // Execute query with $or combining both lookup strategies
75
+ const query = criteria.length === 1 ? criteria[0] : { $or: criteria };
76
+ return await this.service.getAll({ criteria: query });
77
+ }
78
+ /**
79
+ * Finds a record by ID, checking both ObjectId and UUID fields
80
+ */
81
+ findRecordById(records, id) {
82
+ return (records.find((record) => {
83
+ // Check if ID matches the record's id field (transformed from _id)
84
+ if (record.id === id) {
85
+ return true;
86
+ }
87
+ // If UUID field is configured, check that field too
88
+ if (this.uuidFieldName && record[this.uuidFieldName] === id) {
89
+ return true;
90
+ }
91
+ return false;
92
+ }) || null);
10
93
  }
11
94
  withOptions = new DataLoader(async (options) => {
12
95
  const [{ searchKey, comparator, ...rest }] = options;
@@ -30,5 +113,6 @@ let BulkDataLoader2 = class BulkDataLoader2 extends DataLoader {
30
113
  BulkDataLoader2 = __decorate([
31
114
  injectable(),
32
115
  __param(0, unmanaged()),
33
- __metadata("design:paramtypes", [typeof (_a = typeof IBaseService !== "undefined" && IBaseService) === "function" ? _a : Object])
116
+ __param(1, unmanaged()),
117
+ __metadata("design:paramtypes", [typeof (_a = typeof IBaseService !== "undefined" && IBaseService) === "function" ? _a : Object, String])
34
118
  ], BulkDataLoader2);export{BulkDataLoader2};//# sourceMappingURL=bulk-dataloader-v2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-dataloader-v2.js","sources":["../../src/dataloaders/bulk-dataloader-v2.ts"],"sourcesContent":["/* eslint-disable import/no-extraneous-dependencies */\nimport DataLoader from 'dataloader';\nimport { injectable, unmanaged } from 'inversify';\nimport { FilterQuery } from 'mongoose';\nimport { IBaseService, IDataLoader, AsDomainType, DataLoaderOptions } from 'common/server';\n\n@injectable()\nexport class BulkDataLoader2<SchemaType>\n extends DataLoader<string, AsDomainType<SchemaType> | null>\n implements IDataLoader<SchemaType>\n{\n constructor(@unmanaged() private readonly service: IBaseService<SchemaType>) {\n super(async (ids: string[]) => {\n const data = await this.service.getByIds(ids);\n return ids.map((id) => data.find((record) => record.id === id) || null);\n });\n }\n\n withOptions = new DataLoader<DataLoaderOptions<SchemaType>, AsDomainType<SchemaType>[]>(async (options) => {\n const [{ searchKey, comparator, ...rest }] = options;\n const ids = options.map((option) => option.id);\n\n // Create a properly typed criteria object with explicit type assertion\n const criteria = {\n ...(rest.criteria || {}),\n [searchKey as string]: { $in: ids },\n } as FilterQuery<SchemaType>;\n\n const results = await this.service.getAll({\n ...rest,\n criteria,\n });\n\n return options.map((option) =>\n results.filter((item) => {\n if (typeof comparator === 'function') return comparator(option, item);\n return item[searchKey as keyof AsDomainType<SchemaType>]?.toString() === option.id.toString();\n }),\n );\n });\n}\n"],"names":[],"mappings":";AAOO,IAAM,eAAe,GAArB,MAAM,eACT,SAAQ,UAAmD,CAAA;AAGjB,IAAA,OAAA,CAAA;AAA1C,IAAA,WAAA,CAA0C,OAAiC,EAAA;AACvE,QAAA,KAAK,CAAC,OAAO,GAAa,KAAI;YAC1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC9C,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC;AAC5E,SAAC,CAAC,CAAC;QAJmC,IAAO,CAAA,OAAA,GAAP,OAAO,CAA0B;KAK1E;IAED,WAAW,GAAG,IAAI,UAAU,CAA4D,OAAO,OAAO,KAAI;AACtG,QAAA,MAAM,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;AACrD,QAAA,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;;AAG/C,QAAA,MAAM,QAAQ,GAAG;AACb,YAAA,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AACxB,YAAA,CAAC,SAAmB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;SACX,CAAC;QAE7B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;AACtC,YAAA,GAAG,IAAI;YACP,QAAQ;AACX,SAAA,CAAC,CAAC;AAEH,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,KACtB,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,KAAI;YACpB,IAAI,OAAO,UAAU,KAAK,UAAU;AAAE,gBAAA,OAAO,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACtE,YAAA,OAAO,IAAI,CAAC,SAA2C,CAAC,EAAE,QAAQ,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;SACjG,CAAC,CACL,CAAC;AACN,KAAC,CAAC,CAAC;EACN;AAjCY,eAAe,GAAA,UAAA,CAAA;AAD3B,IAAA,UAAU,EAAE;IAKI,OAAA,CAAA,CAAA,EAAA,SAAS,EAAE,CAAA;AAA2B,IAAA,UAAA,CAAA,mBAAA,EAAA,CAAA,QAAA,EAAA,GAAA,OAAA,YAAY,oBAAZ,YAAY,CAAA,KAAA,UAAA,GAAA,EAAA,GAAA,MAAA,CAAA,CAAA;AAJtD,CAAA,EAAA,eAAe,CAiC3B"}
1
+ {"version":3,"file":"bulk-dataloader-v2.js","sources":["../../src/dataloaders/bulk-dataloader-v2.ts"],"sourcesContent":["/* eslint-disable import/no-extraneous-dependencies */\nimport DataLoader from 'dataloader';\nimport { injectable, unmanaged } from 'inversify';\nimport { FilterQuery, Types } from 'mongoose';\nimport { IBaseService, IDataLoader, AsDomainType, DataLoaderOptions } from 'common/server';\n\n/**\n * BulkDataLoader2 with Dual ID System Support\n *\n * Supports both ObjectId and UUID lookups:\n * - ObjectId: MongoDB's native `_id` field\n * - UUID: External identifier stored as `<collection>Id` (e.g., projectId, organizationId)\n *\n * The loader automatically detects the ID format and queries appropriately:\n * - UUIDs contain hyphens (e.g., \"550e8400-e29b-41d4-a957-446655440000\")\n * - ObjectIds are 24-character hex strings (e.g., \"507f1f77bcf86cd799439011\")\n */\n@injectable()\nexport class BulkDataLoader2<SchemaType>\n extends DataLoader<string, AsDomainType<SchemaType> | null>\n implements IDataLoader<SchemaType>\n{\n /**\n * Optional UUID field name for this collection (e.g., 'projectId', 'organizationId')\n * If not provided, the loader will only support ObjectId lookups\n */\n private readonly uuidFieldName?: string;\n\n constructor(\n @unmanaged() private readonly service: IBaseService<SchemaType>,\n @unmanaged() uuidFieldName?: string,\n ) {\n super(async (ids: string[]) => {\n const data = await this.loadByIds(ids);\n return ids.map((id) => this.findRecordById(data, id));\n });\n this.uuidFieldName = uuidFieldName;\n }\n\n /**\n * Detects if an ID is a UUID (contains hyphens) or ObjectId (24-char hex)\n */\n private isUUID(id: string): boolean {\n return id.includes('-');\n }\n\n /**\n * Detects if an ID is a valid ObjectId\n */\n private isObjectId(id: string): boolean {\n return Types.ObjectId.isValid(id) && !this.isUUID(id);\n }\n\n /**\n * Loads records by IDs, supporting both UUID and ObjectId formats\n * Performs a single query with $or conditions for efficient lookup\n */\n private async loadByIds(ids: string[]): Promise<AsDomainType<SchemaType>[]> {\n // Separate UUIDs and ObjectIds for optimized querying\n const uuidIds: string[] = [];\n const objectIds: string[] = [];\n\n ids.forEach((id) => {\n if (this.isUUID(id)) {\n uuidIds.push(id);\n } else if (this.isObjectId(id)) {\n objectIds.push(id);\n }\n });\n\n // If no UUID field is configured, only support ObjectId lookups\n if (!this.uuidFieldName && uuidIds.length > 0) {\n console.warn(\n `[BulkDataLoader2] UUID IDs detected but no uuidFieldName configured. UUIDs will not be resolved: ${uuidIds.join(', ')}`,\n );\n }\n\n // Build query criteria using $or for mixed ID types\n const criteria: FilterQuery<SchemaType>[] = [];\n\n if (objectIds.length > 0) {\n // Query by _id (ObjectId)\n criteria.push({ _id: { $in: objectIds } } as FilterQuery<SchemaType>);\n }\n\n if (uuidIds.length > 0 && this.uuidFieldName) {\n // Query by UUID field (e.g., projectId, organizationId)\n criteria.push({ [this.uuidFieldName]: { $in: uuidIds } } as FilterQuery<SchemaType>);\n }\n\n // If no valid IDs, return empty array\n if (criteria.length === 0) {\n return [];\n }\n\n // Execute query with $or combining both lookup strategies\n const query: FilterQuery<SchemaType> =\n criteria.length === 1 ? criteria[0] : ({ $or: criteria } as FilterQuery<SchemaType>);\n\n return await this.service.getAll({ criteria: query });\n }\n\n /**\n * Finds a record by ID, checking both ObjectId and UUID fields\n */\n private findRecordById(records: AsDomainType<SchemaType>[], id: string): AsDomainType<SchemaType> | null {\n return (\n records.find((record) => {\n // Check if ID matches the record's id field (transformed from _id)\n if (record.id === id) {\n return true;\n }\n\n // If UUID field is configured, check that field too\n if (this.uuidFieldName && (record as any)[this.uuidFieldName] === id) {\n return true;\n }\n\n return false;\n }) || null\n );\n }\n\n withOptions = new DataLoader<DataLoaderOptions<SchemaType>, AsDomainType<SchemaType>[]>(async (options) => {\n const [{ searchKey, comparator, ...rest }] = options;\n const ids = options.map((option) => option.id);\n\n // Create a properly typed criteria object with explicit type assertion\n const criteria = {\n ...(rest.criteria || {}),\n [searchKey as string]: { $in: ids },\n } as FilterQuery<SchemaType>;\n\n const results = await this.service.getAll({\n ...rest,\n criteria,\n });\n\n return options.map((option) =>\n results.filter((item) => {\n if (typeof comparator === 'function') return comparator(option, item);\n return item[searchKey as keyof AsDomainType<SchemaType>]?.toString() === option.id.toString();\n }),\n );\n });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import 'reflect-metadata';
package/lib/module.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- import { Feature } from '@common-stack/server-core';
2
- declare const _default: Feature<any, any>;
1
+ declare const _default: any;
3
2
  export default _default;
package/lib/module.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import {Feature}from'@common-stack/server-core';import {localContainerModule,externalContainerModule}from'./containers/container.js';var module = new Feature({
2
2
  createContainerFunc: [localContainerModule],
3
- createHemeraContainerFunc: [externalContainerModule],
3
+ createMicroServiceContainerFunc: [externalContainerModule],
4
4
  });export{module as default};//# sourceMappingURL=module.js.map
package/lib/module.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sources":["../src/module.ts"],"sourcesContent":["import { Feature } from '@common-stack/server-core';\nimport { externalContainerModule, localContainerModule } from './containers';\n\nexport default new Feature({\n createContainerFunc: [localContainerModule],\n createHemeraContainerFunc: [externalContainerModule],\n});\n"],"names":[],"mappings":"qIAGA,aAAe,IAAI,OAAO,CAAC;IACvB,mBAAmB,EAAE,CAAC,oBAAoB,CAAC;IAC3C,yBAAyB,EAAE,CAAC,uBAAuB,CAAC;AACvD,CAAA,CAAC"}
1
+ {"version":3,"file":"module.js","sources":["../src/module.ts"],"sourcesContent":["import { Feature } from '@common-stack/server-core';\nimport { externalContainerModule, localContainerModule } from './containers';\n\nexport default new Feature({\n createContainerFunc: [localContainerModule],\n createMicroServiceContainerFunc: [externalContainerModule],\n});\n"],"names":[],"mappings":"qIAGA,aAAe,IAAI,OAAO,CAAC;IACvB,mBAAmB,EAAE,CAAC,oBAAoB,CAAC;IAC3C,+BAA+B,EAAE,CAAC,uBAAuB,CAAC;AAC7D,CAAA,CAAC"}
@@ -0,0 +1,118 @@
1
+ /* eslint-disable @typescript-eslint/no-namespace */
2
+ /**
3
+ * @file moleculer-event-handler.ts
4
+ * @description Decorator for marking service methods as Moleculer event handlers
5
+ *
6
+ * This allows event handlers to be defined directly in the service class
7
+ * and automatically registered as Moleculer events.
8
+ */
9
+
10
+ import 'reflect-metadata';
11
+
12
+ /**
13
+ * Moleculer namespace containing event handler utilities
14
+ */
15
+ export namespace Moleculer {
16
+ /**
17
+ * Metadata key for storing event handler information
18
+ */
19
+ export const EVENT_HANDLER_METADATA_KEY = 'moleculer:eventHandler';
20
+
21
+ /**
22
+ * Event handler metadata interface
23
+ */
24
+ export interface EventHandlerMetadata {
25
+ eventName: string;
26
+ methodName: string;
27
+ group?: string;
28
+ }
29
+
30
+ /**
31
+ * Decorator for marking a service method as a Moleculer event handler
32
+ *
33
+ * @param eventName - The event name to listen for
34
+ * @param options - Optional event configuration
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * class OrganizationService implements IOrganizationService {
39
+ * @Moleculer.EventHandler(UserBroadcasterAction.OnUserCreated)
40
+ * async onUserCreated(event: IUserCreationEvent): Promise<void> {
41
+ * await this.createDefaultOrganization(event.user);
42
+ * }
43
+ *
44
+ * @Moleculer.EventHandler(OrganizationServiceAction.OnOrganizationCreated, { group: 'org-setup' })
45
+ * async onOrganizationCreated(event: IOrganizationCreatedEvent): Promise<void> {
46
+ * // Handle organization creation
47
+ * }
48
+ * }
49
+ * ```
50
+ */
51
+ export function EventHandler(
52
+ eventName: string,
53
+ options?: { group?: string }
54
+ ): MethodDecorator {
55
+ return function moleculerEventHandlerDecorator(
56
+ target: object,
57
+ propertyKey: string | symbol,
58
+ descriptor: PropertyDescriptor
59
+ ): PropertyDescriptor {
60
+ // Get existing event handlers for this class
61
+ const existingHandlers: EventHandlerMetadata[] =
62
+ Reflect.getMetadata(EVENT_HANDLER_METADATA_KEY, target.constructor) || [];
63
+
64
+ // Add this handler to the list
65
+ const metadata: EventHandlerMetadata = {
66
+ eventName,
67
+ methodName: propertyKey.toString(),
68
+ group: options?.group,
69
+ };
70
+
71
+ existingHandlers.push(metadata);
72
+
73
+ // Store the updated list
74
+ Reflect.defineMetadata(EVENT_HANDLER_METADATA_KEY, existingHandlers, target.constructor);
75
+
76
+ return descriptor;
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Get all Moleculer event handlers defined on a service class
82
+ *
83
+ * @param serviceClassOrInstance - The service class constructor or instance
84
+ * @returns Array of event handler metadata
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const handlers = Moleculer.getEventHandlers(OrganizationService);
89
+ * // Returns: [
90
+ * // { eventName: 'user.created', methodName: 'onUserCreated' },
91
+ * // { eventName: 'org.created', methodName: 'onOrganizationCreated' }
92
+ * // ]
93
+ * ```
94
+ */
95
+ export function getEventHandlers(
96
+ serviceClassOrInstance: (new (...args: unknown[]) => unknown) | object
97
+ ): EventHandlerMetadata[] {
98
+ const target = typeof serviceClassOrInstance === 'function'
99
+ ? serviceClassOrInstance
100
+ : (serviceClassOrInstance as { constructor: new (...args: unknown[]) => unknown }).constructor;
101
+ return Reflect.getMetadata(EVENT_HANDLER_METADATA_KEY, target) || [];
102
+ }
103
+
104
+ /**
105
+ * Check if a method is marked as a Moleculer event handler
106
+ *
107
+ * @param serviceClassOrInstance - The service class constructor or instance
108
+ * @param methodName - The method name to check
109
+ * @returns Event handler metadata if found, undefined otherwise
110
+ */
111
+ export function isEventHandler(
112
+ serviceClassOrInstance: (new (...args: unknown[]) => unknown) | object,
113
+ methodName: string
114
+ ): EventHandlerMetadata | undefined {
115
+ const handlers = getEventHandlers(serviceClassOrInstance);
116
+ return handlers.find(h => h.methodName === methodName);
117
+ }
118
+ }