Skip to main content

internal/infra/pg/subjectstore.go

internal/infra/pg · 266 lines · 21 declarations · source

Declarations

var ErrInvalidSubject, ErrSubjectNotFound, ErrSubjectConflict

var (
ErrInvalidSubject = errors.New("invalid subject request")
ErrSubjectNotFound = errors.New("subject not found")
ErrSubjectConflict = errors.New("subject reference, retry or version conflict")
)

source

type SubjectStore

type SubjectStore struct {
pool *pgxpool.Pool
schema Schema
}

SubjectStore holds optional identity bookkeeping. It never changes a source's stored attribution and its external references never participate in inference, displayed claims or recall.

source

func NewSubjectStore

func NewSubjectStore(pool *pgxpool.Pool, schema Schema) *SubjectStore

source

type SubjectFields

type SubjectFields struct {
ExternalReference string `json:"external_reference,omitempty"`
Label string `json:"label"`
}

source

type SubjectRegistration

type SubjectRegistration struct {
IdempotencyKey string `json:"idempotency_key"`
SubjectFields
}

source

type SubjectUpdate

type SubjectUpdate struct {
ID string `json:"id"`
ExpectedVersion string `json:"expected_version"`
SubjectFields
}

source

type ManagedSubject

type ManagedSubject struct {
ID string `json:"id"`
Version string `json:"version"`
SubjectFields
UpdatedBy string `json:"updated_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
InactiveAfter *time.Time `json:"inactive_after"`
}

source

type SubjectWrite

type SubjectWrite struct {
ManagedSubject
Replayed bool `json:"replayed"`
}

source

type SubjectPage

type SubjectPage struct {
Subjects []ManagedSubject `json:"subjects"`
Next *RecordCursor `json:"next,omitempty"`
}

source

func subjectUUID

func subjectUUID(value string) (string, error)

source

func subjectFieldsValid

func subjectFieldsValid(f SubjectFields) bool

source

func subjectDigest

func subjectDigest(f SubjectFields) []byte

source

func subjectFailure

func subjectFailure(err error) error

source

const subjectColumns

const subjectColumns = `s.subject_id,s.version::text,coalesce(s.external_reference,''),s.label,s.updated_by::text,s.created_at,s.updated_at,s.inactive_after`

source

const subjectLive

const subjectLive = `(s.inactive_after IS NULL OR s.inactive_after>now() OR EXISTS(SELECT 1 FROM {schema}.observation o WHERE o.scope=s.scope AND o.data_subject_id=s.subject_id))`

source

func subjectDest

func subjectDest(s *ManagedSubject) []any

source

method SubjectStore.Register

func (s *SubjectStore) Register(ctx context.Context, scope, principal string, r SubjectRegistration) (SubjectWrite, error)

Register uses a random ID rather than embedding or hashing a personal reference into attribution. A request's original fingerprint supports lost acknowledgements; erasure leaves only a retry-key tombstone so a delayed registration cannot recreate an erased mapping.

source

method SubjectStore.Get

func (s *SubjectStore) Get(ctx context.Context, scope, id, reference string) (ManagedSubject, error)

Get resolves exactly one project-scoped ID or external reference. No normalization guesses at an application's identifier semantics, and an expired/foreign/absent entry is the same refusal.

source

method SubjectStore.Update

func (s *SubjectStore) Update(ctx context.Context, scope, principal string, r SubjectUpdate) (SubjectWrite, error)

Update rotates a reference without rewriting attribution. The immediate previous version can retry an identical update; a different stale request cannot overwrite a concurrent accepted one.

source

method SubjectStore.List

func (s *SubjectStore) List(ctx context.Context, scope, after string, limit int) (SubjectPage, error)

source

func auditSubjectMutation

func auditSubjectMutation(ctx context.Context, tx pgx.Tx, schema Schema, scope, principal, operation string, magnitude int) error

source