internal/infra/pg/exportstore.go
internal/infra/pg · 240 lines · 8 declarations · source
Declarations
type Exporter
type Exporter struct {
pool *pgxpool.Pool
schema Schema
}
Exporter answers "what do you hold about me".
Why it walks the same registry erasure does
Erasure discovers what to delete from `projection_kind` rather than from a list in code, so a projection added by a migration is swept without anybody remembering to add it. Export has exactly the same obligation and the opposite failure mode: a projection missing from a deletion leaves data behind, which a residual count catches — a projection missing from an export leaves data out, and nothing catches that at all. An export nobody compares against anything looks complete.
So it reads the same table. A kind that erasure would delete is a kind export must produce, and there is a test that fails when the two disagree.
Why it includes what was refused
`rejected_claim` holds verbatim quotes from a person's messages — claims the vocabulary would not admit or whose quote could not be located. They were not stored as facts and they are unambiguously that person's words. An export that omitted them would understate what is held, which is the one direction an export must not err in.
func NewExporter
func NewExporter(pool *pgxpool.Pool, schema Schema) *Exporter
var MaxExportRows
var MaxExportRows = 50000
Export gathers everything held about one data subject in one project.
Read in a single transaction at one snapshot. An export assembled across several reads could show a fact whose evidence had been erased between them — internally inconsistent, and the inconsistency would look like a defect in the memory rather than in the export. MaxExportRows bounds one export. A subject with more than this is exported by source instead, a document or a conversation at a time.
A variable rather than a constant so a test can lower it and watch the refusal happen; it is a bound this deployment holds, not a setting an operator turns up. Changing it at runtime would mean two exports of the same person disagreeing about what "too large" means.
The number is a ceiling on rows across every section, not bytes: a row's size is the person's own words and cannot be predicted here, while a row count is what both the export and the erasure receipt already report, so a caller who hits this can see why in the numbers they already have.
var ErrExportTooLarge
var ErrExportTooLarge = errors.New("the export exceeds the supported size; take it by source")
ErrExportTooLarge is a subject whose export exceeds MaxExportRows. It carries no content, only the bound, because the caller's next move is to narrow the request rather than to read a number.
method Exporter.Export
func (e *Exporter) Export(ctx context.Context, schema Schema, scope, dataSubjectID string) (domain.Export, error)
method Exporter.ExportSources
func (e *Exporter) ExportSources(ctx context.Context, schema Schema, scope string, sources []string) (domain.Export, error)
ExportSources answers what is held about a named set of turns, the way erasure by source deletes one. A document observed project-wide has no person, so a subject is not a way to reach it and, until now, neither was an export.
method Exporter.export
func (e *Exporter) export(ctx context.Context, schema Schema, scope string, sel sourceSelection) (domain.Export, error)
func exportRows
func exportRows(ctx context.Context, tx pgx.Tx, schema Schema, sql string, args ...any) ([]json.RawMessage, error)