file-system/internal/data/share_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

89 lines
2.7 KiB
Go

package data
import (
"context"
"fmt"
"github.com/go-kratos/kratos/v2/log"
"gorm.io/gorm"
)
// ShareRepo implements share link persistence operations using GORM.
type ShareRepo struct {
data *Data
log *log.Helper
}
// NewShareRepo creates a new ShareRepo.
func NewShareRepo(data *Data, logger log.Logger) *ShareRepo {
return &ShareRepo{
data: data,
log: log.NewHelper(logger),
}
}
// Create inserts a new share link record.
func (r *ShareRepo) Create(ctx context.Context, share *ShareLinkPO) error {
return r.data.DB(ctx).Create(share).Error
}
// GetByToken retrieves a share link by its token. Returns nil if not found.
func (r *ShareRepo) GetByToken(ctx context.Context, token string) (*ShareLinkPO, error) {
return r.queryOne(ctx, "token = ?", token)
}
// GetByID retrieves a share link by its ID. Returns nil if not found.
func (r *ShareRepo) GetByID(ctx context.Context, id string) (*ShareLinkPO, error) {
return r.queryOne(ctx, "id = ?", id)
}
// Delete removes a share link by ID and creator. Returns error if not found.
func (r *ShareRepo) Delete(ctx context.Context, id string, createdBy string) error {
result := r.data.DB(ctx).
Where("id = ? AND created_by = ?", id, createdBy).
Delete(&ShareLinkPO{})
if result.Error != nil {
return fmt.Errorf("failed to delete share link: %w", result.Error)
}
if result.RowsAffected == 0 {
return fmt.Errorf("share link not found or not owned by user")
}
return nil
}
// IncrementDownloadCount atomically increments the download count for the given token.
func (r *ShareRepo) IncrementDownloadCount(ctx context.Context, token string) error {
result := r.data.DB(ctx).Model(&ShareLinkPO{}).
Where("token = ?", token).
UpdateColumn("download_count", gorm.Expr("download_count + 1"))
if result.Error != nil {
return fmt.Errorf("failed to increment download count: %w", result.Error)
}
return nil
}
// ListByResource retrieves all share links for a given resource, ordered by created_at descending.
func (r *ShareRepo) ListByResource(ctx context.Context, resourceType string, resourceID string) ([]ShareLinkPO, error) {
var links []ShareLinkPO
err := r.data.DB(ctx).
Where("resource_type = ? AND resource_id = ?", resourceType, resourceID).
Order("created_at DESC").
Find(&links).Error
if err != nil {
return nil, fmt.Errorf("failed to list share links: %w", err)
}
return links, nil
}
func (r *ShareRepo) queryOne(ctx context.Context, query string, args ...interface{}) (*ShareLinkPO, error) {
var share ShareLinkPO
err := r.data.DB(ctx).Where(query, args...).First(&share).Error
if err != nil {
if isRecordNotFound(err) {
return nil, nil
}
return nil, fmt.Errorf("failed to query share link: %w", err)
}
return &share, nil
}