file-system/internal/data/file_meta_repo.go
向宁 bcd637387a feat: add data layer with GORM models, S3 repo, PG repos
Replace old infrastructure layer with Kratos-style data layer:
- data.go: GORM connection, transaction support, Wire ProviderSet, PO models
- file_repo.go: All 12 S3 operations (upload, download, multipart, presign, buckets)
- folder_repo.go: GORM queries including recursive CTE for descendant files
- file_meta_repo.go: CRUD + move operations for file metadata
- share_repo.go: CRUD + increment download count for share links

Deleted old infrastructure/database, infrastructure/repository, infrastructure/s3.
Kept infrastructure/grpc for later integration.
2026-05-25 12:57:42 +08:00

91 lines
2.5 KiB
Go

package data
import (
"context"
"fmt"
"time"
"github.com/go-kratos/kratos/v2/log"
)
// FileMetaRepo implements file metadata persistence operations using GORM.
type FileMetaRepo struct {
data *Data
log *log.Helper
}
// NewFileMetaRepo creates a new FileMetaRepo.
func NewFileMetaRepo(data *Data, logger log.Logger) *FileMetaRepo {
return &FileMetaRepo{
data: data,
log: log.NewHelper(logger),
}
}
// Create inserts a new file metadata record.
func (r *FileMetaRepo) Create(ctx context.Context, file *FileMetaPO) error {
return r.data.DB(ctx).Create(file).Error
}
// GetByID retrieves file metadata by ID. Returns nil if not found.
func (r *FileMetaRepo) GetByID(ctx context.Context, id string) (*FileMetaPO, error) {
var file FileMetaPO
err := r.data.DB(ctx).Where("id = ?", id).First(&file).Error
if err != nil {
if isRecordNotFound(err) {
return nil, nil
}
return nil, fmt.Errorf("failed to get file meta: %w", err)
}
return &file, nil
}
// GetByFolder retrieves all files in a folder, ordered by name.
func (r *FileMetaRepo) GetByFolder(ctx context.Context, folderID string) ([]FileMetaPO, error) {
var files []FileMetaPO
err := r.data.DB(ctx).
Where("folder_id = ?", folderID).
Order("name").
Find(&files).Error
if err != nil {
return nil, fmt.Errorf("failed to get files by folder: %w", err)
}
return files, nil
}
// Move updates the folder_id of a file (moves it to another folder).
func (r *FileMetaRepo) Move(ctx context.Context, fileID string, targetFolderID string, ownerID string) error {
result := r.data.DB(ctx).Model(&FileMetaPO{}).
Where("id = ? AND owner_id = ?", fileID, ownerID).
Updates(map[string]interface{}{
"folder_id": targetFolderID,
"updated_at": gormNow(),
})
if result.Error != nil {
return fmt.Errorf("failed to move file: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("file not found or not owned by user")
}
return nil
}
// Delete removes a file metadata record by ID and ownerID.
func (r *FileMetaRepo) Delete(ctx context.Context, id string, ownerID string) error {
result := r.data.DB(ctx).
Where("id = ? AND owner_id = ?", id, ownerID).
Delete(&FileMetaPO{})
if result.Error != nil {
return fmt.Errorf("failed to delete file meta: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("file not found or not owned by user")
}
return nil
}
// gormNow returns the current UTC time for use in GORM updates.
func gormNow() time.Time {
return time.Now().UTC()
}