Skip to content

Commit

Permalink
Merge pull request #103 from ChubachiPT2024/feature/in-memory-repository
Browse files Browse the repository at this point in the history
インメモリ Repository の実装(残り)
  • Loading branch information
a2311kk authored Jul 6, 2024
2 parents a2becdd + 2749180 commit 7874fd2
Show file tree
Hide file tree
Showing 12 changed files with 313 additions and 6 deletions.
83 changes: 79 additions & 4 deletions src/application/reportLists/reportListApplicationService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@ import { ReportListImportCommand } from './reportListImportCommand'
import path from 'path'
import { InMemoryReportRepository } from 'src/infrastructure/inMemory/reports/inMemoryReportRepository'
import { InMemoryStudentRepository } from 'src/infrastructure/inMemory/students/inMemoryStudentRepository'
import { InMemorySubmissionRepository } from 'src/infrastructure/inMemory/submissions/inMemorySubmissionRepository'
import { InMemoryAssessmentRepository } from 'src/infrastructure/inMemory/assessments/inMemoryAssessmentRepository'

describe('import', () => {
test('The course of the report is saved.', async () => {
const courseRepository = new InMemoryCourseRepository()
const reportRepository = new InMemoryReportRepository()
const studentRepository = new InMemoryStudentRepository()
const submissionRepository = new InMemorySubmissionRepository()
const assessmentRepository = new InMemoryAssessmentRepository()
const service = new ReportListApplicationService(
courseRepository,
reportRepository,
studentRepository
studentRepository,
submissionRepository,
assessmentRepository
)
const command = new ReportListImportCommand(
path.join(__dirname, 'reportListImportTestFiles', 'reportlist.xlsx')
Expand All @@ -31,10 +37,14 @@ describe('import', () => {
const courseRepository = new InMemoryCourseRepository()
const reportRepository = new InMemoryReportRepository()
const studentRepository = new InMemoryStudentRepository()
const submissionRepository = new InMemorySubmissionRepository()
const assessmentRepository = new InMemoryAssessmentRepository()
const service = new ReportListApplicationService(
courseRepository,
reportRepository,
studentRepository
studentRepository,
submissionRepository,
assessmentRepository
)
const command = new ReportListImportCommand(
path.join(__dirname, 'reportListImportTestFiles', 'reportlist.xlsx')
Expand All @@ -52,10 +62,14 @@ describe('import', () => {
const courseRepository = new InMemoryCourseRepository()
const reportRepository = new InMemoryReportRepository()
const studentRepository = new InMemoryStudentRepository()
const submissionRepository = new InMemorySubmissionRepository()
const assessmentRepository = new InMemoryAssessmentRepository()
const service = new ReportListApplicationService(
courseRepository,
reportRepository,
studentRepository
studentRepository,
submissionRepository,
assessmentRepository
)
const command = new ReportListImportCommand(
path.join(__dirname, 'reportListImportTestFiles', 'reportlist.xlsx')
Expand All @@ -73,10 +87,14 @@ describe('import', () => {
const courseRepository = new InMemoryCourseRepository()
const reportRepository = new InMemoryReportRepository()
const studentRepository = new InMemoryStudentRepository()
const submissionRepository = new InMemorySubmissionRepository()
const assessmentRepository = new InMemoryAssessmentRepository()
const service = new ReportListApplicationService(
courseRepository,
reportRepository,
studentRepository
studentRepository,
submissionRepository,
assessmentRepository
)
const command = new ReportListImportCommand(
path.join(__dirname, 'reportListImportTestFiles', 'reportlist.xlsx')
Expand All @@ -89,4 +107,61 @@ describe('import', () => {
expect(student.numId).toBe(23745197)
expect(student.name).toBe('安藤 健')
})

test('The first submission is saved.', async () => {
const courseRepository = new InMemoryCourseRepository()
const reportRepository = new InMemoryReportRepository()
const studentRepository = new InMemoryStudentRepository()
const submissionRepository = new InMemorySubmissionRepository()
const assessmentRepository = new InMemoryAssessmentRepository()
const service = new ReportListApplicationService(
courseRepository,
reportRepository,
studentRepository,
submissionRepository,
assessmentRepository
)
const command = new ReportListImportCommand(
path.join(__dirname, 'reportListImportTestFiles', 'reportlist.xlsx')
)

await service.importAsync(command)

const submissions = await submissionRepository.findAsync(35677)
const submission = submissions.find((x) => x.studentNumId === 23745148)
expect(submission.reportId).toBe(35677)
expect(submission.studentNumId).toBe(23745148)
expect(submission.folderRelativePath).toBe('23745148@a2348mt')
})

test('The first assessment is saved.', async () => {
const courseRepository = new InMemoryCourseRepository()
const reportRepository = new InMemoryReportRepository()
const studentRepository = new InMemoryStudentRepository()
const submissionRepository = new InMemorySubmissionRepository()
const assessmentRepository = new InMemoryAssessmentRepository()
const service = new ReportListApplicationService(
courseRepository,
reportRepository,
studentRepository,
submissionRepository,
assessmentRepository
)
const command = new ReportListImportCommand(
path.join(__dirname, 'reportListImportTestFiles', 'reportlist.xlsx')
)

await service.importAsync(command)

const assessments = await assessmentRepository.findAsync(35677)
const assessment = assessments.find((x) => x.studentNumId === 23745148)

expect(assessment.reportId).toBe(35677)
expect(assessment.studentNumId).toBe(23745148)
expect(assessment.feedback).toBeUndefined()
expect(assessment.memo).toBeUndefined()
expect(assessment.grade).toBeUndefined()
expect(assessment.rank).toBeUndefined()
expect(assessment.score).toBeUndefined()
})
})
21 changes: 20 additions & 1 deletion src/application/reportLists/reportListApplicationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { ReportRepository } from 'src/domain/models/reports/reportRepository'
import { Report } from 'src/domain/models/reports/report'
import { StudentRepository } from 'src/domain/models/students/studentRepository'
import { Student } from 'src/domain/models/students/student'
import { SubmissionRepository } from 'src/domain/models/submissions/submissionRepository'
import { Submission } from 'src/domain/models/submissions/submission'
import { AssessmentRepository } from 'src/domain/models/assessments/assessmentRepository'
import { Assessment } from 'src/domain/models/assessments/assessment'

/**
* レポートリストアプリケーションサービス
Expand All @@ -17,11 +21,15 @@ export class ReportListApplicationService {
* @param courseRepository コースリポジトリ
* @param reportRepository レポートリポジトリ
* @param studentRepository 学生リポジトリ
* @param submissionRepository 提出物リポジトリ
* @param assessmentRepository 個別評価リポジトリ
*/
public constructor(
private readonly courseRepository: CourseRepository,
private readonly reportRepository: ReportRepository,
private readonly studentRepository: StudentRepository
private readonly studentRepository: StudentRepository,
private readonly submissionRepository: SubmissionRepository,
private readonly assessmentRepository: AssessmentRepository
) {}

/**
Expand Down Expand Up @@ -67,6 +75,17 @@ export class ReportListApplicationService {
const numId: number = Number(row.getCell('C').text)
const name: string = row.getCell('D').text
await this.studentRepository.saveAsync(new Student(userId, numId, name))

// TODO できればハイパーリンクから取得
// なぜか isHyperlink が false, hyperlink が undefined で取得できなかった
const folderRelativePath = `${numId}@${userId}`
await this.submissionRepository.saveAsync(
new Submission(reportId, numId, folderRelativePath)
)

// レポート ID と学籍番号以外は未定義で作成
// もし、最初から Excel に値が入っていることがあり得るなら要修正
await this.assessmentRepository.saveAsync(new Assessment(reportId, numId))
}

return reportId
Expand Down
Binary file not shown.
35 changes: 35 additions & 0 deletions src/domain/models/assessments/assessment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* 個別評価
*/
export class Assessment {
/**
* コンストラクタ
*
* @param reportId レポート ID
* @param studentNumId 学籍番号
* @param feedback フィードバック
* @param memo メモ
* @param grade 評点
* @param rank 評点内の位置
* @param score 点数
*/
public constructor(
public readonly reportId: number,
public readonly studentNumId: number,
public readonly feedback?: string,
public readonly memo?: string,
public readonly grade?: number,
public readonly rank?: number,
public readonly score?: number
) {
if (!grade && (grade < 0 || grade > 5)) {
throw new TypeError('The grade must be in [0, 5].')
}

// TODO rank の仕様決定後、バリデーション

if (!score && (score < 0 || score > 100)) {
throw new TypeError('The score must be in [0, 100].')
}
}
}
21 changes: 21 additions & 0 deletions src/domain/models/assessments/assessmentRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Assessment } from './assessment'

/**
* 個別評価リポジトリ
*/
export interface AssessmentRepository {
/**
* 個別評価を保存する
*
* @param assessment 個別評価
*/
saveAsync(assessment: Assessment): Promise<void>

/**
* 個別評価を検索する
*
* @param reportId レポート ID
* @returns 個別評価
*/
findAsync(reportId: number): Promise<Assessment[]>
}
17 changes: 17 additions & 0 deletions src/domain/models/submissions/submission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* 提出物
*/
export class Submission {
/**
* コンストラクタ
*
* @param reportId レポート ID
* @param studentNumId 学籍番号
* @param folderRelativePath 提出物フォルダの相対パス
*/
public constructor(
public readonly reportId: number,
public readonly studentNumId: number,
public readonly folderRelativePath: string
) {}
}
21 changes: 21 additions & 0 deletions src/domain/models/submissions/submissionRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Submission } from './submission'

/**
* 提出物リポジトリ
*/
export interface SubmissionRepository {
/**
* 提出物を保存する
*
* @param submission 提出物
*/
saveAsync(submission: Submission): Promise<void>

/**
* 提出物を検索する
*
* @param reportId レポート ID
* @returns 提出物
*/
findAsync(reportId: number): Promise<Submission[]>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { describe, expect, test } from 'vitest'
import { InMemoryAssessmentRepository } from './inMemoryAssessmentRepository'
import { Assessment } from 'src/domain/models/assessments/assessment'

describe('save', () => {
test('The saved assessment exists.', async () => {
const repository = new InMemoryAssessmentRepository()
const expected = new Assessment(1, 2)
await repository.saveAsync(expected)

const actual = await repository.findAsync(expected.reportId)

expect(actual.length).toBe(1)
expect(actual[0].reportId).toBe(expected.reportId)
expect(actual[0].studentNumId).toBe(expected.studentNumId)
expect(actual[0].feedback).toBe(expected.feedback)
expect(actual[0].memo).toBe(expected.memo)
expect(actual[0].grade).toBe(expected.grade)
expect(actual[0].rank).toBe(expected.rank)
expect(actual[0].score).toBe(expected.score)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Assessment } from 'src/domain/models/assessments/assessment'
import { AssessmentRepository } from 'src/domain/models/assessments/assessmentRepository'

export class InMemoryAssessmentRepository implements AssessmentRepository {
/**
* 提出物
* 1 つ目の Key がレポート ID, 2 つ目の Key が学籍番号
*/
private readonly assessments = new Map<number, Map<number, Assessment>>()

/**
* 個別評価を保存する
*
* @param assessment 個別評価
*/
async saveAsync(assessment: Assessment): Promise<void> {
let map = this.assessments.get(assessment.reportId)
if (!map) {
map = new Map<number, Assessment>()
this.assessments.set(assessment.reportId, map)
}
map.set(assessment.studentNumId, assessment)
}

/**
* 個別評価を検索する
*
* @param reportId レポート ID
* @returns 個別評価
*/
async findAsync(reportId: number): Promise<Assessment[]> {
const map = this.assessments.get(reportId) ?? new Map<number, Assessment>()
return [...map.values()]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, expect, test } from 'vitest'
import { InMemorySubmissionRepository } from './inMemorySubmissionRepository'
import { Submission } from 'src/domain/models/submissions/submission'

describe('save', () => {
test('The saved submission exists.', async () => {
const repository = new InMemorySubmissionRepository()
const expected = new Submission(1, 2, '23745101@a2301aa')
await repository.saveAsync(expected)

const actual = await repository.findAsync(expected.reportId)

expect(actual.length).toBe(1)
expect(actual[0].reportId).toBe(expected.reportId)
expect(actual[0].studentNumId).toBe(expected.studentNumId)
expect(actual[0].folderRelativePath).toBe(expected.folderRelativePath)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Submission } from 'src/domain/models/submissions/submission'
import { SubmissionRepository } from 'src/domain/models/submissions/submissionRepository'

/**
* インメモリ提出物リポジトリ
*/
export class InMemorySubmissionRepository implements SubmissionRepository {
/**
* 提出物
* 1 つ目の Key がレポート ID, 2 つ目の Key が学籍番号
*/
private readonly submissions = new Map<number, Map<number, Submission>>()

/**
* 提出物を保存する
*
* @param submission 提出物
*/
async saveAsync(submission: Submission): Promise<void> {
let map = this.submissions.get(submission.reportId)
if (!map) {
map = new Map<number, Submission>()
this.submissions.set(submission.reportId, map)
}
map.set(submission.studentNumId, submission)
}

/**
* 提出物を検索する
*
* @param reportId レポート ID
* @returns 提出物
*/
async findAsync(reportId: number): Promise<Submission[]> {
const map = this.submissions.get(reportId) ?? new Map<number, Submission>()
return [...map.values()]
}
}
Loading

0 comments on commit 7874fd2

Please sign in to comment.