README.md

# RevisionairEcto

[![Hex.pm](https://img.shields.io/hexpm/v/revisionair_ecto.svg)](https://hex.pm/packages/revisionair_ecto)


A [Revisionair](https://github.com/Qqwy/elixir_revisionair) adapter based on [Ecto](https://github.com/elixir-ecto/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`:

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

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

```elixir

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
      add :struct_name, :string
    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:


```elixir
# 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:

```elixir

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](https://github.com/Qqwy/elixir_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: 
```elixir

{: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.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.