Skip to content

Commit

Permalink
fix(be): add problemTag and problemTestcase to Admin Problem GET API (#…
Browse files Browse the repository at this point in the history
…1397)

* feat: add field resolvers

- problem -> problemTag
- problem -> problemTestcase
- problemTag -> tag

* test: add test cases

* test: add seed data

isVisible이 false인 problem 데이터 2개

* refactor: add PR review comments

* docs: add selection set for getProblems query

Co-authored-by: Jaehyeon1020 <[email protected]>
  • Loading branch information
SH9480P and Jaehyeon1020 authored Feb 16, 2024
1 parent 6d73c0e commit faee9a2
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 8 deletions.
38 changes: 38 additions & 0 deletions backend/apps/admin/src/problem/problem-tag.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { InternalServerErrorException, Logger } from '@nestjs/common'
import { Query, Resolver, ResolveField, Parent } from '@nestjs/graphql'
import { ProblemTag, Tag } from '@generated'
import { ProblemService } from './problem.service'

@Resolver(() => ProblemTag)
export class ProblemTagResolver {
private readonly logger = new Logger(ProblemTagResolver.name)

constructor(private readonly problemService: ProblemService) {}

@ResolveField('tag', () => Tag)
async getTag(@Parent() problemTag: ProblemTag) {
try {
return await this.problemService.getTag(problemTag.tagId)
} catch (error) {
this.logger.error(error)
throw new InternalServerErrorException()
}
}
}

@Resolver(() => Tag)
export class TagResolver {
private readonly logger = new Logger(TagResolver.name)

constructor(private readonly problemService: ProblemService) {}

@Query(() => [Tag])
async getTags() {
try {
return await this.problemService.getTags()
} catch (error) {
this.logger.error(error)
throw new InternalServerErrorException()
}
}
}
3 changes: 2 additions & 1 deletion backend/apps/admin/src/problem/problem.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common'
import { StorageModule } from '@admin/storage/storage.module'
import { ProblemTagResolver, TagResolver } from './problem-tag.resolver'
import { ProblemResolver } from './problem.resolver'
import { ProblemService } from './problem.service'

@Module({
imports: [StorageModule],
providers: [ProblemResolver, ProblemService]
providers: [ProblemResolver, ProblemTagResolver, TagResolver, ProblemService]
})
export class ProblemModule {}
40 changes: 35 additions & 5 deletions backend/apps/admin/src/problem/problem.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,23 @@ import {
UsePipes,
ValidationPipe
} from '@nestjs/common'
import { Args, Context, Query, Int, Mutation, Resolver } from '@nestjs/graphql'
import { ContestProblem, Problem, Tag, WorkbookProblem } from '@generated'
import {
Args,
Context,
Query,
Int,
Mutation,
Resolver,
ResolveField,
Parent
} from '@nestjs/graphql'
import {
ContestProblem,
Problem,
ProblemTag,
ProblemTestcase,
WorkbookProblem
} from '@generated'
import { Prisma } from '@prisma/client'
import { AuthenticatedRequest } from '@libs/auth'
import { OPEN_SPACE_ID } from '@libs/constants'
Expand Down Expand Up @@ -303,8 +318,23 @@ export class ProblemResolver {
}
}

@Query(() => [Tag])
async getTags() {
return await this.problemService.getTags()
@ResolveField('problemTag', () => [ProblemTag])
async getProblemTags(@Parent() problem: Problem) {
try {
return await this.problemService.getProblemTags(problem.id)
} catch (error) {
this.logger.error(error)
throw new InternalServerErrorException()
}
}

@ResolveField('problemTestcase', () => [ProblemTestcase])
async getProblemTestCases(@Parent() problem: Problem) {
try {
return await this.problemService.getProblemTestcases(problem.id)
} catch (error) {
this.logger.error(error)
throw new InternalServerErrorException()
}
}
}
79 changes: 78 additions & 1 deletion backend/apps/admin/src/problem/problem.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import type {
Workbook,
WorkbookProblem,
Contest,
ContestProblem
ContestProblem,
ProblemTestcase,
ProblemTag,
Tag
} from '@generated'
import { Level } from '@generated'
import { expect } from 'chai'
Expand Down Expand Up @@ -43,6 +46,12 @@ const db = {
findMany: stub(),
update: stub()
},
problemTag: {
findMany: stub()
},
tag: {
findUnique: stub()
},
workbook: {
findFirstOrThrow: stub()
},
Expand Down Expand Up @@ -394,6 +403,33 @@ const exampleOrderUpdatedContestProblems: ContestProblem[] = [
}
]

const exampleProblemTestcases: ProblemTestcase[] = [
{
id: 1,
problemId: 1,
input: '1',
output: '1',
scoreWeight: 1,
createTime: new Date(),
updateTime: new Date()
}
]

const exampleProblemTags: ProblemTag[] = [
{
id: 1,
problemId: 1,
tagId: 1
}
]

const exampleTag: Tag = {
id: 1,
name: 'brute force',
createTime: new Date(),
updateTime: new Date()
}

describe('ProblemService', () => {
let service: ProblemService
let storageService: StorageService
Expand Down Expand Up @@ -836,4 +872,45 @@ describe('ProblemService', () => {
).to.be.rejectedWith(EntityNotExistException)
})
})

describe('getTag', () => {
afterEach(() => {
db.tag.findUnique.reset()
})

it('should return a tag object', async () => {
db.tag.findUnique.resolves(exampleTag)
expect(await service.getTag(1)).to.deep.equal(exampleTag)
})

it('should throw an EntityNotExist exception when tagId do not exist', async () => {
await expect(service.getTag(999)).to.be.rejectedWith(
EntityNotExistException
)
})
})

describe('getProblemTags', () => {
afterEach(() => {
db.problemTestcase.findMany.reset()
})

it('should return a problem tag array', async () => {
db.problemTag.findMany.resolves(exampleProblemTags)
expect(await service.getProblemTags(1)).to.deep.equal(exampleProblemTags)
})
})

describe('getProblemTestcases', () => {
afterEach(() => {
db.problemTestcase.findMany.reset()
})

it('should return a problem testcase array', async () => {
db.problemTestcase.findMany.resolves(exampleProblemTestcases)
expect(await service.getProblemTestcases(1)).to.deep.equal(
exampleProblemTestcases
)
})
})
})
29 changes: 29 additions & 0 deletions backend/apps/admin/src/problem/problem.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ProblemWhereInput } from '@generated'
import { Workbook } from 'exceljs'
import {
DuplicateFoundException,
EntityNotExistException,
UnprocessableDataException,
UnprocessableFileDataException
} from '@libs/exception'
Expand Down Expand Up @@ -580,4 +581,32 @@ export class ProblemService {
async getTags(): Promise<Partial<Tag>[]> {
return await this.prisma.tag.findMany()
}

async getTag(tagId: number) {
const tag = await this.prisma.tag.findUnique({
where: {
id: tagId
}
})
if (tag == null) {
throw new EntityNotExistException('problem')
}
return tag
}

async getProblemTags(problemId: number) {
return await this.prisma.problemTag.findMany({
where: {
problemId
}
})
}

async getProblemTestcases(problemId: number) {
return await this.prisma.problemTestcase.findMany({
where: {
problemId
}
})
}
}
28 changes: 27 additions & 1 deletion backend/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,33 @@ const createProblems = async () => {
'3\n1 2 1\n2 3 1\n3 1 1',
'5\n4 5 4\n1 3 4\n1 2 4\n3 2 3\n3 5 2\n1 4 3\n4 2 2\n1 5 4\n5 2 4\n3 4 2'
],
outputExamples: ['3', '35']
outputExamples: ['3', '35'],
isVisible: false
}
})
)

problems.push(
await prisma.problem.create({
data: {
title: '수정중인 문제',
createdById: superAdminUser.id,
groupId: publicGroup.id,
description: `<p>수정 작업 중</p>`,
difficulty: Level.Level3,
inputDescription: `<p>비공개</p>`,
outputDescription: `<p>비공개</p>`,
languages: [Language.C, Language.Cpp, Language.Java, Language.Python3],
hint: `<p>작성중</p>`,
timeLimit: 2000,
memoryLimit: 256,
source: '2024 육군훈련소 입소 코딩 테스트',
inputExamples: [
'3\n1 2 1\n2 3 1\n3 1 1',
'5\n4 5 4\n1 3 4\n1 2 4\n3 2 3\n3 5 2\n1 4 3\n4 2 2\n1 5 4\n5 2 4\n3 4 2'
],
outputExamples: ['3', '35'],
isVisible: false
}
})
)
Expand Down
11 changes: 11 additions & 0 deletions collection/admin/Problem/Get Problems/Succeed.bru
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ body:graphql {
inputDescription
outputDescription
hint
problemTag {
id
tag {
id
name
}
}
problemTestcase {
input
output
}
}
}
}
Expand Down

0 comments on commit faee9a2

Please sign in to comment.