doug-martin / nestjs-query

Easy CRUD for GraphQL.
https://doug-martin.github.io/nestjs-query
MIT License
823 stars 142 forks source link

How to expose relations in custom endpoints #1593

Open epenflow opened 2 months ago

epenflow commented 2 months ago

I’ve been using nestjs-query for a while, but I’m confused about how to expose and fetch relations when using custom endpoints. I could finds any guidance on the documentation. Could someone provide guidance on this.?

event.resolver.ts

import { InjectQueryService, QueryService } from '@nestjs-query/core';
import {
    ArrayConnectionType,
    CRUDResolver,
    CursorConnectionType,
    OffsetConnectionType,
    Relation,
} from '@nestjs-query/query-graphql';
import {
    HttpException,
    HttpStatus,
    Inject,
    Logger,
    UseGuards,
} from '@nestjs/common';
import { Args, Context, ID, Query, Resolver } from '@nestjs/graphql';
import { JwtService } from '@nestjs/jwt';
import { InjectRepository } from '@nestjs/typeorm';
import { OrganizationRole } from 'src/common/decorators';
import { EventEntity, OrganizationEntity } from 'src/common/entities';
import { EventDetailsType, EventType } from 'src/common/graphql';
import {
    EventDetailsArgs,
    EventDetailsConnection,
    EventTypeArgs,
    EventTypeConnection,
} from 'src/common/graphql/args/event.args';
import { JWTAuthGuard, RolesGuard } from 'src/common/guards';
import { GqlContext, JWTPayload } from 'src/common/interfaces';
import { Repository } from 'typeorm';

@Resolver(() => EventDetailsType)
export class EventResolver {
    private readonly logger = new Logger(EventResolver.name);
    constructor(
        @Inject(JwtService)
        private readonly jwtService: JwtService,
        @InjectRepository(OrganizationEntity)
        private readonly organizationRepository: Repository<OrganizationEntity>,
        @InjectQueryService(EventEntity)
        private readonly eventQueryService: QueryService<EventEntity>,
    ) {}

    /**
     *
     * - I want to expose the relations in this method and query all the related entities. How can I achieve this?
     */
    @Query(() => EventDetailsConnection, {
        name: `events`,
        description: `Retrieves a list of events.`,
    })
    async find(@Args() query: EventDetailsArgs) {
        const events = await this.eventQueryService.query(query);
        this.logger.debug({ events });
    }
}

event.args.ts

import {
    PagingStrategies,
    QueryArgsType,
    StaticConnectionType,
} from '@nestjs-query/query-graphql';
import { ArgsType } from '@nestjs/graphql';
import { EventDetailsType, EventType } from 'src/common/graphql/type';

@ArgsType()
export class EventTypeArgs extends QueryArgsType(EventType) {}
export const EventTypeConnection: StaticConnectionType<
    EventType,
    PagingStrategies
> = EventTypeArgs.ConnectionType;

@ArgsType()
export class EventDetailsArgs extends QueryArgsType(EventDetailsType) {}
export const EventDetailsConnection: StaticConnectionType<
    EventDetailsType,
    PagingStrategies
> = EventDetailsArgs.ConnectionType;

event.type.ts

import {
    FilterableField,
    IDField,
    Relation,
} from '@nestjs-query/query-graphql';
import { Field, GraphQLISODateTime, ID, ObjectType } from '@nestjs/graphql';
import { GraphQLString } from 'graphql';
import { OrganizationType } from 'src/common/graphql/type/organization.type';

@ObjectType('Event')
export class EventType {
    @IDField(() => ID, {
        description: `The unique identifier of the event.`,
    })
    id: string;

    @Field(() => GraphQLString, {
        description: `The name of the event.`,
    })
    name!: string;

    @Field(() => GraphQLString, {
        description: `The descriptions of the event.`,
        nullable: true,
    })
    descriptions?: string;

    @FilterableField(() => GraphQLISODateTime, {
        description: `The date and time when event was started.`,
    })
    startDateAt!: Date;

    @FilterableField(() => GraphQLISODateTime, {
        description: `The date and time when event was end.`,
    })
    endDateAt!: Date;
}

@ObjectType('EventDetails')
@Relation('organization', () => OrganizationType, {
    disableRemove: true,
    disableUpdate: true,
})
export class EventDetailsType extends EventType {}

event.entity.ts

import { OrganizationEntity } from 'src/common/entities/organization.entity';
import {
    Column,
    Entity,
    JoinColumn,
    ManyToOne,
    ObjectType,
    PrimaryGeneratedColumn,
} from 'typeorm';

@Entity({
    name: `event`,
})
export class EventEntity {
    /** Event ID */
    @PrimaryGeneratedColumn('uuid')
    id: string;

    /** Event Name */
    @Column('varchar')
    name: string;

    /** Event descriptions */
    @Column({
        type: 'text',
        nullable: true,
    })
    descriptions: string;

    /** Event Start Date */
    @Column({
        type: 'timestamp',
    })
    startDateAt: Date;
    /** Event End Date */
    @Column({
        type: 'timestamp',
    })
    endDateAt: Date;
    /** Relationship to Organization */
    @ManyToOne(
        (): ObjectType<OrganizationEntity> => OrganizationEntity,
        (organization) => organization.events,
    )
    @JoinColumn()
    organization!: OrganizationEntity;
}

organization.type.ts

import { FilterableField, IDField } from '@nestjs-query/query-graphql';
import { Field, GraphQLISODateTime, ID, ObjectType } from '@nestjs/graphql';
import { GraphQLString } from 'graphql';
import { AccountType } from 'src/common/graphql/type/account.type';
import { EventType } from 'src/common/graphql/type/event.type';

@ObjectType('Organization')
export class OrganizationType {
    @IDField(() => ID, {
        description: `The unique identifier of the organization.`,
    })
    id!: string;

    @FilterableField(() => GraphQLString, {
        description: `The name of the organization.`,
    })
    name!: string;

    @FilterableField(() => GraphQLISODateTime, {
        description: `The date and time when organization was created.`,
    })
    createdAt!: Date;

    @FilterableField(() => GraphQLISODateTime, {
        description: `The date and time when organization was updated.`,
    })
    updatedAt!: Date;
}

@ObjectType('OrganizationDetails')
export class OrganizationDetailsType extends OrganizationType {
    @Field(() => AccountType, {
        description: `The account associated with organization.`,
    })
    account: AccountType;

    @Field(() => [EventType], {
        nullable: true,
        description: `The events associated with organization.`,
    })
    events: EventType[];
}

organization.entity.ts

import { AccountEntity } from 'src/common/entities/account.entity';
import { EventEntity } from 'src/common/entities/event.entity';
import {
    Column,
    CreateDateColumn,
    Entity,
    JoinColumn,
    OneToMany,
    OneToOne,
    PrimaryGeneratedColumn,
    UpdateDateColumn,
} from 'typeorm';
@Entity({
    name: `organization`,
})
export class OrganizationEntity {
    /** ID Field */
    @PrimaryGeneratedColumn('uuid')
    id!: string;

    /** Name Field */
    @Column({
        type: 'varchar',
        length: 255,
    })
    name!: string;

    /** The date and time field when organization was generated and last updated */
    @CreateDateColumn()
    createdAt!: Date;
    @UpdateDateColumn()
    updatedAt!: Date;

    /** Relationship to account  */
    @OneToOne(() => AccountEntity, (account) => account.organization)
    @JoinColumn()
    account!: AccountEntity;

    /** Relationship to events */
    @OneToMany(() => EventEntity, (event) => event.organization)
    events: EventEntity[];
}

image