Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Expand the type for ServiceSchema to allow for typed lifecycle handlers #1272

Merged
merged 5 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -720,12 +720,14 @@ declare namespace Moleculer {
version?: string | number;
}

type ServiceSyncLifecycleHandler<S = ServiceSettingSchema> = (this: Service<S>) => void;
type ServiceAsyncLifecycleHandler<S = ServiceSettingSchema> = (
this: Service<S>
type ServiceSyncLifecycleHandler<S = ServiceSettingSchema, T = Service<S>> = (
this: T
) => void;
type ServiceAsyncLifecycleHandler<S = ServiceSettingSchema, T = Service<S>> = (
this: T
) => void | Promise<void>;

interface ServiceSchema<S = ServiceSettingSchema> {
interface ServiceSchema<S = ServiceSettingSchema, T = void> {
name: string;
version?: string | number;
settings?: S;
Expand All @@ -737,9 +739,9 @@ declare namespace Moleculer {
hooks?: ServiceHooks;

events?: ServiceEvents;
created?: ServiceSyncLifecycleHandler<S> | ServiceSyncLifecycleHandler<S>[];
started?: ServiceAsyncLifecycleHandler<S> | ServiceAsyncLifecycleHandler<S>[];
stopped?: ServiceAsyncLifecycleHandler<S> | ServiceAsyncLifecycleHandler<S>[];
created?: ServiceSyncLifecycleHandler<S, T> | ServiceSyncLifecycleHandler<S, T>[];
started?: ServiceAsyncLifecycleHandler<S, T> | ServiceAsyncLifecycleHandler<S, T>[];
stopped?: ServiceAsyncLifecycleHandler<S, T> | ServiceAsyncLifecycleHandler<S, T>[];

[name: string]: any;
}
Expand Down
160 changes: 84 additions & 76 deletions test/typescript/hello-world/greeter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,96 @@

import { Service } from "../../../";
import { Context } from "../../../";
import { ActionHooks, ServiceHooks, ServiceHooksAfter, ServiceSchema } from "../../../";
marceliwac marked this conversation as resolved.
Show resolved Hide resolved
import { ServiceSettingSchema, ServiceSchema } from "../../../";

type GreeterWelcomeParams = {
name: string
};
export interface ActionHelloParams {
name: string;
}

interface GreeterSettings extends ServiceSettingSchema {
defaultName: string;
}

interface GreeterMethods {
uppercase(str: string): string;
}

interface GreeterLocalVars {
myVar: string;
}

export default class GreeterService extends Service {
constructor(broker) {
super(broker);

this.parseServiceSchema({
name: "greeter",
hooks: {
before: {
welcome(ctx: Context<GreeterWelcomeParams>): void {
// console.log(`Service hook "before".`);
ctx.params.name = ctx.params.name.toUpperCase();
}
},
after: {
hello: "anotherHookAfter",
welcome: [
function (ctx: Context<GreeterWelcomeParams>, res: any): any {
// console.log(`Service sync hook "after".`);
return res;
},
async (ctx: Context<GreeterWelcomeParams>, res: any): Promise<any> => {
// console.log(`Service async hook "after".`);
return await Promise.resolve(res);
},
"anotherHookAfter"
],
} as ServiceHooksAfter,
error: {
welcome(ctx: Context<GreeterWelcomeParams>, err: Error): void {
// console.log(`Service hook "error".`);
throw err;
}
}
} as ServiceHooks,
actions: {
hello: {
handler: this.hello,
hooks: {
after: [
function (ctx: Context<GreeterWelcomeParams>, res: any): any {
// console.log(`Action sync hook "after".`);
return res;
},
async (ctx: Context<GreeterWelcomeParams>, res: any): Promise<any> => {
// console.log(`Action async hook "after".`);
return await Promise.resolve(res);
},
"anotherHookAfter"
]
} as ActionHooks
},
welcome: this.welcome
}
} as ServiceSchema);
}
type GreeterThis = Service<GreeterSettings> & GreeterMethods & GreeterLocalVars;

const GreeterService: ServiceSchema<GreeterSettings, GreeterThis> = {
name: "greeter",

/**
* Say a 'Hello'
*
* @returns
* Settings
*/
hello() {
return "Hello Moleculer TS";
}
settings: {
defaultName: "Moleculer",
},

/**
* Welcome a username
*
* @param {String} name - User name
* Dependencies
*/
welcome(ctx: Context<GreeterWelcomeParams>) {
return `Welcome, ${ctx.params.name}!`;
}

async anotherHookAfter(ctx: Context<GreeterWelcomeParams>, res: any): Promise<any> {
// console.log(`Another async hook "after".`);
return await Promise.resolve(res);
}
dependencies: [],

/**
* Actions
*/
actions: {
hello: {
rest: {
method: "GET",
path: "/hello",
},
handler(this: GreeterThis/* , ctx: Context */): string {
return `Hello ${this.settings.defaultName}`;
},
},

welcome: {
rest: "GET /welcome/:name",
params: {
name: "string",
},
handler(this: GreeterThis, ctx: Context<ActionHelloParams>): string {
return `Welcome, ${ctx.params.name}`;
},
},
},

/**
* Events
*/
events: {},

/**
* Methods
*/
methods: {},

/**
* Service created lifecycle event handler
*/
created(this: GreeterThis) {
this.logger.info(`${this.name} service - lifecycle method "created" called.`);
},

/**
* Service started lifecycle event handler
*/
async started(this: GreeterThis) {
this.logger.info(`${this.name} service - lifecycle method "started" called.`);
},

/**
* Service stopped lifecycle event handler
*/
async stopped(this: GreeterThis) {
this.logger.info(`${this.name} service - lifecycle method "stopped" called.`);
},
};

export default GreeterService;
6 changes: 2 additions & 4 deletions test/typescript/hello-world/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ broker.loadService(path.join(__dirname, "greeter.service.ts"));

await broker.call("greeter.hello");
const res = await broker.call("greeter.welcome", { name: "Typescript" });
broker.logger.info("");
broker.logger.info("Result: ", res);
icebob marked this conversation as resolved.
Show resolved Hide resolved
broker.logger.info("");
if (res != "Welcome, TYPESCRIPT!")
broker.logger.info(`Result: ${res}`);
if (res != "Welcome, Typescript")
throw new Error("Result is mismatch!");
else
await broker.stop();
Expand Down