import { ApolloError , AuthenticationError , ForbiddenError , } from 'apollo-server-micro' ; import { ID } from '@api/shared/shared.types' ; import { GraphConnectionArgs } from '../shared/shared.types' ; import BaseRepository from '../shared/base.repository' ; import { createLoader } from '@api/dataloader/dataloader.utils' ; import { PostInput , Maybe , Omit } from '@api/generated/graphql' ; import { findGraphConnection } from '@api/db/db.utils' ; import { generateId } from '../db/db.utils' ; import { PostModel } from './post.model' ; import { MediaModel } from '@api/media/media.model' ; import { ReactableType } from '@api/reactions/reaction.model' ; const createPostByIdLoader = createLoader < ID , PostModel > ( ( postIds ) => PostModel . query ( ) . findByIds ( postIds as ID [ ] ) , ( post ) => post . id ) ; interface PostsCountByUserId { userId : ID ; count : number ; } const createPostsCountByUserIdLoader = createLoader < ID , PostsCountByUserId > ( async ( userIds ) => { const postCounts = await PostModel . knexQuery ( ) . select ( 'userId' ) . count ( '*' ) . whereIn ( 'userId' , userIds as ID [ ] ) . groupBy < PostsCountByUserId [ ] > ( 'userId' ) ; return postCounts ; } , ( postsCount ) => postsCount . userId ) ; const postLoaders = ( ) => ( { postById : createPostByIdLoader ( ) , postsCountByUserId : createPostsCountByUserIdLoader ( ) , } ) ; export type PostGraphConnectionArgs = GraphConnectionArgs & { authorId ? : Maybe < ID > ; categoryId ? : Maybe < string > ; } ; class PostRepository extends BaseRepository { private loaders = postLoaders ( ) ; async create ( input ) { const { viewer } = this . context ; if ( ! viewer ) { throw new AuthenticationError ( 'You are not logged in' ) ; } const { title , categoryId , media } = input ; if ( media . userId !== viewer . id ) { throw new ForbiddenError ( "You can not use another user's media" ) ; } const postId = generateId ( ) ; const post = await PostModel . query ( ) . upsertGraph ( { id : postId , title , category : { id : categoryId } , user : { id : viewer . id } , media : { id : media . id } , reactable : { id : postId , type : ReactableType . POST , } , } , { insertMissing : true , relate : true } ) ; return post ; } async deleteById ( id ) { const { viewer } = this . context ; if ( ! viewer ) { throw new AuthenticationError ( 'You are not logged in' ) ; } const post = await this . findOneById ( id ) ; if ( ! post ) { throw new ApolloError ( 'Post not found' ) ; } if ( post . userId !== viewer . id ) { throw new AuthenticationError ( 'You are not logged in' ) ; } const deletedNum = await PostModel . query ( ) . deleteById ( post . id ) ; return ! ! deletedNum ; } async findOneById ( id ) { const post = await this . loaders . postById . load ( id ) ; return post ; } getCursor ( node ) { return node . id ; } async countByUserId ( userId ) { const result = await this . loaders . postsCountByUserId . load ( userId ) ; return result ?. count ?? 0 ; } async findConnection ( args ) { const { first , after , authorId , categoryId } = args ; const connection = await findGraphConnection ( { after , first , getCursorFn : this . getCursor , orderBy : 'createdAt' , tableName : PostModel . tableName , where : ( query ) => { if ( authorId ) { query . where ( { userId : authorId } ) ; } if ( categoryId ) { query . where ( { categoryId } ) ; } } , } ) ; return connection ; } } export default PostRepository ;