Sobre el proyecto
# @querry-kit/nest
Helpers consolidados de NestJS para las APIs de Query Kit: proyección de campos, servicios de consulta estilo Prisma, políticas CASL, decoradores OpenAPI, pipes, DTOs de paginación y utilidades de objetos.
## 🌐 Ecosistema Querry Kit
La [descripción general de Querry Kit](https://querry-kit.github.io/querry-kit/) conecta los tres paquetes principales:
- [`@querry-kit/nest`](https://github.com/querry-kit/nest) proporciona la API de NestJS y los patrones de controlador.
- [`@querry-kit/nuxt`](https://github.com/querry-kit/nuxt) proporciona clientes de API tipados y primitivas de datos headless para Vue/Nuxt.
- [`@querry-kit/nuxt-ui`](https://github.com/querry-kit/nuxt-ui) proporciona controles de tabla de Nuxt UI construidos sobre esas primitivas.
## 📦 Instalación
```sh
pnpm add @querry-kit/nest
pnpm add @nestjs/common @nestjs/core @nestjs/swagger class-transformer class-validator reflect-metadata
```
Para el adaptador CASL opcional:
```sh
pnpm add @casl/ability @casl/prisma
```
La versión actual del paquete se publica en npm. npm es el canal de distribución principal.
Las etiquetas de release de GitHub siguen disponibles como alternativa:
```sh
pnpm add github:querry-kit/nest#v0.0.1
```
## 🚀 Flujo de trabajo de releases
Los releases se gestionan con Changesets y GitHub Actions. La rama `main` no contiene archivos `dist` confirmados; solo contiene el código fuente, el README y la configuración de los workflows.
Los cambios visibles para el paquete deben incluir un changeset:
```sh
pnpm changeset
```
Cuando los cambios llegan a `main`, el workflow `changesets` crea o actualiza un PR de release. Ese PR contiene el incremento de versión y las actualizaciones del changelog producidas por:
```sh
pnpm changeset version
```
El workflow de publicación en npm usa npm Trusted Publishing a través de GitHub Actions OIDC. El paquete de npm debe estar conectado a este repositorio y workflow en la configuración de publicación del paquete de npm:
- Repositorio: `querry-kit/nest`
- Archivo de workflow: `release.yml`
- Entorno: sin definir
Después de fusionar el PR de release, el workflow `npm publish` se ejecuta para los cambios de versión/changelog. Ejecuta las comprobaciones del paquete, construye `dist` en CI, publica `@querry-kit/nest` en npm, etiqueta el commit de release como `vX.Y.Z` y crea un GitHub Release.
Los consumidores deben instalar desde npm:
```sh
pnpm add @querry-kit/nest
```
## 🧩 Uso
`ResourceQuery` cubre el flujo común de controlador: parsea `fields` opcionales, fusiona los includes requeridos por el endpoint con los valores de `include` del cliente, genera includes de Prisma para las relaciones seleccionadas, llama a un `QueryService`, mapea modelos a DTOs y proyecta la respuesta.
```ts
import { Get, Query, Req } from '@nestjs/common';
import { ApiErrorResponses, ApiPaginatedResponse, ApiResourceQuery, QueryDTO, ResourceQuery } from '@querry-kit/nest';
@Get()
@ApiResourceQuery()
@ApiPaginatedResponse({ model: CustomerDTO })
@ApiErrorResponses({ badRequestDescription: 'Invalid query parameter.' })
async query(@Req() req: AuthRequest, @Query() query: QueryDTO<CustomerTypeMap>) {
return ResourceQuery.query({
service: this.customersService,
query,
schema: CustomerDTO,
ability: req.ability,
map: (customer, ability) => CustomerDTO.fromModel(customer, ability),
});
}
```
Crea servicios de recursos con `QueryService` y un delegado compatible con Prisma:
```ts
import { Injectable } from '@nestjs/common';
import { QueryService, type BaseDelegateTypeMap } from '@querry-kit/nest';
import { Prisma, PrismaService } from '../prisma';
interface CustomerTypeMap extends BaseDelegateTypeMap {
select: Prisma.CustomerSelect;
include: Prisma.CustomerInclude;
whereInput: Prisma.CustomerWhereInput;
orderByWithRelationInput: Prisma.CustomerOrderByWithRelationInput;
whereUniqueInput: Prisma.CustomerWhereUniqueInput;
scalarFieldEnum: Prisma.CustomerScalarFieldEnum;
}
@Injectable()
export class CustomersService extends QueryService<typeof PrismaService.prototype.customer, CustomerTypeMap> {
constructor(prisma: PrismaService) {
super(prisma.customer);
}
}
```
Hay subrutas específicas disponibles para importaciones más pequeñas:
```ts
import { createCaslAccessibleWhere, filterCaslFields } from '@querry-kit/nest/casl';
import { ApiResourceQuery } from '@querry-kit/nest/decorators';
import { Fields } from '@querry-kit/nest/fields';
import { parseObject } from '@querry-kit/nest/object';
import { QueryService } from '@querry-kit/nest/query-service';
```
## 🔐 CASL
CASL es opcional. Pasa `ability` solo cuando el endpoint deba fusionar una cláusula `where` con reconocimiento de autorización a través de `QueryService`; omítelo para APIs que no usan CASL.
```ts
import { createCaslAccessibleWhere } from '@querry-kit/nest/casl';
super(prisma.customer, {
subject: 'Customer',
accessibleWhere: createCaslAccessibleWhere({ action: 'read' }),
});
```
Cuando se pasa una ability a `query`, el servicio combina la cláusula where de CASL con los filtros del usuario como `{ AND: [accessibleWhere, parsedWhere] }`.
Para permisos de respuesta a nivel de campo, filtra el DTO completado sin mutarlo:
```ts
return filterCaslFields(dto, 'Customer', ability);
```
El helper usa la acción `read` por defecto. Pasa `{ action: RoleAction.READ }` cuando una aplicación use acciones en mayúsculas o respaldadas por enum. Solo filtra campos de DTO serializados; sigue pasando la ability a `QueryService` para restringir también las lecturas de base de datos.
## 🎯 Fields
`fields` es opcional por defecto. Cuando se omite, Query Kit devuelve la respuesta DTO completa. Cuando está presente, valida la sintaxis y los campos seleccionados, añade los includes de relación requeridos y proyecta los DTOs devueltos. Las llaves externas son opcionales, por lo que `{id,title}` es equivalente a `id,title`.
```txt
GET /books?fields=id,title
GET /books?fields={id,title}
GET /books?fields=items{id,title},meta{page,perPage,itemCount,pageCount}
GET /books?fields=items{},meta{page}
```
Un valor vacío explícito (`?fields=`) o una selección externa vacía (`?fields={}`) devuelve `{}`. Las selecciones anidadas vacías también son válidas: `items{}` produce objetos de item vacíos, mientras que `meta{page}` conserva solo los metadatos de página solicitados. Un valor que contenga solo espacios en blanco sigue siendo inválido.
Usa `prepareFieldsQuery` directamente cuando un controlador necesite orquestación personalizada del servicio:
```ts
import { Fields, prepareFieldsQuery } from '@querry-kit/nest/fields';
const prepared = prepareFieldsQuery({
fields: query.fields,
include: query.include,
schema: BookDTO,
requiredInclude: { author: true },
});
const { items, pageMeta } = await booksService.query({ ...query, include: prepared.include });
return {
items: Fields.project(items.map(BookDTO.fromModel), prepared.projection),
meta: Fields.project(pageMeta, prepared.metaProjection),
};
```
## 📖 Documentación
- [Getting Started](https://querry-kit.github.io/querry-kit/docs/nest/guide/getting-started)
- [Complete API Example](https://querry-kit.github.io/querry-kit/docs/nest/guide/example-app)
- [CRUD Controller](https://querry-kit.github.io/querry-kit/docs/nest/guide/crud-controller)
- [Fields](https://querry-kit.github.io/querry-kit/docs/nest/api/fields/)
- [Query Service](https://querry-kit.github.io/querry-kit/docs/nest/api/query-service)
- [DTOs and Pagination](https://querry-kit.github.io/querry-kit/docs/nest/api/dtos-pagination)
- [OpenAPI Decorators](https://querry-kit.github.io/querry-kit/docs/nest/api/openapi)
- [CASL](https://querry-kit.github.io/querry-kit/docs/nest/api/casl)
- [API Reference](https://querry-kit.github.io/querry-kit/docs/nest/api/)
## 🛠 Desarrollo
```sh
pnpm install
pnpm lint
pnpm check
pnpm test
pnpm test:coverage
pnpm build
```
La lista de permitidos de compilación del workspace permite los scripts nativos requeridos por el conjunto de herramientas de pruebas y documentación, incluido el observador de archivos de Parcel.
`pnpm test:coverage` recopila todos los archivos fuente, imprime el resumen de cobertura y escribe informes HTML y LCOV en `coverage/`. GitHub Actions ejecuta el mismo comando y conserva el informe como artefacto del workflow.
Comments
0 Rating appears after 10 ratings
Sign in to join the discussion.