• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nestjs / nest / 1e41e624-18ea-4ab6-9e2e-37016498fb6d

27 Nov 2024 07:30AM UTC coverage: 91.993% (+0.05%) from 91.944%
1e41e624-18ea-4ab6-9e2e-37016498fb6d

Pull #14213

circleci

mag123c
feat(common): add error messages for file validators
Pull Request #14213: feat(common): add error messages for file validators

2088 of 2514 branches covered (83.05%)

4 of 4 new or added lines in 2 files covered. (100.0%)

37 existing lines in 4 files now uncovered.

6813 of 7406 relevant lines covered (91.99%)

17.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.41
/packages/microservices/listeners-controller.ts
1
import { Injectable } from '@nestjs/common/interfaces';
2
import { Controller } from '@nestjs/common/interfaces/controllers/controller.interface';
3
import { isUndefined } from '@nestjs/common/utils/shared.utils';
1✔
4
import { ContextIdFactory } from '@nestjs/core/helpers/context-id-factory';
1✔
5
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
1✔
6
import { STATIC_CONTEXT } from '@nestjs/core/injector/constants';
1✔
7
import { NestContainer } from '@nestjs/core/injector/container';
8
import { Injector } from '@nestjs/core/injector/injector';
9
import {
10
  ContextId,
11
  InstanceWrapper,
12
} from '@nestjs/core/injector/instance-wrapper';
13
import { Module } from '@nestjs/core/injector/module';
14
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
15
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
1✔
16
import { REQUEST_CONTEXT_ID } from '@nestjs/core/router/request/request-constants';
1✔
17
import {
1✔
18
  forkJoin,
19
  from as fromPromise,
20
  isObservable,
21
  mergeMap,
22
  Observable,
23
  ObservedValueOf,
24
  of,
25
} from 'rxjs';
26
import { IClientProxyFactory } from './client/client-proxy-factory';
27
import { ClientsContainer } from './container';
28
import { ExceptionFiltersContext } from './context/exception-filters-context';
29
import { RequestContextHost } from './context/request-context-host';
1✔
30
import { RpcContextCreator } from './context/rpc-context-creator';
31
import {
1✔
32
  DEFAULT_CALLBACK_METADATA,
33
  DEFAULT_GRPC_CALLBACK_METADATA,
34
} from './context/rpc-metadata-constants';
35
import { BaseRpcContext } from './ctx-host/base-rpc.context';
36
import { Transport } from './enums';
1✔
37
import {
38
  CustomTransportStrategy,
39
  MessageHandler,
40
  PatternMetadata,
41
  RequestContext,
42
} from './interfaces';
43
import { MicroserviceEntrypointMetadata } from './interfaces/microservice-entrypoint-metadata.interface';
44
import {
1✔
45
  EventOrMessageListenerDefinition,
46
  ListenerMetadataExplorer,
47
} from './listener-metadata-explorer';
48
import { ServerGrpc } from './server';
1✔
49
import { Server } from './server/server';
50

51
export class ListenersController {
1✔
52
  private readonly metadataExplorer = new ListenerMetadataExplorer(
16✔
53
    new MetadataScanner(),
54
  );
55
  private readonly exceptionFiltersCache = new WeakMap();
16✔
56

57
  constructor(
58
    private readonly clientsContainer: ClientsContainer,
16✔
59
    private readonly contextCreator: RpcContextCreator,
16✔
60
    private readonly container: NestContainer,
16✔
61
    private readonly injector: Injector,
16✔
62
    private readonly clientFactory: IClientProxyFactory,
16✔
63
    private readonly exceptionFiltersContext: ExceptionFiltersContext,
16✔
64
    private readonly graphInspector: GraphInspector,
16✔
65
  ) {}
66

67
  public registerPatternHandlers(
68
    instanceWrapper: InstanceWrapper<Controller | Injectable>,
69
    server: Server & CustomTransportStrategy,
70
    moduleKey: string,
71
  ) {
72
    const { instance } = instanceWrapper;
8✔
73

74
    const isStatic = instanceWrapper.isDependencyTreeStatic();
8✔
75
    const patternHandlers = this.metadataExplorer.explore(instance as object);
8✔
76
    const moduleRef = this.container.getModuleByKey(moduleKey);
8✔
77
    const defaultCallMetadata =
78
      server instanceof ServerGrpc
8!
79
        ? DEFAULT_GRPC_CALLBACK_METADATA
80
        : DEFAULT_CALLBACK_METADATA;
81

82
    patternHandlers
8✔
83
      .filter(
84
        ({ transport }) =>
85
          isUndefined(transport) ||
16✔
86
          isUndefined(server.transportId) ||
87
          transport === server.transportId,
88
      )
89
      .reduce((acc, handler) => {
90
        handler.patterns.forEach(pattern =>
13✔
91
          acc.push({ ...handler, patterns: [pattern] }),
13✔
92
        );
93
        return acc;
13✔
94
      }, [])
95
      .forEach((definition: EventOrMessageListenerDefinition) => {
96
        const {
97
          patterns: [pattern],
98
          targetCallback,
99
          methodKey,
100
          extras,
101
          isEventHandler,
102
        } = definition;
13✔
103

104
        this.insertEntrypointDefinition(
13✔
105
          instanceWrapper,
106
          definition,
107
          server.transportId,
108
        );
109

110
        if (isStatic) {
13✔
111
          const proxy = this.contextCreator.create(
11✔
112
            instance as object,
113
            targetCallback,
114
            moduleKey,
115
            methodKey,
116
            STATIC_CONTEXT,
117
            undefined,
118
            defaultCallMetadata,
119
          );
120
          if (isEventHandler) {
11✔
121
            const eventHandler: MessageHandler = async (...args: unknown[]) => {
2✔
122
              const originalArgs = args;
×
123
              const [dataOrContextHost] = originalArgs;
×
124
              if (dataOrContextHost instanceof RequestContextHost) {
×
125
                args = args.slice(1, args.length);
×
126
              }
127
              const returnValue = proxy(...args);
×
128
              return this.forkJoinHandlersIfAttached(
×
129
                returnValue,
130
                originalArgs,
131
                eventHandler,
132
              );
133
            };
134
            return server.addHandler(
2✔
135
              pattern,
136
              eventHandler,
137
              isEventHandler,
138
              extras,
139
            );
140
          } else {
141
            return server.addHandler(pattern, proxy, isEventHandler, extras);
9✔
142
          }
143
        }
144
        const asyncHandler = this.createRequestScopedHandler(
2✔
145
          instanceWrapper,
146
          pattern,
147
          moduleRef,
148
          moduleKey,
149
          methodKey,
150
          defaultCallMetadata,
151
          isEventHandler,
152
        );
153
        server.addHandler(pattern, asyncHandler, isEventHandler, extras);
2✔
154
      });
155
  }
156

157
  public insertEntrypointDefinition(
158
    instanceWrapper: InstanceWrapper,
159
    definition: EventOrMessageListenerDefinition,
160
    transportId: Transport | symbol,
161
  ) {
162
    this.graphInspector.insertEntrypointDefinition<MicroserviceEntrypointMetadata>(
14✔
163
      {
164
        type: 'microservice',
165
        methodName: definition.methodKey,
166
        className: instanceWrapper.metatype?.name,
167
        classNodeId: instanceWrapper.id,
168
        metadata: {
169
          key: definition.patterns.toString(),
170
          transportId:
171
            typeof transportId === 'number'
14✔
172
              ? (Transport[transportId] as keyof typeof Transport)
173
              : transportId,
174
          patterns: definition.patterns,
175
          isEventHandler: definition.isEventHandler,
176
          extras: definition.extras,
177
        },
178
      },
179
      instanceWrapper.id,
180
    );
181
  }
182

183
  public forkJoinHandlersIfAttached(
184
    currentReturnValue: Promise<unknown> | Observable<unknown>,
185
    originalArgs: unknown[],
186
    handlerRef: MessageHandler,
187
  ) {
188
    if (handlerRef.next) {
×
189
      const returnedValueWrapper = handlerRef.next(
×
190
        ...(originalArgs as Parameters<MessageHandler>),
191
      );
192
      return forkJoin({
×
193
        current: this.transformToObservable(currentReturnValue),
194
        next: this.transformToObservable(returnedValueWrapper),
195
      });
196
    }
197
    return currentReturnValue;
×
198
  }
199

200
  public assignClientsToProperties(instance: Controller | Injectable) {
201
    for (const {
1✔
202
      property,
203
      metadata,
204
    } of this.metadataExplorer.scanForClientHooks(instance as object)) {
205
      const client = this.clientFactory.create(metadata);
1✔
206
      this.clientsContainer.addClient(client);
1✔
207

208
      this.assignClientToInstance(instance as object, property, client);
1✔
209
    }
210
  }
211

212
  public assignClientToInstance<T = any>(
213
    instance: Controller | Injectable,
214
    property: string,
215
    client: T,
216
  ) {
217
    Reflect.set(instance as object, property, client);
2✔
218
  }
219

220
  public createRequestScopedHandler(
221
    wrapper: InstanceWrapper,
222
    pattern: PatternMetadata,
223
    moduleRef: Module,
224
    moduleKey: string,
225
    methodKey: string,
226
    defaultCallMetadata: Record<string, any> = DEFAULT_CALLBACK_METADATA,
2✔
227
    isEventHandler = false,
3✔
228
  ) {
229
    const collection = moduleRef.controllers;
4✔
230
    const { instance } = wrapper;
4✔
231

232
    const isTreeDurable = wrapper.isDependencyTreeDurable();
4✔
233

234
    const requestScopedHandler: MessageHandler = async (...args: unknown[]) => {
4✔
235
      try {
2✔
236
        let contextId: ContextId;
237

238
        let [dataOrContextHost] = args;
2✔
239
        if (dataOrContextHost instanceof RequestContextHost) {
2!
240
          contextId = this.getContextId(dataOrContextHost, isTreeDurable);
×
241
          args.shift();
×
242
        } else {
243
          const [data, reqCtx] = args;
2✔
244
          const request = RequestContextHost.create(
2✔
245
            pattern,
246
            data,
247
            reqCtx as BaseRpcContext,
248
          );
249
          contextId = this.getContextId(request, isTreeDurable);
2✔
250
          dataOrContextHost = request;
2✔
251
        }
252

253
        const contextInstance = await this.injector.loadPerContext(
2✔
254
          instance,
255
          moduleRef,
256
          collection,
257
          contextId,
258
        );
259
        const proxy = this.contextCreator.create(
1✔
260
          contextInstance,
261
          contextInstance[methodKey],
262
          moduleKey,
263
          methodKey,
264
          contextId,
265
          wrapper.id,
266
          defaultCallMetadata,
267
        );
268

269
        const returnValue = proxy(...args);
1✔
270
        if (isEventHandler) {
1!
271
          return this.forkJoinHandlersIfAttached(
×
272
            returnValue,
273
            [dataOrContextHost, ...args],
274
            requestScopedHandler,
275
          );
276
        }
277
        return returnValue;
1✔
278
      } catch (err) {
279
        let exceptionFilter = this.exceptionFiltersCache.get(
1✔
280
          instance[methodKey],
281
        );
282
        if (!exceptionFilter) {
1✔
283
          exceptionFilter = this.exceptionFiltersContext.create(
1✔
284
            instance,
285
            instance[methodKey],
286
            moduleKey,
287
          );
288
          this.exceptionFiltersCache.set(instance[methodKey], exceptionFilter);
1✔
289
        }
290
        const host = new ExecutionContextHost(args);
1✔
291
        host.setType('rpc');
1✔
292
        return exceptionFilter.handle(err, host);
1✔
293
      }
294
    };
295
    return requestScopedHandler;
4✔
296
  }
297

298
  private getContextId<T extends RequestContext = any>(
299
    request: T,
300
    isTreeDurable: boolean,
301
  ): ContextId {
302
    const contextId = ContextIdFactory.getByRequest(request);
2✔
303
    if (!request[REQUEST_CONTEXT_ID as any]) {
2✔
304
      Object.defineProperty(request, REQUEST_CONTEXT_ID, {
2✔
305
        value: contextId,
306
        enumerable: false,
307
        writable: false,
308
        configurable: false,
309
      });
310

311
      const requestProviderValue = isTreeDurable ? contextId.payload : request;
2!
312
      this.container.registerRequestProvider(requestProviderValue, contextId);
2✔
313
    }
314
    return contextId;
2✔
315
  }
316

317
  public transformToObservable<T>(
318
    resultOrDeferred: Observable<T> | Promise<T>,
319
  ): Observable<T>;
320
  public transformToObservable<T>(
321
    resultOrDeferred: T,
322
  ): never extends Observable<ObservedValueOf<T>>
323
    ? Observable<T>
324
    : Observable<ObservedValueOf<T>>;
325
  public transformToObservable(resultOrDeferred: any) {
UNCOV
326
    if (resultOrDeferred instanceof Promise) {
×
UNCOV
327
      return fromPromise(resultOrDeferred).pipe(
×
328
        mergeMap(val => (isObservable(val) ? val : of(val))),
×
329
      );
330
    }
331

UNCOV
332
    if (isObservable(resultOrDeferred)) {
×
UNCOV
333
      return resultOrDeferred;
×
334
    }
335

UNCOV
336
    return of(resultOrDeferred);
×
337
  }
338
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc