import { UserInputError } from 'apollo-server-core' ; import _difference from 'lodash/difference' ; import _inter from 'lodash/intersection' ; import _uniq from 'lodash/uniq' ; import { USER_STATE } from 'common/enums' ; import { AuthenticationError , ForbiddenByStateError , ForbiddenError , } from 'common/errors' ; import { fromGlobalId } from 'common/utils' ; import { MutationToPutChapterResolver } from 'definitions' ; const resolver = async ( _ , { input : { id , articles , topic : topicGlobalId , ... rest } } , { viewer , dataSources : { atomService } } ) => { if ( ! viewer . id ) { throw new ForbiddenError ( 'visitor has no permission' ) ; } if ( viewer . state === USER_STATE . frozen ) { throw new ForbiddenByStateError ( `${ viewer . state } user has no permission` ) ; } const properties = { updatedAt : new Date ( ) , ... rest } as typeof rest & { updatedAt : Date ; topicId : string ; } ; const checkArticleIds = async ( ids ) => { if ( ids . length > 0 ) { const articlesObjs = await atomService . findMany ( { table : 'article' , whereIn : [ 'id' , ids ] , } ) ; if ( articlesObjs . length !== ids . length ) { throw new UserInputError ( 'some articles cannot be found.' ) ; } articlesObjs . map ( ( articleObj ) => { if ( articleObj . authorId !== viewer . id ) { throw new AuthenticationError ( 'users can only update their own articles.' ) ; } } ) ; } } ; /**
     * update
     * when id is provided
     */ if ( id ) { const { id : chapterDbId } = fromGlobalId ( id ) ; let chapter = await atomService . findUnique ( { table : 'chapter' , where : { id : chapterDbId } , } ) ; if ( ! chapter ) { throw new UserInputError ( 'cannot find chapter.' ) ; } const topic = await atomService . findUnique ( { table : 'topic' , where : { id : chapter . topicId } , } ) ; if ( ! topic ) { throw new UserInputError ( 'cannot find topic of chapter.' ) ; } if ( topic . userId !== viewer . id ) { throw new AuthenticationError ( 'users can only update chapters in their own topics' ) ; } if ( topicGlobalId && fromGlobalId ( topicGlobalId ) . id !== chapter . topicId ) { const newTopic = await atomService . findUnique ( { table : 'topic' , where : { id : fromGlobalId ( topicGlobalId ) . id } , } ) ; if ( newTopic . userId !== viewer . id ) { throw new AuthenticationError ( 'users can only update chapters in their own topics' ) ; } properties . topicId = newTopic . id ; } if ( Object . keys ( properties ) . length > 0 ) { chapter = await atomService . update ( { table : 'chapter' , where : { id : chapterDbId } , data : properties , } ) ; } if ( articles && articles . length > 0 ) { const newIds = _uniq ( articles ) . map ( ( globalId ) => fromGlobalId ( globalId ) . id ) ; const oldIds = ( await atomService . findMany ( { table : 'article_chapter' , where : { chapterId : chapterDbId } , } ) ) . map ( ( record ) => record . articleId ) ; const addIds = _difference ( newIds , oldIds ) as string [ ] ; const removeIds = _difference ( oldIds , newIds ) ; const updateIds = _inter ( newIds , oldIds ) ; await checkArticleIds ( addIds ) ; await Promise . all ( updateIds . map ( ( articleId ) => atomService . update ( { table : 'article_chapter' , where : { chapterId : chapterDbId , articleId } , data : { order : newIds . indexOf ( articleId ) , updatedAt : new Date ( ) } , } ) ) ) ; await Promise . all ( addIds . map ( ( articleId ) => atomService . create ( { table : 'article_chapter' , data : { chapterId : chapterDbId , articleId , order : newIds . indexOf ( articleId ) , } , } ) ) ) ; await Promise . all ( removeIds . map ( ( articleId ) => atomService . deleteMany ( { table : 'article_chapter' , where : { chapterId : chapterDbId , articleId , } , } ) ) ) ; } return chapter ; } /**
     * create
     * when id is provided
     */ if ( ! id ) { if ( ! rest . title || ! topicGlobalId ) { throw new UserInputError ( 'Title and topic is required for creating chapter.' ) ; } const { id : topicDbId } = fromGlobalId ( topicGlobalId ) ; const topic = await atomService . findUnique ( { table : 'topic' , where : { id : topicDbId } , } ) ; if ( ! topic ) { throw new UserInputError ( 'Topic not found' ) ; } if ( topic . userId !== viewer . id ) { throw new AuthenticationError ( 'Users can only create chapter in their own topics' ) ; } properties . topicId = topic . id ; const order = ( ( await atomService . max ( { table : 'chapter' , column : 'order' , where : { topicId : topicDbId } , } ) ) || 0 ) + 1 ; const chapter = await atomService . create ( { table : 'chapter' , data : { order , ... properties } , } ) ; if ( articles && articles . length > 0 ) { const ids = _uniq ( articles ) . map ( ( globalId ) => fromGlobalId ( globalId ) . id ) as string [ ] ; await checkArticleIds ( ids ) ; await Promise . all ( ids . map ( ( articleId , index ) => atomService . create ( { table : 'article_chapter' , data : { chapterId : chapter . id , articleId , order : index , } , } ) ) ) ; } return chapter ; } } ; export default resolver ;