Sun, 02 Feb 2025 14:12:02 +0100
implement adding/removing variant status in DAO
relates to #491
--- a/setup/postgres/psql_create_tables.sql Sun Feb 02 13:13:27 2025 +0100 +++ b/setup/postgres/psql_create_tables.sql Sun Feb 02 14:12:02 2025 +0100 @@ -198,5 +198,6 @@ issueid integer not null references lpit_issue (issueid), variant integer not null references lpit_variant (id), status issue_status not null default 'InSpecification', + outdated boolean not null default false, primary key (issueid, variant) );
--- a/setup/postgres/psql_patch_1.5.0.sql Sun Feb 02 13:13:27 2025 +0100 +++ b/setup/postgres/psql_patch_1.5.0.sql Sun Feb 02 14:12:02 2025 +0100 @@ -22,5 +22,6 @@ issueid integer not null references lpit_issue (issueid), variant integer not null references lpit_variant (id), status issue_status not null default 'InSpecification', + outdated boolean not null default false, primary key (issueid, variant) );
--- a/src/main/kotlin/de/uapcore/lightpit/dao/PostgresDataAccessObject.kt Sun Feb 02 13:13:27 2025 +0100 +++ b/src/main/kotlin/de/uapcore/lightpit/dao/PostgresDataAccessObject.kt Sun Feb 02 14:12:02 2025 +0100 @@ -729,7 +729,7 @@ // this loop uses that both queries ordered their results by issue id while (true) { if (issue.id == issueid) { - issue.setVariantStatus(variant, status) + issue.setStatusForVariant(variant, status) break } if (!issueIter.hasNext()) break @@ -822,11 +822,82 @@ return issues } - override fun findIssue(id: Int): Issue? = - withStatement("$issueQuery where issueid = ?") { + override fun findIssue(id: Int): Issue? { + val issue = withStatement("$issueQuery where issueid = ?") { setInt(1, id) querySingle { it.extractIssue() } } + if (issue == null) return null + return withStatement( + """ + select s.status, + v.id, v.project, v.name, v.node, v.color, v.ordinal, v.description, v.active + from lpit_issue_variant_status s + join lpit_variant v on v.id = s.variant + where issueid = ? + """.trimIndent() + ) { + setInt(1, issue.id) + executeQuery().let {rs -> + while (rs.next()) { + issue.setStatusForVariant(rs.extractVariant(), rs.getEnum("status")) + } + } + issue + } + } + + private fun updateVariantStatus(issueid: Int, statusMap: Map<Variant, IssueStatus>, newIssue: Boolean = false) { + // different strategy when there are no status entries (anymore) - just delete all existing + if (statusMap.isEmpty()) { + if (!newIssue) { + withStatement("delete from lpit_issue_variant_status where issueid = ?") { + setInt(1, issueid) + executeUpdate() + } + } + return + } + + + // don't need to erase previous status entries when this is a new issue + if (!newIssue) { + withStatement( + """ + update lpit_issue_variant_status + set outdated = true where issueid = ? + """.trimIndent() + ) { + setInt(1, issueid) + executeUpdate() + } + } + + // upsert the status entries + statusMap.forEach { (variant, status) -> + withStatement( + """ + insert into lpit_issue_variant_status (issueid, variant, status) + values (?, ?, ?::issue_status) + on conflict do update + set status = ?::issue_status, outdated = false + """.trimIndent() + ) { + setInt(1, issueid) + setInt(2, variant.id) + setEnum(3, status) + setEnum(4, status) + executeUpdate() + } + } + + if (!newIssue) { + withStatement("delete from lpit_issue_variant_status where outdated and issueid = ?") { + setInt(1, issueid) + executeUpdate() + } + } + } override fun insertIssue(issue: Issue): Int { val id = withStatement( @@ -840,6 +911,7 @@ setInt(col, issue.project.id) querySingle { it.getInt(1) }!! } + updateVariantStatus(id, issue.variantStatus, true) return id } @@ -856,6 +928,7 @@ setInt(col, issue.id) executeUpdate() } + updateVariantStatus(issue.id, issue.variantStatus) } override fun insertHistoryEvent(author: User?, issue: Issue, newId: Int) {
--- a/src/main/kotlin/de/uapcore/lightpit/entities/Issue.kt Sun Feb 02 13:13:27 2025 +0100 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/Issue.kt Sun Feb 02 14:12:02 2025 +0100 @@ -49,16 +49,16 @@ var resolved: Version? = null val isTrackingVariantStatus get() = variantStatus.isNotEmpty() - fun setVariantStatus(variant: Variant, status: IssueStatus) { + fun setStatusForVariant(variant: Variant, status: IssueStatus) { variantStatus[variant] = status } fun removeVariant(variant: Variant) { variantStatus.remove(variant) } - fun getVariantStatus(variant: Variant): IssueStatus? { + fun getStatusForVariant(variant: Variant): IssueStatus? { return variantStatus[variant] } - private val variantStatus = mutableMapOf<Variant, IssueStatus>() + val variantStatus = mutableMapOf<Variant, IssueStatus>() /** * An issue is overdue, if it is not done and the ETA is before the current time.