Current section
Files
Jump to
Current section
Files
sourced_postgres
CHANGELOG.md
CHANGELOG.md
# Changelog
All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.0] - 2026-09-22
### Added
- `Sourced.EventStore.Postgres.Subscriber`, a durable subscriber behaviour. It keeps the last sequence it processed in a `sourced_checkpoints` row and subscribes from it on start, and `handle_events/2` runs inside the transaction that commits that position, so a read model written through the store's repo and its checkpoint can never disagree. A fingerprint of the query is stored with the position and a different query under the same name refuses to start; two processes under one name are detected on commit, and the second stops with `{:checkpoint_moved, name}`. `:start_from` sets where a new name begins — `:origin`, `:latest`, or a sequence — and applies only until a position exists. A `transaction?/2` callback, `true` by default, lets a handler whose work is not in the database run outside the transaction, at-least-once.
- `Sourced.EventStore.Postgres.Checkpoint`, the schema and the `claim/4` and `advance/4` operations behind it.
- Versioned migrations. `Sourced.EventStore.Postgres.Migrations.up/1` and `down/1` take a `:version`, and `up/1` runs only the steps a database is missing, recording where it got to as a comment on `sourced_events`. A database migrated by 0.2.x reads as version 1; version 2 adds `sourced_checkpoints`, so an existing install upgrades with a migration calling `up(version: 2)` and `down(version: 2)`.
### Fixed
- `query/2` now orders results by ascending sequence. Nothing in the query asked Postgres for an order before, so a `:limit` was applied to whatever rows the planner produced first rather than the lowest matching sequences, and the `last_sequence` reported alongside the events depended on that same arbitrary order.
## [0.2.1] - 2026-09-14
### Fixed
- A conditional append inside the caller's own transaction no longer fails with `25P02 in_failed_sql_transaction` when it loses a serialization conflict. The adapter read the conflicting sequence back to build the `OptimisticConcurrencyError`, which works in a transaction it opened itself — that one has already rolled back by then — but not in the caller's, which the failure left open and aborted. Inside the caller's transaction the `Postgrex` serialization failure is now raised as-is: nothing can be read on that connection any more, and the whole transaction has to be rerun regardless.
## [0.2.0] - 2026-08-25
### Fixed
- A transaction that appends and then reads now sees its own events. The read watermark sits at or below the sequence the appender started from, so its own appends were above it and invisible to it — a decision model, a read model projected in the same transaction, or a test asserting on what it just wrote would come back empty. Appends now publish the sequences they drew in a transaction-local setting that reads let through alongside the watermark.
### Changed
- Requires `sourced ~> 0.2`, up from `~> 0.1`, since the contract suite it compiles into its test build only ships from 0.2.0 onward.
## [0.1.0] - 2026-08-24
Initial release: a PostgreSQL event store adapter for [Sourced](https://hex.pm/packages/sourced), built on Ecto and Postgrex.
### Added
- `Sourced.EventStore.Postgres` adapter, running on a repo supplied by the host application rather than a pool of its own, so an append can commit alongside the writes it feeds.
- `Sourced.EventStore.Postgres.Migrations` — `up/0` and `down/0` to delegate to from a host migration, creating the `sourced_events` and `sourced_event_tags` tables, their indexes and triggers, and the functions the read watermark is computed from. Both tables ship with autovacuum tuned for an append-only workload.
- Global, monotonic `BIGINT` sequences from an identity column, so a reader can always resume from the last sequence it saw.
- A read watermark bounding every read at the highest sequence no in-flight append can still commit beneath, keeping reads gap-free despite rollbacks and out-of-order commits. Appenders publish their starting sequence as a shared advisory lock released on commit, abort, or connection death.
- `SERIALIZABLE` appends, with a conditional append's serialization failure translated into a `Sourced.EventStore.OptimisticConcurrencyError`.
- Tag queries served by the `sourced_event_tags` side table, kept in step with the `tags` column by a trigger.
- Subscriptions over `LISTEN`/`NOTIFY`, so a subscriber hears about appends from every node. A statement-level `AFTER INSERT` trigger announces the highest sequence an append inserted; each store keeps one listening connection. Subscribing starts with a catch-up read from `:from`, and the subscription owns its cursor from there, re-querying rather than reading the payload. Delivery is at-most-once and not durable.
- `:name` config for running more than one store on the adapter.
[Unreleased]: https://gitlab.com/dimakula/sourced-postgres/-/compare/0.3.0...main
[0.3.0]: https://gitlab.com/dimakula/sourced-postgres/-/compare/0.2.1...0.3.0
[0.2.1]: https://gitlab.com/dimakula/sourced-postgres/-/compare/0.2.0...0.2.1
[0.2.0]: https://gitlab.com/dimakula/sourced-postgres/-/compare/0.1.0...0.2.0
[0.1.0]: https://gitlab.com/dimakula/sourced-postgres/-/tags/0.1.0