Об этом проекте

# @querry-kit/nest Консолидированные помощники NestJS для API Query Kit: проекция полей, Prisma-подобные query-сервисы, политики CASL, декораторы OpenAPI, пайпы, DTO пагинации и утилиты объектов. ## 🌐 Экосистема Querry Kit [Обзор Querry Kit](https://querry-kit.github.io/querry-kit/) связывает три основных пакета: - [`@querry-kit/nest`](https://github.com/querry-kit/nest) предоставляет API NestJS и паттерны контроллеров. - [`@querry-kit/nuxt`](https://github.com/querry-kit/nuxt) предоставляет типизированные API-клиенты и headless-примитивы данных Vue/Nuxt. - [`@querry-kit/nuxt-ui`](https://github.com/querry-kit/nuxt-ui) предоставляет элементы управления таблицами Nuxt UI, построенные на этих примитивах. ## 📦 Установка ```sh pnpm add @querry-kit/nest pnpm add @nestjs/common @nestjs/core @nestjs/swagger class-transformer class-validator reflect-metadata ``` Для опционального адаптера CASL: ```sh pnpm add @casl/ability @casl/prisma ``` Текущая версия пакета опубликована на npm. npm является основным каналом распространения. Теги релизов GitHub остаются доступны как запасной вариант: ```sh pnpm add github:querry-kit/nest#v0.0.1 ``` ## 🚀 Процесс релиза Релизы управляются через Changesets и GitHub Actions. Ветка `main` не содержит закоммиченных файлов `dist`; она содержит только исходный код, README и конфигурацию workflow. Изменения, видимые в пакете, должны включать changeset: ```sh pnpm changeset ``` Когда изменения попадают в `main`, workflow `changesets` создаёт или обновляет release PR. Этот PR содержит обновление версии и изменения changelog, созданные командой: ```sh pnpm changeset version ``` Workflow публикации в npm использует npm Trusted Publishing через GitHub Actions OIDC. Пакет npm должен быть подключён к этому репозиторию и workflow в настройках публикации пакета npm: - Репозиторий: `querry-kit/nest` - Файл workflow: `release.yml` - Environment: не задан После слияния release PR workflow `npm publish` запускается для изменений версии/changelog. Он выполняет проверки пакета, собирает `dist` в CI, публикует `@querry-kit/nest` в npm, помечает релизный коммит тегом `vX.Y.Z` и создаёт GitHub Release. Потребителям следует устанавливать из npm: ```sh pnpm add @querry-kit/nest ``` ## 🧩 Использование `ResourceQuery` покрывает типичный поток контроллера: парсит опциональные `fields`, объединяет обязательные для эндпоинта includes со значениями `include` от клиента, генерирует Prisma includes для выбранных связей, вызывает `QueryService`, преобразует модели в DTO и проецирует ответ. ```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), }); } ``` Создавайте ресурсные сервисы с `QueryService` и 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); } } ``` Для меньших импортов доступны специализированные подпути: ```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 опционален. Передавайте `ability` только когда эндпоинт должен объединить `where`-условие с учётом авторизации через `QueryService`; опускайте его для API, которые не используют CASL. ```ts import { createCaslAccessibleWhere } from '@querry-kit/nest/casl'; super(prisma.customer, { subject: 'Customer', accessibleWhere: createCaslAccessibleWhere({ action: 'read' }), }); ``` Когда ability передаётся в `query`, сервис объединяет CASL where-условие с пользовательскими фильтрами как `{ AND: [accessibleWhere, parsedWhere] }`. Для разрешений на уровне полей ответа фильтруйте готовый DTO без его мутации: ```ts return filterCaslFields(dto, 'Customer', ability); ``` Помощник по умолчанию использует действие `read`. Передавайте `{ action: RoleAction.READ }`, когда приложение использует действия в верхнем регистре или на основе enum. Он фильтрует только сериализованные поля DTO; продолжайте передавать ability в `QueryService`, чтобы также ограничивать чтение из базы данных. ## 🎯 Fields `fields` по умолчанию опционален. Если он опущен, Query Kit возвращает полный DTO-ответ. Если он присутствует, он валидирует синтаксис и выбранные поля, добавляет необходимые includes для связей и проецирует возвращённые DTO. Внешние фигурные скобки опциональны, поэтому `{id,title}` эквивалентно `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} ``` Явное пустое значение (`?fields=`) или пустая внешняя выборка (`?fields={}`) возвращает `{}`. Пустые вложенные выборки также допустимы: `items{}` создаёт пустые объекты элементов, а `meta{page}` сохраняет только запрошенные метаданные страницы. Значение, содержащее только пробелы, остаётся недопустимым. Используйте `prepareFieldsQuery` напрямую, когда контроллеру нужна кастомная оркестрация сервиса: ```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), }; ``` ## 📖 Документация - [Начало работы](https://querry-kit.github.io/querry-kit/docs/nest/guide/getting-started) - [Полный пример API](https://querry-kit.github.io/querry-kit/docs/nest/guide/example-app) - [CRUD-контроллер](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) - [DTO и пагинация](https://querry-kit.github.io/querry-kit/docs/nest/api/dtos-pagination) - [Декораторы OpenAPI](https://querry-kit.github.io/querry-kit/docs/nest/api/openapi) - [CASL](https://querry-kit.github.io/querry-kit/docs/nest/api/casl) - [Справочник API](https://querry-kit.github.io/querry-kit/docs/nest/api/) ## 🛠 Разработка ```sh pnpm install pnpm lint pnpm check pnpm test pnpm test:coverage pnpm build ``` Allowlist сборки workspace разрешает нативные скрипты, необходимые для тестовой и документационной цепочки инструментов, включая файловый watcher Parcel. `pnpm test:coverage` собирает все исходные файлы, выводит сводку покрытия и записывает HTML- и LCOV-отчёты в `coverage/`. GitHub Actions запускает ту же команду и сохраняет отчёт как артефакт workflow.