TerminusDB.Diff (terminusdb_ex v0.3.3)

Copy Markdown View Source

Document diff and patch API for TerminusDB.

Wraps the /api/diff, /api/patch, and /api/apply endpoints to compare, patch, and apply document changes.

Diffs can be computed between:

  • Two document values (before and after maps).
  • Branch vs branch, commit vs commit, or branch vs commit (by supplying the appropriate resource refs in the before/after fields).

Quick start

config =
  TerminusDB.Config.new(endpoint: "http://localhost:6363")
  |> TerminusDB.Config.with_database("mydb")

# Diff two document values
{:ok, patch} = TerminusDB.Diff.diff_object(config,
  before: %{"@id" => "Person/Alice", "name" => "Alice"},
  after: %{"@id" => "Person/Alice", "name" => "Alicia"}
)

# Apply a patch to a branch
{:ok, _} = TerminusDB.Diff.patch_resource(config,
  patch: patch, message: "update name", author: "admin"
)

Summary

Functions

Diffs two commits and applies the changes onto a branch.

Applies a diff to a branch, or raises.

Compares two document states and returns a structured diff patch.

Compares two document states, or raises TerminusDB.Error.

Diffs two concrete document objects and returns a TerminusDB.Patch struct.

Diffs two concrete document objects, or raises.

Diffs two commit/branch versions and returns a TerminusDB.Patch struct.

Diffs two versions, or raises.

Applies a patch to a "before" object and returns the "after" object (no commit).

Applies a patch, or raises.

Applies a patch to a branch resource (commits the change).

Applies a patch to a branch resource, or raises.

Types

apply_opt()

@type apply_opt() ::
  {:before_version, String.t()}
  | {:after_version, String.t()}
  | {:message, String.t()}
  | {:author, String.t()}
  | {:organization, String.t()}
  | {:repo, String.t()}

compare_opt()

@type compare_opt() ::
  {:before, map()}
  | {:after, map()}
  | {:keep, map()}
  | {:organization, String.t()}

diff_object_opt()

@type diff_object_opt() ::
  {:before, map()}
  | {:after, map()}
  | {:keep, map()}
  | {:organization, String.t()}
  | {:repo, String.t()}

diff_version_opt()

@type diff_version_opt() ::
  {:before_version, String.t()}
  | {:after_version, String.t()}
  | {:organization, String.t()}
  | {:repo, String.t()}

patch_opt()

@type patch_opt() :: {:organization, String.t()}

patch_resource_opt()

@type patch_resource_opt() ::
  {:patch, map()}
  | {:message, String.t()}
  | {:author, String.t()}
  | {:match_final_state, boolean()}
  | {:organization, String.t()}
  | {:repo, String.t()}

Functions

apply(config, opts \\ [])

@spec apply(TerminusDB.Config.t(), [apply_opt()]) ::
  {:ok, map()} | {:error, TerminusDB.Error.t()}

Diffs two commits and applies the changes onto a branch.

Options

  • :before_version (required) - the before commit descriptor.
  • :after_version (required) - the after commit descriptor.
  • :message - commit message.
  • :author - commit author.
  • :organization - overrides config.organization.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, resp} = TerminusDB.Diff.apply(config,
...>   before_version: "admin/mydb/local/commit/abc",
...>   after_version: "admin/mydb/local/commit/def",
...>   author: "admin", message: "apply"
...> )
iex> resp["api:status"]
"api:success"

apply!(config, opts \\ [])

@spec apply!(TerminusDB.Config.t(), [apply_opt()]) :: map()

Applies a diff to a branch, or raises.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Diff.apply!(config,
...>   before_version: "admin/mydb/local/commit/abc",
...>   after_version: "admin/mydb/local/commit/def"
...> )
%{"api:status" => "api:success"}

compare(config, opts \\ [])

@spec compare(TerminusDB.Config.t(), [compare_opt()]) ::
  {:ok, map()} | {:error, TerminusDB.Error.t()}

Compares two document states and returns a structured diff patch.

The before and after values can be:

  • Document maps (with @id and fields) for a value-level diff.
  • Resource references (e.g. "admin/mydb/local/branch/main") for a branch/commit-level diff.

Options

  • :before (required) - the "before" document or resource ref.
  • :after (required) - the "after" document or resource ref.
  • :keep - a map of fields to preserve in the diff (e.g. %{"@id" => true}).
  • :organization - overrides config.organization.

Examples

Diff two document values:

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req ->
...>     {req, Req.Response.new(status: 200, body: %{"name" => %{"@op" => "ValueSwap", "@before" => "Alice", "@after" => "Alicia"}})}
...>   end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, patch} = TerminusDB.Diff.compare(config,
...>   before: %{"@id" => "Person/Alice", "name" => "Alice"},
...>   after: %{"@id" => "Person/Alice", "name" => "Alicia"}
...> )
iex> patch["name"]["@op"]
"ValueSwap"

Diff two branches:

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, _} = TerminusDB.Diff.compare(config,
...>   before: "admin/mydb/local/branch/main",
...>   after: "admin/mydb/local/branch/feature"
...> )
:ok

compare!(config, opts \\ [])

@spec compare!(TerminusDB.Config.t(), [compare_opt()]) :: map()

Compares two document states, or raises TerminusDB.Error.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"name" => %{"@op" => "ValueSwap"}})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Diff.compare!(config,
...>   before: %{"name" => "Alice"},
...>   after: %{"name" => "Alicia"}
...> )
%{"name" => %{"@op" => "ValueSwap"}}

diff_object(config, opts \\ [])

@spec diff_object(TerminusDB.Config.t(), [diff_object_opt()]) ::
  {:ok, TerminusDB.Patch.t()} | {:error, TerminusDB.Error.t()}

Diffs two concrete document objects and returns a TerminusDB.Patch struct.

Options

  • :before (required) - the "before" document map.
  • :after (required) - the "after" document map.
  • :keep - a map of fields to preserve in the diff.
  • :organization - overrides config.organization.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req ->
...>     {req, Req.Response.new(status: 200, body: %{"name" => %{"@op" => "SwapValue", "@before" => "old", "@after" => "new"}})}
...>   end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, patch} = TerminusDB.Diff.diff_object(config,
...>   before: %{"@id" => "Person/1", "name" => "old"},
...>   after: %{"@id" => "Person/1", "name" => "new"}
...> )
iex> patch.content["name"]["@after"]
"new"

diff_object!(config, opts \\ [])

@spec diff_object!(TerminusDB.Config.t(), [diff_object_opt()]) :: TerminusDB.Patch.t()

Diffs two concrete document objects, or raises.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req ->
...>     {req, Req.Response.new(status: 200, body: %{"name" => %{"@op" => "SwapValue", "@before" => "old", "@after" => "new"}})}
...>   end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> patch = TerminusDB.Diff.diff_object!(config,
...>   before: %{"name" => "old"},
...>   after: %{"name" => "new"}
...> )
iex> patch.content["name"]["@after"]
"new"

diff_version(config, opts \\ [])

@spec diff_version(TerminusDB.Config.t(), [diff_version_opt()]) ::
  {:ok, TerminusDB.Patch.t()} | {:error, TerminusDB.Error.t()}

Diffs two commit/branch versions and returns a TerminusDB.Patch struct.

Options

  • :before_version (required) - the before commit/branch descriptor.
  • :after_version (required) - the after commit/branch descriptor.
  • :organization - overrides config.organization.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, patch} = TerminusDB.Diff.diff_version(config,
...>   before_version: "admin/mydb/local/branch/main",
...>   after_version: "admin/mydb/local/branch/feature"
...> )
iex> patch.content
%{}

diff_version!(config, opts \\ [])

@spec diff_version!(TerminusDB.Config.t(), [diff_version_opt()]) ::
  TerminusDB.Patch.t()

Diffs two versions, or raises.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> patch = TerminusDB.Diff.diff_version!(config,
...>   before_version: "admin/mydb/local/branch/main",
...>   after_version: "admin/mydb/local/branch/feature"
...> )
iex> patch.content
%{}

patch(config, opts \\ [])

@spec patch(TerminusDB.Config.t(), [patch_opt() | {:before, map()} | {:patch, map()}]) ::
  {:ok, map()} | {:error, TerminusDB.Error.t()}

Applies a patch to a "before" object and returns the "after" object (no commit).

Options

  • :organization - overrides config.organization.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"@id" => "Person/1", "name" => "new"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, after_obj} = TerminusDB.Diff.patch(config,
...>   before: %{"@id" => "Person/1", "name" => "old"},
...>   patch: %{"name" => %{"@op" => "SwapValue", "@before" => "old", "@after" => "new"}}
...> )
iex> after_obj["name"]
"new"

patch!(config, opts \\ [])

@spec patch!(TerminusDB.Config.t(), [patch_opt() | {:before, map()} | {:patch, map()}]) ::
  map()

Applies a patch, or raises.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"name" => "new"})} end
...> )
iex> TerminusDB.Diff.patch!(config,
...>   before: %{"name" => "old"},
...>   patch: %{"name" => %{"@op" => "SwapValue", "@after" => "new"}}
...> )
%{"name" => "new"}

patch_resource(config, opts \\ [])

@spec patch_resource(TerminusDB.Config.t(), [patch_resource_opt()]) ::
  {:ok, map()} | {:error, TerminusDB.Error.t()}

Applies a patch to a branch resource (commits the change).

Options

  • :patch (required) - the patch content.
  • :message - commit message.
  • :author - commit author.
  • :match_final_state - boolean.
  • :organization - overrides config.organization.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> {:ok, resp} = TerminusDB.Diff.patch_resource(config,
...>   patch: %{"name" => %{"@op" => "SwapValue", "@after" => "new"}},
...>   author: "admin", message: "update"
...> )
iex> resp["api:status"]
"api:success"

patch_resource!(config, opts \\ [])

@spec patch_resource!(TerminusDB.Config.t(), [patch_resource_opt()]) :: map()

Applies a patch to a branch resource, or raises.

Examples

iex> config = TerminusDB.Config.new(
...>   endpoint: "http://localhost:6363",
...>   adapter: fn req -> {req, Req.Response.new(status: 200, body: %{"api:status" => "api:success"})} end
...> ) |> TerminusDB.Config.with_database("mydb")
iex> TerminusDB.Diff.patch_resource!(config, patch: %{})
%{"api:status" => "api:success"}