Repository: flickit-platform/flickit-assessment
Pull request #693: FAC-1004: Create `Kit Language` Table and Entity
Author: login: maziyar-gerami
Labels: name: Ready to Review
Created: 2025-04-07T04:52:43Z | Merged: 2025-04-08T13:43:33Z

### Checklist
Before you label your PR as 'Ready To Review', please check the below list and put an 'X' char into each bracket;

[X] - Did you update the Postman file?
[X] - Did you update the corresponding document?
[X] - Did you review the PR by yourself?
[X] - Did you merge the main branch into this branch recently?
[X] - Did you remove the probable extra code?
[X] - Did you label the PR as 'Ready to Review'?
[X] - Did you update the Jira task to 'In Review'?
[X] - Did you add the Confluence's link to the Jira task as a description?



Diff:
diff --git a/flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaEntity.java b/flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaEntity.java
new file mode 100644
index 0000000000..6709368bb4
--- /dev/null
+++ b/flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaEntity.java
@@ -0,0 +1,38 @@
+package org.flickit.assessment.data.jpa.kit.kitlanguage;
+
+import jakarta.persistence.*;
+import lombok.*;
+import lombok.experimental.FieldNameConstants;
+
+import java.io.Serializable;
+
+@Entity
+@IdClass(KitLanguageJpaEntity.EntityId.class)
+@Table(name = "fak_kit_language")
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+public class KitLanguageJpaEntity {
+
+    @Id
+    @EqualsAndHashCode.Include
+    @Column(name = "kit_id", nullable = false)
+    private Long kitId;
+
+    @Id
+    @EqualsAndHashCode.Include
+    @Column(name = "lang_id", nullable = false)
+    private Integer langId;
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class EntityId implements Serializable {
+
+        private Long kitId;
+        private Integer langId;
+    }
+}
diff --git a/flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaRepository.java b/flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaRepository.java
new file mode 100644
index 0000000000..890ca24cbd
--- /dev/null
+++ b/flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaRepository.java
@@ -0,0 +1,6 @@
+package org.flickit.assessment.data.jpa.kit.kitlanguage;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface KitLanguageJpaRepository extends JpaRepository<KitLanguageJpaEntity, KitLanguageJpaEntity.EntityId> {
+}
diff --git a/flickit-assessment-data/src/main/resources/liquibase/changelog-0.55.xml b/flickit-assessment-data/src/main/resources/liquibase/changelog-0.55.xml
new file mode 100644
index 0000000000..1d4b2814f1
--- /dev/null
+++ b/flickit-assessment-data/src/main/resources/liquibase/changelog-0.55.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+                                       http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
+
+    <changeSet id="0.55-01" author="Maziyar Gerami">
+        <createTable tableName="fak_kit_language">
+            <column name="kit_id" type="bigint">
+                <constraints nullable="false"/>
+            </column>
+            <column name="lang_id" type="int">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+    </changeSet>
+
+    <changeSet id="0.55-02" author="Maziyar Gerami">
+        <addPrimaryKey tableName="fak_kit_language"
+                       columnNames="kit_id, lang_id"
+                       constraintName="pk_fak_kit_language"/>
+    </changeSet>
+
+    <changeSet id="0.55-03" author="Maziyar Gerami">
+        <addForeignKeyConstraint baseTableName="fak_kit_language"
+                                 baseColumnNames="kit_id"
+                                 constraintName="fk_fak_kitlanguage_assessmentkit"
+                                 referencedTableName="fak_assessment_kit"
+                                 referencedColumnNames="id"
+                                 onDelete="CASCADE"/>
+    </changeSet>
+
+    <changeSet id="0.55-04" author="Maziyar Gerami">
+        <sql>
+            INSERT INTO fak_kit_language(kit_id, lang_id)
+            SELECT k.id                     AS kit_id,
+                   k.language_id            AS lang_id
+            FROM fak_assessment_kit k
+        </sql>
+    </changeSet>
+
+</databaseChangeLog>
diff --git a/flickit-assessment-data/src/main/resources/liquibase/changelog-master.xml b/flickit-assessment-data/src/main/resources/liquibase/changelog-master.xml
index f9fc2cb8ab..0f378ff3af 100644
--- a/flickit-assessment-data/src/main/resources/liquibase/changelog-master.xml
+++ b/flickit-assessment-data/src/main/resources/liquibase/changelog-master.xml
@@ -49,4 +49,5 @@
     <include file="classpath:liquibase/changelog-0.49.xml"/>
     <include file="classpath:liquibase/changelog-0.50.xml"/>
     <include file="classpath:liquibase/changelog-0.53.xml"/>
+    <include file="classpath:liquibase/changelog-0.55.xml"/>
 </databaseChangeLog>
diff --git a/flickit-assessment-kit/src/main/java/org/flickit/assessment/kit/adapter/out/persistence/assessmentkit/AssessmentKitPersistenceJpaAdapter.java b/flickit-assessment-kit/src/main/java/org/flickit/assessment/kit/adapter/out/persistence/assessmentkit/AssessmentKitPersistenceJpaAdapter.java
index 3e94a78fd1..901cf1499b 100644
--- a/flickit-assessment-kit/src/main/java/org/flickit/assessment/kit/adapter/out/persistence/assessmentkit/AssessmentKitPersistenceJpaAdapter.java
+++ b/flickit-assessment-kit/src/main/java/org/flickit/assessment/kit/adapter/out/persistence/assessmentkit/AssessmentKitPersistenceJpaAdapter.java
@@ -8,6 +8,8 @@
 import org.flickit.assessment.data.jpa.kit.assessmentkit.AssessmentKitJpaEntity;
 import org.flickit.assessment.data.jpa.kit.assessmentkit.AssessmentKitJpaRepository;
 import org.flickit.assessment.data.jpa.kit.assessmentkit.CountKitStatsView;
+import org.flickit.assessment.data.jpa.kit.kitlanguage.KitLanguageJpaEntity;
+import org.flickit.assessment.data.jpa.kit.kitlanguage.KitLanguageJpaRepository;
 import org.flickit.assessment.data.jpa.kit.kittagrelation.KitTagRelationJpaEntity;
 import org.flickit.assessment.data.jpa.kit.kittagrelation.KitTagRelationJpaRepository;
 import org.flickit.assessment.data.jpa.kit.seq.KitDbSequenceGenerators;
@@ -65,6 +67,7 @@ public class AssessmentKitPersistenceJpaAdapter implements
     private final ExpertGroupJpaRepository expertGroupRepository;
     private final KitTagRelationJpaRepository kitTagRelationRepository;
     private final KitDbSequenceGenerators sequenceGenerators;
+    private final KitLanguageJpaRepository kitLanguageRepository;
 
     @Override
     public PaginatedResponse<LoadKitUsersPort.KitUser> loadKitUsers(LoadKitUsersPort.Param param) {
@@ -121,9 +124,14 @@ public GetKitMinimalInfoUseCase.Result loadKitMinimalInfo(Long kitId) {
 
     @Override
     public Long persist(CreateAssessmentKitPort.Param param) {
+        long kitId = sequenceGenerators.generateKitId();
         AssessmentKitJpaEntity kitEntity = AssessmentKitMapper.toJpaEntity(param);
-        kitEntity.setId(sequenceGenerators.generateKitId());
-        return repository.save(kitEntity).getId();
+        kitEntity.setId(kitId);
+        repository.save(kitEntity);
+
+        KitLanguageJpaEntity languageEntity = new KitLanguageJpaEntity(kitId, kitEntity.getLanguageId());
+        kitLanguageRepository.save(languageEntity);
+        return kitId;
     }
 
     @Override


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: 

Copilot reviewed 2 out of 4 changed files in this pull request and generated 1 comment.

<details>
<summary>Files not reviewed (2)</summary>

* **flickit-assessment-data/src/main/resources/liquibase/changelog-0.54.xml**: Language not supported
* **flickit-assessment-data/src/main/resources/liquibase/changelog-master.xml**: Language not supported
</details>



state: COMMENTED
author_association: NONE
submitted_at: 2025-04-07T04:53:27Z
user: login: maziyar-gerami
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-07T07:12:07Z
user: login: mhzkh
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-08T13:34:10Z

Review comments:
diff_hunk: @@ -0,0 +1,6 @@
+package org.flickit.assessment.data.jpa.kit.kitlanguage;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface KitLanguageJpaRepository extends JpaRepository<KitLanguageJpaEntity, Long> {
path: flickit-assessment-data/src/main/java/org/flickit/assessment/data/jpa/kit/kitlanguage/KitLanguageJpaRepository.java
user: login: Copilot
body: Since KitLanguageJpaEntity uses a composite primary key defined by EntityId, the repository should extend JpaRepository<KitLanguageJpaEntity, KitLanguageJpaEntity.EntityId> instead of JpaRepository<KitLanguageJpaEntity, Long>.
```suggestion
public interface KitLanguageJpaRepository extends JpaRepository<KitLanguageJpaEntity, KitLanguageJpaEntity.EntityId> {
```
created_at: 2025-04-07T04:53:27Z
author_association: NONE
diff_hunk: @@ -121,9 +124,14 @@ public GetKitMinimalInfoUseCase.Result loadKitMinimalInfo(Long kitId) {
 
     @Override
     public Long persist(CreateAssessmentKitPort.Param param) {
path: flickit-assessment-kit/src/main/java/org/flickit/assessment/kit/adapter/out/persistence/assessmentkit/AssessmentKitPersistenceJpaAdapter.java
user: login: maziyar-gerami
body: بنظر من جای درستش همینجاست. الان برای هر دو سرویس ایجاد کیت درست کار میکنه و چون زبان موجود در موجودیت کیت هم داره همینجا قرار داده میشه و البته یک جدول میانی هست، بنظرم جاش همینجاست
created_at: 2025-04-07T07:11:56Z
author_association: COLLABORATOR
diff_hunk: @@ -121,9 +124,14 @@ public GetKitMinimalInfoUseCase.Result loadKitMinimalInfo(Long kitId) {
 
     @Override
     public Long persist(CreateAssessmentKitPort.Param param) {
path: flickit-assessment-kit/src/main/java/org/flickit/assessment/kit/adapter/out/persistence/assessmentkit/AssessmentKitPersistenceJpaAdapter.java
user: login: mhzkh
body: بله کاملا درسته
خیلی ممنون
created_at: 2025-04-08T13:34:10Z
author_association: COLLABORATOR

PR comments:
user: login: maziyar-gerami
created_at: 2025-04-07T05:08:02Z
body: بنظر شما بهتر نبود که از `language_id‍‍‍` بجای `lang_id` استفاده بشه؟ کاملا گویاست ولی ناظر به این نوضوع می‌گم که در جدول `fak_assessment_kit` این ستون رو `language_id` قرار دادیم. و اینکه آیا باید جدول `fak_language` هم روزی اضافه بشه؟
author_association: COLLABORATOR
user: login: mhzkh
created_at: 2025-04-08T13:36:23Z
body: > بنظر شما بهتر نبود که از `language_id‍‍‍` بجای `lang_id` استفاده بشه؟ کاملا گویاست ولی ناظر به این نوضوع می‌گم که در جدول `fak_assessment_kit` این ستون رو `language_id` قرار دادیم. و اینکه آیا باید جدول `fak_language` هم روزی اضافه بشه؟

چرا بهتر بود یکسان باشه. من موقع نوشتن شرح تسک دقت نکرده بودم.
مهم نیست ولی. لازم نیست تغییر بدیم.

جدول fak_language فکر نکنم بسازیم. تعداد زبان‌ها زیاد نیست (نمی‌شه) و با همین اینام پیش میریم احتمالا
author_association: COLLABORATOR
user: login: sonarqubecloud[bot]
created_at: 2025-04-08T13:38:45Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=flickit-assessment-core&pullRequest=693) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=flickit-assessment-core&pullRequest=693&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=flickit-assessment-core&pullRequest=693&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=flickit-assessment-core&pullRequest=693&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=flickit-assessment-core&pullRequest=693&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=flickit-assessment-core&pullRequest=693&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=flickit-assessment-core&pullRequest=693)


author_association: NONE