cairn/internal/models/artifact.go

154 lines
4.2 KiB
Go

package models
import (
"context"
"encoding/json"
"fmt"
"github.com/jackc/pgx/v5/pgxpool"
)
type CreateArtifactParams struct {
RepositoryID string
CommitID string
BuildID *string
Type string
BlobKey string
BlobSize int64
CrashMessage *string
StackTrace *string
Tags json.RawMessage
Metadata json.RawMessage
}
func CreateArtifact(ctx context.Context, pool *pgxpool.Pool, p CreateArtifactParams) (*Artifact, error) {
if p.Tags == nil {
p.Tags = json.RawMessage("{}")
}
if p.Metadata == nil {
p.Metadata = json.RawMessage("{}")
}
a := &Artifact{}
err := pool.QueryRow(ctx, `
INSERT INTO artifacts (repository_id, commit_id, build_id, type, blob_key, blob_size, crash_message, stack_trace, tags, metadata)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id, repository_id, commit_id, build_id, type, blob_key, blob_size, crash_message, stack_trace, tags, metadata, created_at
`, p.RepositoryID, p.CommitID, p.BuildID, p.Type, p.BlobKey, p.BlobSize, p.CrashMessage, p.StackTrace, p.Tags, p.Metadata).Scan(
&a.ID, &a.RepositoryID, &a.CommitID, &a.BuildID, &a.Type, &a.BlobKey, &a.BlobSize,
&a.CrashMessage, &a.StackTrace, &a.Tags, &a.Metadata, &a.CreatedAt,
)
if err != nil {
return nil, fmt.Errorf("creating artifact: %w", err)
}
return a, nil
}
func GetArtifact(ctx context.Context, pool *pgxpool.Pool, id string) (*Artifact, error) {
a := &Artifact{}
err := pool.QueryRow(ctx, `
SELECT a.id, a.repository_id, a.commit_id, a.build_id, a.type, a.blob_key, a.blob_size,
a.crash_message, a.stack_trace, a.tags, a.metadata, a.created_at,
r.name, c.sha
FROM artifacts a
JOIN repositories r ON r.id = a.repository_id
JOIN commits c ON c.id = a.commit_id
WHERE a.id = $1
`, id).Scan(
&a.ID, &a.RepositoryID, &a.CommitID, &a.BuildID, &a.Type, &a.BlobKey, &a.BlobSize,
&a.CrashMessage, &a.StackTrace, &a.Tags, &a.Metadata, &a.CreatedAt,
&a.RepoName, &a.CommitSHA,
)
if err != nil {
return nil, fmt.Errorf("getting artifact: %w", err)
}
return a, nil
}
type ListArtifactsParams struct {
RepositoryID string
CommitSHA string
Type string
SignatureID string
CampaignID string
Limit int
Offset int
}
func ListArtifacts(ctx context.Context, pool *pgxpool.Pool, p ListArtifactsParams) ([]Artifact, int, error) {
if p.Limit <= 0 {
p.Limit = 50
}
baseQuery := `
FROM artifacts a
JOIN repositories r ON r.id = a.repository_id
JOIN commits c ON c.id = a.commit_id
WHERE 1=1
`
args := []any{}
argN := 1
if p.RepositoryID != "" {
baseQuery += fmt.Sprintf(" AND a.repository_id = $%d", argN)
args = append(args, p.RepositoryID)
argN++
}
if p.CommitSHA != "" {
baseQuery += fmt.Sprintf(" AND c.sha = $%d", argN)
args = append(args, p.CommitSHA)
argN++
}
if p.Type != "" {
baseQuery += fmt.Sprintf(" AND a.type = $%d", argN)
args = append(args, p.Type)
argN++
}
if p.SignatureID != "" {
baseQuery += fmt.Sprintf(" AND a.signature_id = $%d", argN)
args = append(args, p.SignatureID)
argN++
}
if p.CampaignID != "" {
baseQuery += fmt.Sprintf(" AND a.campaign_id = $%d", argN)
args = append(args, p.CampaignID)
argN++
}
var total int
err := pool.QueryRow(ctx, "SELECT COUNT(*) "+baseQuery, args...).Scan(&total)
if err != nil {
return nil, 0, fmt.Errorf("counting artifacts: %w", err)
}
selectQuery := fmt.Sprintf(`
SELECT a.id, a.repository_id, a.commit_id, a.build_id, a.type, a.blob_key, a.blob_size,
a.crash_message, a.stack_trace, a.tags, a.metadata, a.created_at,
r.name, c.sha
%s
ORDER BY a.created_at DESC
LIMIT $%d OFFSET $%d
`, baseQuery, argN, argN+1)
args = append(args, p.Limit, p.Offset)
rows, err := pool.Query(ctx, selectQuery, args...)
if err != nil {
return nil, 0, fmt.Errorf("listing artifacts: %w", err)
}
defer rows.Close()
var artifacts []Artifact
for rows.Next() {
var a Artifact
if err := rows.Scan(
&a.ID, &a.RepositoryID, &a.CommitID, &a.BuildID, &a.Type, &a.BlobKey, &a.BlobSize,
&a.CrashMessage, &a.StackTrace, &a.Tags, &a.Metadata, &a.CreatedAt,
&a.RepoName, &a.CommitSHA,
); err != nil {
return nil, 0, fmt.Errorf("scanning artifact: %w", err)
}
artifacts = append(artifacts, a)
}
return artifacts, total, nil
}