All Projects → tobyhede → Postgresql Event Sourcing

tobyhede / Postgresql Event Sourcing

postgresql event sourcing

Labels

Projects that are alternatives of or similar to Postgresql Event Sourcing

Aws Database Migration Samples
A set of sample database and associated items to allow customers to among other things follow along with published database migration recipes.
Stars: ✭ 105 (-28.08%)
Mutual labels:  plpgsql
Scaledger
A double-entry accounting database with a typed GraphQL API
Stars: ✭ 115 (-21.23%)
Mutual labels:  plpgsql
Temporal tables
Stars: ✭ 126 (-13.7%)
Mutual labels:  plpgsql
Panda Cloud
Base on SpringCloud MicroService Framework
Stars: ✭ 108 (-26.03%)
Mutual labels:  plpgsql
Node Sqlcipher
SQLCipher bindings for Node
Stars: ✭ 114 (-21.92%)
Mutual labels:  plpgsql
Pg Auth
A complete authentication system built in Postgres using schemas and functions
Stars: ✭ 117 (-19.86%)
Mutual labels:  plpgsql
Postgraphile Lambda Example
Simple serverless / Lambda example with caching and lightweight bundle
Stars: ✭ 104 (-28.77%)
Mutual labels:  plpgsql
Subzero Starter Kit
Starter Kit and tooling for authoring GraphQL/REST API backends with subZero
Stars: ✭ 136 (-6.85%)
Mutual labels:  plpgsql
Vocabulary V5.0
PALLAS: Build process for OMOP Standardized Vocabularies. Currently not available as independent release. Therefore, do not clone or try to replicate. It is work in progress and not ready for replication.
Stars: ✭ 114 (-21.92%)
Mutual labels:  plpgsql
Partition magic
Скрипт-сниппет для Postgresql на plpgsql, позволяющий лёгко, быстро и просто создавать партицированные таблицы в вашем проекте, а также изменять, добавлять и удалять данные.
Stars: ✭ 120 (-17.81%)
Mutual labels:  plpgsql
Common schema
DBA's framework for MySQL
Stars: ✭ 108 (-26.03%)
Mutual labels:  plpgsql
Bible Database
Bible databases as XML, JSON, SQL & SQLITE3 Database format for various languages. Developers can download it freely for their development works. Freely received, freely give.
Stars: ✭ 111 (-23.97%)
Mutual labels:  plpgsql
Sqlite Parser
An ANTLR4 grammar for SQLite statements.
Stars: ✭ 119 (-18.49%)
Mutual labels:  plpgsql
Screampay
screamPay聚合支付,一个强大到让你尖叫的聚合支付系统,使用Java开发,spring-boot架构,已接入环讯、九派、杉德等主流支付渠道,可直接用于生产环境。
Stars: ✭ 107 (-26.71%)
Mutual labels:  plpgsql
Ccap
open source and transparent cryptocurrency analysis platform
Stars: ✭ 128 (-12.33%)
Mutual labels:  plpgsql
Serverless Postgraphql
Serverless GraphQL endpoint for PostgresSQL using AWS, serverless and PostGraphQL
Stars: ✭ 105 (-28.08%)
Mutual labels:  plpgsql
Pg2go
PostgreSQL script that generates Go struct definitions for all tables in a database
Stars: ✭ 116 (-20.55%)
Mutual labels:  plpgsql
Hierarchy Data Closure Table
This is a mysql and postgresql store procedure and trigger implementation of closure table in RDBMS about hierarchy data model.
Stars: ✭ 135 (-7.53%)
Mutual labels:  plpgsql
Pg jobmon
PostgreSQL extension which provides persistent logging within transactions and functions.
Stars: ✭ 128 (-12.33%)
Mutual labels:  plpgsql
Mytap
MySQL Unit Testing Suite
Stars: ✭ 118 (-19.18%)
Mutual labels:  plpgsql

postgresql-event-sourcing

Experiment using PostgreSQL as a natively event sourcing database.

Uses triggers and functions to manage projections transactionally.

The basic flow of action is:

event -> after insert trigger -> trigger function -> projection function -> projection

The advantage of this model is that triggers ensure the projections are always up to date, but we do not lose the ability to replay the event stream with the same logic.

Events

Event Sourcing ensures that all changes to application state are stored as a sequence of events.

Events are stored in an events table.

We assume that all objects/entities in the system have a globally unique identifier.

Column Details
id Primary Key
uuid Unique ID of the entity the event references
type The event type, used when building projections
body Event data as JSON
inserted_at timestamp of event insert
CREATE TABLE "events" (
  "id" serial primary key not null,
  "uuid" uuid NOT NULL,
  "type" text NOT NULL,
  "body" jsonb NOT NULL,
  "inserted_at" timestamp(6) NOT NULL DEFAULT statement_timestamp()
);

An example event, tracking an update to the name of the user identified by a uuid:

insert into events (type, uuid, body)
values ('user_update', '11111111-1111-1111-1111-111111111111', '{"name": "blah"}');

Projection Triggers

Use after insert triggers on the events table to handle the incoming event actions.

In order to replay the events outside of the trigger mechanism, we wrap a general projection function inside the trigger. This will make more sense in a moment.

Below we create a trigger function and a trigger to execute. The trigger uses a conditional to only fire when the appropriate event type has been inserted.

create or replace function fn_trigger_user_create() returns trigger
  security definer
  language plpgsql
as $$
  begin
    perform fn_project_user_create(new.uuid, new.body);
    return new;
  end;
$$;

create trigger event_insert_user_create after insert on events
  for each row
  when (new.type = 'user_create')
  execute procedure fn_trigger_user_insert();

Projection Functions

A projection function does the actual work of handling the event data and mapping to the appropriate projection.

Multiple triggers and multiple functions can be added to handle different aspects of the same event type if required.

Assuming a users table with a name and uuid, the following function inserts a new user record into the table based on the user_create event.

create or replace function fn_project_user_create(uuid uuid, body jsonb) returns integer
  security definer
  language plpgsql as $$
  declare result int;
  begin
    insert into users(uuid, name, inserted_at, updated_at)
      values(uuid, body->>'name', NOW(), NOW())
      returning id into result;
    return result;
  end;
$$;

JSON can be referenced using the native operators in PostgreSQL 9.5. body->>'name' extracts the value of the name field from the body JSON.

Any constraints on the table will also be enforced, ensuring referential integrity.

Replay Event Stream

Using projection functions means that at any point the events can be replayed, simply by calling the function and passing the correct identifier and data.

The following code replays all user_create events in order

do language plpgsql $$
  declare
    e record;
  begin
    for e in select uuid body from events where type = 'user_create' order by inserted_at asc loop
      perform fn_project_user_create(e.uuid, e.body);
    end loop;
  end;
$$;

Any valid query can be used as the basis for the replay loop, and any combination of valid events.

The following code replays all events for the user identified by the specified uuid:

do language plpgsql $$
  declare
    e record;
  begin
    for e in select type, uuid, body from events where uuid = '11111111-1111-1111-1111-111111111111' order by inserted_at asc loop
    case e.type
      when 'user_create' then
        perform fn_project_user_create(e.uuid, e.body);
	   when 'user_update' then
        perform fn_project_user_update(e.uuid, e.body);
	  end case;
    end loop;
  end;
$$;

All of these functions will be executed in the same transaction block. This doesn't particularly matter in an event sourced system, but it is good to know.

PostgreSQL is not just limited to processing events iteratively.

Below is an example of using a materialized view to project the user data.

create materialized view users_view as
  with t as (
      select *, row_number() over(partition by uuid order by inserted_at desc) as row_number
      from events
      where type = 'user_update'
  )
  select uuid, body->>'name' as name, inserted_at from t where row_number = 1;

select * from users_view;

In this case we assume that the most recent update event contains the correct user data, and we query to find the most recent update_user event for each user identified.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].