package docs import ( "context" "errors" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" docssqlc "github.com/yan1h/agent-coding-workflow/internal/docs/sqlc" "github.com/yan1h/agent-coding-workflow/internal/infra/errs" ) // Repository is the docs persistence contract. type Repository interface { Get(ctx context.Context, wsID uuid.UUID, commitSHA, kind string) (*Summary, error) Upsert(ctx context.Context, in UpsertInput) (*Summary, error) } // UpsertInput carries the fields for a commit_summaries upsert. type UpsertInput struct { WorkspaceID uuid.UUID WorktreeID *uuid.UUID Branch string CommitSHA string Kind string Title *string BodyMD string Model *string Status string Error *string } // PgRepository is the production Repository on a pgxpool.Pool. type PgRepository struct { pool *pgxpool.Pool q *docssqlc.Queries } // NewPostgresRepository builds a PgRepository. func NewPostgresRepository(pool *pgxpool.Pool) *PgRepository { return &PgRepository{pool: pool, q: docssqlc.New(pool)} } var _ Repository = (*PgRepository)(nil) func pgUUID(u uuid.UUID) pgtype.UUID { return pgtype.UUID{Bytes: u, Valid: true} } func pgUUIDPtr(u *uuid.UUID) pgtype.UUID { if u == nil { return pgtype.UUID{} } return pgtype.UUID{Bytes: *u, Valid: true} } func uuidPtr(p pgtype.UUID) *uuid.UUID { if !p.Valid { return nil } id := uuid.UUID(p.Bytes) return &id } func summaryFromRow(r docssqlc.CommitSummary) *Summary { s := &Summary{ ID: uuid.UUID(r.ID.Bytes), WorkspaceID: uuid.UUID(r.WorkspaceID.Bytes), WorktreeID: uuidPtr(r.WorktreeID), Branch: r.Branch, CommitSHA: r.CommitSha, Kind: r.Kind, Title: r.Title, BodyMD: r.BodyMd, Model: r.Model, Status: r.Status, Error: r.Error, } if r.CreatedAt.Valid { s.CreatedAt = r.CreatedAt.Time } return s } func (r *PgRepository) Get(ctx context.Context, wsID uuid.UUID, commitSHA, kind string) (*Summary, error) { row, err := r.q.GetSummary(ctx, docssqlc.GetSummaryParams{ WorkspaceID: pgUUID(wsID), CommitSha: commitSHA, Kind: kind, }) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return nil, nil } return nil, errs.Wrap(err, errs.CodeInternal, "get commit summary") } return summaryFromRow(row), nil } func (r *PgRepository) Upsert(ctx context.Context, in UpsertInput) (*Summary, error) { kind := in.Kind if kind == "" { kind = KindCommit } status := in.Status if status == "" { status = StatusCompleted } row, err := r.q.UpsertSummary(ctx, docssqlc.UpsertSummaryParams{ ID: pgUUID(uuid.New()), WorkspaceID: pgUUID(in.WorkspaceID), WorktreeID: pgUUIDPtr(in.WorktreeID), Branch: in.Branch, CommitSha: in.CommitSHA, Kind: kind, Title: in.Title, BodyMd: in.BodyMD, Model: in.Model, Status: status, Error: in.Error, }) if err != nil { return nil, errs.Wrap(err, errs.CodeInternal, "upsert commit summary") } return summaryFromRow(row), nil }