package store import ( "context" "errors" "gorm.io/gorm" "gcy_hpc_server/internal/model" ) // TemplateStore provides CRUD operations for job templates via GORM. type TemplateStore struct { db *gorm.DB } // NewTemplateStore creates a new TemplateStore. func NewTemplateStore(db *gorm.DB) *TemplateStore { return &TemplateStore{db: db} } // List returns a paginated list of job templates and the total count. func (s *TemplateStore) List(ctx context.Context, page, pageSize int) ([]model.JobTemplate, int, error) { var templates []model.JobTemplate var total int64 if err := s.db.WithContext(ctx).Model(&model.JobTemplate{}).Count(&total).Error; err != nil { return nil, 0, err } offset := (page - 1) * pageSize if err := s.db.WithContext(ctx).Order("id DESC").Limit(pageSize).Offset(offset).Find(&templates).Error; err != nil { return nil, 0, err } return templates, int(total), nil } // GetByID returns a single job template by ID. Returns nil, nil when not found. func (s *TemplateStore) GetByID(ctx context.Context, id int64) (*model.JobTemplate, error) { var t model.JobTemplate err := s.db.WithContext(ctx).First(&t, id).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } if err != nil { return nil, err } return &t, nil } // Create inserts a new job template and returns the generated ID. func (s *TemplateStore) Create(ctx context.Context, req *model.CreateTemplateRequest) (int64, error) { t := &model.JobTemplate{ Name: req.Name, Description: req.Description, Script: req.Script, Partition: req.Partition, QOS: req.QOS, CPUs: req.CPUs, Memory: req.Memory, TimeLimit: req.TimeLimit, } if err := s.db.WithContext(ctx).Create(t).Error; err != nil { return 0, err } return t.ID, nil } // Update modifies an existing job template. Only non-empty/non-zero fields are updated. func (s *TemplateStore) Update(ctx context.Context, id int64, req *model.UpdateTemplateRequest) error { updates := map[string]interface{}{} if req.Name != "" { updates["name"] = req.Name } if req.Description != "" { updates["description"] = req.Description } if req.Script != "" { updates["script"] = req.Script } if req.Partition != "" { updates["partition"] = req.Partition } if req.QOS != "" { updates["qos"] = req.QOS } if req.CPUs > 0 { updates["cpus"] = req.CPUs } if req.Memory != "" { updates["memory"] = req.Memory } if req.TimeLimit != "" { updates["time_limit"] = req.TimeLimit } if len(updates) == 0 { return nil // nothing to update } result := s.db.WithContext(ctx).Model(&model.JobTemplate{}).Where("id = ?", id).Updates(updates) if result.Error != nil { return result.Error } if result.RowsAffected == 0 { return gorm.ErrRecordNotFound } return nil } // Delete removes a job template by ID. Idempotent — returns nil even if the row doesn't exist. func (s *TemplateStore) Delete(ctx context.Context, id int64) error { result := s.db.WithContext(ctx).Delete(&model.JobTemplate{}, id) if result.Error != nil { return result.Error } return nil }