Tema
/
Interneto svetainių serverio dalies kūrimas GO

Lentelė, trigeris ir veikėjo modelis

Trys failai kortelėse: migracija, užklausos ir veikėjo modelis Go. 00006_audit_events.sqlaudit.sqlaudit.go.

1. db/migrations/00006_audit_events.sql (naujas) — audit_events lentelė, jos indeksas ir papildomo-tik užtikrinimas: plpgsql funkcija, kuri RAISE, ir trigeriai, sujungiantys ją su BEFORE UPDATE OR DELETE (kiekvienai eilutei) ir BEFORE TRUNCATE (kiekvienam sakiniui). Atkreipk dėmesį į seq BIGINT GENERATED ALWAYS AS IDENTITY ir be išorinio rakto esančius document_id / actor_* stulpelius.

2. internal/db/queries/audit.sql (naujas) — dvi užklausos: CreateAuditEvent (įterpti vieną eilutę) ir ListAuditEventsByDocument (ORDER BY seq). Paleisk sqlc generate.

3. internal/handlers/audit.go (naujas) — Go pusė veikėjo modelio:

  • evt* įvykio tipo konstantos (po vieną kiekvienam būsenos pokyčiui),
  • auditActor ir jos konstruktoriai actorUser / actorSigner / actorSystem / actorAnonymous — kiekvienas nustato actor_type ir užšaldytą Label,
  • audit(ctx, q, docID, type, message, actor) — rašo vieną eilutę. Ji priima *db.Queries, tad paduodi transakcijai susietą q (per WithTx), kad įrašytum įvykį atomiškai su būsenos pokyčiu, arba h.Queries geriausių-pastangų skaitymo kelio įvykiams,
  • auditBestEffort — puslapio peržiūros įvykiams, kurie niekada neturi sužlugdyti vartotojo užklausos (jis užrašo klaidą į žurnalą, o ne ją grąžina).
func (h *Handlers) audit(ctx context.Context, q *db.Queries, docID pgtype.UUID, eventType, message string, a auditActor) error {
	return q.CreateAuditEvent(ctx, db.CreateAuditEventParams{
		DocumentID: docID, EventType: eventType, Message: message,
		ActorType: a.Type, ActorUserID: a.UserID, ActorSignerID: a.SignerID, ActorLabel: a.Label,
	})
}

Patikra — perseeduok, kad paleistum migraciją, tada bandyk sulaužyti papildomo-tik taisyklę tiesiai psql:

$ psql "$DATABASE_URL" -c "insert into audit_events (document_id, event_type, message, actor_type, actor_label)
                           values (gen_random_uuid(), 'test', 'hi', 'system', 'system');"
INSERT 0 1
$ psql "$DATABASE_URL" -c "update audit_events set message='changed';"
ERROR:  audit_events is append-only: UPDATE is not permitted
$ psql "$DATABASE_URL" -c "delete from audit_events;"
ERROR:  audit_events is append-only: DELETE is not permitted

Įterpimas veikia; atnaujinimas ir trynimas atmetami duomenų bazės, garsiai — ne programos kodo, kurį turi nepamiršti parašyti. Tai ir yra garantija. Ir pastebėk, kad dabar negali ištrinti savo paties bandymo eilutės — o tai būtent ir yra esmė. Norėdamas ją pašalinti, paleisk migracijos down (kuris numeta visą lentelę) ir migruok aukštyn iš naujo.