- PostgreSQL metadata overlay layer on top of existing S3 storage - 3 new tables: folders, files, share_links - Folder CRUD: create, get with children, tree, rename, delete (cascade) - File operations: upload to folder, move between folders - Share links: create with optional password/expiry/download limit, public access - S3 compensation on PG write failure - Existing 14 endpoints untouched
91 lines
3.4 KiB
Go
91 lines
3.4 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"rag/file-system/internal/domain/model"
|
|
)
|
|
|
|
type ShareRepoImpl struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewShareRepository(db *sql.DB) *ShareRepoImpl {
|
|
return &ShareRepoImpl{db: db}
|
|
}
|
|
|
|
func (r *ShareRepoImpl) Create(ctx context.Context, share *model.ShareLink) error {
|
|
_, err := r.db.ExecContext(ctx,
|
|
`INSERT INTO share_links (id, resource_type, resource_id, token, password, expires_at, download_count, max_downloads, created_by, created_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
|
|
share.ID, share.ResourceType, share.ResourceID, share.Token, share.Password, share.ExpiresAt,
|
|
share.DownloadCount, share.MaxDownloads, share.CreatedBy, share.CreatedAt)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create share link: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ShareRepoImpl) GetByToken(ctx context.Context, token string) (*model.ShareLink, error) {
|
|
return r.queryOne(ctx, `SELECT id, resource_type, resource_id, token, password, expires_at, download_count, max_downloads, created_by, created_at FROM share_links WHERE token = $1`, token)
|
|
}
|
|
|
|
func (r *ShareRepoImpl) GetByID(ctx context.Context, id string) (*model.ShareLink, error) {
|
|
return r.queryOne(ctx, `SELECT id, resource_type, resource_id, token, password, expires_at, download_count, max_downloads, created_by, created_at FROM share_links WHERE id = $1`, id)
|
|
}
|
|
|
|
func (r *ShareRepoImpl) Delete(ctx context.Context, id string, createdBy string) error {
|
|
result, err := r.db.ExecContext(ctx, `DELETE FROM share_links WHERE id = $1 AND created_by = $2`, id, createdBy)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete share link: %w", err)
|
|
}
|
|
rows, _ := result.RowsAffected()
|
|
if rows == 0 {
|
|
return fmt.Errorf("share link not found or not owned by user")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ShareRepoImpl) IncrementDownloadCount(ctx context.Context, token string) error {
|
|
_, err := r.db.ExecContext(ctx, `UPDATE share_links SET download_count = download_count + 1 WHERE token = $1`, token)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to increment download count: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *ShareRepoImpl) ListByResource(ctx context.Context, resourceType string, resourceID string) ([]model.ShareLink, error) {
|
|
rows, err := r.db.QueryContext(ctx,
|
|
`SELECT id, resource_type, resource_id, token, password, expires_at, download_count, max_downloads, created_by, created_at FROM share_links WHERE resource_type = $1 AND resource_id = $2 ORDER BY created_at DESC`,
|
|
resourceType, resourceID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list share links: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var links []model.ShareLink
|
|
for rows.Next() {
|
|
var s model.ShareLink
|
|
if err := rows.Scan(&s.ID, &s.ResourceType, &s.ResourceID, &s.Token, &s.Password, &s.ExpiresAt, &s.DownloadCount, &s.MaxDownloads, &s.CreatedBy, &s.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("failed to scan share link: %w", err)
|
|
}
|
|
links = append(links, s)
|
|
}
|
|
return links, rows.Err()
|
|
}
|
|
|
|
func (r *ShareRepoImpl) queryOne(ctx context.Context, query string, args ...interface{}) (*model.ShareLink, error) {
|
|
var s model.ShareLink
|
|
err := r.db.QueryRowContext(ctx, query, args...).
|
|
Scan(&s.ID, &s.ResourceType, &s.ResourceID, &s.Token, &s.Password, &s.ExpiresAt, &s.DownloadCount, &s.MaxDownloads, &s.CreatedBy, &s.CreatedAt)
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to query share link: %w", err)
|
|
}
|
|
return &s, nil
|
|
}
|