revisionair_ecto

A Revisionair Storage Adapter based on Ecto. Keeps track of revisions, changes, versions of your data structures.


Keywords
ecto, elixir-lang, elixir-library, revision
License
MIT

Documentation

RevisionairEcto

Hex.pm

A Revisionair adapter based on Ecto. Allows you to persist and keep track of revisions of your data structures in any of Ecto's supported databases.

The things that you want to keep track of do not necessarily need to be (Ecto-backed) models/schemas. Any data structure can be used (even things that are not structs).

Installation

First, install the library by adding revisionair_ecto to your list of dependencies in mix.exs:

def deps do
  [{:revisionair_ecto, "~> 1.0.0"}]
end

Then, create a migration (mix ecto.gen.migration revisions_table) akin to the following:

defmodule RevisionairEcto.Repo.Migrations.RevisionsTable do
  use Ecto.Migration

  def change do
    create table(:revisions, primary_key: false) do
      add :item_type, :string, null: false
      # If you want to use UUIDs instead, alter the following line to
      # add :item_id, :uuid, null: false
      add :item_id, :integer, null: false
      # If you want to use JSON serialization instead, alter the following line to
      # add :encoded_item, :json, null: false
      add :encoded_item, :binary, null: false
      add :metadata, :map, null: false
      add :revision, :integer, null: false
    end

    create unique_index(:revisions, [:item_type, :item_id, :revision])
  end
end

Finally, in your config/config.exs, add the following lines to configure Revisonair and RevisionairEcto:

# Set default Revisionair storage adapter.
config :revisionair, storage: RevisionairEcto

# Default repo used by RevisionairEcto:
config :revisionair_ecto, repo: RevisionairEcto.Repo

# Uncomment if you use UUIDs instead of numerical ids:
# config :revisionair_ecto, item_id_type: :uuid

# Uncomment if you use JSON serialization instead of binary term storage:
# config :revisionair_ecto, serialization_format: :json

# Uncomment if you use a different table than "revisions" to store the revisions information:
# config :revisionair_ecto, revisions_table: "table_name"

Of course, any of these settings can also be specified in the options parameter when calling any of the Revisionair functions:

Revisionair.store_revision(my_post, [storage: RevisionairEcto, storage_options: [repo: MyOtherRepo, revisions_table: "my_revisions", item_id_type: :uuid, serialization_format: :json]])

(This also allows overriding certain settings only in certain special locations.)

Usage

The functions in this module should not be used directly, rather, the functions that the Revisionair module exposes should be used.

As these function calls will hit the database directly, make sure that especially store_revision is used within a Repo transaction to ensure that the revision is only stored if the other database operations could be performed successfully.

Example:

{:ok, post} = Repo.transaction fn ->
  post = Repo.insert!(%Post{title: "Test", content: "Lorem ipsum"})
  
  :ok = Revisionair.store_revision(post, Post, post.id)
  
  # if using JSON serialization, you must also pass a whitelist of attributes you wish to serialize:
  # :ok = Revisionair.store_revision(post, Post, post.id, [storage_options: [attributes: [:id, :content, :title]]])

  post
end

Revisionair.newest_revision(post)
Revisionair.list_revisions(post)
Revisionair.get_revision(post, 0)

Changelog

  • 1.2.2 Removes unused struct_name column from migration examples.
  • 1.2.1 Updates migration examples (in README and tests) to no longer include unneccesary primary key and superfluous index.
  • 1.2.0 Adds the possibility to serialize data using a JSON format instead of the Erlang Term Format.
  • 1.1.0 Upgrade to Ecto 3.
  • 1.0.2 Removes superfluous and noisy logging call.
  • 1.0.1 Updates Revisionair version.
  • 1.0.0 First Stable Version.