upload-service/internal/store/store.go

118 lines
3.5 KiB
Go

package store
import (
"database/sql"
"time"
)
type FileRecord struct {
ID string
Filename string
R2Key string
SizeBytes int64
ContentType string
UploadedAt time.Time
ExpiresAt *time.Time
PasswordHash *string
DeleteToken string
DownloadCount int64
BatchID *string
}
type Store struct {
db *sql.DB
}
func New(db *sql.DB) *Store {
return &Store{db: db}
}
func (s *Store) Create(f *FileRecord) error {
_, err := s.db.Exec(
`INSERT INTO files (id, filename, r2_key, size_bytes, content_type, expires_at, password_hash, delete_token, batch_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
f.ID, f.Filename, f.R2Key, f.SizeBytes, f.ContentType, f.ExpiresAt, f.PasswordHash, f.DeleteToken, f.BatchID,
)
return err
}
func (s *Store) Get(id string) (*FileRecord, error) {
f := &FileRecord{}
err := s.db.QueryRow(
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
FROM files WHERE id = ?`, id,
).Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID)
if err != nil {
return nil, err
}
return f, nil
}
func (s *Store) IncrementDownloads(id string) error {
_, err := s.db.Exec(`UPDATE files SET download_count = download_count + 1 WHERE id = ?`, id)
return err
}
func (s *Store) Delete(id string) error {
_, err := s.db.Exec(`DELETE FROM files WHERE id = ?`, id)
return err
}
func (s *Store) DeleteByToken(token string) (*FileRecord, error) {
f := &FileRecord{}
err := s.db.QueryRow(
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
FROM files WHERE delete_token = ?`, token,
).Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID)
if err != nil {
return nil, err
}
_, err = s.db.Exec(`DELETE FROM files WHERE delete_token = ?`, token)
if err != nil {
return nil, err
}
return f, nil
}
func (s *Store) ListExpired() ([]*FileRecord, error) {
rows, err := s.db.Query(
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
FROM files WHERE expires_at IS NOT NULL AND expires_at <= datetime('now')`,
)
if err != nil {
return nil, err
}
defer rows.Close()
var files []*FileRecord
for rows.Next() {
f := &FileRecord{}
if err := rows.Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID); err != nil {
return nil, err
}
files = append(files, f)
}
return files, rows.Err()
}
func (s *Store) GetBatch(batchID string) ([]*FileRecord, error) {
rows, err := s.db.Query(
`SELECT id, filename, r2_key, size_bytes, content_type, uploaded_at, expires_at, password_hash, delete_token, download_count, batch_id
FROM files WHERE batch_id = ? ORDER BY filename`, batchID,
)
if err != nil {
return nil, err
}
defer rows.Close()
var files []*FileRecord
for rows.Next() {
f := &FileRecord{}
if err := rows.Scan(&f.ID, &f.Filename, &f.R2Key, &f.SizeBytes, &f.ContentType, &f.UploadedAt, &f.ExpiresAt, &f.PasswordHash, &f.DeleteToken, &f.DownloadCount, &f.BatchID); err != nil {
return nil, err
}
files = append(files, f)
}
return files, rows.Err()
}