pkg/task/stores/mysql/mysql.go

195 lines
5.2 KiB
Go

/*
* Tencent is pleased to support the open source community by making Blueking Container Service available.
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
// Package mysql implemented storage interface.
package mysql
import (
"context"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"git.ifooth.com/common/pkg/task/stores/iface"
"git.ifooth.com/common/pkg/task/types"
)
type mysqlStore struct {
dsn string
debug bool
db *gorm.DB
}
type option func(*mysqlStore)
// WithDebug 是否显示sql语句
func WithDebug(debug bool) option {
return func(s *mysqlStore) {
s.debug = debug
}
}
// New init mysql iface.Store
func New(dsn string, opts ...option) (iface.Store, error) {
store := &mysqlStore{dsn: dsn, debug: false}
for _, opt := range opts {
opt(store)
}
// 是否显示sql语句
level := logger.Warn
if store.debug {
level = logger.Info
}
db, err := gorm.Open(mysql.Open(store.dsn),
&gorm.Config{Logger: logger.Default.LogMode(level)},
)
if err != nil {
return nil, err
}
store.db = db
return store, nil
}
// EnsureTable implement istore EnsureTable interface
func (s *mysqlStore) EnsureTable(ctx context.Context, dst ...any) error {
// 没有自定义数据, 使用默认表结构
if len(dst) == 0 {
dst = []any{&TaskRecord{}, &StepRecord{}}
}
return s.db.WithContext(ctx).AutoMigrate(dst...)
}
// CreateTask implement istore CreateTask interface
func (s *mysqlStore) CreateTask(ctx context.Context, task *types.Task) error {
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
record := getTaskRecord(task)
if err := tx.Create(record).Error; err != nil {
return err
}
steps := getStepRecord(task)
if err := tx.CreateInBatches(steps, 100).Error; err != nil {
return err
}
return nil
})
}
// ListTask implement istore ListTask interface
func (s *mysqlStore) ListTask(ctx context.Context, opt *iface.ListOption) (*iface.Pagination[types.Task], error) {
tx := s.db.WithContext(ctx)
// 条件过滤 0值gorm自动忽略查询
tx = tx.Where(&TaskRecord{
TaskID: opt.TaskID,
TaskType: opt.TaskType,
TaskName: opt.TaskName,
TaskIndex: opt.TaskIndex,
TaskIndexType: opt.TaskIndexType,
Status: opt.Status,
CurrentStep: opt.CurrentStep,
Creator: opt.Creator,
})
// mysql store 使用创建时间过滤
if opt.CreatedGte != nil {
tx = tx.Where("created_at >= ?", opt.CreatedGte)
}
if opt.CreatedLte != nil {
tx = tx.Where("created_at <= ?", opt.CreatedLte)
}
// 只使用id排序
tx = tx.Order("id DESC")
result, count, err := FindByPage[TaskRecord](tx, int(opt.Offset), int(opt.Limit))
if err != nil {
return nil, err
}
items := make([]*types.Task, 0, len(result))
for _, record := range result {
items = append(items, toTask(record, []*StepRecord{}))
}
return &iface.Pagination[types.Task]{
Count: count,
Items: items,
}, nil
}
// UpdateTask implement istore UpdateTask interface
func (s *mysqlStore) UpdateTask(ctx context.Context, task *types.Task) error {
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
updateTask := getUpdateTaskRecord(task)
if err := tx.Model(&TaskRecord{}).
Where("task_id = ?", task.TaskID).
Select(updateTaskField).
Updates(updateTask).Error; err != nil {
return err
}
for _, step := range task.Steps {
if step.Name != task.CurrentStep {
continue
}
updateStep := getUpdateStepRecord(step)
if err := tx.Model(&StepRecord{}).
Where("task_id = ? AND name= ?", task.TaskID, step.Name).
Select(updateStepField).
Updates(updateStep).Error; err != nil {
return err
}
}
return nil
})
}
// DeleteTask implement istore DeleteTask interface
func (s *mysqlStore) DeleteTask(ctx context.Context, taskID string) error {
return s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
if err := tx.Where("task_id = ?", taskID).Delete(&TaskRecord{}).Error; err != nil {
return err
}
if err := tx.Where("task_id = ?", taskID).Delete(&StepRecord{}).Error; err != nil {
return err
}
return nil
})
}
// GetTask implement istore GetTask interface
func (s *mysqlStore) GetTask(ctx context.Context, taskID string) (*types.Task, error) {
tx := s.db.WithContext(ctx)
taskRecord := TaskRecord{}
if err := tx.Where("task_id = ?", taskID).First(&taskRecord).Error; err != nil {
return nil, err
}
stepRecord := []*StepRecord{}
if err := tx.Where("task_id = ?", taskID).Find(&stepRecord).Error; err != nil {
return nil, err
}
return toTask(&taskRecord, stepRecord), nil
}
// PatchTask implement istore PatchTask interface
func (s *mysqlStore) PatchTask(ctx context.Context, opt *iface.PatchOption) error {
return types.ErrNotImplemented
}