3.5 KiB
Postgres Sink Internals
Purpose
internal/sinks/postgres defines weatherfeeder's canonical-event-to-Postgres
mapping. It supplies a schema definition and mapper to feedkit's generic
Postgres sink.
The consumer-facing table contract is
docs/integrations/postgres.md. This document
describes the internal ownership boundary.
Inputs And Outputs
Inputs are canonical feed events. The mapper currently handles these schemas:
weather.observation.v1weather.forecast.v1weather.forecast_discussion.v1weather.weather_story.v1weather.alert.v1
Outputs are feedkit PostgresWrite values for weatherfeeder-owned tables.
Unsupported schemas produce no writes and no error.
Boundaries
- Weatherfeeder owns table definitions in
schema.go. - Weatherfeeder owns canonical payload mapping in
map.go. - Feedkit owns database opening, table and index creation, transactions, inserts, context-aware consumption, and prune execution.
- Postgres mapping consumes canonical events only. It should not understand raw provider schemas.
Config Fields Used
Weatherfeeder registers the postgres sink by passing PostgresSchema() to
feedkit. Feedkit parses sink params:
uriusernamepasswordprune, optional duration
Weatherfeeder-owned mapper code does not read config directly.
External Adapters Used
The runtime registers the sink with:
sinkReg.Register("postgres", fksinks.PostgresFactory(wfpgsink.PostgresSchema()))
Feedkit validates events at the sink boundary, calls the weatherfeeder mapper, validates writes against the compiled schema, inserts rows in a transaction, and optionally prunes rows older than the configured window.
State
The mapper is stateless. Durable state is stored in Postgres through feedkit's sink implementation.
Mapping Rules
Parent rows preserve event envelope fields where the table supports them:
event_idevent_kindevent_sourceevent_schemaevent_emitted_atevent_effective_at
Child rows use positional indexes to preserve canonical array order:
weather_indexperiod_indexmessage_indexstory_indexalert_indexreference_index
Required canonical fields are validated before writes are returned:
- observations require
timestamp; - forecasts require
issuedAtandproduct, and each period requiresstartTimeandendTime; - forecast discussions require
issuedAtandproduct; - weather story runs require
asOf, and each story requiresstartTime,endTime, andupdatedAt; - alert runs require
asOf, and each alert requiresid.
Nullable canonical values are converted to SQL nulls by mapper helpers. Observation present-weather raw values are stored as compact JSON text.
Failure Behavior
Payload decode failures, missing required fields, invalid compact JSON values, or schema/write mismatches return errors to feedkit's sink. Feedkit rolls back the transaction when a write fails.
Unsupported canonical schemas are ignored by this mapper so other routed events can use different sinks without Postgres-specific failures.
Tests To Inspect
internal/sinks/postgres/schema_test.gointernal/sinks/postgres/map_test.go- feedkit Postgres sink tests when changing generic sink behavior assumptions
Invariants
- Persist only canonical schemas.
- Preserve event envelope fields in parent rows.
- Preserve array order with child positional indexes.
- Validate required fields before writing.
- Keep table-contract docs synchronized with schema and mapper changes.