diff --git a/.github/workflows/sql-explain-hook.yml b/.github/workflows/sql-explain-hook.yml new file mode 100644 index 000000000..e8de84a17 --- /dev/null +++ b/.github/workflows/sql-explain-hook.yml @@ -0,0 +1,41 @@ +name: Sql Explain Hook + +on: + pull_request: + branches: ["main"] + workflow_dispatch: + +env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + + +jobs: + sql-explain-hook: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: "17" + distribution: "temurin" + + - name: Jooq Code Generation + run: | + ./gradlew --info jooqCodegenAll + + - name: Generate Explain Docs + run: | + ./gradlew --info api-repo:generateExplainDocs + + - name: Zip Explain Docs + run: | + mv ./api-repo/src/test/resources/explain ./explain + zip explain-docs.zip ./explain/* + + - name: Upload Explain Docs + run: | + curl \ + -F 'payload_json={"username": "GitHubAction", "content": "Check the PR here: [PR #${{ github.event.pull_request.number }}](https://github.com/YAPP-Github/24th-Web-Team-1-BE/pull/${{ github.event.pull_request.number }})"}' \ + -F "file1=@explain-docs.zip" \ + $DISCORD_WEBHOOK diff --git a/api-repo/build.gradle.kts b/api-repo/build.gradle.kts index 2b8b18d10..e3dee1c49 100644 --- a/api-repo/build.gradle.kts +++ b/api-repo/build.gradle.kts @@ -32,4 +32,16 @@ dependencies { /** Local Cache **/ implementation("org.ehcache:ehcache:${DependencyVersion.EHCACHE}") implementation("org.springframework.boot:spring-boot-starter-cache") +} + +tasks { + test { + useJUnitPlatform() + } + + register("generateExplainDocs") { + useJUnitPlatform { + includeTags("explain") + } + } } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt index a87e0cc0b..317fab404 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleDao.kt @@ -12,7 +12,7 @@ import com.few.api.repo.dao.article.record.SelectWorkBookMappedArticleRecord import jooq.jooq_dsl.tables.ArticleIfo import jooq.jooq_dsl.tables.ArticleMst import jooq.jooq_dsl.tables.MappingWorkbookArticle -import org.jooq.DSLContext +import org.jooq.* import org.springframework.cache.annotation.Cacheable import org.springframework.stereotype.Repository @@ -23,56 +23,32 @@ class ArticleDao( @Cacheable(key = "#query.articleId", cacheManager = LOCAL_CM, cacheNames = [SELECT_ARTICLE_RECORD_CACHE]) fun selectArticleRecord(query: SelectArticleRecordQuery): SelectArticleRecord? { - val articleId = query.articleId - - return dslContext.select( - ArticleMst.ARTICLE_MST.ID.`as`(SelectArticleRecord::articleId.name), - ArticleMst.ARTICLE_MST.MEMBER_ID.`as`(SelectArticleRecord::writerId.name), - ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL.`as`(SelectArticleRecord::mainImageURL.name), - ArticleMst.ARTICLE_MST.TITLE.`as`(SelectArticleRecord::title.name), - ArticleMst.ARTICLE_MST.CATEGORY_CD.`as`(SelectArticleRecord::category.name), - ArticleIfo.ARTICLE_IFO.CONTENT.`as`(SelectArticleRecord::content.name), - ArticleMst.ARTICLE_MST.CREATED_AT.`as`(SelectArticleRecord::createdAt.name) - ).from(ArticleMst.ARTICLE_MST) - .join(ArticleIfo.ARTICLE_IFO) - .on(ArticleMst.ARTICLE_MST.ID.eq(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID)) - .where(ArticleMst.ARTICLE_MST.ID.eq(articleId)) - .and(ArticleMst.ARTICLE_MST.DELETED_AT.isNull) + return selectArticleRecordQuery(query) .fetchOneInto(SelectArticleRecord::class.java) } - fun selectWorkBookArticleRecord(query: SelectWorkBookArticleRecordQuery): SelectWorkBookArticleRecord? { - val articleMst = ArticleMst.ARTICLE_MST - val articleIfo = ArticleIfo.ARTICLE_IFO - val mappingWorkbookArticle = MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE - - val articleId = query.articleId - val workbookId = query.workbookId + fun selectArticleRecordQuery(query: SelectArticleRecordQuery) = dslContext.select( + ArticleMst.ARTICLE_MST.ID.`as`(SelectArticleRecord::articleId.name), + ArticleMst.ARTICLE_MST.MEMBER_ID.`as`(SelectArticleRecord::writerId.name), + ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL.`as`(SelectArticleRecord::mainImageURL.name), + ArticleMst.ARTICLE_MST.TITLE.`as`(SelectArticleRecord::title.name), + ArticleMst.ARTICLE_MST.CATEGORY_CD.`as`(SelectArticleRecord::category.name), + ArticleIfo.ARTICLE_IFO.CONTENT.`as`(SelectArticleRecord::content.name), + ArticleMst.ARTICLE_MST.CREATED_AT.`as`(SelectArticleRecord::createdAt.name) + ).from(ArticleMst.ARTICLE_MST) + .join(ArticleIfo.ARTICLE_IFO) + .on(ArticleMst.ARTICLE_MST.ID.eq(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID)) + .where(ArticleMst.ARTICLE_MST.ID.eq(query.articleId)) + .and(ArticleMst.ARTICLE_MST.DELETED_AT.isNull) + .query - return dslContext.select( - articleMst.ID.`as`(SelectWorkBookArticleRecord::articleId.name), - articleMst.MEMBER_ID.`as`(SelectWorkBookArticleRecord::writerId.name), - articleMst.MAIN_IMAGE_URL.`as`(SelectWorkBookArticleRecord::mainImageURL.name), - articleMst.TITLE.`as`(SelectWorkBookArticleRecord::title.name), - articleMst.CATEGORY_CD.`as`(SelectWorkBookArticleRecord::category.name), - articleIfo.CONTENT.`as`(SelectWorkBookArticleRecord::content.name), - articleMst.CREATED_AT.`as`(SelectWorkBookArticleRecord::createdAt.name), - mappingWorkbookArticle.DAY_COL.`as`(SelectWorkBookArticleRecord::day.name) - ).from(articleMst) - .join(articleIfo) - .on(articleMst.ID.eq(articleIfo.ARTICLE_MST_ID)) - .join(mappingWorkbookArticle) - .on(mappingWorkbookArticle.WORKBOOK_ID.eq(workbookId)) - .and(mappingWorkbookArticle.ARTICLE_ID.eq(articleMst.ID)) - .where(articleMst.ID.eq(articleId)) - .and(articleMst.DELETED_AT.isNull) + fun selectWorkBookArticleRecord(query: SelectWorkBookArticleRecordQuery): SelectWorkBookArticleRecord? { + return selectWorkBookArticleRecordQuery(query) .fetchOneInto(SelectWorkBookArticleRecord::class.java) } - fun selectWorkbookMappedArticleRecords(query: SelectWorkbookMappedArticleRecordsQuery): List { - val workbookId = query.workbookId - - return dslContext.select( + fun selectWorkBookArticleRecordQuery(query: SelectWorkBookArticleRecordQuery) = + dslContext.select( ArticleMst.ARTICLE_MST.ID.`as`(SelectWorkBookArticleRecord::articleId.name), ArticleMst.ARTICLE_MST.MEMBER_ID.`as`(SelectWorkBookArticleRecord::writerId.name), ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL.`as`(SelectWorkBookArticleRecord::mainImageURL.name), @@ -81,31 +57,59 @@ class ArticleDao( ArticleIfo.ARTICLE_IFO.CONTENT.`as`(SelectWorkBookArticleRecord::content.name), ArticleMst.ARTICLE_MST.CREATED_AT.`as`(SelectWorkBookArticleRecord::createdAt.name), MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.DAY_COL.`as`(SelectWorkBookArticleRecord::day.name) - ) - .from(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) - .leftJoin(ArticleMst.ARTICLE_MST) - .on(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.ARTICLE_ID.eq(ArticleMst.ARTICLE_MST.ID)) + ).from(ArticleMst.ARTICLE_MST) .join(ArticleIfo.ARTICLE_IFO) .on(ArticleMst.ARTICLE_MST.ID.eq(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID)) - .where(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID.eq(workbookId)) + .join(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) + .on(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID.eq(query.workbookId)) + .and(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.ARTICLE_ID.eq(ArticleMst.ARTICLE_MST.ID)) + .where(ArticleMst.ARTICLE_MST.ID.eq(query.articleId)) .and(ArticleMst.ARTICLE_MST.DELETED_AT.isNull) + .query + + fun selectWorkbookMappedArticleRecords(query: SelectWorkbookMappedArticleRecordsQuery): List { + return selectWorkbookMappedArticleRecordsQuery(query) .fetchInto(SelectWorkBookMappedArticleRecord::class.java) } + fun selectWorkbookMappedArticleRecordsQuery(query: SelectWorkbookMappedArticleRecordsQuery) = dslContext.select( + ArticleMst.ARTICLE_MST.ID.`as`(SelectWorkBookArticleRecord::articleId.name), + ArticleMst.ARTICLE_MST.MEMBER_ID.`as`(SelectWorkBookArticleRecord::writerId.name), + ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL.`as`(SelectWorkBookArticleRecord::mainImageURL.name), + ArticleMst.ARTICLE_MST.TITLE.`as`(SelectWorkBookArticleRecord::title.name), + ArticleMst.ARTICLE_MST.CATEGORY_CD.`as`(SelectWorkBookArticleRecord::category.name), + ArticleIfo.ARTICLE_IFO.CONTENT.`as`(SelectWorkBookArticleRecord::content.name), + ArticleMst.ARTICLE_MST.CREATED_AT.`as`(SelectWorkBookArticleRecord::createdAt.name), + MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.DAY_COL.`as`(SelectWorkBookArticleRecord::day.name) + ) + .from(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) + .leftJoin(ArticleMst.ARTICLE_MST) + .on(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.ARTICLE_ID.eq(ArticleMst.ARTICLE_MST.ID)) + .join(ArticleIfo.ARTICLE_IFO) + .on(ArticleMst.ARTICLE_MST.ID.eq(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID)) + .where(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID.eq(query.workbookId)) + .and(ArticleMst.ARTICLE_MST.DELETED_AT.isNull) + .query + fun insertFullArticleRecord(command: InsertFullArticleRecordCommand): Long { - val mstId = dslContext.insertInto(ArticleMst.ARTICLE_MST) + val mstId = insertArticleMstCommand(command) + .returning(ArticleMst.ARTICLE_MST.ID) + .fetchOne() + insertArticleIfoCommand(mstId!!.getValue(ArticleMst.ARTICLE_MST.ID), command).execute() + return mstId.getValue(ArticleMst.ARTICLE_MST.ID) + } + + fun insertArticleMstCommand(command: InsertFullArticleRecordCommand) = + dslContext.insertInto(ArticleMst.ARTICLE_MST) .set(ArticleMst.ARTICLE_MST.MEMBER_ID, command.writerId) .set(ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL, command.mainImageURL.toString()) .set(ArticleMst.ARTICLE_MST.TITLE, command.title) .set(ArticleMst.ARTICLE_MST.CATEGORY_CD, command.category) - .returning(ArticleMst.ARTICLE_MST.ID) - .fetchOne() - dslContext.insertInto(ArticleIfo.ARTICLE_IFO) - .set(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID, mstId!!.getValue(ArticleMst.ARTICLE_MST.ID)) - .set(ArticleIfo.ARTICLE_IFO.CONTENT, command.content) - .execute() - - return mstId.getValue(ArticleMst.ARTICLE_MST.ID) - } + fun insertArticleIfoCommand( + mstId: Long, + command: InsertFullArticleRecordCommand, + ) = dslContext.insertInto(ArticleIfo.ARTICLE_IFO) + .set(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID, mstId) + .set(ArticleIfo.ARTICLE_IFO.CONTENT, command.content) } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewCountDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewCountDao.kt index 7e21b1cd7..66926ac93 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewCountDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewCountDao.kt @@ -12,21 +12,26 @@ class ArticleViewCountDao( ) { fun upsertArticleViewCount(query: ArticleViewCountQuery) { + upsertArticleViewCountQuery(query) + .execute() + } + + fun upsertArticleViewCountQuery(query: ArticleViewCountQuery) = dslContext.insertInto(ARTICLE_VIEW_COUNT) .set(ARTICLE_VIEW_COUNT.ARTICLE_ID, query.articleId) .set(ARTICLE_VIEW_COUNT.VIEW_COUNT, 1) .set(ARTICLE_VIEW_COUNT.CATEGORY_CD, query.categoryType.code) .onDuplicateKeyUpdate() .set(ARTICLE_VIEW_COUNT.VIEW_COUNT, ARTICLE_VIEW_COUNT.VIEW_COUNT.plus(1)) - .execute() - } fun selectArticleViewCount(command: ArticleViewCountCommand): Long? { - return dslContext.select( - ARTICLE_VIEW_COUNT.VIEW_COUNT - ).from(ARTICLE_VIEW_COUNT) - .where(ARTICLE_VIEW_COUNT.ARTICLE_ID.eq(command.articleId)) - .and(ARTICLE_VIEW_COUNT.DELETED_AT.isNull) - .fetchOneInto(Long::class.java) + return selectArticleViewCountQuery(command).fetchOneInto(Long::class.java) } + + fun selectArticleViewCountQuery(command: ArticleViewCountCommand) = dslContext.select( + ARTICLE_VIEW_COUNT.VIEW_COUNT + ).from(ARTICLE_VIEW_COUNT) + .where(ARTICLE_VIEW_COUNT.ARTICLE_ID.eq(command.articleId)) + .and(ARTICLE_VIEW_COUNT.DELETED_AT.isNull) + .query } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewHisDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewHisDao.kt index 77bbab5b7..9a3b10efd 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewHisDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/article/ArticleViewHisDao.kt @@ -12,6 +12,10 @@ class ArticleViewHisDao( ) { fun insertArticleViewHis(command: ArticleViewHisCommand) { + insertArticleViewHisCommand(command).execute() + } + + fun insertArticleViewHisCommand(command: ArticleViewHisCommand) = dslContext.insertInto( ArticleViewHis.ARTICLE_VIEW_HIS, ArticleViewHis.ARTICLE_VIEW_HIS.ARTICLE_MST_ID, @@ -19,13 +23,15 @@ class ArticleViewHisDao( ).values( command.articleId, command.memberId - ).execute() - } + ) fun countArticleViews(query: ArticleViewHisCountQuery): Long? { - return dslContext.selectCount() - .from(ArticleViewHis.ARTICLE_VIEW_HIS) - .where(ArticleViewHis.ARTICLE_VIEW_HIS.ARTICLE_MST_ID.eq(query.articleId)) + return countArticleViewsQuery(query) .fetchOne(0, Long::class.java) } + + fun countArticleViewsQuery(query: ArticleViewHisCountQuery) = + dslContext.selectCount() + .from(ArticleViewHis.ARTICLE_VIEW_HIS) + .where(ArticleViewHis.ARTICLE_VIEW_HIS.ARTICLE_MST_ID.eq(query.articleId)).query } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt index bddf87640..0e1886e5f 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/member/MemberDao.kt @@ -23,20 +23,20 @@ class MemberDao( @Cacheable(key = "#query.writerId", cacheManager = LOCAL_CM, cacheNames = [SELECT_WRITER_CACHE]) fun selectWriter(query: SelectWriterQuery): WriterRecord? { - val writerId = query.writerId - - return dslContext.select( - Member.MEMBER.ID.`as`(WriterRecord::writerId.name), - DSL.jsonGetAttributeAsText(Member.MEMBER.DESCRIPTION, "name").`as`(WriterRecord::name.name), - DSL.jsonGetAttribute(Member.MEMBER.DESCRIPTION, "url").`as`(WriterRecord::url.name) - ) - .from(Member.MEMBER) - .where(Member.MEMBER.ID.eq(writerId)) - .and(Member.MEMBER.TYPE_CD.eq(MemberType.WRITER.code)) - .and(Member.MEMBER.DELETED_AT.isNull) + return selectWriterQuery(query) .fetchOneInto(WriterRecord::class.java) } + fun selectWriterQuery(query: SelectWriterQuery) = dslContext.select( + Member.MEMBER.ID.`as`(WriterRecord::writerId.name), + DSL.jsonGetAttributeAsText(Member.MEMBER.DESCRIPTION, "name").`as`(WriterRecord::name.name), + DSL.jsonGetAttribute(Member.MEMBER.DESCRIPTION, "url").`as`(WriterRecord::url.name) + ) + .from(Member.MEMBER) + .where(Member.MEMBER.ID.eq(query.writerId)) + .and(Member.MEMBER.TYPE_CD.eq(MemberType.WRITER.code)) + .and(Member.MEMBER.DELETED_AT.isNull) + /** * 작가 목록 조회 쿼리 * query의 writerIds에 해당하는 작가 목록을 조회한다. @@ -48,17 +48,7 @@ class MemberDao( val cachedIdS = cachedValues.map { it.writerId } val notCachedIds = query.writerIds.filter { it !in cachedIdS } - val fetchedValue = dslContext.select( - Member.MEMBER.ID.`as`(WriterRecord::writerId.name), - DSL.jsonGetAttributeAsText(Member.MEMBER.DESCRIPTION, "name") - .`as`(WriterRecord::name.name), - DSL.jsonGetAttribute(Member.MEMBER.DESCRIPTION, "url").`as`(WriterRecord::url.name) - ) - .from(Member.MEMBER) - .where(Member.MEMBER.ID.`in`(notCachedIds)) - .and(Member.MEMBER.TYPE_CD.eq(MemberType.WRITER.code)) - .and(Member.MEMBER.DELETED_AT.isNull) - .orderBy(Member.MEMBER.ID.asc()) + val fetchedValue = selectWritersQuery(notCachedIds) .fetchInto(WriterRecord::class.java).let { cacheManager.addSelectWorkBookCache(it) return@let it @@ -67,25 +57,40 @@ class MemberDao( return cachedValues + fetchedValue } - fun selectMemberByEmail(query: SelectMemberByEmailQuery): MemberIdRecord? { - val email = query.email + fun selectWritersQuery(notCachedIds: List) = dslContext.select( + Member.MEMBER.ID.`as`(WriterRecord::writerId.name), + DSL.jsonGetAttributeAsText(Member.MEMBER.DESCRIPTION, "name") + .`as`(WriterRecord::name.name), + DSL.jsonGetAttribute(Member.MEMBER.DESCRIPTION, "url").`as`(WriterRecord::url.name) + ) + .from(Member.MEMBER) + .where(Member.MEMBER.ID.`in`(notCachedIds)) + .and(Member.MEMBER.TYPE_CD.eq(MemberType.WRITER.code)) + .and(Member.MEMBER.DELETED_AT.isNull) + .orderBy(Member.MEMBER.ID.asc()) - return dslContext.select( - Member.MEMBER.ID.`as`(MemberIdRecord::memberId.name) - ) - .from(Member.MEMBER) - .where(Member.MEMBER.EMAIL.eq(email)) - .and(Member.MEMBER.DELETED_AT.isNull) + fun selectMemberByEmail(query: SelectMemberByEmailQuery): MemberIdRecord? { + return selectMemberByEmailQuery(query) .fetchOneInto(MemberIdRecord::class.java) } + fun selectMemberByEmailQuery(query: SelectMemberByEmailQuery) = dslContext.select( + Member.MEMBER.ID.`as`(MemberIdRecord::memberId.name) + ) + .from(Member.MEMBER) + .where(Member.MEMBER.EMAIL.eq(query.email)) + .and(Member.MEMBER.DELETED_AT.isNull) + fun insertMember(command: InsertMemberCommand): Long? { - val result = dslContext.insertInto(Member.MEMBER) - .set(Member.MEMBER.EMAIL, command.email) - .set(Member.MEMBER.TYPE_CD, command.memberType.code) + val result = insertMemberCommand(command) .returning(Member.MEMBER.ID) .fetchOne() return result?.getValue(Member.MEMBER.ID) } + + fun insertMemberCommand(command: InsertMemberCommand) = + dslContext.insertInto(Member.MEMBER) + .set(Member.MEMBER.EMAIL, command.email) + .set(Member.MEMBER.TYPE_CD, command.memberType.code) } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/ProblemDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/ProblemDao.kt index 63d2f4d90..a10dc6049 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/ProblemDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/ProblemDao.kt @@ -20,7 +20,11 @@ class ProblemDao( private val contentsJsonMapper: ContentsJsonMapper, ) { fun selectProblemContents(query: SelectProblemQuery): SelectProblemRecord? { - return dslContext.select( + return selectProblemContentsQuery(query) + .fetchOneInto(SelectProblemRecord::class.java) + } + fun selectProblemContentsQuery(query: SelectProblemQuery) = + dslContext.select( Problem.PROBLEM.ID.`as`(SelectProblemRecord::id.name), Problem.PROBLEM.TITLE.`as`(SelectProblemRecord::title.name), DSL.field("JSON_UNQUOTE({0})", String::class.java, Problem.PROBLEM.CONTENTS) @@ -29,11 +33,14 @@ class ProblemDao( .from(Problem.PROBLEM) .where(Problem.PROBLEM.ID.eq(query.problemId)) .and(Problem.PROBLEM.DELETED_AT.isNull) - .fetchOneInto(SelectProblemRecord::class.java) - } fun selectProblemAnswer(query: SelectProblemAnswerQuery): SelectProblemAnswerRecord? { - return dslContext.select( + return selectProblemAnswerQuery(query) + .fetchOneInto(SelectProblemAnswerRecord::class.java) + } + + fun selectProblemAnswerQuery(query: SelectProblemAnswerQuery) = + dslContext.select( Problem.PROBLEM.ID.`as`(SelectProblemAnswerRecord::id.name), Problem.PROBLEM.ANSWER.`as`(SelectProblemAnswerRecord::answer.name), Problem.PROBLEM.EXPLANATION.`as`(SelectProblemAnswerRecord::explanation.name) @@ -41,32 +48,33 @@ class ProblemDao( .from(Problem.PROBLEM) .where(Problem.PROBLEM.ID.eq(query.problemId)) .and(Problem.PROBLEM.DELETED_AT.isNull) - .fetchOneInto(SelectProblemAnswerRecord::class.java) - } fun selectProblemsByArticleId(query: SelectProblemsByArticleIdQuery): ProblemIdsRecord? { - val articleId = query.articleId - - return dslContext.select() - .from(Problem.PROBLEM) - .where(Problem.PROBLEM.ARTICLE_ID.eq(articleId)) - .and(Problem.PROBLEM.DELETED_AT.isNull) + return selectProblemsByArticleIdQuery(query) .fetch() .map { it[Problem.PROBLEM.ID] } .let { ProblemIdsRecord(it) } } + fun selectProblemsByArticleIdQuery(query: SelectProblemsByArticleIdQuery) = dslContext.select() + .from(Problem.PROBLEM) + .where(Problem.PROBLEM.ARTICLE_ID.eq(query.articleId)) + .and(Problem.PROBLEM.DELETED_AT.isNull) + fun insertProblems(command: List) { dslContext.batch( command.map { - dslContext.insertInto(Problem.PROBLEM) - .set(Problem.PROBLEM.ARTICLE_ID, it.articleId) - .set(Problem.PROBLEM.CREATOR_ID, it.createrId) - .set(Problem.PROBLEM.TITLE, it.title) - .set(Problem.PROBLEM.CONTENTS, JSON.valueOf(contentsJsonMapper.toJson(it.contents))) - .set(Problem.PROBLEM.ANSWER, it.answer) - .set(Problem.PROBLEM.EXPLANATION, it.explanation) + insertProblemCommand(it) } ).execute() } + + fun insertProblemCommand(it: InsertProblemsCommand) = + dslContext.insertInto(Problem.PROBLEM) + .set(Problem.PROBLEM.ARTICLE_ID, it.articleId) + .set(Problem.PROBLEM.CREATOR_ID, it.createrId) + .set(Problem.PROBLEM.TITLE, it.title) + .set(Problem.PROBLEM.CONTENTS, JSON.valueOf(contentsJsonMapper.toJson(it.contents))) + .set(Problem.PROBLEM.ANSWER, it.answer) + .set(Problem.PROBLEM.EXPLANATION, it.explanation) } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/SubmitHistoryDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/SubmitHistoryDao.kt index 7336a95b1..e63482826 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/SubmitHistoryDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/problem/SubmitHistoryDao.kt @@ -11,14 +11,17 @@ class SubmitHistoryDao( ) { fun insertSubmitHistory(command: InsertSubmitHistoryCommand): Long? { - val result = dslContext.insertInto(SUBMIT_HISTORY) - .set(SUBMIT_HISTORY.PROBLEM_ID, command.problemId) - .set(SUBMIT_HISTORY.MEMBER_ID, command.memberId) - .set(SUBMIT_HISTORY.SUBMIT_ANS, command.submitAns) - .set(SUBMIT_HISTORY.IS_SOLVED, command.isSolved) + val result = insertSubmitCommand(command) .returning(SUBMIT_HISTORY.ID) .fetchOne() return result?.getValue(SUBMIT_HISTORY.ID) } + + fun insertSubmitCommand(command: InsertSubmitHistoryCommand) = + dslContext.insertInto(SUBMIT_HISTORY) + .set(SUBMIT_HISTORY.PROBLEM_ID, command.problemId) + .set(SUBMIT_HISTORY.MEMBER_ID, command.memberId) + .set(SUBMIT_HISTORY.SUBMIT_ANS, command.submitAns) + .set(SUBMIT_HISTORY.IS_SOLVED, command.isSolved) } \ No newline at end of file diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt index c0c942e73..b8e6eaebc 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/subscription/SubscriptionDao.kt @@ -19,13 +19,16 @@ class SubscriptionDao( ) { fun insertWorkbookSubscription(command: InsertWorkbookSubscriptionCommand) { - dslContext.insertInto(SUBSCRIPTION) - .set(SUBSCRIPTION.MEMBER_ID, command.memberId) - .set(SUBSCRIPTION.TARGET_WORKBOOK_ID, command.workbookId) + insertWorkbookSubscriptionCommand(command) .returning(SUBSCRIPTION.ID) .fetchOne() } + fun insertWorkbookSubscriptionCommand(command: InsertWorkbookSubscriptionCommand) = + dslContext.insertInto(SUBSCRIPTION) + .set(SUBSCRIPTION.MEMBER_ID, command.memberId) + .set(SUBSCRIPTION.TARGET_WORKBOOK_ID, command.workbookId) + fun reSubscribeWorkbookSubscription(command: InsertWorkbookSubscriptionCommand) { dslContext.update(SUBSCRIPTION) .set(SUBSCRIPTION.DELETED_AT, null as LocalDateTime?) @@ -45,7 +48,12 @@ class SubscriptionDao( } fun selectTopWorkbookSubscriptionStatus(query: SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery): WorkbookSubscriptionStatus? { - return dslContext.select( + return selectTopWorkbookSubscriptionStatusQuery(query) + .fetchOneInto(WorkbookSubscriptionStatus::class.java) + } + + fun selectTopWorkbookSubscriptionStatusQuery(query: SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery) = + dslContext.select( SUBSCRIPTION.TARGET_WORKBOOK_ID.`as`(WorkbookSubscriptionStatus::workbookId.name), SUBSCRIPTION.DELETED_AT.isNull.`as`(WorkbookSubscriptionStatus::isActiveSub.name), SUBSCRIPTION.PROGRESS.add(1).`as`(WorkbookSubscriptionStatus::day.name) @@ -55,24 +63,28 @@ class SubscriptionDao( .and(SUBSCRIPTION.TARGET_WORKBOOK_ID.eq(query.workbookId)) .orderBy(SUBSCRIPTION.CREATED_AT.desc()) .limit(1) - .fetchOneInto(WorkbookSubscriptionStatus::class.java) - } fun updateDeletedAtInAllSubscription(command: UpdateDeletedAtInAllSubscriptionCommand) { + updateDeletedAtInAllSubscriptionCommand(command) + .execute() + } + + fun updateDeletedAtInAllSubscriptionCommand(command: UpdateDeletedAtInAllSubscriptionCommand) = dslContext.update(SUBSCRIPTION) .set(SUBSCRIPTION.DELETED_AT, LocalDateTime.now()) .set(SUBSCRIPTION.UNSUBS_OPINION, command.opinion) // TODO: opinion row 마다 중복 해결 .where(SUBSCRIPTION.MEMBER_ID.eq(command.memberId)) - .execute() - } fun countWorkbookMappedArticles(query: CountWorkbookMappedArticlesQuery): Int? { - return dslContext.selectCount() - .from(MAPPING_WORKBOOK_ARTICLE) - .where(MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID.eq(query.workbookId)) + return countWorkbookMappedArticlesQuery(query) .fetchOne(0, Int::class.java) } + fun countWorkbookMappedArticlesQuery(query: CountWorkbookMappedArticlesQuery) = + dslContext.selectCount() + .from(MAPPING_WORKBOOK_ARTICLE) + .where(MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID.eq(query.workbookId)) + fun countAllSubscriptionStatus(): CountAllSubscriptionStatusRecord { val total = dslContext.selectCount() .from(SUBSCRIPTION) diff --git a/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt b/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt index a27ab95db..f7c2ee39b 100644 --- a/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt +++ b/api-repo/src/main/kotlin/com/few/api/repo/dao/workbook/WorkbookDao.kt @@ -19,7 +19,12 @@ class WorkbookDao( ) { @Cacheable(key = "#query.id", cacheManager = LOCAL_CM, cacheNames = [LocalCacheConfig.SELECT_WORKBOOK_RECORD_CACHE]) fun selectWorkBook(query: SelectWorkBookRecordQuery): SelectWorkBookRecord? { - return dslContext.select( + return selectWorkBookQuery(query) + .fetchOneInto(SelectWorkBookRecord::class.java) + } + + fun selectWorkBookQuery(query: SelectWorkBookRecordQuery) = + dslContext.select( Workbook.WORKBOOK.ID.`as`(SelectWorkBookRecord::id.name), Workbook.WORKBOOK.TITLE.`as`(SelectWorkBookRecord::title.name), Workbook.WORKBOOK.MAIN_IMAGE_URL.`as`(SelectWorkBookRecord::mainImageUrl.name), @@ -30,20 +35,21 @@ class WorkbookDao( .from(Workbook.WORKBOOK) .where(Workbook.WORKBOOK.ID.eq(query.id)) .and(Workbook.WORKBOOK.DELETED_AT.isNull) - .fetchOneInto(SelectWorkBookRecord::class.java) - } fun insertWorkBook(command: InsertWorkBookCommand): Long? { - return dslContext.insertInto(Workbook.WORKBOOK) - .set(Workbook.WORKBOOK.TITLE, command.title) - .set(Workbook.WORKBOOK.MAIN_IMAGE_URL, command.mainImageUrl.toString()) - .set(Workbook.WORKBOOK.CATEGORY_CD, CategoryType.convertToCode(command.category)) - .set(Workbook.WORKBOOK.DESCRIPTION, command.description) + return insertWorkBookCommand(command) .returning(Workbook.WORKBOOK.ID) .fetchOne() ?.id } + fun insertWorkBookCommand(command: InsertWorkBookCommand) = + dslContext.insertInto(Workbook.WORKBOOK) + .set(Workbook.WORKBOOK.TITLE, command.title) + .set(Workbook.WORKBOOK.MAIN_IMAGE_URL, command.mainImageUrl.toString()) + .set(Workbook.WORKBOOK.CATEGORY_CD, CategoryType.convertToCode(command.category)) + .set(Workbook.WORKBOOK.DESCRIPTION, command.description) + fun mapWorkBookToArticle(command: MapWorkBookToArticleCommand) { dslContext.insertInto(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID, command.workbookId) diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/InsertUpdateExplainGenerator.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/InsertUpdateExplainGenerator.kt new file mode 100644 index 000000000..6dce1fed3 --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/InsertUpdateExplainGenerator.kt @@ -0,0 +1,25 @@ +package com.few.api.repo.explain + +import org.jooq.DSLContext +import org.jooq.JSON +import org.jooq.impl.DSL + +class InsertUpdateExplainGenerator { + companion object { + fun execute(dslContext: DSLContext, sql: String, values: List): String { + return dslContext.explain( + DSL.query( + values.foldIndexed(sql) { index, acc, value -> + if (value is JSON) { + value.toString().replace("\"", "\\\"").let { + return@foldIndexed acc.replaceFirst("?", "\"$it\"") + } + } else { + acc.replaceFirst("?", "\"$value\"") + } + } + ) + ).toString() + } + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/ResultGenerator.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/ResultGenerator.kt new file mode 100644 index 000000000..be9f0e18f --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/ResultGenerator.kt @@ -0,0 +1,27 @@ +package com.few.api.repo.explain + +import org.jooq.Query +import java.io.File + +class ResultGenerator { + + companion object { + fun execute(query: Query, explain: String, fileName: String) { + File("src/test/resources/explain").let { dir -> + if (!dir.exists()) { + dir.mkdirs() + } + + File(dir, "$fileName.txt").let { file -> + if (file.exists()) { + file.delete() + } + file.createNewFile() + file.appendText(query.toString()) + file.appendText("\n\n") + file.appendText(explain) + } + } + } + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt new file mode 100644 index 000000000..b1818b3d7 --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleDaoExplainGenerateTest.kt @@ -0,0 +1,125 @@ +package com.few.api.repo.explain.article + +import com.few.api.repo.dao.article.ArticleDao +import com.few.api.repo.dao.article.command.InsertFullArticleRecordCommand +import com.few.api.repo.dao.article.query.SelectArticleRecordQuery +import com.few.api.repo.dao.article.query.SelectWorkBookArticleRecordQuery +import com.few.api.repo.dao.article.query.SelectWorkbookMappedArticleRecordsQuery +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import com.few.data.common.code.CategoryType +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.ArticleIfo +import jooq.jooq_dsl.tables.ArticleMst +import jooq.jooq_dsl.tables.MappingWorkbookArticle +import org.jooq.DSLContext +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import java.net.URL + +@Tag("explain") +class ArticleDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var articleDao: ArticleDao + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(ArticleMst.ARTICLE_MST).execute() + dslContext.deleteFrom(ArticleIfo.ARTICLE_IFO).execute() + dslContext.deleteFrom(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE).execute() + dslContext.insertInto(ArticleMst.ARTICLE_MST) + .set(ArticleMst.ARTICLE_MST.ID, 1L) + .set(ArticleMst.ARTICLE_MST.MEMBER_ID, 1L) + .set(ArticleMst.ARTICLE_MST.MAIN_IMAGE_URL, "http://localhost:8080/image1.jpg") + .set(ArticleMst.ARTICLE_MST.TITLE, "this is title1") + .set(ArticleMst.ARTICLE_MST.CATEGORY_CD, CategoryType.fromCode(0)!!.code) + .execute() + dslContext.insertInto(ArticleIfo.ARTICLE_IFO) + .set(ArticleIfo.ARTICLE_IFO.ARTICLE_MST_ID, 1L) + .set(ArticleIfo.ARTICLE_IFO.CONTENT, "this is content1") + .execute() + dslContext.insertInto(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) + .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID, 1L) + .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.ARTICLE_ID, 1L) + .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.DAY_COL, 0) + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun selectArticleRecordQueryExplain() { + val query = SelectArticleRecordQuery(1L).let { + articleDao.selectArticleRecordQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectArticleRecordQueryExplain") + } + + @Test + fun selectWorkBookArticleRecordQueryExplain() { + val query = SelectWorkBookArticleRecordQuery(1L, 1L).let { + articleDao.selectWorkBookArticleRecordQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectWorkBookArticleRecordQueryExplain") + } + + @Test + fun selectWorkbookMappedArticleRecordsQueryExplain() { + val query = SelectWorkbookMappedArticleRecordsQuery(1L).let { + articleDao.selectWorkbookMappedArticleRecordsQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectWorkbookMappedArticleRecordsQueryExplain") + } + + @Test + fun insertArticleMstCommandExplain() { + val command = InsertFullArticleRecordCommand( + 100L, + URL("http://localhost:8080/image1.jpg"), + "this is title1", + CategoryType.fromCode(0)!!.code, + "this is content1" + ).let { + articleDao.insertArticleMstCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertArticleMstCommandExplain") + } + + @Test + fun insertArticleIfoCommandExplain() { + val command = InsertFullArticleRecordCommand( + 100L, + URL("http://localhost:8080/image1.jpg"), + "this is title1", + CategoryType.fromCode(0)!!.code, + "this is content1" + ).let { + articleDao.insertArticleIfoCommand(1L, it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertArticleIfoCommandExplain") + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleViewCountDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleViewCountDaoExplainGenerateTest.kt new file mode 100644 index 000000000..81ee73653 --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleViewCountDaoExplainGenerateTest.kt @@ -0,0 +1,64 @@ +package com.few.api.repo.explain.article + +import com.few.api.repo.dao.article.ArticleViewCountDao +import com.few.api.repo.dao.article.command.ArticleViewCountCommand +import com.few.api.repo.dao.article.query.ArticleViewCountQuery +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import com.few.data.common.code.CategoryType +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.ArticleViewCount +import org.jooq.DSLContext +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +@Tag("explain") +class ArticleViewCountDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var articleViewCountDao: ArticleViewCountDao + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(ArticleViewCount.ARTICLE_VIEW_COUNT).execute() + dslContext.insertInto(ArticleViewCount.ARTICLE_VIEW_COUNT) + .set(ArticleViewCount.ARTICLE_VIEW_COUNT.ARTICLE_ID, 1L) + .set(ArticleViewCount.ARTICLE_VIEW_COUNT.VIEW_COUNT, 1) + .set(ArticleViewCount.ARTICLE_VIEW_COUNT.CATEGORY_CD, CategoryType.fromCode(0)!!.code) + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun selectArticleViewCountQueryExplain() { + val query = ArticleViewCountCommand(1L).let { + articleViewCountDao.selectArticleViewCountQuery(it) + } + + val explain = dslContext.explain(query).toString() + ResultGenerator.execute(query, explain, "selectArticleViewCountQueryExplain") + } + + @Test + fun upsertArticleViewCountQueryExplain() { + val command = ArticleViewCountQuery( + articleId = 1L, + categoryType = CategoryType.fromCode(0)!! + ).let { + articleViewCountDao.upsertArticleViewCountQuery(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "upsertArticleViewCountQueryExplain") + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleViewHisDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleViewHisDaoExplainGenerateTest.kt new file mode 100644 index 000000000..69572d698 --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/article/ArticleViewHisDaoExplainGenerateTest.kt @@ -0,0 +1,62 @@ +package com.few.api.repo.explain.article + +import com.few.api.repo.dao.article.ArticleViewHisDao +import com.few.api.repo.dao.article.command.ArticleViewHisCommand +import com.few.api.repo.dao.article.query.ArticleViewHisCountQuery +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.* +import org.jooq.DSLContext +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +@Tag("explain") +class ArticleViewHisDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var articleViewHisDao: ArticleViewHisDao + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(ArticleViewHis.ARTICLE_VIEW_HIS).execute() + dslContext.insertInto(ArticleViewHis.ARTICLE_VIEW_HIS) + .set(ArticleViewHis.ARTICLE_VIEW_HIS.ARTICLE_MST_ID, 1L) + .set(ArticleViewHis.ARTICLE_VIEW_HIS.MEMBER_ID, 1L) + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun countArticleViewsQueryExplain() { + val query = ArticleViewHisCountQuery(1L).let { + articleViewHisDao.countArticleViewsQuery(it) + } + + val explain = dslContext.explain(query).toString() + ResultGenerator.execute(query, explain, "selectArticleViewCountQueryExplain") + } + + @Test + fun insertArticleViewHisCommandExplain() { + val command = ArticleViewHisCommand( + articleId = 1L, + memberId = 1L + ).let { + articleViewHisDao.insertArticleViewHisCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertArticleViewHisCommandExplain") + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/member/MemberDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/member/MemberDaoExplainGenerateTest.kt new file mode 100644 index 000000000..b28e40585 --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/member/MemberDaoExplainGenerateTest.kt @@ -0,0 +1,113 @@ +package com.few.api.repo.explain.member + +import com.few.api.repo.dao.member.MemberDao +import com.few.api.repo.dao.member.command.InsertMemberCommand +import com.few.api.repo.dao.member.query.SelectMemberByEmailQuery +import com.few.api.repo.dao.member.query.SelectWriterQuery +import com.few.api.repo.dao.member.support.WriterDescription +import com.few.api.repo.dao.member.support.WriterDescriptionJsonMapper +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import com.few.data.common.code.MemberType +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.Member +import org.jooq.DSLContext +import org.jooq.JSON +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import java.net.URL + +@Tag("explain") +class MemberDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var memberDao: MemberDao + + @Autowired + private lateinit var writerDescriptionJsonMapper: WriterDescriptionJsonMapper + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(Member.MEMBER).execute() + dslContext.insertInto(Member.MEMBER) + .set(Member.MEMBER.ID, 1) + .set(Member.MEMBER.EMAIL, "member@gmail.com") + .set(Member.MEMBER.TYPE_CD, MemberType.NORMAL.code) + .execute() + + val writerDescription = writerDescriptionJsonMapper.toJson( + WriterDescription("few2", URL("http://localhost:8080/writers/url2")) + ) + + dslContext.insertInto(Member.MEMBER) + .set(Member.MEMBER.ID, 2) + .set(Member.MEMBER.EMAIL, "writer2@gmail.com") + .set(Member.MEMBER.TYPE_CD, MemberType.WRITER.code) + .set(Member.MEMBER.DESCRIPTION, JSON.valueOf(writerDescription)) + .execute() + + dslContext.insertInto(Member.MEMBER) + .set(Member.MEMBER.ID, 3) + .set(Member.MEMBER.EMAIL, "writer3@gmail.com") + .set(Member.MEMBER.TYPE_CD, MemberType.WRITER.code) + .set(Member.MEMBER.DESCRIPTION, JSON.valueOf(writerDescription)) + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun selectWriterQueryExplain() { + val query = SelectWriterQuery(1).let { + memberDao.selectWriterQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectWriterQueryExplain") + } + + @Test + fun selectWritersQueryExplain() { + val query = listOf(2L, 3L).let { + memberDao.selectWritersQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectWritersQueryExplain") + } + + @Test + fun selectMemberByEmailQueryExplain() { + val query = SelectMemberByEmailQuery("member@gmail.com").let { + memberDao.selectMemberByEmailQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectMemberByEmailQueryExplainExplain") + } + + @Test + fun insertMemberCommandExplain() { + val command = InsertMemberCommand( + email = "test100@gmail.com", + memberType = MemberType.NORMAL + ).let { + memberDao.insertMemberCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertMemberCommandExplain") + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/problem/ProblemDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/problem/ProblemDaoExplainGenerateTest.kt new file mode 100644 index 000000000..3b795b15b --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/problem/ProblemDaoExplainGenerateTest.kt @@ -0,0 +1,137 @@ +package com.few.api.repo.explain.problem + +import com.few.api.repo.dao.problem.ProblemDao +import com.few.api.repo.dao.problem.SubmitHistoryDao +import com.few.api.repo.dao.problem.command.InsertProblemsCommand +import com.few.api.repo.dao.problem.command.InsertSubmitHistoryCommand +import com.few.api.repo.dao.problem.query.SelectProblemAnswerQuery +import com.few.api.repo.dao.problem.query.SelectProblemQuery +import com.few.api.repo.dao.problem.query.SelectProblemsByArticleIdQuery +import com.few.api.repo.dao.problem.support.Content +import com.few.api.repo.dao.problem.support.Contents +import com.few.api.repo.dao.problem.support.ContentsJsonMapper +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.* +import org.jooq.DSLContext +import org.jooq.JSON +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +@Tag("explain") +class ProblemDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var problemDao: ProblemDao + + @Autowired + private lateinit var submitHistoryDao: SubmitHistoryDao + + @Autowired + private lateinit var contentsJsonMapper: ContentsJsonMapper + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(Problem.PROBLEM).execute() + val contents = Contents( + listOf( + Content(1, "content1"), + Content(2, "content2") + ) + ).let { + contentsJsonMapper.toJson(it) + } + dslContext.insertInto(Problem.PROBLEM) + .set(Problem.PROBLEM.ID, 1) + .set(Problem.PROBLEM.ARTICLE_ID, 1) + .set(Problem.PROBLEM.TITLE, "problem title") + .set(Problem.PROBLEM.CONTENTS, JSON.valueOf(contents)) + .set(Problem.PROBLEM.ANSWER, "1") + .set(Problem.PROBLEM.EXPLANATION, "explanation") + .set(Problem.PROBLEM.CREATOR_ID, 1) + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun selectProblemContentsQueryExplain() { + val query = SelectProblemQuery(1L).let { + problemDao.selectProblemContentsQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectProblemContentsQueryExplain") + } + + @Test + fun selectProblemAnswerQueryExplain() { + val query = SelectProblemAnswerQuery(1L).let { + problemDao.selectProblemAnswerQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectProblemAnswerQueryExplain") + } + + @Test + fun selectProblemsByArticleIdQueryExplain() { + val query = SelectProblemsByArticleIdQuery(1L).let { + problemDao.selectProblemsByArticleIdQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectProblemsByArticleIdQueryExplain") + } + + @Test + fun insertProblemCommandExplain() { + val command = InsertProblemsCommand( + articleId = 1L, + createrId = 1, + title = "problem title", + contents = Contents( + listOf( + Content(1, "content1"), + Content(2, "content2") + ) + ), + answer = "1", + explanation = "explanation" + ).let { + problemDao.insertProblemCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertProblemCommandExplain") + } + + @Test + fun insertSubmitCommandExplain() { + val command = InsertSubmitHistoryCommand( + memberId = 1L, + problemId = 1L, + submitAns = "1", + isSolved = true + ).let { + submitHistoryDao.insertSubmitCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertSubmitCommandExplain") + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt new file mode 100644 index 000000000..8ddd24902 --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/subscription/SubscriptionDaoExplainGenerateTest.kt @@ -0,0 +1,102 @@ +package com.few.api.repo.explain.subscription + +import com.few.api.repo.dao.subscription.SubscriptionDao +import com.few.api.repo.dao.subscription.command.InsertWorkbookSubscriptionCommand +import com.few.api.repo.dao.subscription.command.UpdateDeletedAtInAllSubscriptionCommand +import com.few.api.repo.dao.subscription.query.CountWorkbookMappedArticlesQuery +import com.few.api.repo.dao.subscription.query.SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.* +import org.jooq.DSLContext +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired + +@Tag("explain") +class SubscriptionDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var subscriptionDao: SubscriptionDao + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(Subscription.SUBSCRIPTION).execute() + dslContext.deleteFrom(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE).execute() + dslContext.insertInto(Subscription.SUBSCRIPTION) + .set(Subscription.SUBSCRIPTION.MEMBER_ID, 1L) + .set(Subscription.SUBSCRIPTION.TARGET_WORKBOOK_ID, 1L) + .set(Subscription.SUBSCRIPTION.PROGRESS, 0) + .execute() + dslContext.insertInto(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE) + .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.WORKBOOK_ID, 1L) + .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.ARTICLE_ID, 1L) + .set(MappingWorkbookArticle.MAPPING_WORKBOOK_ARTICLE.DAY_COL, 1) + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun selectTopWorkbookSubscriptionStatusQuery() { + val query = SelectAllWorkbookSubscriptionStatusNotConsiderDeletedAtQuery( + memberId = 1L, + workbookId = 1L + ).let { + subscriptionDao.selectTopWorkbookSubscriptionStatusQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectTopWorkbookSubscriptionStatusQueryExplain") + } + + @Test + fun countWorkbookMappedArticlesQueryExplain() { + val query = CountWorkbookMappedArticlesQuery( + workbookId = 1L + ).let { + subscriptionDao.countWorkbookMappedArticlesQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "countWorkbookMappedArticlesQueryExplain") + } + + @Test + fun insertWorkbookSubscriptionCommandExplain() { + val command = InsertWorkbookSubscriptionCommand( + memberId = 1L, + workbookId = 1L + ).let { + subscriptionDao.insertWorkbookSubscriptionCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "insertWorkbookSubscriptionCommandExplain") + } + + @Test + fun updateDeletedAtInAllSubscriptionCommandExplain() { + val command = UpdateDeletedAtInAllSubscriptionCommand( + memberId = 1L, + opinion = "test" + ).let { + subscriptionDao.updateDeletedAtInAllSubscriptionCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + + ResultGenerator.execute(command, explain, "updateDeletedAtInAllSubscriptionCommandExplain") + } +} \ No newline at end of file diff --git a/api-repo/src/test/kotlin/com/few/api/repo/explain/workbook/WorkbookDaoExplainGenerateTest.kt b/api-repo/src/test/kotlin/com/few/api/repo/explain/workbook/WorkbookDaoExplainGenerateTest.kt new file mode 100644 index 000000000..0a7aef21b --- /dev/null +++ b/api-repo/src/test/kotlin/com/few/api/repo/explain/workbook/WorkbookDaoExplainGenerateTest.kt @@ -0,0 +1,69 @@ +package com.few.api.repo.explain.workbook + +import com.few.api.repo.dao.workbook.WorkbookDao +import com.few.api.repo.dao.workbook.command.InsertWorkBookCommand +import com.few.api.repo.dao.workbook.query.SelectWorkBookRecordQuery +import com.few.api.repo.explain.InsertUpdateExplainGenerator +import com.few.api.repo.explain.ResultGenerator +import com.few.api.repo.jooq.JooqTestSpec +import com.few.data.common.code.CategoryType +import io.github.oshai.kotlinlogging.KotlinLogging +import jooq.jooq_dsl.tables.* +import org.jooq.DSLContext +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import java.net.URL + +@Tag("explain") +class WorkbookDaoExplainGenerateTest : JooqTestSpec() { + + private val log = KotlinLogging.logger {} + + @Autowired + private lateinit var dslContext: DSLContext + + @Autowired + private lateinit var workbookDao: WorkbookDao + + @BeforeEach + fun setUp() { + log.debug { "===== start setUp =====" } + dslContext.deleteFrom(Workbook.WORKBOOK).execute() + dslContext.insertInto(Workbook.WORKBOOK) + .set(Workbook.WORKBOOK.ID, 1) + .set(Workbook.WORKBOOK.TITLE, "title1") + .set(Workbook.WORKBOOK.MAIN_IMAGE_URL, "http://localhost:8080/image1.jpg") + .set(Workbook.WORKBOOK.CATEGORY_CD, CategoryType.fromCode(0)!!.code) + .set(Workbook.WORKBOOK.DESCRIPTION, "description1") + .execute() + log.debug { "===== finish setUp =====" } + } + + @Test + fun selectWorkBookQueryExplain() { + val query = SelectWorkBookRecordQuery(1L).let { + workbookDao.selectWorkBookQuery(it) + } + + val explain = dslContext.explain(query).toString() + + ResultGenerator.execute(query, explain, "selectWorkBookQueryExplain") + } + + @Test + fun insertWorkBookCommandExplain() { + val command = InsertWorkBookCommand( + title = "title2", + mainImageUrl = URL("http://localhost:8080/image2.jpg"), + description = "description2", + category = CategoryType.fromCode(0)!!.name + ).let { + workbookDao.insertWorkBookCommand(it) + } + + val explain = InsertUpdateExplainGenerator.execute(dslContext, command.sql, command.bindValues) + ResultGenerator.execute(command, explain, "insertWorkBookCommandExplain") + } +} \ No newline at end of file