Packages
commanded
1.4.0-rc.0
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.0
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
1.0.0-rc.1
1.0.0-rc.0
0.19.1
0.19.0
0.18.1
0.18.0
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.16.0-rc.1
0.16.0-rc.0
0.15.1
0.15.0
0.14.0
0.14.0-rc.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.5
0.8.4
0.8.3
0.8.1
0.8.0
0.7.1
0.6.2
0.6.1
0.6.0
0.4.0
0.3.1
0.3.0
0.2.1
0.2.0
0.1.0
Use Commanded to build your own Elixir applications following the CQRS/ES pattern.
Current section
Files
Jump to
Current section
Files
lib/commanded/snapshotting.ex
defmodule Commanded.Snapshotting do
@moduledoc false
alias Commanded.EventStore
alias Commanded.EventStore.{SnapshotData, TypeProvider}
alias Commanded.Snapshotting
defstruct [
:application,
:source_uuid,
:snapshot_every,
:snapshot_module_version,
snapshot_version: 0
]
def new(application, source_uuid, opts) do
%Snapshotting{
application: application,
source_uuid: source_uuid,
snapshot_every: Keyword.get(opts, :snapshot_every),
snapshot_module_version: Keyword.get(opts, :snapshot_version, 1)
}
end
def read_snapshot(%Snapshotting{} = snapshotting) do
%Snapshotting{application: application, source_uuid: source_uuid} = snapshotting
with :ok <- validate_configured(snapshotting),
{:ok, snapshot} <- EventStore.read_snapshot(application, source_uuid),
:ok <- validate_snapshot(snapshotting, snapshot) do
{:ok, snapshot}
end
end
@doc """
Take a snapshot of the source state.
"""
def take_snapshot(%Snapshotting{} = snapshotting, source_version, source_state)
when is_number(source_version) do
%Snapshotting{
application: application,
source_uuid: source_uuid,
snapshot_module_version: snapshot_module_version
} = snapshotting
snapshot = %SnapshotData{
source_uuid: source_uuid,
source_version: source_version,
source_type: TypeProvider.to_string(source_state),
data: source_state,
metadata: %{"snapshot_module_version" => snapshot_module_version}
}
case EventStore.record_snapshot(application, snapshot) do
:ok -> {:ok, %Snapshotting{snapshotting | snapshot_version: source_version}}
{:error, error} -> {:error, error}
end
end
@doc """
Take a snapshot now?
"""
def snapshot_required?(%Snapshotting{} = snapshotting, source_version)
when is_integer(source_version) do
%Snapshotting{snapshot_every: snapshot_every, snapshot_version: snapshot_version} =
snapshotting
enabled?(snapshotting) && source_version - snapshot_version >= snapshot_every
end
defp validate_configured(%Snapshotting{} = snapshotting) do
if enabled?(snapshotting) do
:ok
else
{:error, :snapshotting_not_configured}
end
end
# Is snapshotting configured?
defp enabled?(%Snapshotting{snapshot_every: snapshot_every}),
do: is_integer(snapshot_every) && snapshot_every > 0
# Was the snapshot taken at the expected module version?
defp validate_snapshot(%Snapshotting{} = snapshotting, %SnapshotData{} = snapshot) do
%Snapshotting{snapshot_module_version: snapshot_module_version} = snapshotting
%SnapshotData{metadata: metadata} = snapshot
if Map.get(metadata, "snapshot_module_version", 1) == snapshot_module_version do
:ok
else
{:error, :outdated_snapshot}
end
end
end