nestjs-query

website·Indexed 29 days ago

https://tripss.github.io/nestjs-query/

A collection of packages designed to simplify the creation of CRUD APIs for GraphQL and REST transports within NestJS. It provides a common interface for persistence layers including TypeORM, Mongoose, and Typegoose, featuring built-in support for filtering, paging, relations, and authorization via decorators like @FilterableField and @Authorize.

Tokens
47.5K
Snippets
233
Records
272
Agent score
74%

What's inside nestjs-query

  1. Overview of the nestjs-query Query interface

    The Query interface is the core of nestjs-query and is used across its various ORM integrations (TypeORM, Sequelize, Mongoose, and Typegoose). A Query object consists of three optional fields: filter for data selection, paging for result windowing, and sorting for result order.
  2. Overview of nestjs-query relation decorators

    Depending on the relation type and desired GraphQL behavior (pagination, filtering), use the following decorators:

    • @Relation: Single value (1:1, N:1).
    • @FilterableRelation: Single value, allows filtering parent by relation fields.
    • @UnPagedRelation: Array of values (M:N, 1:N), returns all records.
    • @FilterableUnPagedRelation: Array of values, allows filtering parent by relation fields.
    • @OffsetConnection: Collection using offset-based pagination.
    • @FilterableOffsetConnection: Offset connection, allows filtering parent by relation fields.
    • @CursorConnection: Collection using cursor-based pagination.
    • @FilterableCursorConnection: Cursor connection, allows filtering parent by relation fields.

    Important Notes:

    • Mongoose Limitation: @FilterableUnPagedRelation, @FilterableOffsetConnection, and @FilterableCursorConnection are not supported by Mongoose.
    • Performance: nestjs-query uses a request-scoped dataloader when loading relations to prevent the N+1 query problem.
  3. Overview of Nestjs-Query features

    Nestjs-Query is a collection of packages for NestJS that simplifies the creation of CRUD endpoints for GraphQL. Key features include:

    • Out-of-the-box CRUD for GraphQL using TypeORM, Sequelize, or Mongoose.
    • Aggregate queries on objects and their relations.
    • Built-in subscriptions for all CRUD operations.
    • Support for one-to-one, one-to-many, many-to-one, and many-to-many relations.
    • Integrated dataloader to prevent the N+1 query problem.
    • Relay connections for paginated results.
  4. Overview of CRUDResolver GraphQL mutations

    The CRUDResolver automatically exposes six mutation endpoints. The names of these endpoints are derived from the class name or the name provided to the @ObjectType decorator. For a DTO named TodoItem, the following endpoints are generated:

    • createOneTodoItem: Create a single record.
    • createManyTodoItems: Create multiple records.
    • updateOneTodoItem: Update a single record by ID.
    • updateManyTodoItems: Update multiple records based on a filter.
    • deleteOneTodoItem: Delete a single record by ID.
    • deleteManyTodoItems: Delete multiple records based on a filter.
  5. Overview of nestjs-query GraphQL hooks

    nestjs-query provides a set of decorators to modify incoming GraphQL requests before they are processed. These hooks can be applied to DTOs (including custom create or update DTOs). Each hook can be implemented as either a simple function or a class that extends Hook to leverage NestJS dependency injection.

    Available hooks include:

    • @BeforeFindOne: Before findOne query.
    • @BeforeQueryMany: Before queryMany query.
    • @BeforeCreateOne: Before createOne mutation.
    • @BeforeCreateMany: Before createMany mutation.
    • @BeforeUpdateOne: Before updateOne mutation.
    • @BeforeUpdateMany: Before updateMany mutation.
    • @BeforeDeleteOne: Before deleteOne mutation.
    • @BeforeDeleteMany: Before deleteMany mutation.
  6. Override QueryService methods using ProxyQueryService

    The ProxyQueryService delegates calls to another query service. It is used when you need to override specific methods (e.g., adding logging or timing to create, update, or delete) without extending the original service class directly.
  7. Use Assemblers to translate between DTOs and Entities

    Assemblers in nestjs-query are used to translate Data Transfer Objects (DTOs) into underlying database entities and vice versa. They are necessary when the DTO and Entity have different shapes, such as when using computed fields, mapping different field names (e.g., due to legacy database columns), or transforming DTOs before they reach the persistence QueryService.

    By using Assemblers, you maintain a separation of concerns: Resolvers handle GraphQL/transport logic, Services handle business logic using DTO contracts, and Assemblers handle the translation to the persistence layer. This allows the API to evolve independently of the database model.

  8. Update Relation Decorators for v0.23.0

    v0.22.x-to-v0.23.x

    The relation decorators have been renamed to be more explicit about their behavior. The previous @Relation, @FilterableRelation, @Connection, and @FilterableConnection decorators are replaced by the following:

    • @Relation: Single value relation (1:1, N:1).
    • @FilterableRelation: @Relation that allows filtering the parent by relation DTO fields.
    • @UnPagedRelation: Array of relations returning all records (no pagination).
    • @FilterableUnPagedRelation: @UnPagedRelation that allows filtering the parent by relation DTO fields.
    • @OffsetConnection: Collection using offset-based pagination.
    • @FilterableOffsetConnection: @OffsetConnection that allows filtering the parent by relation DTO fields.
    • @CursorConnection: Collection using cursor-based pagination.
    • @FilterableCursorConnection: @CursorConnection that allows filtering the parent by relation DTO fields.
    // Old: @Relation('subTasks', () => [TodoItem])
    // New:
    @OffsetConnection('subTasks', () => TodoItem)
    
    // Old: @FilterableRelation('subTasks', () => [TodoItem])
    // New:
    @FilterableOffsetConnection('subTasks', () => TodoItem)
    
    // Old: @Relation('subTasks', () => [TodoItem], {pagingStrategy: PagingStrategies.NONE})
    // New:
    @UnPagedRelation('subTasks', () => TodoItem)
    
    // Old: @Connection('subTasks', () => TodoItem)
    // New:
    @CursorConnection('subTasks', () => TodoItem)
  9. Understand the AuthorizationContext properties

    When using a CustomAuthorizer, the AuthorizationContext object provides metadata about the current operation to help determine access rights:
    interface AuthorizationContext {
      operationName: string; // e.g., 'queryMany' or 'updateOne'
      operationGroup: 'read' | 'create' | 'update' | 'delete' | 'export';
      readonly: boolean;     // true if the operation does not modify data
      many: boolean;          // true if the operation can affect multiple records
    }