Skip to content

Commit 813e893

Browse files
authored
feat: add support for 'rpc' and 'ws' context type (#894)
1 parent aae47e6 commit 813e893

File tree

3 files changed

+53
-29
lines changed

3 files changed

+53
-29
lines changed

src/decorator.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants'
2-
import { HttpArgumentsHost, CustomParamFactory, ExecutionContext } from '@nestjs/common/interfaces'
2+
import { CustomParamFactory, ExecutionContext, HttpArgumentsHost } from '@nestjs/common/interfaces'
33
import { Request as ExpressRequest } from 'express'
44
import { FastifyRequest } from 'fastify'
55
import { Paginate, PaginateQuery } from './decorator'
@@ -18,6 +18,7 @@ const decoratorfactory = getParamDecoratorFactory<PaginateQuery>(Paginate)
1818

1919
function expressContextFactory(query: ExpressRequest['query']): Partial<ExecutionContext> {
2020
const mockContext: Partial<ExecutionContext> = {
21+
getType: <ContextType>() => 'http' as ContextType,
2122
switchToHttp: (): HttpArgumentsHost =>
2223
Object({
2324
getRequest: (): Partial<ExpressRequest> =>
@@ -34,6 +35,7 @@ function expressContextFactory(query: ExpressRequest['query']): Partial<Executio
3435

3536
function fastifyContextFactory(query: FastifyRequest['query']): Partial<ExecutionContext> {
3637
const mockContext: Partial<ExecutionContext> = {
38+
getType: <ContextType>() => 'http' as ContextType,
3739
switchToHttp: (): HttpArgumentsHost =>
3840
Object({
3941
getRequest: (): Partial<FastifyRequest> =>

src/decorator.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createParamDecorator, ExecutionContext } from '@nestjs/common'
22
import type { Request as ExpressRequest } from 'express'
33
import type { FastifyRequest } from 'fastify'
4-
import { pickBy, Dictionary, isString, mapKeys } from 'lodash'
4+
import { Dictionary, isString, mapKeys, pickBy } from 'lodash'
55

66
function isRecord(data: unknown): data is Record<string, unknown> {
77
return data !== null && typeof data === 'object' && !Array.isArray(data)
@@ -50,18 +50,34 @@ function parseParam<T>(queryParam: unknown, parserLogic: (param: string, res: an
5050
}
5151

5252
export const Paginate = createParamDecorator((_data: unknown, ctx: ExecutionContext): PaginateQuery => {
53-
const request: ExpressRequest | FastifyRequest = ctx.switchToHttp().getRequest()
54-
const query = request.query as Record<string, unknown>
53+
let path: string
54+
let query: Record<string, unknown>
5555

56-
// Determine if Express or Fastify to rebuild the original url and reduce down to protocol, host and base url
57-
let originalUrl: string
58-
if (isExpressRequest(request)) {
59-
originalUrl = request.protocol + '://' + request.get('host') + request.originalUrl
60-
} else {
61-
originalUrl = request.protocol + '://' + request.hostname + request.url
56+
switch (ctx.getType()) {
57+
case 'http':
58+
const request: ExpressRequest | FastifyRequest = ctx.switchToHttp().getRequest()
59+
query = request.query as Record<string, unknown>
60+
61+
// Determine if Express or Fastify to rebuild the original url and reduce down to protocol, host and base url
62+
let originalUrl: string
63+
if (isExpressRequest(request)) {
64+
originalUrl = request.protocol + '://' + request.get('host') + request.originalUrl
65+
} else {
66+
originalUrl = request.protocol + '://' + request.hostname + request.url
67+
}
68+
69+
const urlParts = new URL(originalUrl)
70+
path = urlParts.protocol + '//' + urlParts.host + urlParts.pathname
71+
break
72+
case 'ws':
73+
query = ctx.switchToWs().getData()
74+
path = null
75+
break
76+
case 'rpc':
77+
query = ctx.switchToRpc().getData()
78+
path = null
79+
break
6280
}
63-
const urlParts = new URL(originalUrl)
64-
const path = urlParts.protocol + '//' + urlParts.host + urlParts.pathname
6581

6682
const searchBy = parseParam<string>(query.searchBy, singleSplit)
6783
const sortBy = parseParam<[string, string]>(query.sortBy, multipleSplit)

src/paginate.ts

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -395,16 +395,6 @@ export async function paginate<T extends ObjectLiteral>(
395395
items = await queryBuilder.getMany()
396396
}
397397

398-
let path: string
399-
const { queryOrigin, queryPath } = getQueryUrlComponents(query.path)
400-
if (config.relativePath) {
401-
path = queryPath
402-
} else if (config.origin) {
403-
path = config.origin + queryPath
404-
} else {
405-
path = queryOrigin + queryPath
406-
}
407-
408398
const sortByQuery = sortBy.map((order) => `&sortBy=${order.join(':')}`).join('')
409399
const searchQuery = query.search ? `&search=${query.search}` : ''
410400

@@ -429,6 +419,18 @@ export async function paginate<T extends ObjectLiteral>(
429419

430420
const options = `&limit=${limit}${sortByQuery}${searchQuery}${searchByQuery}${selectQuery}${filterQuery}`
431421

422+
let path: string = null
423+
if (query.path !== null) {
424+
// `query.path` does not exist in RPC/WS requests and is set to null then.
425+
const { queryOrigin, queryPath } = getQueryUrlComponents(query.path)
426+
if (config.relativePath) {
427+
path = queryPath
428+
} else if (config.origin) {
429+
path = config.origin + queryPath
430+
} else {
431+
path = queryOrigin + queryPath
432+
}
433+
}
432434
const buildLink = (p: number): string => path + '?page=' + p + options
433435

434436
const totalPages = isPaginated ? Math.ceil(totalItems / limit) : 1
@@ -446,13 +448,17 @@ export async function paginate<T extends ObjectLiteral>(
446448
select: isQuerySelected ? selectParams : undefined,
447449
filter: query.filter,
448450
},
449-
links: {
450-
first: page == 1 ? undefined : buildLink(1),
451-
previous: page - 1 < 1 ? undefined : buildLink(page - 1),
452-
current: buildLink(page),
453-
next: page + 1 > totalPages ? undefined : buildLink(page + 1),
454-
last: page == totalPages || !totalItems ? undefined : buildLink(totalPages),
455-
},
451+
// If there is no `path`, don't build links.
452+
links:
453+
path !== null
454+
? {
455+
first: page == 1 ? undefined : buildLink(1),
456+
previous: page - 1 < 1 ? undefined : buildLink(page - 1),
457+
current: buildLink(page),
458+
next: page + 1 > totalPages ? undefined : buildLink(page + 1),
459+
last: page == totalPages || !totalItems ? undefined : buildLink(totalPages),
460+
}
461+
: ({} as Paginated<T>['links']),
456462
}
457463

458464
return Object.assign(new Paginated<T>(), results)

0 commit comments

Comments
 (0)