fix(view): add unique index for task buckets (#1005)

This commit is contained in:
kolaente
2025-06-24 12:45:17 +02:00
committed by GitHub
parent 8a6ad2be1f
commit 842a71019d
3 changed files with 67 additions and 16 deletions

View File

@@ -35,17 +35,17 @@ function createSingleTaskInBucket(count = 1, attrs = {}) {
}
function createTaskWithBuckets(buckets, count = 1) {
const data = TaskFactory.create(10, {
project_id: 1,
})
TaskBucketFactory.truncate()
data.forEach(t => TaskBucketFactory.create(count, {
task_id: t.id,
bucket_id: buckets[0].id,
project_view_id: buckets[0].project_view_id,
}, false))
const data = TaskFactory.create(count, {
project_id: 1,
})
TaskBucketFactory.truncate()
data.forEach(t => TaskBucketFactory.create(1, {
task_id: t.id,
bucket_id: buckets[0].id,
project_view_id: buckets[0].project_view_id,
}, false))
return data
return data
}
describe('Project View Kanban', () => {

View File

@@ -0,0 +1,44 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-present Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20250624092830",
Description: "add unique index for task buckets",
Migrate: func(tx *xorm.Engine) error {
var query string
switch tx.Dialect().URI().DBType {
case schemas.MYSQL:
query = "CREATE UNIQUE INDEX UQE_task_buckets_task_project_view ON task_buckets (task_id, project_view_id)"
default:
query = "CREATE UNIQUE INDEX IF NOT EXISTS UQE_task_buckets_task_project_view ON task_buckets (task_id, project_view_id)"
}
_, err := tx.Exec(query)
return err
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@@ -25,13 +25,20 @@ import (
"xorm.io/xorm"
)
// TaskBucket represents the relation between a task and a kanban bucket.
// A task can only appear once per project view which is ensured by a
// unique index on the combination of task_id and project_view_id.
type TaskBucket struct {
BucketID int64 `xorm:"bigint not null index" json:"bucket_id" param:"bucket"`
Bucket *Bucket `xorm:"-" json:"bucket"`
TaskID int64 `xorm:"bigint not null index" json:"task_id"`
ProjectViewID int64 `xorm:"bigint not null index" json:"project_view_id" param:"view"`
ProjectID int64 `xorm:"-" json:"-" param:"project"`
Task *Task `xorm:"-" json:"task"`
BucketID int64 `xorm:"bigint not null index" json:"bucket_id" param:"bucket"`
Bucket *Bucket `xorm:"-" json:"bucket"`
// The task which belongs to the bucket. Together with ProjectViewID
// this field is part of a unique index to prevent duplicates.
TaskID int64 `xorm:"bigint not null index unique(task_view)" json:"task_id"`
// The view this bucket belongs to. Combined with TaskID this forms a
// unique index.
ProjectViewID int64 `xorm:"bigint not null index unique(task_view)" json:"project_view_id" param:"view"`
ProjectID int64 `xorm:"-" json:"-" param:"project"`
Task *Task `xorm:"-" json:"task"`
web.Rights `xorm:"-" json:"-"`
web.CRUDable `xorm:"-" json:"-"`