Create/Get for submission (including the one legitimate status transition — submission is not append-only, unlike the other three), Create/GetLatest for extraction and evidence_package, Create for finding plus ListCurrentFindings which applies the anti-join documented in the migration (a finding referenced by another row's `supersedes` is not "current"). Tested against real Postgres, including that the append-only trigger still rejects UPDATE on evidence_package via this new code path, and that ListCurrentFindings actually hides a finding once a correction supersedes it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
57 lines
1.9 KiB
Go
57 lines
1.9 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Extraction ist das Ergebnis der Stufe-1-Extraktion für einen Beitrag.
|
|
// Payload ist das rohe, vom Modell gelieferte JSON — nicht eine
|
|
// abgeleitete Repräsentation. Append-only: siehe Migration.
|
|
type Extraction struct {
|
|
ID string
|
|
SubmissionID string
|
|
Payload []byte
|
|
ModelVersion string
|
|
PromptVersion string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// CreateExtraction speichert eine Extraktion. payload ist das rohe
|
|
// JSON, wie es das Modell zurückgegeben hat (siehe extract.Result.RawJSON).
|
|
func (s *Store) CreateExtraction(ctx context.Context, submissionID string, payload []byte, modelVersion, promptVersion string) (Extraction, error) {
|
|
var e Extraction
|
|
err := s.Pool.QueryRow(ctx, `
|
|
INSERT INTO extraction (submission_id, payload, model_version, prompt_version)
|
|
VALUES ($1, $2, $3, $4)
|
|
RETURNING id, submission_id, payload, model_version, prompt_version, created_at
|
|
`, submissionID, payload, modelVersion, promptVersion).Scan(
|
|
&e.ID, &e.SubmissionID, &e.Payload, &e.ModelVersion, &e.PromptVersion, &e.CreatedAt,
|
|
)
|
|
if err != nil {
|
|
return Extraction{}, fmt.Errorf("store: create extraction: %w", err)
|
|
}
|
|
return e, nil
|
|
}
|
|
|
|
// GetLatestExtraction liest die zuletzt erzeugte Extraktion für einen
|
|
// Beitrag (append-only: es kann mehrere geben, z. B. bei einer erneuten
|
|
// Prüfung — die aktuellste zählt).
|
|
func (s *Store) GetLatestExtraction(ctx context.Context, submissionID string) (Extraction, error) {
|
|
var e Extraction
|
|
err := s.Pool.QueryRow(ctx, `
|
|
SELECT id, submission_id, payload, model_version, prompt_version, created_at
|
|
FROM extraction
|
|
WHERE submission_id = $1
|
|
ORDER BY created_at DESC
|
|
LIMIT 1
|
|
`, submissionID).Scan(
|
|
&e.ID, &e.SubmissionID, &e.Payload, &e.ModelVersion, &e.PromptVersion, &e.CreatedAt,
|
|
)
|
|
if err != nil {
|
|
return Extraction{}, fmt.Errorf("store: get latest extraction: %w", err)
|
|
}
|
|
return e, nil
|
|
}
|