Skip to content

Commit

Permalink
feat: add support for 'rpc' and 'ws' context type (#894)
Browse files Browse the repository at this point in the history
  • Loading branch information
AAAAAAAAlan authored Sep 6, 2024
1 parent aae47e6 commit 813e893
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 29 deletions.
4 changes: 3 additions & 1 deletion src/decorator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants'
import { HttpArgumentsHost, CustomParamFactory, ExecutionContext } from '@nestjs/common/interfaces'
import { CustomParamFactory, ExecutionContext, HttpArgumentsHost } from '@nestjs/common/interfaces'
import { Request as ExpressRequest } from 'express'
import { FastifyRequest } from 'fastify'
import { Paginate, PaginateQuery } from './decorator'
Expand All @@ -18,6 +18,7 @@ const decoratorfactory = getParamDecoratorFactory<PaginateQuery>(Paginate)

function expressContextFactory(query: ExpressRequest['query']): Partial<ExecutionContext> {
const mockContext: Partial<ExecutionContext> = {
getType: <ContextType>() => 'http' as ContextType,
switchToHttp: (): HttpArgumentsHost =>
Object({
getRequest: (): Partial<ExpressRequest> =>
Expand All @@ -34,6 +35,7 @@ function expressContextFactory(query: ExpressRequest['query']): Partial<Executio

function fastifyContextFactory(query: FastifyRequest['query']): Partial<ExecutionContext> {
const mockContext: Partial<ExecutionContext> = {
getType: <ContextType>() => 'http' as ContextType,
switchToHttp: (): HttpArgumentsHost =>
Object({
getRequest: (): Partial<FastifyRequest> =>
Expand Down
38 changes: 27 additions & 11 deletions src/decorator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common'
import type { Request as ExpressRequest } from 'express'
import type { FastifyRequest } from 'fastify'
import { pickBy, Dictionary, isString, mapKeys } from 'lodash'
import { Dictionary, isString, mapKeys, pickBy } from 'lodash'

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

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

// Determine if Express or Fastify to rebuild the original url and reduce down to protocol, host and base url
let originalUrl: string
if (isExpressRequest(request)) {
originalUrl = request.protocol + '://' + request.get('host') + request.originalUrl
} else {
originalUrl = request.protocol + '://' + request.hostname + request.url
switch (ctx.getType()) {
case 'http':
const request: ExpressRequest | FastifyRequest = ctx.switchToHttp().getRequest()
query = request.query as Record<string, unknown>

// Determine if Express or Fastify to rebuild the original url and reduce down to protocol, host and base url
let originalUrl: string
if (isExpressRequest(request)) {
originalUrl = request.protocol + '://' + request.get('host') + request.originalUrl
} else {
originalUrl = request.protocol + '://' + request.hostname + request.url
}

const urlParts = new URL(originalUrl)
path = urlParts.protocol + '//' + urlParts.host + urlParts.pathname
break
case 'ws':
query = ctx.switchToWs().getData()
path = null
break
case 'rpc':
query = ctx.switchToRpc().getData()
path = null
break
}
const urlParts = new URL(originalUrl)
const path = urlParts.protocol + '//' + urlParts.host + urlParts.pathname

const searchBy = parseParam<string>(query.searchBy, singleSplit)
const sortBy = parseParam<[string, string]>(query.sortBy, multipleSplit)
Expand Down
40 changes: 23 additions & 17 deletions src/paginate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,16 +395,6 @@ export async function paginate<T extends ObjectLiteral>(
items = await queryBuilder.getMany()
}

let path: string
const { queryOrigin, queryPath } = getQueryUrlComponents(query.path)
if (config.relativePath) {
path = queryPath
} else if (config.origin) {
path = config.origin + queryPath
} else {
path = queryOrigin + queryPath
}

const sortByQuery = sortBy.map((order) => `&sortBy=${order.join(':')}`).join('')
const searchQuery = query.search ? `&search=${query.search}` : ''

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

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

let path: string = null
if (query.path !== null) {
// `query.path` does not exist in RPC/WS requests and is set to null then.
const { queryOrigin, queryPath } = getQueryUrlComponents(query.path)
if (config.relativePath) {
path = queryPath
} else if (config.origin) {
path = config.origin + queryPath
} else {
path = queryOrigin + queryPath
}
}
const buildLink = (p: number): string => path + '?page=' + p + options

const totalPages = isPaginated ? Math.ceil(totalItems / limit) : 1
Expand All @@ -446,13 +448,17 @@ export async function paginate<T extends ObjectLiteral>(
select: isQuerySelected ? selectParams : undefined,
filter: query.filter,
},
links: {
first: page == 1 ? undefined : buildLink(1),
previous: page - 1 < 1 ? undefined : buildLink(page - 1),
current: buildLink(page),
next: page + 1 > totalPages ? undefined : buildLink(page + 1),
last: page == totalPages || !totalItems ? undefined : buildLink(totalPages),
},
// If there is no `path`, don't build links.
links:
path !== null
? {
first: page == 1 ? undefined : buildLink(1),
previous: page - 1 < 1 ? undefined : buildLink(page - 1),
current: buildLink(page),
next: page + 1 > totalPages ? undefined : buildLink(page + 1),
last: page == totalPages || !totalItems ? undefined : buildLink(totalPages),
}
: ({} as Paginated<T>['links']),
}

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

0 comments on commit 813e893

Please sign in to comment.