Skip to content

Commit d645e3d

Browse files
committed
fix dynamic id field in types
1 parent 9c39472 commit d645e3d

File tree

2 files changed

+138
-44
lines changed

2 files changed

+138
-44
lines changed

index.d.ts

Lines changed: 117 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ declare module "@moleculer/database" {
7777
/** Params for populating action */
7878
params?: Record<string, any>;
7979
/** Handler function for populating */
80-
handler?: (ids: any[], docs: any[], rule: PopulateDefinition, ctx: Context<any, any>) => Promise<any>;
80+
handler?: (
81+
ids: any[],
82+
docs: any[],
83+
rule: PopulateDefinition,
84+
ctx: Context<any, any>
85+
) => Promise<any>;
8186
/** Key field name in the target service */
8287
keyField?: string;
8388
/** Populated field name in entity */
@@ -118,20 +123,42 @@ declare module "@moleculer/database" {
118123
/** Transformation function when setting value */
119124
set?: (value: any, entity: any, field: BaseFieldDefinition, ctx: Context<any, any>) => any;
120125
/** Custom validation function */
121-
validate?: string | ((
126+
validate?:
127+
| string
128+
| ((
129+
value: any,
130+
entity: any,
131+
field: BaseFieldDefinition,
132+
ctx: Context<any, any>
133+
) => Promise<boolean | string>);
134+
/** Lifecycle hook: called when entity is created */
135+
onCreate?: (
122136
value: any,
123137
entity: any,
124138
field: BaseFieldDefinition,
125139
ctx: Context<any, any>
126-
) => Promise<boolean | string>);
127-
/** Lifecycle hook: called when entity is created */
128-
onCreate?: (value: any, entity: any, field: BaseFieldDefinition, ctx: Context<any, any>) => any;
140+
) => any;
129141
/** Lifecycle hook: called when entity is updated */
130-
onUpdate?: (value: any, entity: any, field: BaseFieldDefinition, ctx: Context<any, any>) => any;
142+
onUpdate?: (
143+
value: any,
144+
entity: any,
145+
field: BaseFieldDefinition,
146+
ctx: Context<any, any>
147+
) => any;
131148
/** Lifecycle hook: called when entity is replaced */
132-
onReplace?: (value: any, entity: any, field: BaseFieldDefinition, ctx: Context<any, any>) => any;
149+
onReplace?: (
150+
value: any,
151+
entity: any,
152+
field: BaseFieldDefinition,
153+
ctx: Context<any, any>
154+
) => any;
133155
/** Lifecycle hook: called when entity is removed (enables soft delete) */
134-
onRemove?: (value: any, entity: any, field: BaseFieldDefinition, ctx: Context<any, any>) => any;
156+
onRemove?: (
157+
value: any,
158+
entity: any,
159+
field: BaseFieldDefinition,
160+
ctx: Context<any, any>
161+
) => any;
135162
}
136163

137164
export interface StringFieldDefinition extends BaseFieldDefinition {
@@ -266,8 +293,13 @@ declare module "@moleculer/database" {
266293
}
267294

268295
export interface Scopes {
269-
[scopeName: string]: Record<string, any>
270-
| ((query: Record<string, any>, ctx: Context<any, any>, params: any) => Record<string, any>);
296+
[scopeName: string]:
297+
| Record<string, any>
298+
| ((
299+
query: Record<string, any>,
300+
ctx: Context<any, any>,
301+
params: any
302+
) => Record<string, any>);
271303
}
272304

273305
export interface IndexDefinition {
@@ -510,6 +542,8 @@ declare module "@moleculer/database" {
510542
}
511543

512544
type ScopeParam = boolean | string | string[];
545+
type PopulateParam = string | string[];
546+
type FieldsParam = string | string[];
513547

514548
// Query parameters for database operations
515549
export interface FindParams {
@@ -518,7 +552,7 @@ declare module "@moleculer/database" {
518552
/** Number of entities to skip */
519553
offset?: number | undefined;
520554
/** Fields to include in results */
521-
fields?: string | string[];
555+
fields?: FieldsParam;
522556
/** Sort order */
523557
sort?: string | string[] | Record<string, any>;
524558
/** Search text */
@@ -530,7 +564,7 @@ declare module "@moleculer/database" {
530564
/** Scope to apply */
531565
scope?: ScopeParam;
532566
/** Fields to populate */
533-
populate?: string | string[];
567+
populate?: PopulateParam;
534568
/** Custom query */
535569
query?: Record<string, any> | string;
536570
}
@@ -542,26 +576,28 @@ declare module "@moleculer/database" {
542576
pageSize?: number;
543577
}
544578

545-
export interface GetParams {
546-
/** Entity ID */
547-
[idField: string]: any;
579+
export type GetParams<TIdField extends string = "id", TIdType = string> = {
580+
/** Entity ID(s) */
581+
[K in TIdField]: TIdType;
582+
} & {
548583
/** Fields to include in results */
549-
fields?: string | string[];
584+
fields?: FieldsParam;
550585
/** Scope to apply */
551586
scope?: ScopeParam;
552587
/** Fields to populate */
553-
populate?: string | string[];
554-
}
588+
populate?: PopulateParam;
589+
};
555590

556-
export interface ResolveParams {
591+
export type ResolveParams<TIdField extends string = "id", TIdType = string> = {
557592
/** Entity ID(s) */
558-
[idField: string]: any | any[];
593+
[K in TIdField]: TIdType | TIdType[];
594+
} & {
559595
/** Fields to include in results */
560-
fields?: string | string[];
596+
fields?: FieldsParam;
561597
/** Scope to apply */
562598
scope?: ScopeParam;
563599
/** Fields to populate */
564-
populate?: string | string[];
600+
populate?: PopulateParam;
565601
/** Convert result array to object with ID as key */
566602
mapping?: boolean;
567603
/** Throw error if entity not found */
@@ -695,33 +731,61 @@ declare module "@moleculer/database" {
695731
maintenanceAdapters(): Promise<void>;
696732

697733
// Entity methods
698-
findEntities<T = any>(ctx: Context<any, any>, params?: FindParams, opts?: FindOptions): Promise<T[]>;
734+
findEntities<T = any>(
735+
ctx: Context<any, any>,
736+
params?: FindParams,
737+
opts?: FindOptions
738+
): Promise<T[]>;
699739
countEntities(
700740
ctx: Context<any, any>,
701741
params?: Omit<FindParams, "limit" | "offset" | "fields" | "sort">
702742
): Promise<number>;
703-
findEntity<T = any>(ctx: Context<any, any>, params?: GetParams, opts?: FindOptions): Promise<T | null>;
704-
resolveEntities<T = any>(
743+
findEntity<T = any>(
744+
ctx: Context<any, any>,
745+
params?: Omit<FindParams, "limit" | "offset">,
746+
opts?: FindOptions
747+
): Promise<T | null>;
748+
resolveEntities<T = any, TIdField = "id", TIdType = string>(
705749
ctx: Context<any, any>,
706-
params: ResolveParams,
750+
params: ResolveParams<TIdField, TIdType>,
707751
opts?: ResolveEntityOptions
708752
): Promise<T | T[] | Record<string, T>>;
709-
createEntity<T = any>(ctx: Context<any, any>, params: Partial<T>, opts?: CreateEntityOptions): Promise<T>;
753+
createEntity<T = any>(
754+
ctx: Context<any, any>,
755+
params: Partial<T>,
756+
opts?: CreateEntityOptions
757+
): Promise<T>;
710758
createEntities<T = any>(
711759
ctx: Context<any, any>,
712760
entities: Partial<T>[],
713761
opts?: CreateEntitiesOptions
714762
): Promise<T[] | number>;
715-
updateEntity<T = any>(ctx: Context<any, any>, params: Partial<T>, opts?: UpdateEntityOptions): Promise<T>;
716-
updateEntity<T = any>(ctx: Context<any, any>, params: any, opts: UpdateEntityRawOptions): Promise<T>;
763+
updateEntity<T = any>(
764+
ctx: Context<any, any>,
765+
params: Partial<T>,
766+
opts?: UpdateEntityOptions
767+
): Promise<T>;
768+
updateEntity<T = any>(
769+
ctx: Context<any, any>,
770+
params: any,
771+
opts: UpdateEntityRawOptions
772+
): Promise<T>;
717773
updateEntities<T = any>(
718774
ctx: Context<any, any>,
719775
params: UpdateEntitiesParams<T>,
720776
opts?: UpdateEntityOptions
721777
): Promise<T[]>;
722-
replaceEntity<T = any>(ctx: Context<any, any>, params: Partial<T>, opts?: UpdateEntityOptions): Promise<T>;
723-
removeEntity(ctx: Context<any, any>, params: { [idField: string]: any }, opts?: RemoveEntityOptions): Promise<any>;
724-
removeEntities(ctx: Context<any, any>, params: RemoveEntitiesParams, opts?: RemoveEntitiesOptions): Promise<number>;
778+
replaceEntity<T = any>(
779+
ctx: Context<any, any>,
780+
params: Partial<T>,
781+
opts?: UpdateEntityOptions
782+
): Promise<T>;
783+
removeEntity(ctx: Context<any, any>, params: any, opts?: RemoveEntityOptions): Promise<any>;
784+
removeEntities(
785+
ctx: Context<any, any>,
786+
params: RemoveEntitiesParams,
787+
opts?: RemoveEntitiesOptions
788+
): Promise<number>;
725789
clearEntities(ctx?: Context<any, any>): Promise<number>;
726790
streamEntities(ctx: Context<any, any>, params?: FindParams, opts?: FindOptions): any;
727791

@@ -731,7 +795,12 @@ declare module "@moleculer/database" {
731795
params?: Partial<T>,
732796
opts?: ValidateParamsOptions
733797
): Promise<T>;
734-
authorizeFields(fields: any[], ctx: Context<any, any>, params: any, opts?: any): Promise<any[]>;
798+
authorizeFields(
799+
fields: any[],
800+
ctx: Context<any, any>,
801+
params: any,
802+
opts?: any
803+
): Promise<any[]>;
735804
sanitizeParams(params: any, opts?: any): any;
736805

737806
// Transformation methods
@@ -756,8 +825,18 @@ declare module "@moleculer/database" {
756825
decodeID<TOld, TNew>(id: TOld): TNew;
757826

758827
// Field authorization
759-
checkFieldAuthority<T = any>(ctx?: Context<any, any> | null, permission: any, params: T, field: Record<string, any>): Promise<boolean>;
760-
checkScopeAuthority(ctx?: Context<any, any> | null, name: string, operation: "add" | "remove", scope: Record<string, any>): Promise<boolean>;
828+
checkFieldAuthority<T = any>(
829+
ctx?: Context<any, any> | null,
830+
permission: any,
831+
params: T,
832+
field: Record<string, any>
833+
): Promise<boolean>;
834+
checkScopeAuthority(
835+
ctx?: Context<any, any> | null,
836+
name: string,
837+
operation: "add" | "remove",
838+
scope: Record<string, any>
839+
): Promise<boolean>;
761840

762841
// Monitoring
763842
startSpan(ctx: Context<any, any>, name: string, tags?: Record<string, any>): any;
@@ -775,7 +854,7 @@ declare module "@moleculer/database" {
775854
createMany?: ActionHandler<any[]>;
776855
update?: ActionHandler<any>;
777856
replace?: ActionHandler<any>;
778-
remove?: ActionHandler<{ [idField: string]: any }>;
857+
remove?: ActionHandler<any>;
779858
}
780859

781860
// Database action handler with proper this context
@@ -789,13 +868,13 @@ declare module "@moleculer/database" {
789868
handler?: DatabaseActionHandler<TParams, TMeta>;
790869
}
791870

792-
// Custom hooks interface
871+
// Custom hooks interface
793872
export interface DatabaseHooks extends ServiceHooks {
794873
customs?: Record<string, Function | Function[] | string | string[]>;
795874
}
796875

797876
export interface DatabaseLocalVariables {
798-
// Adapter management
877+
// Adapter management
799878
adapters: Map<string, any>;
800879

801880
// Field definitions

test/typescript/index.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ const postServiceSchema: ServiceSchema<
394394
id: "string"
395395
},
396396
async handler(ctx: Context<{ id: string }>) {
397-
const post = await this.findEntity<Post>(ctx, { id: ctx.params.id });
397+
const post = await this.findEntity<Post>(ctx, { query: { a: 5 } });
398398
if (!post) {
399399
throw new EntityNotFoundError(ctx.params.id);
400400
}
@@ -483,6 +483,12 @@ const getParams: GetParams = {
483483
scope: false,
484484
populate: ["author"]
485485
};
486+
const getParams2: GetParams<"key", number> = {
487+
key: 123,
488+
fields: ["id", "title", "content", "author"],
489+
scope: false,
490+
populate: ["author"]
491+
};
486492

487493
// Test resolve parameters
488494
const resolveParams: ResolveParams = {
@@ -492,6 +498,13 @@ const resolveParams: ResolveParams = {
492498
throwIfNotExist: false,
493499
reorderResult: true
494500
};
501+
const resolveParams2: ResolveParams<"key", number> = {
502+
key: [123, 456],
503+
fields: ["id", "title", "votes"],
504+
mapping: true,
505+
throwIfNotExist: false,
506+
reorderResult: true
507+
};
495508

496509
// =============================================================================
497510
// Service Usage Testing (simulating broker calls)
@@ -606,7 +619,7 @@ function demonstrateDirectServiceMethods(service: MoleculerService & DatabaseMet
606619
const firstPost: Post | undefined = posts[0];
607620

608621
// Find single entity
609-
const post = await service.findEntity<Post>(ctx, getParams);
622+
const post = await service.findEntity<Post>(ctx, { query: { a: 5 } });
610623
const title: string | undefined = post?.title;
611624

612625
// Count entities
@@ -746,7 +759,7 @@ function demonstrateErrorHandling() {
746759
async function testAsyncError(ctx: Context): Promise<Post | null> {
747760
try {
748761
const service = ctx.service as MoleculerService & DatabaseMethods;
749-
const post = await service.findEntity<Post>(ctx, { id: "nonExistentId" });
762+
const post = await service.findEntity<Post>(ctx, { query: { a: 5 } });
750763
return post;
751764
} catch (error) {
752765
if (error instanceof EntityNotFoundError) {
@@ -998,7 +1011,7 @@ function testTypeInference() {
9981011
const service = ctx.service as MoleculerService & DatabaseMethods;
9991012

10001013
// Should infer Post type
1001-
const post = await service.findEntity<Post>(ctx, { id: ctx.params.id });
1014+
const post = await service.findEntity<Post>(ctx, { query: { a: 5 } });
10021015

10031016
// Should infer Post[] type
10041017
const posts = await service.findEntities<Post>(ctx, { limit: 10 });
@@ -1075,6 +1088,9 @@ const advancedServiceSchema: ServiceSchema<
10751088
async handler(ctx: Context<{ slug: string }>) {
10761089
const post = await this.findEntity<Post>(ctx, {
10771090
query: { slug: ctx.params.slug },
1091+
scope: "published",
1092+
search: "<search-term>",
1093+
searchFields: ["title", "content"],
10781094
populate: ["author", "categories"]
10791095
});
10801096
return post;
@@ -1135,7 +1151,7 @@ const advancedServiceSchema: ServiceSchema<
11351151
let counter = 1;
11361152

11371153
// Ensure uniqueness
1138-
while (await this.findEntity(ctx, { slug })) {
1154+
while (await this.findEntity(ctx, { query: { slug } })) {
11391155
slug = `${baseSlug}-${counter}`;
11401156
counter++;
11411157
}
@@ -1145,7 +1161,6 @@ const advancedServiceSchema: ServiceSchema<
11451161

11461162
async getRelatedPosts(ctx: Context, postId: string, limit: number = 5): Promise<Post[]> {
11471163
const post = await this.findEntity<Post>(ctx, {
1148-
id: postId,
11491164
populate: ["categories"]
11501165
});
11511166

0 commit comments

Comments
 (0)