Packages
eventstore
0.2.0
1.4.8
1.4.7
1.4.6
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.3
1.2.2
1.2.1
1.2.0
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.0
0.17.0
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.0
0.14.0-rc.0
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.0
0.11.0-rc.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.1
0.2.0
0.1.0
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Event store using PostgreSQL for persistence.
Current section
Files
Jump to
Current section
Files
lib/event_store/storage/appender.ex
defmodule EventStore.Storage.Appender do
@moduledoc """
Append-only storage of events for a stream
"""
require Logger
alias EventStore.{EventData,RecordedEvent}
alias EventStore.Sql.Statements
alias EventStore.Storage.Appender
def append(conn, stream_id, expected_version, events) do
case Appender.Query.query_latest_version(conn, stream_id) do
{:ok, ^expected_version} -> execute_using_multirow_value_insert(conn, stream_id, expected_version, events)
{:ok, latest_version} -> wrong_expected_version(stream_id, expected_version, latest_version)
{:error, reason} -> failed_to_append(stream_id, reason)
end
end
defp wrong_expected_version(stream_id, expected_version, latest_version) do
Logger.warn "failed to append events to stream id #{stream_id}, expected version #{expected_version} but latest version is #{latest_version}"
{:error, :wrong_expected_version}
end
defp failed_to_append(stream_id, reason) do
Logger.warn "failed to append events to stream id #{stream_id} due to #{reason}"
{:error, reason}
end
defp execute_using_multirow_value_insert(conn, stream_id, expected_version, events) do
prepared_events = prepare_events(events, stream_id, expected_version)
statement = build_insert_statement(events)
parameters = build_insert_parameters(prepared_events)
conn
|> Postgrex.query(statement, parameters)
|> handle_response(stream_id, prepared_events)
end
defp build_insert_statement(events) do
Statements.create_events(length(events))
end
defp build_insert_parameters(prepared_events) do
prepared_events
|> Enum.reduce([], fn(event, parameters) ->
parameters ++ [
event.stream_id,
event.stream_version,
event.correlation_id,
event.event_type,
event.headers,
event.payload
]
end)
end
defp prepare_events(events, stream_id, expected_version) do
initial_stream_version = expected_version + 1
events
|> Enum.map(&map_to_recorded_event(&1))
|> Enum.map(&assign_stream_id(&1, stream_id))
|> Enum.with_index(initial_stream_version)
|> Enum.map(&assign_stream_version/1)
end
defp map_to_recorded_event(%EventData{correlation_id: correlation_id, event_type: event_type, headers: headers, payload: payload}) do
%RecordedEvent{
correlation_id: correlation_id,
event_type: event_type,
headers: headers,
payload: payload
}
end
defp assign_stream_id(%RecordedEvent{} = event, stream_id) do
%RecordedEvent{event | stream_id: stream_id}
end
defp assign_stream_version({%RecordedEvent{} = event, stream_version}) do
%RecordedEvent{event | stream_version: stream_version}
end
defp handle_response({:ok, %Postgrex.Result{num_rows: 0}}, stream_id, _events) do
Logger.info "failed to append any events to stream id #{stream_id}"
{:ok, []}
end
defp handle_response({:ok, %Postgrex.Result{num_rows: num_rows, rows: rows}}, stream_id, events) do
Logger.info "appended #{num_rows} events to stream id #{stream_id}"
persisted_events =
Enum.zip(events, rows)
|> Enum.map(fn {event, [event_id, created_at]} ->
%RecordedEvent{event | event_id: event_id, created_at: created_at}
end)
{:ok, persisted_events}
end
defp handle_response({:error, reason}, stream_id, events) do
Logger.warn "failed to append events to stream id #{stream_id} due to #{reason}"
{:error, reason}
end
defmodule Query do
def query_latest_version(conn, stream_id) do
conn
|> Postgrex.query(Statements.query_latest_version, [stream_id])
|> handle_response
end
defp handle_response({:ok, %Postgrex.Result{num_rows: 0}}) do
# no stored events, so latest version is 0
{:ok, 0}
end
defp handle_response({:ok, %Postgrex.Result{rows: [[latest_version]]}}) do
{:ok, latest_version}
end
end
end