graphqlnestjstypeormresolver

ManyToOne field doesn't appear in Parent resolver


I'm having some trouble with an entity in a NestJS project. I'm using TypeOrm to manage the PostgreSQL database, GraphQL and DataLoader to load, for example, the users in the database.

Now, I've this entity:

import { ObjectType, Field, ID } from "@nestjs/graphql";
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { Comment } from "./comment.entity";
import { User } from "./user.entity";

@ObjectType()
@Entity({name: 'comments_likes'})
export class CommentLike {

    @Field()
    @PrimaryGeneratedColumn()
    id: number;

    @Field()
    @Column({type: 'timestamptz', nullable: false})
    liked_at: Date

    @Field()
    @ManyToOne(() => Comment, (comment) => comment.id)
    @JoinColumn({name: 'refId'})
    ref: number;

    @Field({nullable: false})
    @ManyToOne(() => User, (user)  => user.id)
    @JoinColumn({name: 'ownerId'})
    owner: number
}

As you can see, I have four different columns: the id, the liked_at timestamp, the ref to the comment id, and the owner that is a number that represents a user in users table.

Now, this is my resolver:

import { Args, Context, Mutation, Parent, Query, ResolveField, Resolver }    from '@nestjs/graphql';
import { User } from '../../models/user.entity';
import { CommentLike } from '../../models/like_comment.entity';
import { LikeCommentInput } from './input/like-comment.input';
import { LikesCommentService } from './likes-comment.service';
import DataLoader from 'dataloader';

@Resolver(CommentLike)
export class LikesCommentResolver {

    constructor(
        private readonly likesCommentService: LikesCommentService
    ) {}

    @Query(() => CommentLike)
    public async getCommentLikeById(@Args('id') id: number) : Promise<CommentLike> {
        return this.likesCommentService.commentLikeRepo.findOne({id: id});
    }

    @Mutation(() => CommentLike)
    public async addCommentLike(@Args('data') input: LikeCommentInput) : Promise<CommentLike> {
        const newLike = new CommentLike;
        newLike.liked_at = input.liked_at;
        newLike.owner = input.owner
        newLike.ref = input.comment;

        return this.likesCommentService.commentLikeRepo.save(newLike);
    }

    @ResolveField('owner', () => User)
    public async getOwner(@Parent() commentLike: CommentLike, @Context('usersLoader') usersLoader: DataLoader<number, User>) : Promise<User> {
        console.log(commentLike, typeof commentLike);
        return usersLoader.load(commentLike.owner);
    }

}

My problem is in the getCommentLikeById, when I try to run this GraphQL query:

query {
    getCommentLikeById(id: 2) {
        owner {
            username
        }
    }
}

As error, I got The loader.load() function must be called with a value,but got: undefined. that is referred to the ResolveProperty function getOwner. In this funciton I added a console.log just to see the @Parent parameter, and I saw that I receive only the id and the liked_at timestamp and not the owner field either the ref field.

I tried to add {eager: true} to the ManyToOne, but in this way I receive back all the User object, and I want only the id in order to load the User through the DataLoader.

Thank you for any advice on how to do this :)!


Solution

  • Ok, I fixed it editing the entity in this way

    import { ObjectType, Field, ID } from "@nestjs/graphql";
    import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, RelationId } from "typeorm";
    import { Comment } from "./comment.entity";
    import { User } from "./user.entity";
    
    @ObjectType()
    @Entity({name: 'comments_likes'})
    export class CommentLike {
    
        @Field()
        @PrimaryGeneratedColumn()
        id: number;
    
        @Field()
        @Column({type: 'timestamptz', nullable: false})
        liked_at: Date
    
        @Field()
        @ManyToOne(() => Comment, (comment) => comment.id)
        @JoinColumn({name: 'refId'})
        ref: number;
    
        @Field({nullable: false})
        @ManyToOne(() => User, (user) => user.id)
        @JoinColumn({name: 'ownerId'})
        owner: User
    
        @Column()
        ownerId: number
    }
    

    Just added at the end one Column, see also this answer.

    Maybe this will help someone having the same problem!