Files
mcr/internal/db/upload.go
Kyle Isom dddc66f31b Phases 5, 6, 8: OCI pull/push paths and admin REST API
Phase 5 (OCI pull): internal/oci/ package with manifest GET/HEAD by
tag/digest, blob GET/HEAD with repo membership check, tag listing with
OCI pagination, catalog listing. Multi-segment repo names via
parseOCIPath() right-split routing. DB query layer in
internal/db/repository.go.

Phase 6 (OCI push): blob uploads (monolithic and chunked) with
uploadManager tracking in-progress BlobWriters, manifest push
implementing full ARCHITECTURE.md §5 flow in a single SQLite
transaction (create repo, upsert manifest, populate manifest_blobs,
atomic tag move). Digest verification on both blob commit and manifest
push-by-digest.

Phase 8 (admin REST): /v1 endpoints for auth (login/logout/health),
repository management (list/detail/delete), policy CRUD with engine
reload, audit log listing with filters, GC trigger/status stubs.
RequireAdmin middleware, platform-standard error format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 18:25:18 -07:00

81 lines
2.0 KiB
Go

package db
import (
"database/sql"
"errors"
"fmt"
)
// ErrUploadNotFound indicates the requested upload UUID does not exist.
var ErrUploadNotFound = errors.New("db: upload not found")
// UploadRow represents a row in the uploads table.
type UploadRow struct {
ID int64
UUID string
RepositoryID int64
ByteOffset int64
}
// CreateUpload inserts a new upload row and returns its ID.
func (d *DB) CreateUpload(uuid string, repoID int64) error {
_, err := d.Exec(
`INSERT INTO uploads (uuid, repository_id) VALUES (?, ?)`,
uuid, repoID,
)
if err != nil {
return fmt.Errorf("db: create upload: %w", err)
}
return nil
}
// GetUpload returns the upload with the given UUID.
func (d *DB) GetUpload(uuid string) (*UploadRow, error) {
var u UploadRow
err := d.QueryRow(
`SELECT id, uuid, repository_id, byte_offset FROM uploads WHERE uuid = ?`, uuid,
).Scan(&u.ID, &u.UUID, &u.RepositoryID, &u.ByteOffset)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUploadNotFound
}
return nil, fmt.Errorf("db: get upload: %w", err)
}
return &u, nil
}
// UpdateUploadOffset sets the byte_offset for an upload.
func (d *DB) UpdateUploadOffset(uuid string, offset int64) error {
result, err := d.Exec(
`UPDATE uploads SET byte_offset = ? WHERE uuid = ?`,
offset, uuid,
)
if err != nil {
return fmt.Errorf("db: update upload offset: %w", err)
}
n, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("db: update upload offset rows affected: %w", err)
}
if n == 0 {
return ErrUploadNotFound
}
return nil
}
// DeleteUpload removes the upload row with the given UUID.
func (d *DB) DeleteUpload(uuid string) error {
result, err := d.Exec(`DELETE FROM uploads WHERE uuid = ?`, uuid)
if err != nil {
return fmt.Errorf("db: delete upload: %w", err)
}
n, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("db: delete upload rows affected: %w", err)
}
if n == 0 {
return ErrUploadNotFound
}
return nil
}