Add BlobStore (ref counting), FileStore (soft delete + pagination), FolderStore (materialized path), UploadStore (idempotent upsert), and update AutoMigrate. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"gcy_hpc_server/internal/model"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type FolderStore struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewFolderStore(db *gorm.DB) *FolderStore {
|
|
return &FolderStore{db: db}
|
|
}
|
|
|
|
func (s *FolderStore) Create(ctx context.Context, folder *model.Folder) error {
|
|
return s.db.WithContext(ctx).Create(folder).Error
|
|
}
|
|
|
|
func (s *FolderStore) GetByID(ctx context.Context, id int64) (*model.Folder, error) {
|
|
var folder model.Folder
|
|
err := s.db.WithContext(ctx).First(&folder, id).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &folder, nil
|
|
}
|
|
|
|
func (s *FolderStore) GetByPath(ctx context.Context, path string) (*model.Folder, error) {
|
|
var folder model.Folder
|
|
err := s.db.WithContext(ctx).Where("path = ?", path).First(&folder).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &folder, nil
|
|
}
|
|
|
|
func (s *FolderStore) ListByParentID(ctx context.Context, parentID *int64) ([]model.Folder, error) {
|
|
var folders []model.Folder
|
|
query := s.db.WithContext(ctx)
|
|
if parentID == nil {
|
|
query = query.Where("parent_id IS NULL")
|
|
} else {
|
|
query = query.Where("parent_id = ?", *parentID)
|
|
}
|
|
if err := query.Order("name ASC").Find(&folders).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return folders, nil
|
|
}
|
|
|
|
// GetSubTree returns all folders whose path starts with the given prefix.
|
|
func (s *FolderStore) GetSubTree(ctx context.Context, path string) ([]model.Folder, error) {
|
|
var folders []model.Folder
|
|
if err := s.db.WithContext(ctx).Where("path LIKE ?", path+"%").Find(&folders).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return folders, nil
|
|
}
|
|
|
|
// HasChildren checks if a folder has sub-folders or files.
|
|
func (s *FolderStore) HasChildren(ctx context.Context, id int64) (bool, error) {
|
|
folder, err := s.GetByID(ctx, id)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if folder == nil {
|
|
return false, nil
|
|
}
|
|
|
|
// Check for sub-folders
|
|
var subFolderCount int64
|
|
if err := s.db.WithContext(ctx).Model(&model.Folder{}).Where("parent_id = ?", id).Count(&subFolderCount).Error; err != nil {
|
|
return false, fmt.Errorf("count sub-folders: %w", err)
|
|
}
|
|
if subFolderCount > 0 {
|
|
return true, nil
|
|
}
|
|
|
|
// Check for files
|
|
var fileCount int64
|
|
if err := s.db.WithContext(ctx).Model(&model.File{}).Where("folder_id = ?", id).Count(&fileCount).Error; err != nil {
|
|
return false, fmt.Errorf("count files: %w", err)
|
|
}
|
|
return fileCount > 0, nil
|
|
}
|
|
|
|
func (s *FolderStore) Delete(ctx context.Context, id int64) error {
|
|
result := s.db.WithContext(ctx).Delete(&model.Folder{}, id)
|
|
if result.Error != nil {
|
|
return result.Error
|
|
}
|
|
return nil
|
|
}
|