### Project Setup and Running Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Provides instructions on how to set up and run the NestJS GraphQL Tools project, including database creation, configuration, dependency installation, and starting the development server. ```bash createdb -h localhost -p 5432 -U postgres nestjs_graphql_tools_development_public; ``` ```bash yarn install yarn start:dev ``` -------------------------------- ### Project Setup and Running Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Provides instructions on how to set up and run the NestJS GraphQL Tools project, including database creation, configuration, dependency installation, and starting the development server. ```bash createdb -h localhost -p 5432 -U postgres nestjs_graphql_tools_development_public; ``` ```bash yarn install yarn start:dev ``` -------------------------------- ### Project Setup and Development Server Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/contributing.md Installs project dependencies using npm and starts the development server. Requires a configured database connection as specified in 'config/default.json'. ```bash npm i npm run start:dev ``` -------------------------------- ### Installation Guide Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Provides instructions for installing the nestjs-graphql-tools package using npm or yarn. ```bash npm i nestjs-graphql-tools or yarn add nestjs-graphql-tools ``` -------------------------------- ### Installation Guide Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Provides instructions for installing the nestjs-graphql-tools library using either npm or yarn package managers. ```bash npm i nestjs-graphql-tools or yarn add nestjs-graphql-tools ``` -------------------------------- ### GraphQL Federation Query Example Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Provides an example GraphQL query to fetch posts and their associated author details, demonstrating the use of GraphQL Federation to resolve relationships between different services. ```graphql { posts { id title authorId user { id name } } } ``` -------------------------------- ### GraphQL Federation Query Example Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Provides an example GraphQL query to fetch posts and their associated author details, demonstrating the use of GraphQL Federation to resolve relationships between different services. ```graphql { posts { id title authorId user { id name } } } ``` -------------------------------- ### GraphQL Sorting Example Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Provides an example of how to use sorting in GraphQL queries, specifying the order and nulls handling for a field. ```graphql { users( order_by: { id: ASC_NULLS_LAST } ) { id } } ``` -------------------------------- ### Database Creation Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/contributing.md Creates a new PostgreSQL database named 'nestjs_graphql_tools_development_public' on localhost with the user 'postgres'. This is a prerequisite for running the project. ```bash createdb -h localhost -U postgres nestjs_graphql_tools_development_public; ``` -------------------------------- ### GraphQL Query Example Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Demonstrates a complex GraphQL query structure with filtering, ordering, and pagination capabilities provided by the library. ```graphql { users( where: { id: { in: [1,2,3,4] } task_title: { like: "%Task%" } } order_by: {email: ASC, created_at: DESC} paginate: {page: 1, per_page: 10} ) { id fname lname email tasks(order_by: {id: ASC_NULLS_LAST}) { id title } } } ``` -------------------------------- ### GraphQL Query Example Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Demonstrates a complex GraphQL query structure with filtering, ordering, and pagination capabilities, showcasing the library's ability to build efficient queries. ```graphql { users( where: { id: { in: [1,2,3,4] } task_title: { like: "%Task%" } } order_by: {email: ASC, created_at: DESC} paginate: {page: 1, per_page: 10} ) { id fname lname email tasks(order_by: {id: ASC_NULLS_LAST}) { id title } } } ``` -------------------------------- ### Filter Usage Guide Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Provides a step-by-step guide on how to integrate filtering into NestJS GraphQL resolvers. It covers adding the `@Filter()` parameter with `FilterArgs` and how the decorator generates TypeORM-compatible query conditions. ```typescript // 1. Add @Filter() parameter with type of FilterArgs // 2. @Filter() will return typeorm compatible condition which you can use in your query builder. ``` -------------------------------- ### Filter Usage Guide Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Provides a step-by-step guide on how to integrate filtering into NestJS GraphQL resolvers. It covers adding the `@Filter()` parameter with `FilterArgs` and how the decorator generates TypeORM-compatible query conditions. ```typescript // 1. Add @Filter() parameter with type of FilterArgs // 2. @Filter() will return typeorm compatible condition which you can use in your query builder. ``` -------------------------------- ### GraphQL Federation with @ResolveReference and @GraphqlLoader Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Explains how to implement GraphQL Federation by annotating a method with both @ResolveReference and @GraphqlLoader. This enables referencing entities across different GraphQL services. The example shows how to resolve a reference for a User entity. ```typescript // users-application/src/users/users.resolver.ts @ResolveReference() @GraphqlLoader() async resolveReference( @Loader() loader: LoaderData, ) { const ids = loader.ids; const users = this.usersService.findByIds(ids); return loader.helpers.mapManyToOneRelation(users, loader.ids, 'id') } ``` ```typescript // users-application/src/users/users.service.ts @Injectable() export class UsersService { private users: User[] = [ { id: 1, name: 'John Doe' }, { id: 2, name: 'Richard Roe' }, ]; findByIds(idsList: number[]): User[] { return this.users.filter((user) => idsList.some(id => Number(id) === user.id)); } } ``` -------------------------------- ### GraphQL Federation with @ResolveReference and @GraphqlLoader Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Explains how to implement GraphQL Federation by annotating a method with both @ResolveReference and @GraphqlLoader. This enables referencing entities across different GraphQL services. The example shows how to resolve a reference for a User entity. ```typescript // users-application/src/users/users.resolver.ts @ResolveReference() @GraphqlLoader() async resolveReference( @Loader() loader: LoaderData, ) { const ids = loader.ids; const users = this.usersService.findByIds(ids); return loader.helpers.mapManyToOneRelation(users, loader.ids, 'id') } ``` ```typescript // users-application/src/users/users.service.ts @Injectable() export class UsersService { private users: User[] = [ { id: 1, name: 'John Doe' }, { id: 2, name: 'Richard Roe' }, ]; findByIds(idsList: number[]): User[] { return this.users.filter((user) => idsList.some(id => Number(id) === user.id)); } } ``` -------------------------------- ### ResolveField with Filter Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Illustrates how to use the `@Filter` decorator within a `@ResolveField` to filter related data. This example shows filtering tasks associated with a user, leveraging `GraphqlLoader` for efficient data fetching. ```typescript @Resolver(() => UserObjectType) export class UserResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @ResolveField(() => TaskObjectType) @GraphqlLoader() async tasks( @Loader() loader: LoaderData, @Filter(() => TaskObjectType) filter: FilterArgs, ) { const qb = this.taskRepository.createQueryBuilder() .where(filter) .andWhere({ assignee_id: In(loader.ids) }); const tasks = await qb.getMany(); return loader.helpers.mapOneToManyRelation(tasks, loader.ids, 'assignee_id'); } } ``` -------------------------------- ### Field Extraction with @SelectedFields Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Explains how to use the `@SelectedFields` decorator to retrieve only the fields requested in a GraphQL query. This optimizes database queries by selecting only necessary columns, as shown in the TypeORM example. ```typescript @Resolver(() => TaskObjectType) export class TaskResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @Query(() => [TaskObjectType]) async tasks( @Filter(() => TaskObjectType) filter: FilterArgs, @SelectedFields({sqlAlias: 't'}) selectedFields: SelectedFieldsResult // Requested fields will be here. sqlAlias is optional thing. It useful in case if you're using alias in query builder ) { const res = await this.taskRepository.createQueryBuilder('t') .select(selectedFields.fieldsData.fieldsString) // fieldsString return array of strings .where(filter) .getMany(); return res; } } ``` ```graphql { tasks { id title } } ``` ```sql SELECT "t"."id" AS "t_id", "t"."title" AS "t_title" FROM "task" "t" ``` -------------------------------- ### Docsify Initialization and Plugin Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/index.html This snippet shows the configuration for Docsify, a documentation site generator. It includes settings for sidebar depth, maximum heading level, automatic scrolling to top, repository linking, history mode routing, and code copying functionality. Additionally, it defines a plugin `OnReady` that hooks into Docsify's ready event to highlight code elements using Prism.js. ```javascript window.$docsify = { subMaxLevel: 1, maxLevel: 3, auto2top: true, repo: 'Adrinalin4ik/Nestjs-Graphql-Tools', routerMode: 'history', copyCode: { buttonText: 'Copy to clipboard', errorText: 'Error', successText: 'Copied' } }; const OnReady = (hook, vm) => { hook.ready(function () { console.log('ready'); Array.from(document.getElementsByTagName('code')).forEach(x => Prism.highlightElement(x)); }); }; $docsify.plugins = [].concat($docsify.plugins || [], OnReady); ``` -------------------------------- ### Sorting with GraphQL Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Shows how to implement sorting in GraphQL queries using the `@Sorting` decorator. It covers basic sorting with ASC/DESC and NULLS FIRST/LAST options, and demonstrates its usage with TypeORM's query builder. ```graphql { users( order_by: { id: ASC_NULLS_LAST } ) { id } } ``` -------------------------------- ### Users Query with Raw Filters and Pagination Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Demonstrates how to use raw filters with the `@Filter` decorator, allowing direct access to user-provided raw filter data, along with pagination. ```typescript import { Resolver, Query } from '@nestjs/graphql'; import { UserObjectType } from './user.object-type'; // Assuming UserObjectType is defined elsewhere import { UserFilterInputType } from './user-filter.input-type'; // Assuming UserFilterInputType is defined elsewhere import { Filter, RawFilterArgs, Paginator, PaginatorArgs } from 'nestjs-graphql-tools'; // Assuming these decorators/types are from the library export class UserResolver { @Query(() => [UserObjectType]) async usersRaw( @Filter(() => [UserObjectType, UserFilterInputType], {sqlAlias: 'u', raw: true}) filter: RawFilterArgs, @Paginator() paginator: PaginatorArgs ) { // Your customer filter logic.. return []; } } ``` -------------------------------- ### Pagination with @Paginator() Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Demonstrates the implementation of pagination in GraphQL resolvers using the `@Paginator()` decorator. It shows how to retrieve pagination arguments (page and per_page) and apply them to TypeORM queries for efficient data retrieval. ```typescript @Resolver(() => TaskObjectType) export class TaskResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @Query(() => [TaskObjectType]) async tasks( @Paginator() paginator: PaginatorArgs ) { const qb = this.taskRepository.createQueryBuilder('t'); if (paginator) { qb.offset(paginator.page * paginator.per_page).limit(paginator.per_page) } return qb.getMany(); } } ``` -------------------------------- ### Pagination with @Paginator() Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Shows how to implement pagination in GraphQL resolvers using the @Paginator() decorator, which provides page and per_page information. ```typescript @Resolver(() => TaskObjectType) export class TaskResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @Query(() => [TaskObjectType]) async tasks( @Paginator() paginator: PaginatorArgs, ) { const qb = this.taskRepository.createQueryBuilder('t'); if (paginator) { qb.offset(paginator.page * paginator.per_page).limit(paginator.per_page) } return qb.getMany(); } } ``` -------------------------------- ### Raw Sorting Access Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Explains how to enable raw sorting access, allowing developers to intercept and process raw sorting arguments directly within their resolvers. This is useful for building custom sorting interpreters. ```typescript export class UserResolver { @Query(() => [UserObjectType]) async usersRaw( @Sorting(() => [UserObjectType], { sqlAlias: 'u', raw: true}) sorting: RawSortingArgs, @Paginator() paginator: PaginatorArgs ) { // Your customer filter logic.. return []; } } ``` -------------------------------- ### Data Loader for One-to-Many Relations Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Illustrates how to use the `@GraphqlLoader` decorator and `@Loader` parameter in a NestJS resolver to efficiently fetch related data (tasks for users) and solve the N+1 problem. It shows how to map the fetched data to the expected shape for GraphQL. ```typescript @Resolver(() => UserObjectType) export class UserResolver { @ResolveField(() => TaskObjectType) @GraphqlLoader() async tasks( @Loader() loader: LoaderData, @Args('story_points') story_points: number, // custom search arg ) { const tasks = await getRepository(Task).find({ where: { assignee_id: In(loader.ids) // assignee_id is foreign key from Task to User table story_points } }); return loader.helpers.mapOneToManyRelation(tasks, loader.ids, 'assignee_id'); // this helper will construct an object like { : Task }. Graphql expects this shape. } } ``` -------------------------------- ### Users Query with Custom Filters and Sorting Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Illustrates a users query that utilizes custom filters defined in `UserFilterInputType` and applies sorting based on provided arguments. ```typescript import { Resolver, Query, Args } from '@nestjs/graphql'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserObjectType } from './user.object-type'; // Assuming UserObjectType is defined elsewhere import { Task } from '../task/task.entity'; // Assuming Task entity is defined elsewhere import { User } from './user.entity'; // Assuming User entity is defined elsewhere import { Filter, FilterArgs, Sorting, SortArgs } from 'nestjs-graphql-tools'; // Assuming these decorators/types are from the library import { UserFilterInputType } from './user-filter.input-type'; // Assuming UserFilterInputType is defined elsewhere @Resolver(() => UserObjectType) export class UserResolver { constructor( @InjectRepository(Task) public readonly taskRepository: Repository, @InjectRepository(StoryModel) public readonly storyRepository: Repository, // Assuming StoryModel is defined elsewhere @InjectRepository(User) public readonly userRepository: Repository ) {} @Query(() => [UserObjectType]) users( @Filter(() => [UserObjectType, UserFilterInputType]) filter: FilterArgs, // <-- Object model and Filter model. It is possible to provide only one model or more that 2. @Sorting(() => UserObjectType, { sqlAlias: 'u' }) sorting: SortArgs ) { const qb = this.userRepository.createQueryBuilder('u') .leftJoin('task', 't', 't.assignee_id = u.id') .where(filter) .orderBy(sorting); return qb.getMany() } } ``` -------------------------------- ### Many-to-One Relation with GraphQL Loader Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Demonstrates how to resolve a many-to-one relationship in NestJS using the @GraphqlLoader decorator. It shows how to inject the repository, define the foreign key, and use the loader to fetch related user data efficiently. ```typescript import { Resolver, ResolveField, Injectable } from '@nestjs/graphql'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Brackets, In } from 'typeorm'; import { GraphqlLoader, Loader, LoaderData, Filter } from 'nestjs-graphql-tools'; // Assuming TaskObjectType and UserObjectType are defined elsewhere // Assuming User entity is defined elsewhere @Resolver(() => TaskObjectType) export class TaskResolver { constructor( @InjectRepository(User) public readonly userRepository: Repository ) {} @ResolveField(() => UserObjectType) @GraphqlLoader({ foreignKey: 'assignee_id' // Here we're providing foreigh key. Decorator gather all the keys from parent and provide it in loader.ids }) async assignee( @Loader() loader: LoaderData, @Filter(() => UserObjectType) filter: Brackets, ) { const qb = this.userRepository.createQueryBuilder('u') .where(filter) .andWhere({ id: In(loader.ids) // Here will be assigne_ids }) const users = await qb.getMany(); return loader.helpers.mapManyToOneRelation(users, loader.ids); // This helper provide the shape {assignee_id: User} } } ``` -------------------------------- ### Query with Filters Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Demonstrates how to use the `@Filter` decorator to apply filters to GraphQL queries. It shows how to combine TypeORM query builder conditions with custom filters and additional arguments. ```typescript import { Resolver, Query, Args, ResolveField, Root, } from "@nestjs/graphql"; import { InjectRepository, Repository, } from "@nestjs/typeorm"; import { Filter, FilterArgs, GraphqlLoader, Loader, LoaderData, Paginator, PaginatorArgs, SortArgs, Sorting, } from "nestjs-graphql-tools"; import { UserObjectType, TaskObjectType, } from "./dto"; // Assuming these are your DTOs import { User, Task, StoryModel, } from "./entities"; // Assuming these are your entities @Resolver(() => UserObjectType) export class UserResolver { constructor( @InjectRepository(Task) public readonly taskRepository: Repository, @InjectRepository(User) public readonly userRepository: Repository, @InjectRepository(StoryModel) public readonly storyRepository: Repository ) {} @Query(() => [UserObjectType]) users( @Filter(() => [UserObjectType, UserFilterInputType]) filter: FilterArgs, @Sorting(() => UserObjectType, { sqlAlias: 'u' }) sorting: SortArgs ) { const qb = this.userRepository.createQueryBuilder('u') .leftJoin('task', 't', 't.assignee_id = u.id') .where(filter) .orderBy(sorting); return qb.getMany() } @Query(() => [UserObjectType]) async usersRaw( @Filter(() => [UserObjectType, UserFilterInputType], {sqlAlias: 'u', raw: true}) filter: RawFilterArgs, @Paginator() paginator: PaginatorArgs ) { // Your customer filter logic.. return []; } } @InputType() export class UserFilterInputType { @FilterField(() => String, { sqlExp: 't.title'}) task_title: string; @FilterField(() => String, { sqlExp: 't.story_points'}) task_story_points: number; @FilterField(() => String, { sqlExp: 'concat(u.fname, ' ', u.lname)'}) full_name: string; } @Resolver(() => TaskObjectType) export class TaskResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @Query(() => [TaskObjectType]) async tasks( @Sorting(() => TaskObjectType, { sqlAlias: 't' }) sorting: SortArgs ) { const qb = this.taskRepository.createQueryBuilder('t') .orderBy(sorting); return qb.getMany(); } } ``` -------------------------------- ### Many-to-One Relation with GraphQL Loader Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Demonstrates how to resolve a many-to-one relationship in NestJS using the @GraphqlLoader decorator. It shows how to inject the repository, define the foreign key, and use the loader to fetch related user data efficiently. ```typescript import { Resolver, ResolveField, Injectable } from '@nestjs/graphql'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Brackets, In } from 'typeorm'; import { GraphqlLoader, Loader, LoaderData, Filter } from 'nestjs-graphql-tools'; // Assuming TaskObjectType and UserObjectType are defined elsewhere // Assuming User entity is defined elsewhere @Resolver(() => TaskObjectType) export class TaskResolver { constructor( @InjectRepository(User) public readonly userRepository: Repository ) {} @ResolveField(() => UserObjectType) @GraphqlLoader({ foreignKey: 'assignee_id' // Here we're providing foreigh key. Decorator gather all the keys from parent and provide it in loader.ids }) async assignee( @Loader() loader: LoaderData, @Filter(() => UserObjectType) filter: Brackets, ) { const qb = this.userRepository.createQueryBuilder('u') .where(filter) .andWhere({ id: In(loader.ids) // Here will be assigne_ids }) const users = await qb.getMany(); return loader.helpers.mapManyToOneRelation(users, loader.ids); // This helper provide the shape {assignee_id: User} } } ``` -------------------------------- ### Data Loader for One-to-Many Relations Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Illustrates how to use the `@GraphqlLoader` decorator and `@Loader` parameter in a NestJS resolver to efficiently fetch one-to-many relationships and solve the n+1 problem. ```typescript @Resolver(() => UserObjectType) export class UserResolver { @ResolveField(() => TaskObjectType) @GraphqlLoader() async tasks( @Loader() loader: LoaderData, @Args('story_points') story_points: number, // custom search arg ) { const tasks = await getRepository(Task).find({ where: { assignee_id: In(loader.ids) // assignee_id is foreign key from Task to User table story_points } }); return loader.helpers.mapOneToManyRelation(tasks, loader.ids, 'assignee_id'); // this helper will construct an object like { : Task }. Graphql expects this shape. } } ``` -------------------------------- ### Tasks Query with Sorting Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Shows how to apply sorting to a query for tasks, using the `@Sorting` decorator to specify the order and optionally an SQL alias. ```typescript import { Resolver, Query } from '@nestjs/graphql'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { TaskObjectType } from '../task/task.object-type'; // Assuming TaskObjectType is defined elsewhere import { Task } from '../task/task.entity'; // Assuming Task entity is defined elsewhere import { Sorting, SortArgs } from 'nestjs-graphql-tools'; // Assuming these decorators/types are from the library @Resolver(() => TaskObjectType) export class TaskResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @Query(() => [TaskObjectType]) async tasks( /* SqlAlias is an ptional argument. Allows to provide alias in case if you have many tables joined. In current case it doesn't required */ @Sorting(() => TaskObjectType, { sqlAlias: 't' }) sorting: SortArgs ) { const qb = this.taskRepository.createQueryBuilder('t') .orderBy(sorting); return qb.getMany(); } } ``` -------------------------------- ### Users Query with Filters Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Demonstrates how to use the @Query decorator with filters to retrieve users. It supports filtering based on TypeORM conditions and custom arguments like task title. ```typescript import { Resolver, Query, Args } from '@nestjs/graphql'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserObjectType } from './user.object-type'; // Assuming UserObjectType is defined elsewhere import { Task } from '../task/task.entity'; // Assuming Task entity is defined elsewhere import { User } from './user.entity'; // Assuming User entity is defined elsewhere import { Filter } from 'nestjs-graphql-tools'; // Assuming Filter decorator is from this library import { FilterArgs } from 'nestjs-graphql-tools'; // Assuming FilterArgs type is from this library @Resolver(() => UserObjectType) export class UserResolver { constructor( @InjectRepository(Task) public readonly taskRepository: Repository, @InjectRepository(User) public readonly userRepository: Repository ) {} @Query(() => [UserObjectType]) users( @Filter(() => UserObjectType) filter: FilterArgs, // It will return typeorm condition @Args('task_title', {nullable: true}) taskTitle: string, // You can add custom additional filter if needed ) { const qb = this.userRepository.createQueryBuilder('u') .leftJoin('task', 't', 't.assignee_id = u.id') .where(filter) .distinct(); if (taskTitle) { // mixed filters qb.andWhere(`t.title ilike :title`, { title: `%${taskTitle}%` }) } return qb.getMany() } } ``` -------------------------------- ### Inherited Models with @InheritedModel() Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Explains the use of the @InheritedModel() decorator to create base models with common attributes, facilitating code reuse in GraphQL schemas. ```typescript // To use it, decorate your base model with the @InheritedModel() decorator. // You can find usage of it in base.dto.ts file inside src folder. ``` -------------------------------- ### Polymorphic Resolver with Nested Data Loading Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Demonstrates how to use `@GraphqlLoader` and `@SelectedUnionTypes` decorators to resolve polymorphic relationships and load nested data efficiently. It handles mapping GraphQL types to database types and querying specific fields based on selection. ```typescript // Parent class // task.resolver.ts @Resolver(() => TaskObjectType) export class TaskResolver { constructor( @InjectRepository(Task) public readonly taskRepository: Repository, @InjectRepository(Description) public readonly descriptionRepository: Repository ) {} @ResolveField(() => [DescriptionObjectType]) @GraphqlLoader() async descriptions( @Loader() loader: LoaderData, @SelectedUnionTypes({ nestedPolymorphicResolverName: 'descriptionable', }) selectedUnions: SelectedUnionTypesResult // <-- This decorator will gather and provide selected union types. NestedPolymorphicResolverName argument allows to specify where specifically it should gather the fields ) { // Mapping graphql types to the database types const selectedTypes = Array.from(selectedUnions.types.keys()).map(type => { switch (type) { case DescriptionTextObjectType.name: return DescriptionType.Text; case DescriptionChecklistObjectType.name: return DescriptionType.Checklist; } }); const qb = this.descriptionRepository.createQueryBuilder('d') .andWhere({ task_id: In(loader.ids), description_type: In(selectedTypes) // finding only selected types }) const descriptions = await qb.getMany(); return loader.helpers.mapOneToManyRelation(descriptions, loader.ids, 'task_id'); } } // Polymorphic resolver // description.resolver.ts @Resolver(() => DescriptionObjectType) export class DescriptionResolver { constructor( @InjectRepository(DescriptionText) public readonly descriptionTextRepository: Repository, @InjectRepository(DescriptionChecklist) public readonly descriptionChecklistRepository: Repository, ) {} @ResolveField(() => [DescriptionableUnion], { nullable: true }) @GraphqlLoader({ polymorphic: { idField: 'description_id', typeField: 'description_type' } }) async descriptionable( @Loader() loader: PolymorphicLoaderData<[DescriptionText | DescriptionChecklist], number, DescriptionType>, // <-- It will return aggregated polymorphicTypes @SelectedUnionTypes() types: SelectedUnionTypesResult // <-- It will extract from the query and return selected union types ) { const results = []; // <-- We need to gather all entities to the single array for (const item of loader.polimorphicTypes) { switch(item.descriminator) { case DescriptionType.Text: const textDescriptions = await this.descriptionTextRepository.createQueryBuilder() .select(types.getFields(DescriptionTextObjectType)) .where({ id: In(item.ids) }) .getRawMany(); results.push({ descriminator: DescriptionType.Text, entities: textDescriptions }) break; case DescriptionType.Checklist: const checklistDescriptions = await this.descriptionChecklistRepository.createQueryBuilder() .select(types.getFields(DescriptionChecklistObjectType)) .where({ id: In(item.ids) }) .getRawMany(); results.push({ descriminator: DescriptionType.Checklist, entities: checklistDescriptions }) break; default: break; } } return loader.helpers.mapOneToManyPolymorphicRelation(results, loader.ids); // <-- This helper will change shape of responce to the shape which is sutable for graphql } } ``` -------------------------------- ### Polymorphic Resolver with Nested Data Loading Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Demonstrates how to use `@GraphqlLoader` and `@SelectedUnionTypes` decorators to resolve polymorphic relationships and load nested data efficiently. It handles mapping GraphQL types to database types and querying specific fields based on selection. ```typescript // Parent class // task.resolver.ts @Resolver(() => TaskObjectType) export class TaskResolver { constructor( @InjectRepository(Task) public readonly taskRepository: Repository, @InjectRepository(Description) public readonly descriptionRepository: Repository ) {} @ResolveField(() => [DescriptionObjectType]) @GraphqlLoader() async descriptions( @Loader() loader: LoaderData, @SelectedUnionTypes({ nestedPolymorphicResolverName: 'descriptionable', }) selectedUnions: SelectedUnionTypesResult // <-- This decorator will gather and provide selected union types. NestedPolymorphicResolverName argument allows to specify where specifically it should gather the fields ) { // Mapping graphql types to the database types const selectedTypes = Array.from(selectedUnions.types.keys()).map(type => { switch (type) { case DescriptionTextObjectType.name: return DescriptionType.Text; case DescriptionChecklistObjectType.name: return DescriptionType.Checklist; } }); const qb = this.descriptionRepository.createQueryBuilder('d') .andWhere({ task_id: In(loader.ids), description_type: In(selectedTypes) // finding only selected types }) const descriptions = await qb.getMany(); return loader.helpers.mapOneToManyRelation(descriptions, loader.ids, 'task_id'); } } // Polymorphic resolver // description.resolver.ts @Resolver(() => DescriptionObjectType) export class DescriptionResolver { constructor( @InjectRepository(DescriptionText) public readonly descriptionTextRepository: Repository, @InjectRepository(DescriptionChecklist) public readonly descriptionChecklistRepository: Repository, ) {} @ResolveField(() => [DescriptionableUnion], { nullable: true }) @GraphqlLoader({ polymorphic: { idField: 'description_id', typeField: 'description_type' } }) async descriptionable( @Loader() loader: PolymorphicLoaderData<[DescriptionText | DescriptionChecklist], number, DescriptionType>, // <-- It will return aggregated polymorphicTypes @SelectedUnionTypes() types: SelectedUnionTypesResult // <-- It will extract from the query and return selected union types ) { const results = []; // <-- We need to gather all entities to the single array for (const item of loader.polimorphicTypes) { switch(item.descriminator) { case DescriptionType.Text: const textDescriptions = await this.descriptionTextRepository.createQueryBuilder() .select(types.getFields(DescriptionTextObjectType)) .where({ id: In(item.ids) }) .getRawMany(); results.push({ descriminator: DescriptionType.Text, entities: textDescriptions }) break; case DescriptionType.Checklist: const checklistDescriptions = await this.descriptionChecklistRepository.createQueryBuilder() .select(types.getFields(DescriptionChecklistObjectType)) .where({ id: In(item.ids) }) .getRawMany(); results.push({ descriminator: DescriptionType.Checklist, entities: checklistDescriptions }) break; default: break; } } return loader.helpers.mapOneToManyPolymorphicRelation(results, loader.ids); // <-- This helper will change shape of responce to the shape which is sutable for graphql } } ``` -------------------------------- ### GraphQL Loader Polymorphic Relations Configuration Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Explains how to configure the @GraphqlLoader decorator to handle polymorphic relations. It specifies the `idField` and `typeField` to correctly gather and group related data based on different types. ```APIDOC @GraphqlLoader decorator for polymorphic relations: Configuration: polymorphic: { idField: string; // Name of polymorphic id attribute of the parent model typeField: string; // Name of polymorphic type attribute of the parent model } Usage Example: ```typescript @GraphqlLoader({ polymorphic: { idField: 'description_id', typeField: 'description_type' } }) // ... resolver methods ``` Aggregated Data Structure: The `@Loader` decorator will provide an attribute called `polymorphicTypes` with the following shape: ```typescript [ { type: string | number; ids: string[] | number[]; } ] ``` This structure allows the resolver to efficiently fetch and map polymorphic associations by grouping IDs by their respective types. ``` -------------------------------- ### ResolveField with Filter for Tasks Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Shows how to use @ResolveField with @GraphqlLoader and @Filter to retrieve tasks associated with a user, applying filters and loader data. ```typescript import { Resolver, ResolveField } from '@nestjs/graphql'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserObjectType } from './user.object-type'; // Assuming UserObjectType is defined elsewhere import { TaskObjectType } from '../task/task.object-type'; // Assuming TaskObjectType is defined elsewhere import { Task } from '../task/task.entity'; // Assuming Task entity is defined elsewhere import { Filter } from 'nestjs-graphql-tools'; // Assuming Filter decorator is from this library import { FilterArgs } from 'nestjs-graphql-tools'; // Assuming FilterArgs type is from this library import { GraphqlLoader, Loader, LoaderData } from 'nestjs-graphql-tools'; // Assuming these are from the library @Resolver(() => UserObjectType) export class UserResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @ResolveField(() => TaskObjectType) @GraphqlLoader() async tasks( @Loader() loader: LoaderData, @Filter(() => TaskObjectType) filter: FilterArgs, ) { const qb = this.taskRepository.createQueryBuilder() .where(filter) .andWhere({ assignee_id: In(loader.ids) }); const tasks = await qb.getMany(); return loader.helpers.mapOneToManyRelation(tasks, loader.ids, 'assignee_id'); } } ``` -------------------------------- ### Base Models and Inheritance Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Describes the use of the `@InheritedModel()` decorator to create base models with common attributes in NestJS GraphQL. This promotes code reusability and maintainability by defining shared fields once. ```typescript // In order to make base model with common attributes it is required to decorate base model with the `@InheritedModel()` decorator. You can find usage of it in base.dto.ts file inside src folder. ``` -------------------------------- ### GraphQL Filtering with Operators Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Explains how to implement filtering in GraphQL queries using the `@Filter()` decorator. It details the structure of filter conditions, including operators like `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `like`, `notlike`, `between`, and `notbetween`, and how they translate to TypeORM query builder conditions. ```graphql # Basic example 1 { users(where: {id: {eq: 1}}) { id } } # Basic example 2 { users( where: { and: [ { email: {like: "yahoo.com"} } { email: {like: "google.com"} } ], or: { id: { between: [1,2,3] } } } ) { id } } ``` -------------------------------- ### GraphQL Filtering with Operators Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Explains how to implement filtering in GraphQL queries using the `@Filter()` decorator. It details the structure of filter conditions, including operators like `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `like`, `notlike`, `between`, and `notbetween`, and how they translate to TypeORM query builder conditions. ```graphql # Basic example 1 { users(where: {id: {eq: 1}}) { id } } # Basic example 2 { users( where: { and: [ { email: {like: "yahoo.com"} } { email: {like: "google.com"} } ], or: { id: { between: [1,2,3] } } } ) { id } } ``` -------------------------------- ### GraphQL Loader Polymorphic Relations Configuration Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Explains how to configure the @GraphqlLoader decorator to handle polymorphic relations. It specifies the `idField` and `typeField` to correctly gather and group related data based on different types. ```APIDOC @GraphqlLoader decorator for polymorphic relations: Configuration: polymorphic: { idField: string; // Name of polymorphic id attribute of the parent model typeField: string; // Name of polymorphic type attribute of the parent model } Usage Example: ```typescript @GraphqlLoader({ polymorphic: { idField: 'description_id', typeField: 'description_type' } }) // ... resolver methods ``` Aggregated Data Structure: The `@Loader` decorator will provide an attribute called `polymorphicTypes` with the following shape: ```typescript [ { type: string | number; ids: string[] | number[]; } ] ``` This structure allows the resolver to efficiently fetch and map polymorphic associations by grouping IDs by their respective types. ``` -------------------------------- ### Configuration Option: FILTER_OPERATION_PREFIX Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Details an environment variable `FILTER_OPERATION_PREFIX` that can be used to configure operation prefixes for filtering, similar to Hasura's WHERE operators. ```bash FILTER_OPERATION_PREFIX=_ ``` -------------------------------- ### Raw Sorting Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Enables access to raw sorting values provided by the user, allowing for custom sorting interpreters. Use @Sorting({ raw: true }) to enable this feature. ```typescript @Query(() => [UserObjectType]) async usersRaw( @Sorting(() => [UserObjectType], { sqlAlias: 'u', raw: true}) sorting: RawSortingArgs, @Paginator() paginator: PaginatorArgs ) { // Your customer filter logic.. return []; } ``` -------------------------------- ### Custom Sorting Fields Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Defines how to create custom sorting logic using decorators like @SortingField. It allows mapping GraphQL fields to SQL expressions for sorting query results. ```typescript // sorting.dto.ts @InputType() export class UserSortingInputType { @SortingField({sqlExp: 't.story_points'}) task_story_points: number; } // user.resolver.ts @Resolver(() => UserObjectType) export class UserResolver { constructor( @InjectRepository(Task) public readonly taskRepository: Repository, @InjectRepository(StoryModel) public readonly storyRepository: Repository, @InjectRepository(User) public readonly userRepository: Repository ) {} @Query(() => [UserObjectType]) users( /* SqlAlias is an optional argument. You can provide alias in case if you have many tables joined. Object model and Sorting model. Ability to provide 1+ model. It accepts both Object and Sorting models. Next model in array extends previous model overriding fields with the same names. */ @Sorting(() => [UserObjectType, UserSortingInputType], { sqlAlias: 'u' }) sorting: SortArgs ) { const qb = this.userRepository.createQueryBuilder('u') .leftJoin('task', 't', 't.assignee_id = u.id') .orderBy(sorting) .distinct(); return qb.getMany() } } ``` -------------------------------- ### Field Extraction with @SelectedFields Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/docs/README.md Illustrates how to retrieve only the fields requested in a GraphQL query using the @SelectedFields decorator, optimizing database queries. ```typescript @Resolver(() => TaskObjectType) export class TaskResolver { constructor(@InjectRepository(Task) public readonly taskRepository: Repository) {} @Query(() => [TaskObjectType]) async tasks( @Filter(() => TaskObjectType) filter: FilterArgs, @SelectedFields({sqlAlias: 't'}) selectedFields: SelectedFieldsResult // Requested fields will be here. sqlAlias is optional thing. It useful in case if you're using alias in query builder ) { const res = await this.taskRepository.createQueryBuilder('t') .select(selectedFields.fieldsData.fieldsString) // fieldsString return array of strings .where(filter) .getMany(); return res; } } ``` ```graphql { tasks { id title } } ``` ```sql SELECT "t"."id" AS "t_id", "t"."title" AS "t_title" FROM "task" "t" ``` -------------------------------- ### Configuration Option: FILTER_OPERATION_PREFIX Source: https://github.com/adrinalin4ik/nestjs-graphql-tools/blob/master/README.md Details an environment variable `FILTER_OPERATION_PREFIX` that can be used to configure operation prefixes for filtering, similar to Hasura's WHERE operators. ```bash FILTER_OPERATION_PREFIX=_ ```