PostgreSQL
Read a config or secret value from a Postgres table, with native watch via LISTEN/NOTIFY. Built on pgx/v5.
| Scheme | postgres:// |
| Module | github.com/xavidop/mamori/providers/postgres |
| Sensitive | no (opt-in with WithSensitive) |
| Watch | native (LISTEN/NOTIFY) |
| Auth | DATABASE_URL (or WithDSN) |
Install
go get github.com/xavidop/mamori/providers/postgres
import _ "github.com/xavidop/mamori/providers/postgres"
Using the ref
A postgres:// ref points at one row of a table (a key/value lookup), optionally selecting a field from a JSON value.
postgres://<table>/<key>[#json-field][?key_col=<c>&val_col=<c>]
| Part | Required | What it means |
|---|---|---|
<table> |
yes | The table to read. May be schema-qualified with a single dot (public.settings). Validated against a strict identifier allowlist. |
<key> |
yes | The row key, bound as the $1 query parameter (never interpolated) and matched with WHERE <key_col> = $1. |
#json-field |
no | Parse the value column as a JSON object and return one field (via mamori.SelectKey). |
?key_col=<c> |
no | Override the key column name (default key). |
?val_col=<c> |
no | Override the value column name (default value). |
Examples
postgres://settings/greeting- runsSELECT value FROM settings WHERE key = $1with$1 = 'greeting'.postgres://settings/http?val_col=int_value- reads the same row but from theint_valuecolumn instead ofvalue.postgres://settings/db#host- reads the JSON object at keydband returns itshostfield.postgres://public.settings/feature_x?key_col=name&val_col=data- runsSELECT data FROM public.settings WHERE name = $1.
type Config struct {
Greeting string `source:"postgres://settings/greeting"`
Timeout int `source:"postgres://settings/http?val_col=int_value"`
DBPass secret.String `source:"postgres://secrets/db_password"`
}
The row key is always bound as the $1 parameter, while the table and column names are validated against a strict identifier allowlist (^[A-Za-z_][A-Za-z0-9_]*$, with one optional schema dot) before any query is built, so a ref can never be used for SQL injection. Value.Version is a content hash of the value by default, or the column named by WithVersionColumn (cast to text) for exact native change detection. Values are non-sensitive unless you set WithSensitive(true) or wrap the field in secret.String.
Watch
Watch issues LISTEN <channel> (default mamori_config) and re-queries on each NOTIFY. Have your writes signal the channel, for example with a trigger:
CREATE OR REPLACE FUNCTION mamori_notify() RETURNS trigger AS $$
BEGIN PERFORM pg_notify('mamori_config', NEW.key); RETURN NEW; END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER settings_notify AFTER INSERT OR UPDATE ON settings
FOR EACH ROW EXECUTE FUNCTION mamori_notify();
Configuration
import pgprov "github.com/xavidop/mamori/providers/postgres"
mamori.WithProvider(pgprov.New(pgprov.WithDSN(os.Getenv("DATABASE_URL"))))
Verified with an in-memory fake (including a test that the identifier allowlist rejects malicious names); live behavior is covered by //go:build integration tests.