Sobre o projeto

# @querry-kit/nest Helpers NestJS consolidados para APIs Query Kit: projeção de campos, serviços de consulta estilo Prisma, políticas CASL, decoradores OpenAPI, pipes, DTOs de paginação e utilitários de objetos. ## 🌐 Ecossistema Querry Kit A [visão geral do Querry Kit](https://querry-kit.github.io/querry-kit/) conecta os três pacotes principais: - [`@querry-kit/nest`](https://github.com/querry-kit/nest) fornece a API NestJS e os padrões de controller. - [`@querry-kit/nuxt`](https://github.com/querry-kit/nuxt) fornece clientes de API tipados e primitivas de dados headless para Vue/Nuxt. - [`@querry-kit/nuxt-ui`](https://github.com/querry-kit/nuxt-ui) fornece controles de tabela do Nuxt UI construídos sobre essas primitivas. ## 📦 Instalação ```sh pnpm add @querry-kit/nest pnpm add @nestjs/common @nestjs/core @nestjs/swagger class-transformer class-validator reflect-metadata ``` Para o adaptador CASL opcional: ```sh pnpm add @casl/ability @casl/prisma ``` A versão atual do pacote é publicada no npm. O npm é o canal de distribuição principal. As tags de release do GitHub permanecem disponíveis como alternativa: ```sh pnpm add github:querry-kit/nest#v0.0.1 ``` ## 🚀 Fluxo de Release Os releases são conduzidos por Changesets e GitHub Actions. A branch `main` não contém arquivos `dist` commitados; contém apenas o código-fonte, o README e a configuração de workflows. Alterações visíveis no pacote devem incluir um changeset: ```sh pnpm changeset ``` Quando alterações chegam à `main`, o workflow `changesets` cria ou atualiza um PR de release. Esse PR contém o bump de versão e as atualizações de changelog produzidas por: ```sh pnpm changeset version ``` O workflow de publicação no npm usa npm Trusted Publishing via GitHub Actions OIDC. O pacote npm deve estar conectado a este repositório e workflow nas configurações de publicação do pacote npm: - Repositório: `querry-kit/nest` - Arquivo de workflow: `release.yml` - Environment: não definido Após o merge do PR de release, o workflow `npm publish` é executado para as alterações de versão/changelog. Ele executa verificações do pacote, faz build do `dist` na CI, publica `@querry-kit/nest` no npm, marca o commit de release como `vX.Y.Z` e cria um GitHub Release. Consumidores devem instalar a partir do npm: ```sh pnpm add @querry-kit/nest ``` ## 🧩 Uso `ResourceQuery` cobre o fluxo comum de controller: faz parsing do `fields` opcional, mescla includes exigidos pelo endpoint com valores de `include` do cliente, gera includes Prisma para relações selecionadas, chama um `QueryService`, mapeia models para DTOs e projeta a resposta. ```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), }); } ``` Crie serviços de recurso com `QueryService` e um delegate compatível com 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); } } ``` Subpaths focados estão disponíveis para imports menores: ```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 é opcional. Passe `ability` apenas quando o endpoint deve mesclar uma cláusula `where` ciente de autorização através do `QueryService`; omita para APIs que não usam CASL. ```ts import { createCaslAccessibleWhere } from '@querry-kit/nest/casl'; super(prisma.customer, { subject: 'Customer', accessibleWhere: createCaslAccessibleWhere({ action: 'read' }), }); ``` Quando uma ability é passada para `query`, o serviço combina a cláusula where do CASL com os filtros do usuário como `{ AND: [accessibleWhere, parsedWhere] }`. Para permissões de resposta em nível de campo, filtre o DTO completo sem mutá-lo: ```ts return filterCaslFields(dto, 'Customer', ability); ``` O helper usa a ação `read` por padrão. Passe `{ action: RoleAction.READ }` quando uma aplicação usa ações em maiúsculas ou baseadas em enum. Ele filtra apenas campos de DTO serializados; continue passando a ability para o `QueryService` para restringir também as leituras no banco de dados. ## 🎯 Fields `fields` é opcional por padrão. Quando omitido, o Query Kit retorna a resposta DTO completa. Quando presente, valida a sintaxe e os campos selecionados, adiciona includes de relação necessários e projeta os DTOs retornados. As chaves externas são opcionais, então `{id,title}` é 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} ``` Um valor vazio explícito (`?fields=`) ou seleção externa vazia (`?fields={}`) retorna `{}`. Seleções aninhadas vazias também são válidas: `items{}` produz objetos de item vazios, enquanto `meta{page}` mantém apenas os metadados de página solicitados. Um valor contendo apenas espaços em branco permanece inválido. Use `prepareFieldsQuery` diretamente quando um controller precisar de orquestração customizada de serviço: ```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), }; ``` ## 📖 Documentação - [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/) ## 🛠 Desenvolvimento ```sh pnpm install pnpm lint pnpm check pnpm test pnpm test:coverage pnpm build ``` A allowlist de build do workspace permite os scripts nativos exigidos pela toolchain de testes e documentação, incluindo o file watcher do Parcel. `pnpm test:coverage` coleta todos os arquivos-fonte, imprime o resumo de cobertura e grava relatórios HTML e LCOV em `coverage/`. O GitHub Actions executa o mesmo comando e retém o relatório como artefato de workflow.