diff --git a/integration/nestjs-metadata-grpc-js/hero.bin b/integration/nestjs-metadata-grpc-js/hero.bin new file mode 100644 index 000000000..089060a58 Binary files /dev/null and b/integration/nestjs-metadata-grpc-js/hero.bin differ diff --git a/integration/nestjs-metadata-grpc-js/hero.proto b/integration/nestjs-metadata-grpc-js/hero.proto new file mode 100644 index 000000000..5fbd820f3 --- /dev/null +++ b/integration/nestjs-metadata-grpc-js/hero.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package hero; + +service HeroService { + rpc FindOneHero (HeroById) returns (Hero) {} + rpc FindOneVillain (VillainById) returns (Villain) {} + rpc FindManyVillain (stream VillainById) returns (stream Villain) {} +} + +message HeroById { + int32 id = 1; +} + +message VillainById { + int32 id = 1; +} + +message Hero { + int32 id = 1; + string name = 2; +} + +message Villain { + int32 id = 1; + string name = 2; +} diff --git a/integration/nestjs-metadata-grpc-js/hero.ts b/integration/nestjs-metadata-grpc-js/hero.ts new file mode 100644 index 000000000..cd145b685 --- /dev/null +++ b/integration/nestjs-metadata-grpc-js/hero.ts @@ -0,0 +1,68 @@ +/* eslint-disable */ +import { GrpcMethod, GrpcStreamMethod } from '@nestjs/microservices'; +import { util, configure } from 'protobufjs/minimal'; +import * as Long from 'long'; +import { Observable } from 'rxjs'; +import { Metadata } from '@grpc/grpc-js'; + +export const protobufPackage = 'hero'; + +export interface HeroById { + id: number; +} + +export interface VillainById { + id: number; +} + +export interface Hero { + id: number; + name: string; +} + +export interface Villain { + id: number; + name: string; +} + +export const HERO_PACKAGE_NAME = 'hero'; + +export interface HeroServiceClient { + findOneHero(request: HeroById, metadata?: Metadata): Observable; + + findOneVillain(request: VillainById, metadata?: Metadata): Observable; + + findManyVillain(request: Observable, metadata?: Metadata): Observable; +} + +export interface HeroServiceController { + findOneHero(request: HeroById, metadata?: Metadata): Promise | Observable | Hero; + + findOneVillain(request: VillainById, metadata?: Metadata): Promise | Observable | Villain; + + findManyVillain(request: Observable, metadata?: Metadata): Observable; +} + +export function HeroServiceControllerMethods() { + return function (constructor: Function) { + const grpcMethods: string[] = ['findOneHero', 'findOneVillain']; + for (const method of grpcMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcMethod('HeroService', method)(constructor.prototype[method], method, descriptor); + } + const grpcStreamMethods: string[] = ['findManyVillain']; + for (const method of grpcStreamMethods) { + const descriptor: any = Reflect.getOwnPropertyDescriptor(constructor.prototype, method); + GrpcStreamMethod('HeroService', method)(constructor.prototype[method], method, descriptor); + } + }; +} + +export const HERO_SERVICE_NAME = 'HeroService'; + +// If you get a compile-error about 'Constructor and ... have no overlap', +// add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'. +if (util.Long !== Long) { + util.Long = Long as any; + configure(); +} diff --git a/integration/nestjs-metadata-grpc-js/nestjs-metadata-test.ts b/integration/nestjs-metadata-grpc-js/nestjs-metadata-test.ts new file mode 100644 index 000000000..ee81d9528 --- /dev/null +++ b/integration/nestjs-metadata-grpc-js/nestjs-metadata-test.ts @@ -0,0 +1,8 @@ +import { SampleService } from './sample-service'; + +describe('nestjs-metadata-test', () => { + it('compiles', () => { + const service = new SampleService(); + expect(service).not.toBeUndefined(); + }); +}); diff --git a/integration/nestjs-metadata-grpc-js/parameters.txt b/integration/nestjs-metadata-grpc-js/parameters.txt new file mode 100644 index 000000000..116886240 --- /dev/null +++ b/integration/nestjs-metadata-grpc-js/parameters.txt @@ -0,0 +1 @@ +nestJs=true,addGrpcMetadata=true,outputServices=grpc-js diff --git a/integration/nestjs-metadata-grpc-js/sample-service.ts b/integration/nestjs-metadata-grpc-js/sample-service.ts new file mode 100644 index 000000000..ff285546e --- /dev/null +++ b/integration/nestjs-metadata-grpc-js/sample-service.ts @@ -0,0 +1,25 @@ +import { HeroServiceController, HeroById, Hero, Villain, VillainById } from './hero'; +import { Metadata } from 'grpc'; +import { Observable, Subject } from 'rxjs'; + +export class SampleService implements HeroServiceController { + findOneHero(request: HeroById, metadata?: Metadata): Promise { + return Promise.resolve({ id: 1, name: 'test' }); + } + + findOneVillain(request: VillainById, metadata?: Metadata): Promise { + return Promise.resolve({ id: 1, name: 'test' }); + } + + findManyVillain(request: Observable): Observable { + const hero$ = new Subject(); + + const onNext = (villainById: VillainById) => { + hero$.next({ id: 1, name: 'test' }); + }; + const onComplete = () => hero$.complete(); + request.subscribe(onNext, null, onComplete); + + return hero$.asObservable(); + } +} diff --git a/src/generate-nestjs.ts b/src/generate-nestjs.ts index 08450b703..0856f2fc5 100644 --- a/src/generate-nestjs.ts +++ b/src/generate-nestjs.ts @@ -14,8 +14,6 @@ import { assertInstanceOf, FormattedMethodDescriptor, maybeAddComment, singular import { camelCase } from './case'; import { Context } from './context'; -const Metadata = imp('Metadata@grpc'); - export function generateNestjsServiceController( ctx: Context, fileDesc: FileDescriptorProto, @@ -25,6 +23,8 @@ export function generateNestjsServiceController( const { options } = ctx; const chunks: Code[] = []; + const Metadata = options.outputServices === 'grpc-js' ? imp('Metadata@@grpc/grpc-js') : imp('Metadata@grpc'); + maybeAddComment(sourceInfo, chunks, serviceDesc.options?.deprecated); const t = options.context ? `<${contextTypeVar}>` : ''; chunks.push(code` @@ -96,6 +96,8 @@ export function generateNestjsServiceClient( const { options } = ctx; const chunks: Code[] = []; + const Metadata = options.outputServices === 'grpc-js' ? imp('Metadata@@grpc/grpc-js') : imp('Metadata@grpc'); + maybeAddComment(sourceInfo, chunks); const t = options.context ? `<${contextTypeVar}>` : ``; chunks.push(code`