From e9f28cbd61f670b9a6dd9a06fa6d496df0a76e1d Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Thu, 27 Jul 2017 16:20:11 +0200 Subject: [PATCH 01/32] Add new add_prefix function in paper_trail module This new function will allow the user to add information to the Ecto meta :prefix in order to use a different tenant for the operation on the version struct. --- lib/paper_trail.ex | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index 20253f8e..03c9ab35 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -267,7 +267,7 @@ defmodule PaperTrail do end, origin: options[:origin], meta: options[:meta] - } + } |> add_prefix(options[:prefix]) end defp make_version_struct(%{event: "update"}, changeset, options) do originator_ref = options[@originator[:name]] || options[:originator] @@ -282,7 +282,7 @@ defmodule PaperTrail do end, origin: options[:origin], meta: options[:meta] - } + } |> add_prefix(options[:prefix]) end defp make_version_struct(%{event: "delete"}, model, options) do originator_ref = options[@originator[:name]] || options[:originator] @@ -297,7 +297,7 @@ defmodule PaperTrail do end, origin: options[:origin], meta: options[:meta] - } + } |> add_prefix(options[:prefix]) end defp get_sequence_from_model(changeset) do @@ -318,4 +318,7 @@ defmodule PaperTrail do relationships = model.__struct__.__schema__(:associations) Map.drop(model, [:__struct__, :__meta__] ++ relationships) end + + defp add_prefix(changeset), do: changeset + defp add_prefix(changeset, prefix), do: Ecto.put_meta(changeset, prefix: prefix) end From c27bbc8dde468f5c00271a2df8f877b36c7d9ab5 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Thu, 27 Jul 2017 16:27:58 +0200 Subject: [PATCH 02/32] Add default value for the new :prefix option on the functions definitions --- lib/paper_trail.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index 03c9ab35..f72627e6 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -48,7 +48,7 @@ defmodule PaperTrail do @doc """ Inserts a record to the database with a related version insertion in one transaction """ - def insert(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do + def insert(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do transaction_order = case @client.strict_mode() do true -> Multi.new @@ -109,7 +109,7 @@ defmodule PaperTrail do @doc """ Same as insert/2 but returns only the model struct or raises if the changeset is invalid. """ - def insert!(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do + def insert!(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do @repo.transaction(fn -> case @client.strict_mode() do true -> @@ -146,7 +146,7 @@ defmodule PaperTrail do @doc """ Updates a record from the database with a related version insertion in one transaction """ - def update(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do + def update(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do transaction_order = case @client.strict_mode() do true -> Multi.new @@ -198,7 +198,7 @@ defmodule PaperTrail do @doc """ Same as update/2 but returns only the model struct or raises if the changeset is invalid. """ - def update!(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do + def update!(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do @repo.transaction(fn -> case @client.strict_mode() do true -> @@ -227,7 +227,7 @@ defmodule PaperTrail do @doc """ Deletes a record from the database with a related version insertion in one transaction """ - def delete(struct, options \\ [origin: nil, meta: nil, originator: nil]) do + def delete(struct, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do transaction = Multi.new |> Multi.delete(:model, struct) |> Multi.run(:version, fn %{} -> @@ -245,7 +245,7 @@ defmodule PaperTrail do @doc """ Same as delete/2 but returns only the model struct or raises if the changeset is invalid. """ - def delete!(struct, options \\ [origin: nil, meta: nil, originator: nil]) do + def delete!(struct, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do @repo.transaction(fn -> model = @repo.delete!(struct) version_struct = make_version_struct(%{event: "delete"}, struct, options) From 61737dc895f628809f38ef3ad0c4f093a9f680b3 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Thu, 27 Jul 2017 16:42:15 +0200 Subject: [PATCH 03/32] Add patter matching case for nil prefix on add_prefix function --- lib/paper_trail.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index f72627e6..d4bdb8fb 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -319,6 +319,6 @@ defmodule PaperTrail do Map.drop(model, [:__struct__, :__meta__] ++ relationships) end - defp add_prefix(changeset), do: changeset + defp add_prefix(changeset, nil), do: changeset defp add_prefix(changeset, prefix), do: Ecto.put_meta(changeset, prefix: prefix) end From d4d8e4094ad0de11f47343ce703a843cdd509f0e Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Fri, 28 Jul 2017 11:24:44 +0200 Subject: [PATCH 04/32] Add defdelegate in PaperTrail module to PaperTrail.VersionQueries This allows to remove unnecessary functions from PaperTrail module --- lib/paper_trail.ex | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index d4bdb8fb..177d17c6 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -1,8 +1,6 @@ defmodule PaperTrail do import Ecto.Changeset - alias PaperTrail.VersionQueries - alias Ecto.Multi alias PaperTrail.Version @@ -10,40 +8,13 @@ defmodule PaperTrail do @originator @client.originator() @repo @client.repo() - @doc """ - Gets all the versions of a record given a module and its id - """ - def get_versions(model, id) do - VersionQueries.get_versions(model, id) - end - - @doc """ - Gets all the versions of a record - """ - def get_versions(record) do - VersionQueries.get_versions(record) - end - - @doc """ - Gets the last version of a record given its module reference and its id - """ - def get_version(model, id) do - VersionQueries.get_version(model, id) - end - - @doc """ - Gets the last version of a record - """ - def get_version(record) do - VersionQueries.get_version(record) - end - - @doc """ - Gets the current model record/struct of a version - """ - def get_current_model(version) do - VersionQueries.get_current_model(version) - end + defdelegate get_version(a), to: PaperTrail.VersionQueries + defdelegate get_version(a, b), to: PaperTrail.VersionQueries + defdelegate get_version(a, b, c), to: PaperTrail.VersionQueries + defdelegate get_versions(a), to: PaperTrail.VersionQueries + defdelegate get_versions(a, b), to: PaperTrail.VersionQueries + defdelegate get_versions(a, b, c), to: PaperTrail.VersionQueries + defdelegate get_current_model(version), to: PaperTrail.VersionQueries @doc """ Inserts a record to the database with a related version insertion in one transaction From 59f34c420debd9f695dd7a7885413616a4fbbd1f Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Fri, 28 Jul 2017 11:25:40 +0200 Subject: [PATCH 05/32] Add new definition for version_query function to merge options into the Ecto query --- lib/paper_trail/version_queries.ex | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/paper_trail/version_queries.ex b/lib/paper_trail/version_queries.ex index c209b66e..bbeeb14e 100644 --- a/lib/paper_trail/version_queries.ex +++ b/lib/paper_trail/version_queries.ex @@ -43,9 +43,14 @@ defmodule PaperTrail.VersionQueries do @repo.get("Elixir." <> version.item_type |> String.to_existing_atom, version.item_id) end - defp version_query(item_type, id) do - from v in Version, - where: v.item_type == ^item_type and v.item_id == ^id + from v in Version, where: v.item_type == ^item_type and v.item_id == ^id + end + defp version_query(item_type, id, options) do + with opts <- Enum.into(options, %{}) do + version_query(item_type, id) + |> Ecto.Queryable.to_query() + |> Map.merge(opts) + end end end From e71b3d403800a8f94376dc244925d4a98fbd7d41 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Fri, 28 Jul 2017 11:27:59 +0200 Subject: [PATCH 06/32] Add new definitions for all the functions in PaperTrail.VersionQueries Includes new definitions in order to be able to pass a list of options to the final query and be able to set data such as Ecto :prefix. This adds some basic documentation as well. --- lib/paper_trail/version_queries.ex | 86 +++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/lib/paper_trail/version_queries.ex b/lib/paper_trail/version_queries.ex index bbeeb14e..c0097d17 100644 --- a/lib/paper_trail/version_queries.ex +++ b/lib/paper_trail/version_queries.ex @@ -4,36 +4,94 @@ defmodule PaperTrail.VersionQueries do @repo PaperTrail.RepoClient.repo + @type result :: Ecto.Query.t + + @doc """ + Gets all the versions of a record. + """ + @spec get_versions(record :: Ecto.Schema.t) :: result + def get_versions(record), do: get_versions(record, []) + @doc """ Gets all the versions of a record given a module and its id """ - def get_versions(model, id) do - item_type = model |> Module.split |> List.last - version_query(item_type, id) |> @repo.all - end + @spec get_versions(model :: module, id :: pos_integer) :: result + def get_versions(model, id) when is_atom(model) and is_integer(id), do: get_versions(model, id, []) @doc """ - Gets all the versions of a record + Gets all the versions of a record. + + A list of options is optional, so you can set for example the :prefix of the query, + wich allows you to change between different tenants. + + # Usage example: + + iex(1)> PaperTrail.VersionQueries.get_versions(record, [prefix: "tenant_id"]) """ - def get_versions(record) do + @spec get_versions(record :: Ecto.Schema.t, options :: []) :: result + def get_versions(record, options) when is_map(record) do item_type = record.__struct__ |> Module.split |> List.last - version_query(item_type, record.id) |> @repo.all + version_query(item_type, record.id, options) |> @repo.all + end + + @doc """ + Gets all the versions of a record given a module and its id. + + A list of options is optional, so you can set for example the :prefix of the query, + wich allows you to change between different tenants. + + # Usage example: + + iex(1)> PaperTrail.VersionQueries.get_versions(ModelName, id, [prefix: "tenant_id"]) + """ + @spec get_versions(model :: module, id :: pos_integer, options :: []) :: result + def get_versions(model, id, options) do + item_type = model |> Module.split |> List.last + version_query(item_type, id, options) |> @repo.all end @doc """ - Gets the last version of a record given its module reference and its id + Gets the last version of a record. + """ + @spec get_version(record :: Ecto.Schema.t) :: result + def get_version(record), do: get_version(record, []) + + @doc """ + Gets the last version of a record given its module reference and its id. """ - def get_version(model, id) do - item_type = Module.split(model) |> List.last - last(version_query(item_type, id)) |> @repo.one + @spec get_version(model :: module, id :: pos_integer) :: result + def get_version(model, id) when is_atom(model) and is_integer(id), do: get_version(model, id, []) + + @doc """ + Gets the last version of a record given its module reference and its id. + + A list of options is optional, so you can set for example the :prefix of the query, + wich allows you to change between different tenants. + + # Usage example: + + iex(1)> PaperTrail.VersionQueries.get_version(ModelName, id, [prefix: "tenant_id"]) + """ + @spec get_version(model :: module, id :: pos_integer, options :: []) :: result + def get_version(model, id, options) do + item_type = model |> Module.split |> List.last + last(version_query(item_type, id, options)) |> @repo.one end @doc """ - Gets the last version of a record + Gets the last version of a record. + + A list of options is optional, so you can set for example the :prefix of the query, + wich allows you to change between different tenants. + + # Usage example: + + iex(1)> PaperTrail.VersionQueries.get_version(record, [prefix: "tenant_id"]) """ - def get_version(record) do + @spec get_version(record :: Ecto.Schema.t, options :: []) :: result + def get_version(record, options) when is_map(record) do item_type = record.__struct__ |> Module.split |> List.last - last(version_query(item_type, record.id)) |> @repo.one + last(version_query(item_type, record.id, options)) |> @repo.one end @doc """ From ad52cb49ff83f1cae9809251a87b59fbc77d74c9 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Fri, 28 Jul 2017 11:33:34 +0200 Subject: [PATCH 07/32] Remove result type from PaperTrail.VersionQueries and specifies the value on the spec --- lib/paper_trail/version_queries.ex | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/paper_trail/version_queries.ex b/lib/paper_trail/version_queries.ex index c0097d17..0ebde545 100644 --- a/lib/paper_trail/version_queries.ex +++ b/lib/paper_trail/version_queries.ex @@ -4,18 +4,16 @@ defmodule PaperTrail.VersionQueries do @repo PaperTrail.RepoClient.repo - @type result :: Ecto.Query.t - @doc """ Gets all the versions of a record. """ - @spec get_versions(record :: Ecto.Schema.t) :: result + @spec get_versions(record :: Ecto.Schema.t) :: Ecto.Query.t def get_versions(record), do: get_versions(record, []) @doc """ Gets all the versions of a record given a module and its id """ - @spec get_versions(model :: module, id :: pos_integer) :: result + @spec get_versions(model :: module, id :: pos_integer) :: Ecto.Query.t def get_versions(model, id) when is_atom(model) and is_integer(id), do: get_versions(model, id, []) @doc """ @@ -28,7 +26,7 @@ defmodule PaperTrail.VersionQueries do iex(1)> PaperTrail.VersionQueries.get_versions(record, [prefix: "tenant_id"]) """ - @spec get_versions(record :: Ecto.Schema.t, options :: []) :: result + @spec get_versions(record :: Ecto.Schema.t, options :: []) :: Ecto.Query.t def get_versions(record, options) when is_map(record) do item_type = record.__struct__ |> Module.split |> List.last version_query(item_type, record.id, options) |> @repo.all @@ -44,7 +42,7 @@ defmodule PaperTrail.VersionQueries do iex(1)> PaperTrail.VersionQueries.get_versions(ModelName, id, [prefix: "tenant_id"]) """ - @spec get_versions(model :: module, id :: pos_integer, options :: []) :: result + @spec get_versions(model :: module, id :: pos_integer, options :: []) :: Ecto.Query.t def get_versions(model, id, options) do item_type = model |> Module.split |> List.last version_query(item_type, id, options) |> @repo.all @@ -53,13 +51,13 @@ defmodule PaperTrail.VersionQueries do @doc """ Gets the last version of a record. """ - @spec get_version(record :: Ecto.Schema.t) :: result + @spec get_version(record :: Ecto.Schema.t) :: Ecto.Query.t def get_version(record), do: get_version(record, []) @doc """ Gets the last version of a record given its module reference and its id. """ - @spec get_version(model :: module, id :: pos_integer) :: result + @spec get_version(model :: module, id :: pos_integer) :: Ecto.Query.t def get_version(model, id) when is_atom(model) and is_integer(id), do: get_version(model, id, []) @doc """ @@ -72,7 +70,7 @@ defmodule PaperTrail.VersionQueries do iex(1)> PaperTrail.VersionQueries.get_version(ModelName, id, [prefix: "tenant_id"]) """ - @spec get_version(model :: module, id :: pos_integer, options :: []) :: result + @spec get_version(model :: module, id :: pos_integer, options :: []) :: Ecto.Query.t def get_version(model, id, options) do item_type = model |> Module.split |> List.last last(version_query(item_type, id, options)) |> @repo.one @@ -88,7 +86,7 @@ defmodule PaperTrail.VersionQueries do iex(1)> PaperTrail.VersionQueries.get_version(record, [prefix: "tenant_id"]) """ - @spec get_version(record :: Ecto.Schema.t, options :: []) :: result + @spec get_version(record :: Ecto.Schema.t, options :: []) :: Ecto.Query.t def get_version(record, options) when is_map(record) do item_type = record.__struct__ |> Module.split |> List.last last(version_query(item_type, record.id, options)) |> @repo.one From 83a0d7a3716049f54446bcd33c201ba721979fe1 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Fri, 28 Jul 2017 11:44:48 +0200 Subject: [PATCH 08/32] Change param names in defdelegates for better readability --- lib/paper_trail.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index 177d17c6..c0bcd857 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -8,12 +8,12 @@ defmodule PaperTrail do @originator @client.originator() @repo @client.repo() - defdelegate get_version(a), to: PaperTrail.VersionQueries - defdelegate get_version(a, b), to: PaperTrail.VersionQueries - defdelegate get_version(a, b, c), to: PaperTrail.VersionQueries - defdelegate get_versions(a), to: PaperTrail.VersionQueries - defdelegate get_versions(a, b), to: PaperTrail.VersionQueries - defdelegate get_versions(a, b, c), to: PaperTrail.VersionQueries + defdelegate get_version(record), to: PaperTrail.VersionQueries + defdelegate get_version(model_or_record, id_or_options), to: PaperTrail.VersionQueries + defdelegate get_version(model, id, options), to: PaperTrail.VersionQueries + defdelegate get_versions(record), to: PaperTrail.VersionQueries + defdelegate get_versions(model_or_record, id_or_options), to: PaperTrail.VersionQueries + defdelegate get_versions(model, id, options), to: PaperTrail.VersionQueries defdelegate get_current_model(version), to: PaperTrail.VersionQueries @doc """ From 4ef58a01d92f9c1797dde59ff6fa3d3ccfd2f854 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Fri, 28 Jul 2017 12:30:29 +0200 Subject: [PATCH 09/32] Add some multi tenancy documentation on README.md --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/README.md b/README.md index 932b2c04..27d97fad 100644 --- a/README.md +++ b/README.md @@ -379,6 +379,58 @@ Bang functions assume the operation will always be successful, otherwise functio # "updated_at" => "2016-09-15T22:00:59"}, # item_id: 1, item_type: "Post", originator_id: nil, originator: nil, meta: nil} ``` + +## Working with multi tenancy + +Sometimes you have to deal with applications where you need multi tenancy capabilities, +and you want to keep tracking of the versions of your data on different schemas (PostgreSQL) +or databases (MySQL). + +You can use the [Ecto.Query prefix](https://hexdocs.pm/ecto/Ecto.Query.html#module-query-prefix) +in order to switch between different schemas/databases for your own data, so +you can specify in your changeset where to store your record. Example: + +```elixir +tenant = "tenant_id" +changeset = User.changeset(%User{}, %{first_name: "Izel", last_name: "Nakri"}) + +changeset +|> Ecto.Queryable.to_query() +|> Map.put(:prefix, tenant) +|> Repo.insert() +``` + +PaperTrail also allows you to store the `Version` entries generated by your activity in +different schemas/databases by using the value of the element `:prefix` on the options +of the functions. Example: + +```elixir +tenant = "tenant_id" + +changeset = + User.changeset(%User{}, %{first_name: "Izel", last_name: "Nakri"}) + |> Ecto.Queryable.to_query() + |> Map.put(:prefix, tenant) + +PaperTrail.insert(changeset, [prefix: tenant]) +``` + +By doing this, you're storing the new `User` entry into the schema/database +specified by the `:prefix` value (`tenant_id`). Notice that the `User`'s changeset it's sent +with the `:prefix` already set properly, so PaperTrail **only will take care of the +storage of the generated `Version` entry in the desired schema/database**, be sure +to add this info to your changeset before the execution of the PaperTrail function. + +PaperTrail can get versions of records or models from different schemas/databases as well +by using the value of the element `:prefix` on the options of the functions. Example: + +```elixir +tenant = "tenant_id" +id = 1 + +PaperTrail.get_versions(User, id, [prefix: tenant]) +``` + ## Suggestions - PaperTrail.Version(s) order matter, - don't delete your paper_trail versions, instead you can merge them From 696a6c3e06365f886af981ed7f253872b054345f Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:07:07 +0200 Subject: [PATCH 10/32] Add new MultiTenantHelper module into example test support folder This module contains functions related with multi tenancy for test purposes --- example/test/support/multi_tenant_helper.exs | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 example/test/support/multi_tenant_helper.exs diff --git a/example/test/support/multi_tenant_helper.exs b/example/test/support/multi_tenant_helper.exs new file mode 100644 index 00000000..7261019a --- /dev/null +++ b/example/test/support/multi_tenant_helper.exs @@ -0,0 +1,36 @@ +defmodule MultiTenantHelper do + alias Ecto.Adapters.SQL + alias Ecto.Changeset + + import Mix.Ecto, only: [build_repo_priv: 1] + + @migrations_path "migrations" + @tenant "tenant_id" + + def add_prefix_to_changeset(%Changeset{} = changeset) do + %{changeset | data: add_prefix_to_struct(changeset.data)} + end + + def add_prefix_to_query(query) do + query |> Ecto.Queryable.to_query() |> Map.put(:prefix, @tenant) + end + + def add_prefix_to_struct(%{__struct__: _} = model) do + Ecto.put_meta(model, prefix: @tenant) + end + + def setup_tenant(repo, direction \\ :up, opts \\ [all: true]) do + # Drop the previous tenant to reset the data + SQL.query(repo, "DROP SCHEMA \"#{@tenant}\" CASCADE", []) + + opts_with_prefix = Keyword.put(opts, :prefix, @tenant) + + # Create new tenant + SQL.query(repo, "CREATE SCHEMA \"#{@tenant}\"", []) + Ecto.Migrator.run(repo, migrations_path(repo), direction, opts_with_prefix) + end + + def tenant(), do: @tenant + + defp migrations_path(repo), do: Path.join(build_repo_priv(repo), @migrations_path) +end From a50177ad1cb7900fbf0e1a5bc1cd2a690c50570e Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:07:27 +0200 Subject: [PATCH 11/32] Add new MultiTenantHelper module into lib test support folder This module contains functions related with multi tenancy for test purposes --- test/support/multi_tenant_helper.exs | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 test/support/multi_tenant_helper.exs diff --git a/test/support/multi_tenant_helper.exs b/test/support/multi_tenant_helper.exs new file mode 100644 index 00000000..13e4a32c --- /dev/null +++ b/test/support/multi_tenant_helper.exs @@ -0,0 +1,36 @@ +defmodule PaperTrailTest.MultiTenantHelper do + alias Ecto.Adapters.SQL + alias Ecto.Changeset + + import Mix.Ecto, only: [build_repo_priv: 1] + + @migrations_path "migrations" + @tenant "tenant_id" + + def add_prefix_to_changeset(%Changeset{} = changeset) do + %{changeset | data: add_prefix_to_struct(changeset.data)} + end + + def add_prefix_to_query(query) do + query |> Ecto.Queryable.to_query() |> Map.put(:prefix, @tenant) + end + + def add_prefix_to_struct(%{__struct__: _} = model) do + Ecto.put_meta(model, prefix: @tenant) + end + + def setup_tenant(repo, direction \\ :up, opts \\ [all: true]) do + # Drop the previous tenant to reset the data + SQL.query(repo, "DROP SCHEMA \"#{@tenant}\" CASCADE", []) + + opts_with_prefix = Keyword.put(opts, :prefix, @tenant) + + # Create new tenant + SQL.query(repo, "CREATE SCHEMA \"#{@tenant}\"", []) + Ecto.Migrator.run(repo, migrations_path(repo), direction, opts_with_prefix) + end + + def tenant(), do: @tenant + + defp migrations_path(repo), do: Path.join(build_repo_priv(repo), @migrations_path) +end From f2519dbe638f10da9aa470fb892a17856d18d6f3 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:08:12 +0200 Subject: [PATCH 12/32] Add new QueryHelper module into example test support folder This module contains functions related with models queries for test purposes --- example/test/support/query_helper.exs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 example/test/support/query_helper.exs diff --git a/example/test/support/query_helper.exs b/example/test/support/query_helper.exs new file mode 100644 index 00000000..72a17740 --- /dev/null +++ b/example/test/support/query_helper.exs @@ -0,0 +1,24 @@ +defmodule QueryHelper do + import Ecto.Query + + # Company related query functions + def company_count(), do: (from company in Company, select: count(company.id)) + def company_count(:multitenant), do: company_count() |> MultiTenantHelper.add_prefix_to_query() + + def first_company(), do: (first(Company, :id) |> preload(:people)) + def first_company(:multitenant), do: first_company() |> MultiTenantHelper.add_prefix_to_query() + + def filter_company(opts), do: (from c in Company, where: c.name == ^opts[:name], limit: ^opts[:limit]) + def filter_company(opts, :multitenant), do: filter_company(opts) |> MultiTenantHelper.add_prefix_to_query() + + # Person related query functions + def person_count(), do: (from person in Person, select: count(person.id)) + def person_count(:multitenant), do: person_count() |> MultiTenantHelper.add_prefix_to_query() + + def first_person(), do: (first(Person, :id) |> preload(:company)) + def first_person(:multitenant), do: first_person() |> MultiTenantHelper.add_prefix_to_query() + + # Version related query functions + def version_count(), do: (from version in PaperTrail.Version, select: count(version.id)) + def version_count(:multitenant), do: version_count() |> MultiTenantHelper.add_prefix_to_query() +end From c62150edf40b050f603812b6c636644af13eea29 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:08:37 +0200 Subject: [PATCH 13/32] Add new ChangesetHelper module into example test support folder This module contains functions related with models changesets for test purposes --- example/test/support/changeset_helper.exs | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 example/test/support/changeset_helper.exs diff --git a/example/test/support/changeset_helper.exs b/example/test/support/changeset_helper.exs new file mode 100644 index 00000000..68fa269e --- /dev/null +++ b/example/test/support/changeset_helper.exs @@ -0,0 +1,24 @@ +defmodule ChangesetHelper do + + # Company related changeset functions + def new_company(attrs), do: Company.changeset(%Company{}, attrs) + def new_company(attrs, :multitenant) do + new_company(attrs) |> MultiTenantHelper.add_prefix_to_changeset() + end + + def update_company(company, attrs), do: Company.changeset(company, attrs) + def update_company(company, attrs, :multitenant) do + update_company(company, attrs) |> MultiTenantHelper.add_prefix_to_changeset() + end + + # Person related changeset functions + def new_person(attrs), do: Person.changeset(%Person{}, attrs) + def new_person(attrs, :multitenant) do + new_person(attrs) |> MultiTenantHelper.add_prefix_to_changeset() + end + + def update_person(person, attrs), do: Person.changeset(person, attrs) + def update_person(person, attrs, :multitenant) do + update_person(person, attrs) |> MultiTenantHelper.add_prefix_to_changeset() + end +end From 2c4aa4d100c80b5d79a6be99dbea4dd98ee552d8 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:09:05 +0200 Subject: [PATCH 14/32] Require new support helpers in example test_helper file --- example/test/test_helper.exs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/example/test/test_helper.exs b/example/test/test_helper.exs index 52b68bae..434cc696 100644 --- a/example/test/test_helper.exs +++ b/example/test/test_helper.exs @@ -3,4 +3,8 @@ ExUnit.configure seed: 0 Mix.Task.run "ecto.create", ~w(-r Repo) Mix.Task.run "ecto.migrate", ~w(-r Repo) +Code.require_file("test/support/multi_tenant_helper.exs") +Code.require_file("test/support/query_helper.exs") +Code.require_file("test/support/changeset_helper.exs") + ExUnit.start From 9bd355f2ec1adbe3a7d56fbf3e27161ac50ba59d Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:10:31 +0200 Subject: [PATCH 15/32] Add refactor in example company test in order to use helpers --- example/test/company_test.exs | 70 ++++++++++++----------------------- 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/example/test/company_test.exs b/example/test/company_test.exs index 15370a37..2c123ec3 100644 --- a/example/test/company_test.exs +++ b/example/test/company_test.exs @@ -12,24 +12,16 @@ defmodule CompanyTest do end test "creating a company creates a company version with correct attributes" do - new_company = Company.changeset(%Company{}, %{ - name: "Acme LLC", is_active: true, city: "Greenwich", people: [] - }) + {:ok, result} = + %{name: "Acme LLC", is_active: true, city: "Greenwich", people: []} + |> ChangesetHelper.new_company() + |> PaperTrail.insert(origin: "test") - {:ok, result} = PaperTrail.insert(new_company, origin: "test") - - company_count = Repo.all( - from company in Company, - select: count(company.id) - ) + company_count = QueryHelper.company_count() |> Repo.all() + version_count = QueryHelper.version_count() |> Repo.all() + first_company = QueryHelper.first_company() |> Repo.one() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) - - version_count = Repo.all( - from version in PaperTrail.Version, - select: count(version.id) - ) - version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert company_count == [1] @@ -50,7 +42,7 @@ defmodule CompanyTest do assert Map.drop(version, [:id]) == %{ event: "insert", item_type: "Company", - item_id: Repo.one(first(Company, :id)).id, + item_id: first_company.id, item_changes: Map.drop(result[:model], [:__meta__, :__struct__, :people]), origin: "test", originator_id: nil, @@ -59,27 +51,19 @@ defmodule CompanyTest do end test "updating a company creates a company version with correct item_changes" do - old_company = first(Company, :id) |> preload(:people) |> Repo.one - new_company = Company.changeset(old_company, %{ - city: "Hong Kong", - website: "http://www.acme.com", - facebook: "acme.llc" - }) + first_company = QueryHelper.first_company() |> Repo.one() - {:ok, result} = PaperTrail.update(new_company) + {:ok, result} = + ChangesetHelper.update_company(first_company, %{ + city: "Hong Kong", + website: "http://www.acme.com", + facebook: "acme.llc" + }) |> PaperTrail.update() - company_count = Repo.all( - from company in Company, - select: count(company.id) - ) + company_count = QueryHelper.company_count() |> Repo.all() + version_count = QueryHelper.version_count() |> Repo.all() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) - - version_count = Repo.all( - from version in PaperTrail.Version, - select: count(version.id) - ) - version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert company_count == [1] @@ -100,7 +84,7 @@ defmodule CompanyTest do assert Map.drop(version, [:id]) == %{ event: "update", item_type: "Company", - item_id: Repo.one(first(Company, :id)).id, + item_id: first_company.id, item_changes: %{city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc"}, origin: nil, originator_id: nil, @@ -109,22 +93,16 @@ defmodule CompanyTest do end test "deleting a company creates a company version with correct attributes" do - company = first(Company, :id) |> preload(:people) |> Repo.one + company = QueryHelper.first_company() |> Repo.one() - {:ok, result} = PaperTrail.delete(company) + {:ok, result} = + company + |> PaperTrail.delete() - company_count = Repo.all( - from company in Company, - select: count(company.id) - ) + company_count = QueryHelper.company_count() |> Repo.all() + version_count = QueryHelper.version_count() |> Repo.all() company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) - - version_count = Repo.all( - from version in PaperTrail.Version, - select: count(version.id) - ) - version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert company_count == [0] From 77b669cde726bf2fae18fa6a8c2725aeccfac2da Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:17:54 +0200 Subject: [PATCH 16/32] Add refactor in example person test in order to use helpers --- example/test/person_test.exs | 111 +++++++++++++---------------------- 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/example/test/person_test.exs b/example/test/person_test.exs index c24d52bf..08edfd4b 100644 --- a/example/test/person_test.exs +++ b/example/test/person_test.exs @@ -9,46 +9,33 @@ defmodule PersonTest do Repo.delete_all(Company) Repo.delete_all(PaperTrail.Version) - Company.changeset(%Company{}, %{ - name: "Acme LLC", - website: "http://www.acme.com" - }) |> Repo.insert + %{name: "Acme LLC", website: "http://www.acme.com"} + |> ChangesetHelper.new_company() + |> Repo.insert() - Company.changeset(%Company{}, %{ - name: "Another Company Corp.", - is_active: true, - address: "Sesame street 100/3, 101010" - }) |> Repo.insert + %{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"} + |> ChangesetHelper.new_company() + |> Repo.insert() :ok end - test "creating a person with meta tag creates a person version with correct attributes" do - company = first(Company, :id) |> Repo.one + test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do + company = QueryHelper.first_company() |> Repo.one() - new_person = Person.changeset(%Person{}, %{ - first_name: "Izel", - last_name: "Nakri", - gender: true, - company_id: company.id - }) - - {:ok, result} = PaperTrail.insert(new_person, origin: "admin", meta: %{}) # add link name later on + {:ok, result} = + %{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id} + |> ChangesetHelper.new_person() + |> PaperTrail.insert(origin: "admin", meta: %{}) - person_count = Repo.all( - from person in Person, - select: count(person.id) - ) + person_count = QueryHelper.person_count() |> Repo.all() + version_count = QueryHelper.version_count() |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) - - version_count = Repo.all( - from version in PaperTrail.Version, - select: count(version.id) - ) - version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + first_person = QueryHelper.first_person() |> Repo.one() + assert person_count == [1] assert version_count == [1] @@ -64,7 +51,7 @@ defmodule PersonTest do assert Map.drop(version, [:id]) == %{ event: "insert", item_type: "Person", - item_id: Repo.one(first(Person, :id)).id, + item_id: first_person.id, item_changes: Map.drop(result[:model], [:__meta__, :__struct__, :company]), origin: "admin", originator_id: nil, @@ -72,38 +59,27 @@ defmodule PersonTest do } end - test "updating a person creates a person version with correct attributes" do - old_person = first(Person, :id) |> Repo.one + test "[multi tenant] updating a person creates a person version with correct attributes" do + first_person = QueryHelper.first_person() |> Repo.one() - target_company = Repo.one( - from c in Company, - where: c.name == "Another Company Corp.", - limit: 1 - ) + target_company = + [name: "Another Company Corp.", limit: 1] + |> QueryHelper.filter_company() + |> Repo.one() - new_person = Person.changeset(old_person, %{ - first_name: "Isaac", - visit_count: 10, - birthdate: ~D[1992-04-01], - company_id: target_company.id - }) - - {:ok, result} = PaperTrail.update(new_person, origin: "user:1", meta: %{ - linkname: "izelnakri" - }) + {:ok, result} = + ChangesetHelper.update_person(first_person, %{ + first_name: "Isaac", + visit_count: 10, + birthdate: ~D[1992-04-01], + company_id: target_company.id + }) + |> PaperTrail.update(origin: "user:1", meta: %{linkname: "izelnakri"}) - person_count = Repo.all( - from person in Person, - select: count(person.id) - ) + person_count = QueryHelper.person_count() |> Repo.all() + version_count = QueryHelper.version_count() |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) - - version_count = Repo.all( - from version in PaperTrail.Version, - select: count(version.id) - ) - version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert person_count == [1] @@ -121,7 +97,7 @@ defmodule PersonTest do assert Map.drop(version, [:id]) == %{ event: "update", item_type: "Person", - item_id: Repo.one(first(Person, :id)).id, + item_id: first_person.id, item_changes: %{ first_name: "Isaac", visit_count: 10, @@ -136,20 +112,15 @@ defmodule PersonTest do } end - test "deleting a person creates a person version with correct attributes" do - person = first(Person, :id) |> preload(:company) |> Repo.one - - {:ok, result} = PaperTrail.delete(person) + test "[multi tenant] deleting a person creates a person version with correct attributes" do + person = QueryHelper.first_person() |> Repo.one() - person_count = Repo.all( - from person in Person, - select: count(person.id) - ) + {:ok, result} = + person + |> PaperTrail.delete() - version_count = Repo.all( - from version in PaperTrail.Version, - select: count(version.id) - ) + person_count = QueryHelper.person_count() |> Repo.all() + version_count = QueryHelper.version_count() |> Repo.all() version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) From 4975d2bb3b89e075c34821ea52365da27e850330 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:18:39 +0200 Subject: [PATCH 17/32] Add new multi_tenant_company_test file --- example/test/multi_tenant_company_test.exs | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 example/test/multi_tenant_company_test.exs diff --git a/example/test/multi_tenant_company_test.exs b/example/test/multi_tenant_company_test.exs new file mode 100644 index 00000000..01bc0f13 --- /dev/null +++ b/example/test/multi_tenant_company_test.exs @@ -0,0 +1,141 @@ +defmodule MultiTenantCompanyTest do + use ExUnit.Case + import Ecto.Query + + setup_all do + MultiTenantHelper.setup_tenant(Repo) + :ok + end + + test "[multi tenant] creating a company creates a company version with correct attributes" do + {:ok, result} = + %{name: "Acme LLC", is_active: true, city: "Greenwich", people: []} + |> ChangesetHelper.new_company(:multitenant) + |> PaperTrail.insert(origin: "test", prefix: MultiTenantHelper.tenant()) + + company_count = QueryHelper.company_count(:multitenant) |> Repo.all() + version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + first_company = QueryHelper.first_company(:multitenant) |> Repo.one() + + company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) + version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + + assert company_count == [1] + assert version_count == [1] + + assert company == %{ + name: "Acme LLC", + is_active: true, + city: "Greenwich", + website: nil, + address: nil, + facebook: nil, + twitter: nil, + founded_in: nil, + people: [] + } + + assert Map.drop(version, [:id]) == %{ + event: "insert", + item_type: "Company", + item_id: first_company.id, + item_changes: Map.drop(result[:model], [:__meta__, :__struct__, :people]), + origin: "test", + originator_id: nil, + meta: nil + } + end + + test "[multi tenant] updating a company creates a company version with correct item_changes" do + first_company = QueryHelper.first_company(:multitenant) |> Repo.one() + + {:ok, result} = + ChangesetHelper.update_company(first_company, %{ + city: "Hong Kong", + website: "http://www.acme.com", + facebook: "acme.llc" + }, :multitenant) |> PaperTrail.update(prefix: MultiTenantHelper.tenant()) + + company_count = QueryHelper.company_count(:multitenant) |> Repo.all() + version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + + company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) + version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + + assert company_count == [1] + assert version_count == [2] + + assert company == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil, + people: [] + } + + assert Map.drop(version, [:id]) == %{ + event: "update", + item_type: "Company", + item_id: first_company.id, + item_changes: %{city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc"}, + origin: nil, + originator_id: nil, + meta: nil + } + end + + test "[multi tenant] deleting a company creates a company version with correct attributes" do + company = QueryHelper.first_company(:multitenant) |> Repo.one() + + {:ok, result} = + company + |> PaperTrail.delete(prefix: MultiTenantHelper.tenant()) + + company_count = QueryHelper.company_count(:multitenant) |> Repo.all() + version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + + company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) + version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + + assert company_count == [0] + assert version_count == [3] + + assert company_ref == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil, + people: [] + } + + assert Map.drop(version, [:id]) == %{ + event: "delete", + item_type: "Company", + item_id: company.id, + item_changes: %{ + id: company.id, + inserted_at: company.inserted_at, + updated_at: company.updated_at, + name: "Acme LLC", + is_active: true, + website: "http://www.acme.com", + city: "Hong Kong", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil + }, + origin: nil, + originator_id: nil, + meta: nil + } + end +end From 96ecccd4ec7186f0a3cd556c81f39315d3927240 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 11:19:20 +0200 Subject: [PATCH 18/32] Add new multi_tenant_person_test file --- example/test/multi_tenant_person_test.exs | 147 ++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 example/test/multi_tenant_person_test.exs diff --git a/example/test/multi_tenant_person_test.exs b/example/test/multi_tenant_person_test.exs new file mode 100644 index 00000000..b9dc7dff --- /dev/null +++ b/example/test/multi_tenant_person_test.exs @@ -0,0 +1,147 @@ +defmodule MultiTenantPersonTest do + use ExUnit.Case + import Ecto.Query + + setup_all do + MultiTenantHelper.setup_tenant(Repo) + + %{name: "Acme LLC", website: "http://www.acme.com"} + |> ChangesetHelper.new_company(:multitenant) + |> Repo.insert() + + %{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"} + |> ChangesetHelper.new_company(:multitenant) + |> Repo.insert() + + :ok + end + + test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do + company = QueryHelper.first_company(:multitenant) |> Repo.one() + + {:ok, result} = + %{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id} + |> ChangesetHelper.new_person(:multitenant) + |> PaperTrail.insert(origin: "admin", meta: %{}, prefix: MultiTenantHelper.tenant()) + + person_count = QueryHelper.person_count(:multitenant) |> Repo.all() + version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + + person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) + version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + + first_person = QueryHelper.first_person(:multitenant) |> Repo.one() + + assert person_count == [1] + assert version_count == [1] + + assert Map.drop(person, [:company]) == %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + visit_count: nil, + birthdate: nil, + company_id: company.id + } + + assert Map.drop(version, [:id]) == %{ + event: "insert", + item_type: "Person", + item_id: first_person.id, + item_changes: Map.drop(result[:model], [:__meta__, :__struct__, :company]), + origin: "admin", + originator_id: nil, + meta: %{} + } + end + + test "[multi tenant] updating a person creates a person version with correct attributes" do + first_person = QueryHelper.first_person(:multitenant) |> Repo.one() + + target_company = + [name: "Another Company Corp.", limit: 1] + |> QueryHelper.filter_company(:multitenant) + |> Repo.one() + + {:ok, result} = + ChangesetHelper.update_person(first_person, %{ + first_name: "Isaac", + visit_count: 10, + birthdate: ~D[1992-04-01], + company_id: target_company.id + }, :multitenant) + |> PaperTrail.update([origin: "user:1", meta: %{linkname: "izelnakri"}, + prefix: MultiTenantHelper.tenant()]) + + person_count = QueryHelper.person_count(:multitenant) |> Repo.all() + version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + + person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) + version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + + assert person_count == [1] + assert version_count == [2] + + assert Map.drop(person, [:company]) == %{ + company_id: target_company.id, + first_name: "Isaac", + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), # this is the only problem + last_name: "Nakri", + gender: true + } + + assert Map.drop(version, [:id]) == %{ + event: "update", + item_type: "Person", + item_id: first_person.id, + item_changes: %{ + first_name: "Isaac", + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + company_id: target_company.id + }, + origin: "user:1", + originator_id: nil, + meta: %{ + linkname: "izelnakri" + } + } + end + + test "[multi tenant] deleting a person creates a person version with correct attributes" do + person = QueryHelper.first_person(:multitenant) |> Repo.one() + + {:ok, result} = + person + |> PaperTrail.delete(prefix: MultiTenantHelper.tenant()) + + person_count = QueryHelper.person_count(:multitenant) |> Repo.all() + version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + + version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) + + assert person_count == [0] + assert version_count == [3] + + assert Map.drop(version, [:id]) == %{ + event: "delete", + item_type: "Person", + item_id: person.id, + item_changes: %{ + id: person.id, + inserted_at: person.inserted_at, + updated_at: person.updated_at, + first_name: "Isaac", + last_name: "Nakri", + gender: true, + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + company_id: person.company.id + }, + origin: nil, + originator_id: nil, + meta: nil + } + end +end From d01fedffe336193eb645975991ee176a921b878b Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 13:37:38 +0200 Subject: [PATCH 19/32] Add tests for multi tenant in bang_functions_simple_mode_test Includes some new functions as well with common behaviors --- .../bang_functions_simple_mode_test.exs | 443 +++++++++++++++++- 1 file changed, 434 insertions(+), 9 deletions(-) diff --git a/test/paper_trail/bang_functions_simple_mode_test.exs b/test/paper_trail/bang_functions_simple_mode_test.exs index 2f691397..b6297683 100644 --- a/test/paper_trail/bang_functions_simple_mode_test.exs +++ b/test/paper_trail/bang_functions_simple_mode_test.exs @@ -6,6 +6,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do alias PaperTrail.Version alias SimpleCompany, as: Company alias SimplePerson, as: Person + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant @repo PaperTrail.RepoClient.repo @create_company_params %{name: "Acme LLC", is_active: true, city: "Greenwich"} @@ -18,17 +19,14 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do Application.put_env(:paper_trail, :repo, PaperTrail.Repo) Code.eval_file("lib/paper_trail.ex") Code.eval_file("lib/version.ex") + MultiTenant.setup_tenant(@repo) :ok end setup do - @repo.delete_all(Person) - @repo.delete_all(Company) - @repo.delete_all(Version) + reset_all_data() on_exit fn -> - @repo.delete_all(Person) - @repo.delete_all(Company) - @repo.delete_all(Version) + reset_all_data() end :ok end @@ -374,24 +372,451 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do assert old_person == person_before_deletion end - defp create_user do - User.changeset(%User{}, %{token: "fake-token", username: "izelnakri"}) |> @repo.insert! + # Multi tenant tests + test "[multi tenant] creating a company creates a company version with correct attributes" do + user = create_user(:multitenant) + company = create_company_with_version_multi(@create_company_params, originator: user) + + company_count = Company.count(:multitenant) + version_count = Version.count(MultiTenant.tenant()) + + version = PaperTrail.get_version(company, prefix: MultiTenant.tenant()) + |> serialize + + assert company_count == 1 + assert version_count == 1 + assert company |> serialize |> Map.drop([:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Greenwich", + website: nil, + address: nil, + facebook: nil, + twitter: nil, + founded_in: nil + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "insert", + item_type: "SimpleCompany", + item_id: company.id, + item_changes: company |> serialize |> convert_to_string_map, + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == first_company(:multitenant) + end + + test "[multi tenant] PaperTrail.insert!/2 with an error raises Ecto.InvalidChangesetError" do + assert_raise(Ecto.InvalidChangesetError, fn -> + create_company_with_version_multi(%{name: nil, is_active: true, city: "Greenwich"}) + end) + end + + test "[multi tenant] updating a company with originator creates a correct company version" do + tenant = MultiTenant.tenant() + user = create_user(:multitenant) + inserted_company = create_company_with_version_multi() + updated_company = update_company_with_version_multi( + inserted_company, @update_company_params, user: user + ) + + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + company = updated_company |> serialize + version = PaperTrail.get_version(updated_company, prefix: tenant) + |> serialize + + assert company_count == 1 + assert version_count == 2 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "update", + item_type: "SimpleCompany", + item_id: company.id, + item_changes: convert_to_string_map(%{ + city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" + }), + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == first_company(:multitenant) |> serialize + end + + test "[multi tenant] updating a company with originator[user] creates a correct company version" do + tenant = MultiTenant.tenant() + + user = create_user(:multitenant) + inserted_company = create_company_with_version_multi() + updated_company = update_company_with_version_multi( + inserted_company, @update_company_params, user: user + ) + + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + company = updated_company |> serialize + version = PaperTrail.get_version(updated_company, prefix: tenant) + |> serialize + + assert company_count == 1 + assert version_count == 2 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "update", + item_type: "SimpleCompany", + item_id: company.id, + item_changes: convert_to_string_map(%{ + city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" + }), + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == first_company(:multitenant) |> serialize + end + + test "[multi tenant] PaperTrail.update!/2 with an error raises Ecto.InvalidChangesetError" do + assert_raise(Ecto.InvalidChangesetError, fn -> + inserted_company = create_company_with_version_multi() + update_company_with_version_multi(inserted_company, %{ + name: nil, city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" + }) + end) + end + + test "[multi tenant] deleting a company creates a company version with correct attributes" do + tenant = MultiTenant.tenant() + + user = create_user(:multitenant) + inserted_company = create_company_with_version_multi() + updated_company = update_company_with_version_multi(inserted_company) + company_before_deletion = first_company(:multitenant) |> serialize + deleted_company = PaperTrail.delete!(updated_company, originator: user, + prefix: tenant) + + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + company = deleted_company |> serialize + version = PaperTrail.get_version(deleted_company, prefix: tenant) |> serialize + + assert company_count == 0 + assert version_count == 3 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "delete", + item_type: "SimpleCompany", + item_id: company.id, + item_changes: convert_to_string_map(%{ + id: company.id, + inserted_at: company.inserted_at, + updated_at: company.updated_at, + name: "Acme LLC", + is_active: true, + website: "http://www.acme.com", + city: "Hong Kong", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil + }), + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == company_before_deletion + end + + test "[multi tenant] PaperTrail.delete!/2 with an error raises Ecto.InvalidChangesetError" do + tenant = MultiTenant.tenant() + + assert_raise(Ecto.InvalidChangesetError, fn -> + inserted_company = create_company_with_version_multi() + Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(prefix: tenant) + + inserted_company + |> Company.changeset + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.delete!(prefix: tenant) + end) + end + + test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do + tenant = MultiTenant.tenant() + + create_company_with_version_multi() + second_company = Company.changeset(%Company{}, %{ + name: "Another Company Corp.", + is_active: true, + address: "Sesame street 100/3, 101010" + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(prefix: tenant) + + inserted_person = Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: second_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(origin: "admin", meta: %{linkname: "izelnakri"}, prefix: tenant) + + person_count = Person.count(:multitenant) + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + person = inserted_person |> serialize + version = PaperTrail.get_version(inserted_person, prefix: tenant) |> serialize + + assert person_count == 1 + assert company_count == 2 + assert version_count == 3 + assert Map.drop(person, [:id, :inserted_at, :updated_at]) == %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + visit_count: nil, + birthdate: nil, + company_id: second_company.id + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "insert", + item_type: "SimplePerson", + item_id: person.id, + item_changes: convert_to_string_map(person), + originator_id: nil, + origin: "admin", + meta: %{"linkname" => "izelnakri"} + } + assert person == first_person(:multitenant) |> serialize + end + + test "[multi tenant] updating a person creates a person version with correct attributes" do + tenant = MultiTenant.tenant() + + inserted_initial_company = create_company_with_version_multi(%{ + name: "Acme LLC", website: "http://www.acme.com" + }) + inserted_target_company = create_company_with_version_multi(%{ + name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010" + }) + inserted_person = Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_target_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(origin: "admin", prefix: tenant) + + updated_person = Person.changeset(inserted_person, %{ + first_name: "Isaac", + visit_count: 10, + birthdate: ~D[1992-04-01], + company_id: inserted_initial_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.update!(origin: "scraper", meta: %{linkname: "izelnakri"}, prefix: tenant) + + person_count = Person.count(:multitenant) + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + person = updated_person |> serialize + version = PaperTrail.get_version(updated_person, prefix: tenant) |> serialize + + assert person_count == 1 + assert company_count == 2 + assert version_count == 4 + assert Map.drop(person, [:id, :inserted_at, :updated_at]) == %{ + company_id: inserted_initial_company.id, + first_name: "Isaac", + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + last_name: "Nakri", + gender: true + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "update", + item_type: "SimplePerson", + item_id: person.id, + item_changes: convert_to_string_map(%{ + first_name: "Isaac", + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + company_id: inserted_initial_company.id + }), + originator_id: nil, + origin: "scraper", + meta: %{"linkname" => "izelnakri"} + } + assert person == first_person(:multitenant) |> serialize + end + + test "[multi tenant] deleting a person creates a person version with correct attributes" do + tenant = MultiTenant.tenant() + + create_company_with_version_multi(%{name: "Acme LLC", website: "http://www.acme.com"}) + inserted_target_company = create_company_with_version_multi(%{ + name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010" + }) + inserted_person = Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_target_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(origin: "admin", prefix: tenant) + + updated_person = Person.changeset(inserted_person, %{ + first_name: "Isaac", + visit_count: 10, + birthdate: ~D[1992-04-01], + company_id: inserted_target_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.update!(origin: "scraper", meta: %{linkname: "izelnakri"}, prefix: tenant) + + person_before_deletion = first_person(:multitenant) |> serialize + deleted_person = PaperTrail.delete!( + updated_person, origin: "admin", meta: %{linkname: "izelnakri"}, prefix: tenant + ) + + person_count = Person.count(:multitenant) + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + old_person = updated_person |> serialize + version = PaperTrail.get_version(deleted_person, prefix: tenant) |> serialize + + assert person_count == 0 + assert company_count == 2 + assert version_count == 5 + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "delete", + item_type: "SimplePerson", + item_id: old_person.id, + item_changes: convert_to_string_map(%{ + id: old_person.id, + inserted_at: old_person.inserted_at, + updated_at: old_person.updated_at, + first_name: "Isaac", + last_name: "Nakri", + gender: true, + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + company_id: inserted_target_company.id + }), + originator_id: nil, + origin: "admin", + meta: %{"linkname" => "izelnakri"} + } + assert old_person == person_before_deletion + end + + # Functions + defp create_user() do + User.changeset(%User{}, %{token: "fake-token", username: "izelnakri"}) + |> @repo.insert! + end + defp create_user(:multitenant) do + User.changeset(%User{}, %{token: "fake-token", username: "izelnakri"}) + |> MultiTenant.add_prefix_to_changeset() + |> @repo.insert! end defp create_company_with_version(params \\ @create_company_params, options \\ nil) do Company.changeset(%Company{}, params) |> PaperTrail.insert!(options) end + defp create_company_with_version_multi(params \\ @create_company_params, options \\ nil) do + opts_with_prefix = Keyword.put(options || [], :prefix, MultiTenant.tenant()) + + Company.changeset(%Company{}, params) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(opts_with_prefix) + end defp update_company_with_version(company, params \\ @update_company_params, options \\ nil) do Company.changeset(company, params) |> PaperTrail.update!(options) end + defp update_company_with_version_multi(company, params \\ @update_company_params, options \\ nil) do + opts_with_prefix = Keyword.put(options || [], :prefix, MultiTenant.tenant()) + + Company.changeset(company, params) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.update!(opts_with_prefix) + end + + defp first_company(:multitenant) do + first(Company, :id) |> MultiTenant.add_prefix_to_query() |> @repo.one() + end + defp first_person(:multitenant) do + first(Person, :id) |> MultiTenant.add_prefix_to_query() |> @repo.one() + end defp serialize(model) do relationships = model.__struct__.__schema__(:associations) Map.drop(model, [:__struct__, :__meta__] ++ relationships) end - def convert_to_string_map(map) do + defp reset_all_data() do + @repo.delete_all(Person) + @repo.delete_all(Company) + @repo.delete_all(Version) + + Person + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + + Company + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + + Version + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + end + + defp convert_to_string_map(map) do map |> Poison.encode! |> Poison.decode! end end From 95b33124921dd3637d675b52e3b31647b5eb8138 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 13:38:10 +0200 Subject: [PATCH 20/32] Add tests for multi tenant in bang_functions_strict_mode_test Includes some new functions as well with common behaviors --- .../bang_functions_strict_mode_test.exs | 459 +++++++++++++++++- 1 file changed, 450 insertions(+), 9 deletions(-) diff --git a/test/paper_trail/bang_functions_strict_mode_test.exs b/test/paper_trail/bang_functions_strict_mode_test.exs index 4b88a1c2..33ad71a7 100644 --- a/test/paper_trail/bang_functions_strict_mode_test.exs +++ b/test/paper_trail/bang_functions_strict_mode_test.exs @@ -6,6 +6,7 @@ defmodule PaperTrailTest.StrictModeBangFunctions do alias PaperTrail.Version alias StrictCompany, as: Company alias StrictPerson, as: Person + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant @repo PaperTrail.RepoClient.repo @create_company_params %{name: "Acme LLC", is_active: true, city: "Greenwich"} @@ -18,17 +19,14 @@ defmodule PaperTrailTest.StrictModeBangFunctions do Application.put_env(:paper_trail, :repo, PaperTrail.Repo) Code.eval_file("lib/paper_trail.ex") Code.eval_file("lib/version.ex") + MultiTenant.setup_tenant(@repo) :ok end setup do - @repo.delete_all(Person) - @repo.delete_all(Company) - @repo.delete_all(Version) + reset_all_data() on_exit fn -> - @repo.delete_all(Person) - @repo.delete_all(Company) - @repo.delete_all(Version) + reset_all_data() end :ok end @@ -388,24 +386,467 @@ defmodule PaperTrailTest.StrictModeBangFunctions do assert deleted_person |> serialize == person_before_deletion |> serialize end - defp create_user do - User.changeset(%User{}, %{token: "fake-token", username: "izelnakri"}) |> @repo.insert! + # Multi tenant tests + test "[multi tenant] creating a company creates a company version with correct attributes" do + user = create_user(:multitenant) + inserted_company = create_company_with_version_multi(@create_company_params, user: user) + + company_count = Company.count(:multitenant) + version_count = Version.count(MultiTenant.tenant()) + + company = inserted_company |> serialize() + version = PaperTrail.get_version(inserted_company, prefix: MultiTenant.tenant()) + |> serialize() + + assert company_count == 1 + assert version_count == 1 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Greenwich", + website: nil, + address: nil, + facebook: nil, + twitter: nil, + founded_in: nil, + first_version_id: version.id, + current_version_id: version.id + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "insert", + item_type: "StrictCompany", + item_id: company.id, + item_changes: convert_to_string_map(company), + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == first_company(:multitenant) |> serialize + end + + test "[multi tenant] creating a company without changeset creates a company version with correct attributes" do + inserted_company = create_company_with_version_multi(%{name: "Acme LLC"}, prefix: MultiTenant.tenant()) + company_count = Company.count(:multitenant) + version_count = Version.count(MultiTenant.tenant()) + + company = inserted_company |> serialize + version = PaperTrail.get_version(inserted_company, prefix: MultiTenant.tenant()) + |> serialize + + assert company_count == 1 + assert version_count == 1 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: nil, + city: nil, + website: nil, + address: nil, + facebook: nil, + twitter: nil, + founded_in: nil, + first_version_id: version.id, + current_version_id: version.id + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "insert", + item_type: "StrictCompany", + item_id: company.id, + item_changes: convert_to_string_map(company), + originator_id: nil, + origin: nil, + meta: nil + } + end + + test "[multi tenant] PaperTrail.insert!/2 with an error raises Ecto.InvalidChangesetError" do + assert_raise(Ecto.InvalidChangesetError, fn -> + create_company_with_version_multi(%{name: nil, is_active: true, city: "Greenwich"}) + end) + end + + test "[multi tenant] updating a company creates a company version with correct item_changes" do + tenant = MultiTenant.tenant() + + user = create_user(:multitenant) + inserted_company = create_company_with_version_multi() + inserted_company_version = PaperTrail.get_version(inserted_company, prefix: tenant) + |> serialize + updated_company = update_company_with_version_multi( + inserted_company, @update_company_params, originator: user + ) + + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + company = updated_company |> serialize + updated_company_version = PaperTrail.get_version(updated_company, prefix: tenant) + |> serialize + + assert company_count == 1 + assert version_count == 2 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil, + first_version_id: inserted_company_version.id, + current_version_id: updated_company_version.id + } + assert Map.drop(updated_company_version, [:id, :inserted_at]) == %{ + event: "update", + item_type: "StrictCompany", + item_id: company.id, + item_changes: convert_to_string_map(%{ + city: "Hong Kong", + website: "http://www.acme.com", + facebook: "acme.llc", + current_version_id: updated_company_version.id + }), + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == first_company(:multitenant) |> serialize + end + + test "[multi tenant] PaperTrail.update!/2 with an error raises Ecto.InvalidChangesetError" do + assert_raise(Ecto.InvalidChangesetError, fn -> + inserted_company = create_company_with_version_multi() + update_company_with_version_multi(inserted_company, %{ + name: nil, city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" + }) + end) + end + + test "[multi tenant] deleting a company creates a company version with correct attributes" do + tenant = MultiTenant.tenant() + + user = create_user(:multitenant) + inserted_company = create_company_with_version_multi() + inserted_company_version = PaperTrail.get_version(inserted_company, prefix: tenant) + updated_company = update_company_with_version_multi(inserted_company) + updated_company_version = PaperTrail.get_version(updated_company, prefix: tenant) + company_before_deletion = first_company(:multitenant) |> serialize + deleted_company = PaperTrail.delete!(updated_company, user: user, prefix: tenant) + + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + old_company = deleted_company |> serialize + deleted_company_version = PaperTrail.get_version(deleted_company, prefix: tenant) + |> serialize + + assert company_count == 0 + assert version_count == 3 + assert Map.drop(old_company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil, + first_version_id: inserted_company_version.id, + current_version_id: updated_company_version.id + } + assert Map.drop(deleted_company_version, [:id, :inserted_at]) == %{ + event: "delete", + item_type: "StrictCompany", + item_id: old_company.id, + item_changes: convert_to_string_map(%{ + id: old_company.id, + inserted_at: old_company.inserted_at, + updated_at: old_company.updated_at, + name: "Acme LLC", + is_active: true, + website: "http://www.acme.com", + city: "Hong Kong", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil, + first_version_id: inserted_company_version.id, + current_version_id: updated_company_version.id + }), + originator_id: user.id, + origin: nil, + meta: nil + } + assert old_company == company_before_deletion + end + + test "[multi tenant] PaperTrail.delete!/2 with an error raises Ecto.InvalidChangesetError" do + tenant = MultiTenant.tenant() + + assert_raise(Ecto.InvalidChangesetError, fn -> + inserted_company = create_company_with_version_multi() + Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(prefix: tenant) + + inserted_company + |> Company.changeset + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.delete!(prefix: tenant) + end) + end + + test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do + tenant = MultiTenant.tenant() + + create_company_with_version_multi(%{name: "Acme LLC", website: "http://www.acme.com"}) + inserted_company = create_company_with_version_multi(%{ + name: "Another Company Corp.", + is_active: true, + address: "Sesame street 100/3, 101010" + }) + inserted_person = Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(origin: "admin", meta: %{linkname: "izelnakri"}, prefix: tenant) + + person_count = Person.count(:multitenant) + version_count = Version.count(tenant) + + person = inserted_person |> serialize + version = PaperTrail.get_version(inserted_person, prefix: tenant) |> serialize + + assert person_count == 1 + assert version_count == 3 + assert Map.drop(person, [:id, :inserted_at, :updated_at]) == %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + visit_count: nil, + birthdate: nil, + company_id: inserted_company.id, + first_version_id: version.id, + current_version_id: version.id + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "insert", + item_type: "StrictPerson", + item_id: person.id, + item_changes: convert_to_string_map(person), + originator_id: nil, + origin: "admin", + meta: %{"linkname" => "izelnakri"} + } + assert person == first_person(:multitenant) |> serialize + end + + test "[multi tenant] updating a person creates a person version with correct attributes" do + tenant = MultiTenant.tenant() + + inserted_initial_company = create_company_with_version_multi(%{ + name: "Acme LLC", website: "http://www.acme.com" + }) + inserted_target_company = create_company_with_version_multi(%{ + name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010" + }) + inserted_person = Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_target_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(origin: "admin", prefix: tenant) + + inserted_person_version = PaperTrail.get_version(inserted_person, prefix: tenant) + |> serialize + updated_person = Person.changeset(inserted_person, %{ + first_name: "Isaac", + visit_count: 10, + birthdate: ~D[1992-04-01], + company_id: inserted_initial_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.update!(origin: "scraper", meta: %{linkname: "izelnakri"}, prefix: tenant) + + person_count = Person.count(:multitenant) + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + person = updated_person |> serialize + updated_person_version = PaperTrail.get_version(updated_person, prefix: tenant) + |> serialize + + assert person_count == 1 + assert company_count == 2 + assert version_count == 4 + assert Map.drop(person, [:id, :inserted_at, :updated_at]) == %{ + company_id: inserted_initial_company.id, + first_name: "Isaac", + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), # this is the only problem + last_name: "Nakri", + gender: true, + first_version_id: inserted_person_version.id, + current_version_id: updated_person_version.id + } + assert Map.drop(updated_person_version, [:id, :inserted_at]) == %{ + event: "update", + item_type: "StrictPerson", + item_id: person.id, + item_changes: convert_to_string_map(%{ + first_name: "Isaac", + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + current_version_id: updated_person_version.id, + company_id: inserted_initial_company.id + }), + originator_id: nil, + origin: "scraper", + meta: %{"linkname" => "izelnakri"} + } + assert person == first_person(:multitenant) |> serialize + end + + test "[multi tenant] deleting a person creates a person version with correct attributes" do + tenant = MultiTenant.tenant() + + create_company_with_version_multi(%{name: "Acme LLC", website: "http://www.acme.com"}) + inserted_company = create_company_with_version_multi(%{ + name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010" + }) + inserted_person = Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: inserted_company.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(origin: "admin", prefix: tenant) + + inserted_person_version = PaperTrail.get_version(inserted_person, prefix: tenant) + |> serialize + updated_person = Person.changeset(inserted_person, %{ + first_name: "Isaac", + visit_count: 10, + birthdate: ~D[1992-04-01] + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.update!(origin: "scraper", meta: %{linkname: "izelnakri"}, prefix: tenant) + + updated_person_version = PaperTrail.get_version(updated_person, prefix: tenant) + |> serialize + person_before_deletion = first_person(:multitenant) + deleted_person = PaperTrail.delete!( + updated_person, origin: "admin", meta: %{linkname: "izelnakri"}, prefix: tenant + ) + deleted_person_version = PaperTrail.get_version(deleted_person, prefix: tenant) + |> serialize + + person_count = Person.count(:multitenant) + company_count = Company.count(:multitenant) + version_count = Version.count(tenant) + + assert person_count == 0 + assert company_count == 2 + assert version_count == 5 + assert Map.drop(deleted_person_version, [:id, :inserted_at]) == %{ + event: "delete", + item_type: "StrictPerson", + item_id: deleted_person.id, + item_changes: convert_to_string_map(%{ + id: deleted_person.id, + inserted_at: deleted_person.inserted_at, + updated_at: deleted_person.updated_at, + first_name: "Isaac", + last_name: "Nakri", + gender: true, + visit_count: 10, + birthdate: elem(Ecto.Date.cast(~D[1992-04-01]), 1), + company_id: inserted_company.id, + first_version_id: inserted_person_version.id, + current_version_id: updated_person_version.id + }), + originator_id: nil, + origin: "admin", + meta: %{"linkname" => "izelnakri"} + } + assert deleted_person |> serialize == person_before_deletion |> serialize + end + + # Functions + defp create_user() do + User.changeset(%User{}, %{token: "fake-token", username: "izelnakri"}) + |> @repo.insert! + end + defp create_user(:multitenant) do + User.changeset(%User{}, %{token: "fake-token", username: "izelnakri"}) + |> MultiTenant.add_prefix_to_changeset() + |> @repo.insert! end defp create_company_with_version(params \\ @create_company_params, options \\ nil) do Company.changeset(%Company{}, params) |> PaperTrail.insert!(options) end + defp create_company_with_version_multi(params \\ @create_company_params, options \\ nil) do + opts_with_prefix = Keyword.put(options || [], :prefix, MultiTenant.tenant()) + + Company.changeset(%Company{}, params) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert!(opts_with_prefix) + end defp update_company_with_version(company, params \\ @update_company_params, options \\ nil) do Company.changeset(company, params) |> PaperTrail.update!(options) end + defp update_company_with_version_multi(company, params \\ @update_company_params, options \\ nil) do + opts_with_prefix = Keyword.put(options || [], :prefix, MultiTenant.tenant()) + + Company.changeset(company, params) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.update!(opts_with_prefix) + end + + defp first_company(:multitenant) do + first(Company, :id) |> MultiTenant.add_prefix_to_query() |> @repo.one() + end + defp first_person(:multitenant) do + first(Person, :id) |> MultiTenant.add_prefix_to_query() |> @repo.one() + end defp serialize(model) do relationships = model.__struct__.__schema__(:associations) Map.drop(model, [:__struct__, :__meta__] ++ relationships) end - def convert_to_string_map(map) do + defp reset_all_data() do + @repo.delete_all(Person) + @repo.delete_all(Company) + @repo.delete_all(Version) + + Person + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + + Company + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + + Version + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + end + + defp convert_to_string_map(map) do map |> Poison.encode! |> Poison.decode! end end From 8a2dfb5b069106c9de2fa54af69caae80d4d1ebe Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 13:38:49 +0200 Subject: [PATCH 21/32] Add new count functions for multi tenancy in test support models --- test/support/simple_models.exs | 14 ++++++++++++++ test/support/strict_models.exs | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/test/support/simple_models.exs b/test/support/simple_models.exs index d1c5a400..c9846008 100644 --- a/test/support/simple_models.exs +++ b/test/support/simple_models.exs @@ -1,6 +1,8 @@ defmodule SimpleCompany do use Ecto.Schema + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant + import Ecto.Changeset import Ecto.Query @@ -31,11 +33,18 @@ defmodule SimpleCompany do def count do from(record in __MODULE__, select: count(record.id)) |> PaperTrail.RepoClient.repo.one end + def count(:multitenant) do + from(record in __MODULE__, select: count(record.id)) + |> MultiTenant.add_prefix_to_query() + |> PaperTrail.RepoClient.repo.one + end end defmodule SimplePerson do use Ecto.Schema + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant + import Ecto.Changeset import Ecto.Query @@ -62,4 +71,9 @@ defmodule SimplePerson do def count do from(record in __MODULE__, select: count(record.id)) |> PaperTrail.RepoClient.repo.one end + def count(:multitenant) do + from(record in __MODULE__, select: count(record.id)) + |> MultiTenant.add_prefix_to_query() + |> PaperTrail.RepoClient.repo.one + end end diff --git a/test/support/strict_models.exs b/test/support/strict_models.exs index e7e24319..2217b994 100644 --- a/test/support/strict_models.exs +++ b/test/support/strict_models.exs @@ -1,6 +1,8 @@ defmodule StrictCompany do use Ecto.Schema + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant + import Ecto.Changeset import Ecto.Query @@ -34,11 +36,18 @@ defmodule StrictCompany do def count do from(record in __MODULE__, select: count(record.id)) |> PaperTrail.RepoClient.repo.one end + def count(:multitenant) do + from(record in __MODULE__, select: count(record.id)) + |> MultiTenant.add_prefix_to_query() + |> PaperTrail.RepoClient.repo.one + end end defmodule StrictPerson do use Ecto.Schema + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant + import Ecto.Changeset import Ecto.Query @@ -67,4 +76,9 @@ defmodule StrictPerson do def count do from(record in __MODULE__, select: count(record.id)) |> PaperTrail.RepoClient.repo.one end + def count(:multitenant) do + from(record in __MODULE__, select: count(record.id)) + |> MultiTenant.add_prefix_to_query() + |> PaperTrail.RepoClient.repo.one + end end From a1ffd4454d044d1b43c8feca2beaae46ff1bfc63 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 13:52:00 +0200 Subject: [PATCH 22/32] Add new functions for multi tenancy in lib/version.ex --- lib/version.ex | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/version.ex b/lib/version.ex index d4472468..907e663a 100644 --- a/lib/version.ex +++ b/lib/version.ex @@ -37,6 +37,12 @@ defmodule PaperTrail.Version do def count do from(version in __MODULE__, select: count(version.id)) |> PaperTrail.RepoClient.repo.one end + def count(options) do + from(version in __MODULE__, select: count(version.id)) + |> Ecto.Queryable.to_query() + |> Map.put(:prefix, options[:prefix]) + |> PaperTrail.RepoClient.repo.one + end @doc """ Returns the first version record in the database by :inserted_at @@ -45,6 +51,12 @@ defmodule PaperTrail.Version do from(record in __MODULE__, limit: 1, order_by: [asc: :inserted_at]) |> PaperTrail.RepoClient.repo.one end + def first(options) do + from(record in __MODULE__, limit: 1, order_by: [asc: :inserted_at]) + |> Ecto.Queryable.to_query() + |> Map.put(:prefix, options[:prefix]) + |> PaperTrail.RepoClient.repo.one + end @doc """ Returns the last version record in the database by :inserted_at @@ -53,4 +65,10 @@ defmodule PaperTrail.Version do from(record in __MODULE__, limit: 1, order_by: [desc: :inserted_at]) |> PaperTrail.RepoClient.repo.one end + def last(options) do + from(record in __MODULE__, limit: 1, order_by: [desc: :inserted_at]) + |> Ecto.Queryable.to_query() + |> Map.put(:prefix, options[:prefix]) + |> PaperTrail.RepoClient.repo.one + end end From 8a422209bbed8844fd1a65a5d44999112ef94324 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 13:52:47 +0200 Subject: [PATCH 23/32] Add changes in tests to use new definition of Version functions with new params --- .../bang_functions_simple_mode_test.exs | 17 ++++++++------- .../bang_functions_strict_mode_test.exs | 21 +++++++++++-------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/test/paper_trail/bang_functions_simple_mode_test.exs b/test/paper_trail/bang_functions_simple_mode_test.exs index b6297683..00831204 100644 --- a/test/paper_trail/bang_functions_simple_mode_test.exs +++ b/test/paper_trail/bang_functions_simple_mode_test.exs @@ -374,13 +374,14 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do # Multi tenant tests test "[multi tenant] creating a company creates a company version with correct attributes" do + tenant = MultiTenant.tenant() user = create_user(:multitenant) company = create_company_with_version_multi(@create_company_params, originator: user) company_count = Company.count(:multitenant) - version_count = Version.count(MultiTenant.tenant()) + version_count = Version.count(prefix: tenant) - version = PaperTrail.get_version(company, prefix: MultiTenant.tenant()) + version = PaperTrail.get_version(company, prefix: tenant) |> serialize assert company_count == 1 @@ -422,7 +423,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do ) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) company = updated_company |> serialize version = PaperTrail.get_version(updated_company, prefix: tenant) @@ -464,7 +465,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do ) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) company = updated_company |> serialize version = PaperTrail.get_version(updated_company, prefix: tenant) @@ -516,7 +517,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do prefix: tenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) company = deleted_company |> serialize version = PaperTrail.get_version(deleted_company, prefix: tenant) |> serialize @@ -601,7 +602,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do person_count = Person.count(:multitenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) person = inserted_person |> serialize version = PaperTrail.get_version(inserted_person, prefix: tenant) |> serialize @@ -658,7 +659,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do person_count = Person.count(:multitenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) person = updated_person |> serialize version = PaperTrail.get_version(updated_person, prefix: tenant) |> serialize @@ -723,7 +724,7 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do person_count = Person.count(:multitenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) old_person = updated_person |> serialize version = PaperTrail.get_version(deleted_person, prefix: tenant) |> serialize diff --git a/test/paper_trail/bang_functions_strict_mode_test.exs b/test/paper_trail/bang_functions_strict_mode_test.exs index 33ad71a7..e9fb16c2 100644 --- a/test/paper_trail/bang_functions_strict_mode_test.exs +++ b/test/paper_trail/bang_functions_strict_mode_test.exs @@ -388,14 +388,15 @@ defmodule PaperTrailTest.StrictModeBangFunctions do # Multi tenant tests test "[multi tenant] creating a company creates a company version with correct attributes" do + tenant = MultiTenant.tenant() user = create_user(:multitenant) inserted_company = create_company_with_version_multi(@create_company_params, user: user) company_count = Company.count(:multitenant) - version_count = Version.count(MultiTenant.tenant()) + version_count = Version.count(prefix: tenant) company = inserted_company |> serialize() - version = PaperTrail.get_version(inserted_company, prefix: MultiTenant.tenant()) + version = PaperTrail.get_version(inserted_company, prefix: tenant) |> serialize() assert company_count == 1 @@ -425,12 +426,14 @@ defmodule PaperTrailTest.StrictModeBangFunctions do end test "[multi tenant] creating a company without changeset creates a company version with correct attributes" do + tenant = MultiTenant.tenant() + inserted_company = create_company_with_version_multi(%{name: "Acme LLC"}, prefix: MultiTenant.tenant()) company_count = Company.count(:multitenant) - version_count = Version.count(MultiTenant.tenant()) + version_count = Version.count(prefix: tenant) company = inserted_company |> serialize - version = PaperTrail.get_version(inserted_company, prefix: MultiTenant.tenant()) + version = PaperTrail.get_version(inserted_company, prefix: tenant) |> serialize assert company_count == 1 @@ -476,7 +479,7 @@ defmodule PaperTrailTest.StrictModeBangFunctions do ) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) company = updated_company |> serialize updated_company_version = PaperTrail.get_version(updated_company, prefix: tenant) @@ -534,7 +537,7 @@ defmodule PaperTrailTest.StrictModeBangFunctions do deleted_company = PaperTrail.delete!(updated_company, user: user, prefix: tenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) old_company = deleted_company |> serialize deleted_company_version = PaperTrail.get_version(deleted_company, prefix: tenant) @@ -620,7 +623,7 @@ defmodule PaperTrailTest.StrictModeBangFunctions do |> PaperTrail.insert!(origin: "admin", meta: %{linkname: "izelnakri"}, prefix: tenant) person_count = Person.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) person = inserted_person |> serialize version = PaperTrail.get_version(inserted_person, prefix: tenant) |> serialize @@ -680,7 +683,7 @@ defmodule PaperTrailTest.StrictModeBangFunctions do person_count = Person.count(:multitenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) person = updated_person |> serialize updated_person_version = PaperTrail.get_version(updated_person, prefix: tenant) @@ -754,7 +757,7 @@ defmodule PaperTrailTest.StrictModeBangFunctions do person_count = Person.count(:multitenant) company_count = Company.count(:multitenant) - version_count = Version.count(tenant) + version_count = Version.count(prefix: tenant) assert person_count == 0 assert company_count == 2 From cf638d6924853931f54ccf043ec97025f9fbcc11 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 13:53:08 +0200 Subject: [PATCH 24/32] Require new support helper in lib test_helper file --- test/test_helper.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_helper.exs b/test/test_helper.exs index 2eff7b9f..badc1e80 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -7,6 +7,7 @@ PaperTrail.UUIDRepo.start_link Code.require_file("test/support/simple_models.exs") Code.require_file("test/support/strict_models.exs") Code.require_file("test/support/uuid_models.exs") +Code.require_file("test/support/multi_tenant_helper.exs") ExUnit.configure seed: 0 From b914cfdfde3207050becdcf6f87a7c145376f65e Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 14:07:41 +0200 Subject: [PATCH 25/32] Add multi tenancy tests in paper_trail_version_test file --- test/paper_trail/paper_trail_version_test.exs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/paper_trail/paper_trail_version_test.exs b/test/paper_trail/paper_trail_version_test.exs index bffdccac..fdf83d9b 100644 --- a/test/paper_trail/paper_trail_version_test.exs +++ b/test/paper_trail/paper_trail_version_test.exs @@ -2,6 +2,7 @@ defmodule PaperTrailTest.Version do use ExUnit.Case alias PaperTrail.Version + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant @valid_attrs %{ event: "insert", @@ -20,13 +21,20 @@ defmodule PaperTrailTest.Version do Application.put_env(:paper_trail, :repo, PaperTrail.Repo) Code.eval_file("lib/paper_trail.ex") Code.eval_file("lib/version.ex") + MultiTenant.setup_tenant(@repo) :ok end setup do @repo.delete_all(Version) + Version + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() on_exit fn -> @repo.delete_all(Version) + Version + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() end :ok end @@ -63,6 +71,29 @@ defmodule PaperTrailTest.Version do } end + # Multi tenant tests + test "[multi tenant] count works" do + versions = add_three_versions_multi() + Version.count(prefix: MultiTenant.tenant()) == length(versions) + end + + test "[multi tenant] first works" do + versions = add_three_versions_multi() + Version.first(prefix: MultiTenant.tenant()) |> serialize == @valid_attrs + end + + test "[multi tenant] last works" do + versions = add_three_versions_multi() + Version.last(prefix: MultiTenant.tenant()) |> serialize != %{ + event: "insert", + item_type: "Person", + item_id: 3, + item_changes: %{first_name: "Yukihiro", last_name: "Matsumoto"}, + origin: "test", + inserted_at: DateTime.from_naive!(~N[1965-04-14 01:00:00.000], "Etc/UTC") + } + end + def add_three_versions do @repo.insert_all(Version, [ @valid_attrs, @@ -84,6 +115,27 @@ defmodule PaperTrailTest.Version do } ], returning: true) |> elem(1) end + def add_three_versions_multi do + @repo.insert_all(Version, [ + @valid_attrs, + %{ + event: "insert", + item_type: "Person", + item_id: 2, + item_changes: %{first_name: "Brendan", last_name: "Eich"}, + origin: "test", + inserted_at: DateTime.from_naive!(~N[1961-07-04 01:00:00.000], "Etc/UTC") + }, + %{ + event: "insert", + item_type: "Person", + item_id: 3, + item_changes: %{first_name: "Yukihiro", last_name: "Matsumoto"}, + origin: "test", + inserted_at: DateTime.from_naive!(~N[1965-04-14 01:00:00.000], "Etc/UTC") + } + ], returning: true, prefix: MultiTenant.tenant()) |> elem(1) + end def serialize(nil), do: nil def serialize(resource) do From 7414a66fd118acfe6e2e9fcebef25ce61366b410 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 14:31:24 +0200 Subject: [PATCH 26/32] Add some changes to the previous code added in paper_trail_version_test file --- test/paper_trail/paper_trail_version_test.exs | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/test/paper_trail/paper_trail_version_test.exs b/test/paper_trail/paper_trail_version_test.exs index fdf83d9b..0fa1a97e 100644 --- a/test/paper_trail/paper_trail_version_test.exs +++ b/test/paper_trail/paper_trail_version_test.exs @@ -55,12 +55,12 @@ defmodule PaperTrailTest.Version do end test "first works" do - versions = add_three_versions() + add_three_versions() Version.first() |> serialize == @valid_attrs end test "last works" do - versions = add_three_versions() + add_three_versions() Version.last() |> serialize != %{ event: "insert", item_type: "Person", @@ -73,17 +73,17 @@ defmodule PaperTrailTest.Version do # Multi tenant tests test "[multi tenant] count works" do - versions = add_three_versions_multi() + versions = add_three_versions(MultiTenant.tenant()) Version.count(prefix: MultiTenant.tenant()) == length(versions) end test "[multi tenant] first works" do - versions = add_three_versions_multi() + add_three_versions(MultiTenant.tenant()) Version.first(prefix: MultiTenant.tenant()) |> serialize == @valid_attrs end test "[multi tenant] last works" do - versions = add_three_versions_multi() + add_three_versions(MultiTenant.tenant()) Version.last(prefix: MultiTenant.tenant()) |> serialize != %{ event: "insert", item_type: "Person", @@ -94,28 +94,7 @@ defmodule PaperTrailTest.Version do } end - def add_three_versions do - @repo.insert_all(Version, [ - @valid_attrs, - %{ - event: "insert", - item_type: "Person", - item_id: 2, - item_changes: %{first_name: "Brendan", last_name: "Eich"}, - origin: "test", - inserted_at: DateTime.from_naive!(~N[1961-07-04 01:00:00.000], "Etc/UTC") - }, - %{ - event: "insert", - item_type: "Person", - item_id: 3, - item_changes: %{first_name: "Yukihiro", last_name: "Matsumoto"}, - origin: "test", - inserted_at: DateTime.from_naive!(~N[1965-04-14 01:00:00.000], "Etc/UTC") - } - ], returning: true) |> elem(1) - end - def add_three_versions_multi do + def add_three_versions(prefix \\ nil) do @repo.insert_all(Version, [ @valid_attrs, %{ @@ -134,7 +113,7 @@ defmodule PaperTrailTest.Version do origin: "test", inserted_at: DateTime.from_naive!(~N[1965-04-14 01:00:00.000], "Etc/UTC") } - ], returning: true, prefix: MultiTenant.tenant()) |> elem(1) + ], returning: true, prefix: prefix) |> elem(1) end def serialize(nil), do: nil From 5f51b7e2c30a637b523822f144f068294e93a15a Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 14:56:49 +0200 Subject: [PATCH 27/32] Add multi tenancy tests in version_queries_test file --- test/paper_trail/version_queries_test.exs | 64 +++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/test/paper_trail/version_queries_test.exs b/test/paper_trail/version_queries_test.exs index 6a792358..ecc35660 100644 --- a/test/paper_trail/version_queries_test.exs +++ b/test/paper_trail/version_queries_test.exs @@ -4,15 +4,15 @@ defmodule PaperTrailTest.VersionQueries do alias PaperTrail.Version alias SimpleCompany, as: Company alias SimplePerson, as: Person + alias PaperTrailTest.MultiTenantHelper, as: MultiTenant import Ecto.Query @repo PaperTrail.RepoClient.repo setup_all do - @repo.delete_all(Person) - @repo.delete_all(Company) - @repo.delete_all(Version) + MultiTenant.setup_tenant(@repo) + reset_all_data() Company.changeset(%Company{}, %{ name: "Acme LLC", is_active: true, city: "Greenwich" @@ -61,26 +61,65 @@ defmodule PaperTrailTest.VersionQueries do company_id: another_company.id }) |> PaperTrail.update(set_by: "user:1", meta: %{linkname: "izelnakri"}) + # Multi tenant + Company.changeset(%Company{}, %{ + name: "Acme LLC", is_active: true, city: "Greenwich" + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert(prefix: MultiTenant.tenant()) + + company_multi = first(Company, :id) + |> MultiTenant.add_prefix_to_query() + |> @repo.one + + Person.changeset(%Person{}, %{ + first_name: "Izel", + last_name: "Nakri", + gender: true, + company_id: company_multi.id + }) + |> MultiTenant.add_prefix_to_changeset() + |> PaperTrail.insert(set_by: "admin", prefix: MultiTenant.tenant()) + :ok end test "get_version gives us the right version" do + tenant = MultiTenant.tenant() last_person = last(Person, :id) |> @repo.one target_version = last(Version, :id) |> @repo.one + last_person_multi = last(Person, :id) + |> MultiTenant.add_prefix_to_query() + |> @repo.one + target_version_multi = last(Version, :id) + |> MultiTenant.add_prefix_to_query() + |> @repo.one assert PaperTrail.get_version(last_person) == target_version assert PaperTrail.get_version(Person, last_person.id) == target_version + assert PaperTrail.get_version(last_person_multi, prefix: tenant) == target_version_multi + assert PaperTrail.get_version(Person, last_person_multi.id, prefix: tenant) == target_version_multi end test "get_versions gives us the right versions" do + tenant = MultiTenant.tenant() last_person = last(Person, :id) |> @repo.one target_versions = @repo.all( from version in Version, where: version.item_type == "SimplePerson" and version.item_id == ^last_person.id ) + last_person_multi = last(Person, :id) + |> MultiTenant.add_prefix_to_query() + |> @repo.one + target_versions_multi = from(version in Version, + where: version.item_type == "SimplePerson" and version.item_id == ^last_person_multi.id) + |> MultiTenant.add_prefix_to_query() + |> @repo.all assert PaperTrail.get_versions(last_person) == target_versions assert PaperTrail.get_versions(Person, last_person.id) == target_versions + assert PaperTrail.get_versions(last_person_multi, prefix: tenant) == target_versions_multi + assert PaperTrail.get_versions(Person, last_person_multi.id, prefix: tenant) == target_versions_multi end test "get_current_model/1 gives us the current record of a version" do @@ -90,4 +129,23 @@ defmodule PaperTrailTest.VersionQueries do assert PaperTrail.get_current_model(first_version) == person end # query meta data!! + + # Functions + defp reset_all_data() do + @repo.delete_all(Person) + @repo.delete_all(Company) + @repo.delete_all(Version) + + Person + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + + Company + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + + Version + |> MultiTenant.add_prefix_to_query() + |> @repo.delete_all() + end end From c50eef8398d774cb8dad6461d367324577e08067 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Tue, 1 Aug 2017 15:17:51 +0200 Subject: [PATCH 28/32] Add dreamingechoes to credits section in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 27d97fad..aa822e53 100644 --- a/README.md +++ b/README.md @@ -444,6 +444,7 @@ Many thanks to: - [Jason Draper](https://github.com/drapergeek) - UUID primary keys feature - [Josh Taylor](https://github.com/joshuataylor) - Maintenance and new feature suggestions - [Mitchell Henke](https://github.com/mitchellhenke) - Fixed weird elixir compiler warnings +- [Iván González](https://github.com/dreamingechoes) - Multi tenancy feature and some minor refactors - [Izel Nakri](https://github.com/izelnakri) - The Originator of this library. See what I did there ;) Additional thanks to: From 0604631e10330645473d0d5dbce0fbcadb2df2a4 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Sat, 5 Aug 2017 16:13:48 +0200 Subject: [PATCH 29/32] Remove changeset_helper.exs and query_helper.exs from example/test/support Now the aux functions used on the example app tests are located in each test file in stead of in one separated module. --- example/test/company_test.exs | 31 ++++++---- example/test/multi_tenant_company_test.exs | 49 +++++++++++---- example/test/multi_tenant_person_test.exs | 71 +++++++++++++++++----- example/test/person_test.exs | 44 +++++++++----- example/test/support/changeset_helper.exs | 24 -------- example/test/support/query_helper.exs | 24 -------- example/test/test_helper.exs | 2 - 7 files changed, 141 insertions(+), 104 deletions(-) delete mode 100644 example/test/support/changeset_helper.exs delete mode 100644 example/test/support/query_helper.exs diff --git a/example/test/company_test.exs b/example/test/company_test.exs index 2c123ec3..73421c2d 100644 --- a/example/test/company_test.exs +++ b/example/test/company_test.exs @@ -14,12 +14,12 @@ defmodule CompanyTest do test "creating a company creates a company version with correct attributes" do {:ok, result} = %{name: "Acme LLC", is_active: true, city: "Greenwich", people: []} - |> ChangesetHelper.new_company() + |> new_company() |> PaperTrail.insert(origin: "test") - company_count = QueryHelper.company_count() |> Repo.all() - version_count = QueryHelper.version_count() |> Repo.all() - first_company = QueryHelper.first_company() |> Repo.one() + company_count = company_count() |> Repo.all() + version_count = version_count() |> Repo.all() + first_company = first_company() |> Repo.one() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -51,17 +51,17 @@ defmodule CompanyTest do end test "updating a company creates a company version with correct item_changes" do - first_company = QueryHelper.first_company() |> Repo.one() + first_company = first_company() |> Repo.one() {:ok, result} = - ChangesetHelper.update_company(first_company, %{ + update_company(first_company, %{ city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" }) |> PaperTrail.update() - company_count = QueryHelper.company_count() |> Repo.all() - version_count = QueryHelper.version_count() |> Repo.all() + company_count = company_count() |> Repo.all() + version_count = version_count() |> Repo.all() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -93,14 +93,14 @@ defmodule CompanyTest do end test "deleting a company creates a company version with correct attributes" do - company = QueryHelper.first_company() |> Repo.one() + company = first_company() |> Repo.one() {:ok, result} = company |> PaperTrail.delete() - company_count = QueryHelper.company_count() |> Repo.all() - version_count = QueryHelper.version_count() |> Repo.all() + company_count = company_count() |> Repo.all() + version_count = version_count() |> Repo.all() company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -142,4 +142,13 @@ defmodule CompanyTest do meta: nil } end + + # Company related functions + def company_count(), do: (from company in Company, select: count(company.id)) + def first_company(), do: (first(Company, :id) |> preload(:people)) + def new_company(attrs), do: Company.changeset(%Company{}, attrs) + def update_company(company, attrs), do: Company.changeset(company, attrs) + + # Version related functions + def version_count(), do: (from version in PaperTrail.Version, select: count(version.id)) end diff --git a/example/test/multi_tenant_company_test.exs b/example/test/multi_tenant_company_test.exs index 01bc0f13..01db36bd 100644 --- a/example/test/multi_tenant_company_test.exs +++ b/example/test/multi_tenant_company_test.exs @@ -10,12 +10,12 @@ defmodule MultiTenantCompanyTest do test "[multi tenant] creating a company creates a company version with correct attributes" do {:ok, result} = %{name: "Acme LLC", is_active: true, city: "Greenwich", people: []} - |> ChangesetHelper.new_company(:multitenant) + |> new_company() |> PaperTrail.insert(origin: "test", prefix: MultiTenantHelper.tenant()) - company_count = QueryHelper.company_count(:multitenant) |> Repo.all() - version_count = QueryHelper.version_count(:multitenant) |> Repo.all() - first_company = QueryHelper.first_company(:multitenant) |> Repo.one() + company_count = company_count() |> Repo.all() + version_count = version_count() |> Repo.all() + first_company = first_company() |> Repo.one() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -47,17 +47,17 @@ defmodule MultiTenantCompanyTest do end test "[multi tenant] updating a company creates a company version with correct item_changes" do - first_company = QueryHelper.first_company(:multitenant) |> Repo.one() + first_company = first_company() |> Repo.one() {:ok, result} = - ChangesetHelper.update_company(first_company, %{ + update_company(first_company, %{ city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" - }, :multitenant) |> PaperTrail.update(prefix: MultiTenantHelper.tenant()) + }) |> PaperTrail.update(prefix: MultiTenantHelper.tenant()) - company_count = QueryHelper.company_count(:multitenant) |> Repo.all() - version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + company_count = company_count() |> Repo.all() + version_count = version_count() |> Repo.all() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -89,14 +89,14 @@ defmodule MultiTenantCompanyTest do end test "[multi tenant] deleting a company creates a company version with correct attributes" do - company = QueryHelper.first_company(:multitenant) |> Repo.one() + company = first_company() |> Repo.one() {:ok, result} = company |> PaperTrail.delete(prefix: MultiTenantHelper.tenant()) - company_count = QueryHelper.company_count(:multitenant) |> Repo.all() - version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + company_count = company_count() |> Repo.all() + version_count = version_count() |> Repo.all() company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -138,4 +138,29 @@ defmodule MultiTenantCompanyTest do meta: nil } end + + # Company related functions + def company_count() do + (from company in Company, select: count(company.id)) + |> MultiTenantHelper.add_prefix_to_query() + end + def first_company() do + (first(Company, :id) + |> preload(:people)) + |> MultiTenantHelper.add_prefix_to_query() + end + def new_company(attrs) do + Company.changeset(%Company{}, attrs) + |> MultiTenantHelper.add_prefix_to_changeset() + end + def update_company(company, attrs) do + Company.changeset(company, attrs) + |> MultiTenantHelper.add_prefix_to_changeset() + end + + # Version related functions + def version_count() do + (from version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + end end diff --git a/example/test/multi_tenant_person_test.exs b/example/test/multi_tenant_person_test.exs index b9dc7dff..310d79e3 100644 --- a/example/test/multi_tenant_person_test.exs +++ b/example/test/multi_tenant_person_test.exs @@ -6,31 +6,31 @@ defmodule MultiTenantPersonTest do MultiTenantHelper.setup_tenant(Repo) %{name: "Acme LLC", website: "http://www.acme.com"} - |> ChangesetHelper.new_company(:multitenant) + |> new_company() |> Repo.insert() %{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"} - |> ChangesetHelper.new_company(:multitenant) + |> new_company() |> Repo.insert() :ok end test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do - company = QueryHelper.first_company(:multitenant) |> Repo.one() + company = first_company() |> Repo.one() {:ok, result} = %{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id} - |> ChangesetHelper.new_person(:multitenant) + |> new_person() |> PaperTrail.insert(origin: "admin", meta: %{}, prefix: MultiTenantHelper.tenant()) - person_count = QueryHelper.person_count(:multitenant) |> Repo.all() - version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + person_count = person_count() |> Repo.all() + version_count = version_count() |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) - first_person = QueryHelper.first_person(:multitenant) |> Repo.one() + first_person = first_person() |> Repo.one() assert person_count == [1] assert version_count == [1] @@ -56,25 +56,25 @@ defmodule MultiTenantPersonTest do end test "[multi tenant] updating a person creates a person version with correct attributes" do - first_person = QueryHelper.first_person(:multitenant) |> Repo.one() + first_person = first_person() |> Repo.one() target_company = [name: "Another Company Corp.", limit: 1] - |> QueryHelper.filter_company(:multitenant) + |> filter_company() |> Repo.one() {:ok, result} = - ChangesetHelper.update_person(first_person, %{ + update_person(first_person, %{ first_name: "Isaac", visit_count: 10, birthdate: ~D[1992-04-01], company_id: target_company.id - }, :multitenant) + }) |> PaperTrail.update([origin: "user:1", meta: %{linkname: "izelnakri"}, prefix: MultiTenantHelper.tenant()]) - person_count = QueryHelper.person_count(:multitenant) |> Repo.all() - version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + person_count = person_count() |> Repo.all() + version_count = version_count() |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -110,14 +110,14 @@ defmodule MultiTenantPersonTest do end test "[multi tenant] deleting a person creates a person version with correct attributes" do - person = QueryHelper.first_person(:multitenant) |> Repo.one() + person = first_person() |> Repo.one() {:ok, result} = person |> PaperTrail.delete(prefix: MultiTenantHelper.tenant()) - person_count = QueryHelper.person_count(:multitenant) |> Repo.all() - version_count = QueryHelper.version_count(:multitenant) |> Repo.all() + person_count = person_count() |> Repo.all() + version_count = version_count() |> Repo.all() version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -144,4 +144,43 @@ defmodule MultiTenantPersonTest do meta: nil } end + + # Person related functions + def person_count() do + (from person in Person, select: count(person.id)) + |> MultiTenantHelper.add_prefix_to_query() + end + def first_person() do + (first(Person, :id) |> preload(:company)) + |> MultiTenantHelper.add_prefix_to_query() + end + def new_person(attrs) do + Person.changeset(%Person{}, attrs) + |> MultiTenantHelper.add_prefix_to_changeset() + end + def update_person(person, attrs) do + Person.changeset(person, attrs) + |> MultiTenantHelper.add_prefix_to_changeset() + end + + # Company related functions + def first_company() do + (first(Company, :id) + |> preload(:people)) + |> MultiTenantHelper.add_prefix_to_query() + end + def new_company(attrs) do + Company.changeset(%Company{}, attrs) + |> MultiTenantHelper.add_prefix_to_changeset() + end + def filter_company(opts) do + (from c in Company, where: c.name == ^opts[:name], limit: ^opts[:limit]) + |> MultiTenantHelper.add_prefix_to_query() + end + + # Version related functions + def version_count() do + (from version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + end end diff --git a/example/test/person_test.exs b/example/test/person_test.exs index 08edfd4b..6859a1ef 100644 --- a/example/test/person_test.exs +++ b/example/test/person_test.exs @@ -10,31 +10,31 @@ defmodule PersonTest do Repo.delete_all(PaperTrail.Version) %{name: "Acme LLC", website: "http://www.acme.com"} - |> ChangesetHelper.new_company() + |> new_company() |> Repo.insert() %{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"} - |> ChangesetHelper.new_company() + |> new_company() |> Repo.insert() :ok end test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do - company = QueryHelper.first_company() |> Repo.one() + company = first_company() |> Repo.one() {:ok, result} = %{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id} - |> ChangesetHelper.new_person() + |> new_person() |> PaperTrail.insert(origin: "admin", meta: %{}) - person_count = QueryHelper.person_count() |> Repo.all() - version_count = QueryHelper.version_count() |> Repo.all() + person_count = person_count() |> Repo.all() + version_count = version_count() |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) - first_person = QueryHelper.first_person() |> Repo.one() + first_person = first_person() |> Repo.one() assert person_count == [1] assert version_count == [1] @@ -60,15 +60,15 @@ defmodule PersonTest do end test "[multi tenant] updating a person creates a person version with correct attributes" do - first_person = QueryHelper.first_person() |> Repo.one() + first_person = first_person() |> Repo.one() target_company = [name: "Another Company Corp.", limit: 1] - |> QueryHelper.filter_company() + |> filter_company() |> Repo.one() {:ok, result} = - ChangesetHelper.update_person(first_person, %{ + update_person(first_person, %{ first_name: "Isaac", visit_count: 10, birthdate: ~D[1992-04-01], @@ -76,8 +76,8 @@ defmodule PersonTest do }) |> PaperTrail.update(origin: "user:1", meta: %{linkname: "izelnakri"}) - person_count = QueryHelper.person_count() |> Repo.all() - version_count = QueryHelper.version_count() |> Repo.all() + person_count = person_count() |> Repo.all() + version_count = version_count() |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -113,14 +113,14 @@ defmodule PersonTest do end test "[multi tenant] deleting a person creates a person version with correct attributes" do - person = QueryHelper.first_person() |> Repo.one() + person = first_person() |> Repo.one() {:ok, result} = person |> PaperTrail.delete() - person_count = QueryHelper.person_count() |> Repo.all() - version_count = QueryHelper.version_count() |> Repo.all() + person_count = person_count() |> Repo.all() + version_count = version_count() |> Repo.all() version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -147,4 +147,18 @@ defmodule PersonTest do meta: nil } end + + # Person related functions + def person_count(), do: (from person in Person, select: count(person.id)) + def first_person(), do: (first(Person, :id) |> preload(:company)) + def new_person(attrs), do: Person.changeset(%Person{}, attrs) + def update_person(person, attrs), do: Person.changeset(person, attrs) + + # Company related functions + def first_company(), do: (first(Company, :id) |> preload(:people)) + def new_company(attrs), do: Company.changeset(%Company{}, attrs) + def filter_company(opts), do: (from c in Company, where: c.name == ^opts[:name], limit: ^opts[:limit]) + + # Version related functions + def version_count(), do: (from version in PaperTrail.Version, select: count(version.id)) end diff --git a/example/test/support/changeset_helper.exs b/example/test/support/changeset_helper.exs deleted file mode 100644 index 68fa269e..00000000 --- a/example/test/support/changeset_helper.exs +++ /dev/null @@ -1,24 +0,0 @@ -defmodule ChangesetHelper do - - # Company related changeset functions - def new_company(attrs), do: Company.changeset(%Company{}, attrs) - def new_company(attrs, :multitenant) do - new_company(attrs) |> MultiTenantHelper.add_prefix_to_changeset() - end - - def update_company(company, attrs), do: Company.changeset(company, attrs) - def update_company(company, attrs, :multitenant) do - update_company(company, attrs) |> MultiTenantHelper.add_prefix_to_changeset() - end - - # Person related changeset functions - def new_person(attrs), do: Person.changeset(%Person{}, attrs) - def new_person(attrs, :multitenant) do - new_person(attrs) |> MultiTenantHelper.add_prefix_to_changeset() - end - - def update_person(person, attrs), do: Person.changeset(person, attrs) - def update_person(person, attrs, :multitenant) do - update_person(person, attrs) |> MultiTenantHelper.add_prefix_to_changeset() - end -end diff --git a/example/test/support/query_helper.exs b/example/test/support/query_helper.exs deleted file mode 100644 index 72a17740..00000000 --- a/example/test/support/query_helper.exs +++ /dev/null @@ -1,24 +0,0 @@ -defmodule QueryHelper do - import Ecto.Query - - # Company related query functions - def company_count(), do: (from company in Company, select: count(company.id)) - def company_count(:multitenant), do: company_count() |> MultiTenantHelper.add_prefix_to_query() - - def first_company(), do: (first(Company, :id) |> preload(:people)) - def first_company(:multitenant), do: first_company() |> MultiTenantHelper.add_prefix_to_query() - - def filter_company(opts), do: (from c in Company, where: c.name == ^opts[:name], limit: ^opts[:limit]) - def filter_company(opts, :multitenant), do: filter_company(opts) |> MultiTenantHelper.add_prefix_to_query() - - # Person related query functions - def person_count(), do: (from person in Person, select: count(person.id)) - def person_count(:multitenant), do: person_count() |> MultiTenantHelper.add_prefix_to_query() - - def first_person(), do: (first(Person, :id) |> preload(:company)) - def first_person(:multitenant), do: first_person() |> MultiTenantHelper.add_prefix_to_query() - - # Version related query functions - def version_count(), do: (from version in PaperTrail.Version, select: count(version.id)) - def version_count(:multitenant), do: version_count() |> MultiTenantHelper.add_prefix_to_query() -end diff --git a/example/test/test_helper.exs b/example/test/test_helper.exs index 434cc696..0191ced3 100644 --- a/example/test/test_helper.exs +++ b/example/test/test_helper.exs @@ -4,7 +4,5 @@ Mix.Task.run "ecto.create", ~w(-r Repo) Mix.Task.run "ecto.migrate", ~w(-r Repo) Code.require_file("test/support/multi_tenant_helper.exs") -Code.require_file("test/support/query_helper.exs") -Code.require_file("test/support/changeset_helper.exs") ExUnit.start From ead9cc6120b5350cb9f4f8535f19c15360cbb233 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Sun, 6 Aug 2017 15:48:04 +0200 Subject: [PATCH 30/32] Add final refactor to example app test files Removes all the aux functions in order to make all the variables more explicit and easier to understand. Removes some typos in person_test description. --- example/test/company_test.exs | 55 ++++++---- example/test/multi_tenant_company_test.exs | 87 +++++++++------- example/test/multi_tenant_person_test.exs | 116 ++++++++++----------- example/test/person_test.exs | 85 ++++++++------- 4 files changed, 187 insertions(+), 156 deletions(-) diff --git a/example/test/company_test.exs b/example/test/company_test.exs index 73421c2d..b2e49af1 100644 --- a/example/test/company_test.exs +++ b/example/test/company_test.exs @@ -13,13 +13,20 @@ defmodule CompanyTest do test "creating a company creates a company version with correct attributes" do {:ok, result} = - %{name: "Acme LLC", is_active: true, city: "Greenwich", people: []} - |> new_company() + %Company{} + |> Company.changeset(%{name: "Acme LLC", is_active: true, city: "Greenwich", people: []}) |> PaperTrail.insert(origin: "test") - company_count = company_count() |> Repo.all() - version_count = version_count() |> Repo.all() - first_company = first_company() |> Repo.one() + company_count = + from(company in Company, select: count(company.id)) + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() + first_company = + first(Company, :id) + |> preload(:people) + |> Repo.one() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -51,17 +58,25 @@ defmodule CompanyTest do end test "updating a company creates a company version with correct item_changes" do - first_company = first_company() |> Repo.one() + first_company = + first(Company, :id) + |> preload(:people) + |> Repo.one() {:ok, result} = - update_company(first_company, %{ + first_company + |> Company.changeset(%{ city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" }) |> PaperTrail.update() - company_count = company_count() |> Repo.all() - version_count = version_count() |> Repo.all() + company_count = + from(company in Company, select: count(company.id)) + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -93,14 +108,21 @@ defmodule CompanyTest do end test "deleting a company creates a company version with correct attributes" do - company = first_company() |> Repo.one() + company = + first(Company, :id) + |> preload(:people) + |> Repo.one() {:ok, result} = company |> PaperTrail.delete() - company_count = company_count() |> Repo.all() - version_count = version_count() |> Repo.all() + company_count = + from(company in Company, select: count(company.id)) + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -142,13 +164,4 @@ defmodule CompanyTest do meta: nil } end - - # Company related functions - def company_count(), do: (from company in Company, select: count(company.id)) - def first_company(), do: (first(Company, :id) |> preload(:people)) - def new_company(attrs), do: Company.changeset(%Company{}, attrs) - def update_company(company, attrs), do: Company.changeset(company, attrs) - - # Version related functions - def version_count(), do: (from version in PaperTrail.Version, select: count(version.id)) end diff --git a/example/test/multi_tenant_company_test.exs b/example/test/multi_tenant_company_test.exs index 01db36bd..b55ccf95 100644 --- a/example/test/multi_tenant_company_test.exs +++ b/example/test/multi_tenant_company_test.exs @@ -9,13 +9,24 @@ defmodule MultiTenantCompanyTest do test "[multi tenant] creating a company creates a company version with correct attributes" do {:ok, result} = - %{name: "Acme LLC", is_active: true, city: "Greenwich", people: []} - |> new_company() + %Company{} + |> Company.changeset(%{name: "Acme LLC", is_active: true, city: "Greenwich", people: []}) + |> MultiTenantHelper.add_prefix_to_changeset() |> PaperTrail.insert(origin: "test", prefix: MultiTenantHelper.tenant()) - company_count = company_count() |> Repo.all() - version_count = version_count() |> Repo.all() - first_company = first_company() |> Repo.one() + company_count = + from(company in Company, select: count(company.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + first_company = + first(Company, :id) + |> preload(:people) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -47,17 +58,30 @@ defmodule MultiTenantCompanyTest do end test "[multi tenant] updating a company creates a company version with correct item_changes" do - first_company = first_company() |> Repo.one() + first_company = + first(Company, :id) + |> preload(:people) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() {:ok, result} = - update_company(first_company, %{ + first_company + |> Company.changeset(%{ city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc" - }) |> PaperTrail.update(prefix: MultiTenantHelper.tenant()) - - company_count = company_count() |> Repo.all() - version_count = version_count() |> Repo.all() + }) + |> MultiTenantHelper.add_prefix_to_changeset() + |> PaperTrail.update(prefix: MultiTenantHelper.tenant()) + + company_count = + from(company in Company, select: count(company.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -89,14 +113,24 @@ defmodule MultiTenantCompanyTest do end test "[multi tenant] deleting a company creates a company version with correct attributes" do - company = first_company() |> Repo.one() + company = + first(Company, :id) + |> preload(:people) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() {:ok, result} = company |> PaperTrail.delete(prefix: MultiTenantHelper.tenant()) - company_count = company_count() |> Repo.all() - version_count = version_count() |> Repo.all() + company_count = + from(company in Company, select: count(company.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -138,29 +172,4 @@ defmodule MultiTenantCompanyTest do meta: nil } end - - # Company related functions - def company_count() do - (from company in Company, select: count(company.id)) - |> MultiTenantHelper.add_prefix_to_query() - end - def first_company() do - (first(Company, :id) - |> preload(:people)) - |> MultiTenantHelper.add_prefix_to_query() - end - def new_company(attrs) do - Company.changeset(%Company{}, attrs) - |> MultiTenantHelper.add_prefix_to_changeset() - end - def update_company(company, attrs) do - Company.changeset(company, attrs) - |> MultiTenantHelper.add_prefix_to_changeset() - end - - # Version related functions - def version_count() do - (from version in PaperTrail.Version, select: count(version.id)) - |> MultiTenantHelper.add_prefix_to_query() - end end diff --git a/example/test/multi_tenant_person_test.exs b/example/test/multi_tenant_person_test.exs index 310d79e3..04a23280 100644 --- a/example/test/multi_tenant_person_test.exs +++ b/example/test/multi_tenant_person_test.exs @@ -5,32 +5,49 @@ defmodule MultiTenantPersonTest do setup_all do MultiTenantHelper.setup_tenant(Repo) - %{name: "Acme LLC", website: "http://www.acme.com"} - |> new_company() + %Company{} + |> Company.changeset(%{name: "Acme LLC", website: "http://www.acme.com"}) + |> MultiTenantHelper.add_prefix_to_changeset() |> Repo.insert() - %{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"} - |> new_company() + %Company{} + |> Company.changeset(%{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"}) + |> MultiTenantHelper.add_prefix_to_changeset() |> Repo.insert() :ok end test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do - company = first_company() |> Repo.one() + company = + first(Company, :id) + |> preload(:people) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() {:ok, result} = - %{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id} - |> new_person() + %Person{} + |> Person.changeset(%{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id}) + |> MultiTenantHelper.add_prefix_to_changeset() |> PaperTrail.insert(origin: "admin", meta: %{}, prefix: MultiTenantHelper.tenant()) - person_count = person_count() |> Repo.all() - version_count = version_count() |> Repo.all() + person_count = + from(person in Person, select: count(person.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) - first_person = first_person() |> Repo.one() + first_person = + first(Person, :id) + |> preload(:company) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() assert person_count == [1] assert version_count == [1] @@ -56,25 +73,37 @@ defmodule MultiTenantPersonTest do end test "[multi tenant] updating a person creates a person version with correct attributes" do - first_person = first_person() |> Repo.one() + first_person = + first(Person, :id) + |> preload(:company) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() target_company = - [name: "Another Company Corp.", limit: 1] - |> filter_company() + from(c in Company, where: c.name == "Another Company Corp.", limit: 1) + |> MultiTenantHelper.add_prefix_to_query() |> Repo.one() {:ok, result} = - update_person(first_person, %{ + first_person + |> Person.changeset(%{ first_name: "Isaac", visit_count: 10, birthdate: ~D[1992-04-01], company_id: target_company.id }) + |> MultiTenantHelper.add_prefix_to_changeset() |> PaperTrail.update([origin: "user:1", meta: %{linkname: "izelnakri"}, prefix: MultiTenantHelper.tenant()]) - person_count = person_count() |> Repo.all() - version_count = version_count() |> Repo.all() + person_count = + from(person in Person, select: count(person.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -110,14 +139,24 @@ defmodule MultiTenantPersonTest do end test "[multi tenant] deleting a person creates a person version with correct attributes" do - person = first_person() |> Repo.one() + person = + first(Person, :id) + |> preload(:company) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.one() {:ok, result} = person |> PaperTrail.delete(prefix: MultiTenantHelper.tenant()) - person_count = person_count() |> Repo.all() - version_count = version_count() |> Repo.all() + person_count = + from(person in Person, select: count(person.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> MultiTenantHelper.add_prefix_to_query() + |> Repo.all() version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -144,43 +183,4 @@ defmodule MultiTenantPersonTest do meta: nil } end - - # Person related functions - def person_count() do - (from person in Person, select: count(person.id)) - |> MultiTenantHelper.add_prefix_to_query() - end - def first_person() do - (first(Person, :id) |> preload(:company)) - |> MultiTenantHelper.add_prefix_to_query() - end - def new_person(attrs) do - Person.changeset(%Person{}, attrs) - |> MultiTenantHelper.add_prefix_to_changeset() - end - def update_person(person, attrs) do - Person.changeset(person, attrs) - |> MultiTenantHelper.add_prefix_to_changeset() - end - - # Company related functions - def first_company() do - (first(Company, :id) - |> preload(:people)) - |> MultiTenantHelper.add_prefix_to_query() - end - def new_company(attrs) do - Company.changeset(%Company{}, attrs) - |> MultiTenantHelper.add_prefix_to_changeset() - end - def filter_company(opts) do - (from c in Company, where: c.name == ^opts[:name], limit: ^opts[:limit]) - |> MultiTenantHelper.add_prefix_to_query() - end - - # Version related functions - def version_count() do - (from version in PaperTrail.Version, select: count(version.id)) - |> MultiTenantHelper.add_prefix_to_query() - end end diff --git a/example/test/person_test.exs b/example/test/person_test.exs index 6859a1ef..181101e7 100644 --- a/example/test/person_test.exs +++ b/example/test/person_test.exs @@ -9,32 +9,42 @@ defmodule PersonTest do Repo.delete_all(Company) Repo.delete_all(PaperTrail.Version) - %{name: "Acme LLC", website: "http://www.acme.com"} - |> new_company() + %Company{} + |> Company.changeset(%{name: "Acme LLC", website: "http://www.acme.com"}) |> Repo.insert() - %{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"} - |> new_company() + %Company{} + |> Company.changeset(%{name: "Another Company Corp.", is_active: true, address: "Sesame street 100/3, 101010"}) |> Repo.insert() :ok end - test "[multi tenant] creating a person with meta tag creates a person version with correct attributes" do - company = first_company() |> Repo.one() + test "creating a person with meta tag creates a person version with correct attributes" do + company = + first(Company, :id) + |> preload(:people) + |> Repo.one() {:ok, result} = - %{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id} - |> new_person() + %Person{} + |> Person.changeset(%{first_name: "Izel", last_name: "Nakri", gender: true, company_id: company.id}) |> PaperTrail.insert(origin: "admin", meta: %{}) - person_count = person_count() |> Repo.all() - version_count = version_count() |> Repo.all() + person_count = + from(person in Person, select: count(person.id)) + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) - first_person = first_person() |> Repo.one() + first_person = + first(Person, :id) + |> preload(:company) + |> Repo.one() assert person_count == [1] assert version_count == [1] @@ -59,25 +69,31 @@ defmodule PersonTest do } end - test "[multi tenant] updating a person creates a person version with correct attributes" do - first_person = first_person() |> Repo.one() + test "updating a person creates a person version with correct attributes" do + first_person = + first(Person, :id) + |> preload(:company) + |> Repo.one() target_company = - [name: "Another Company Corp.", limit: 1] - |> filter_company() + from(c in Company, where: c.name == "Another Company Corp.", limit: 1) |> Repo.one() {:ok, result} = - update_person(first_person, %{ + first_person + |> Person.changeset(%{ first_name: "Isaac", visit_count: 10, birthdate: ~D[1992-04-01], company_id: target_company.id - }) - |> PaperTrail.update(origin: "user:1", meta: %{linkname: "izelnakri"}) + }) |> PaperTrail.update(origin: "user:1", meta: %{linkname: "izelnakri"}) - person_count = person_count() |> Repo.all() - version_count = version_count() |> Repo.all() + person_count = + from(person in Person, select: count(person.id)) + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -112,15 +128,22 @@ defmodule PersonTest do } end - test "[multi tenant] deleting a person creates a person version with correct attributes" do - person = first_person() |> Repo.one() + test "deleting a person creates a person version with correct attributes" do + person = + first(Person, :id) + |> preload(:company) + |> Repo.one() {:ok, result} = person |> PaperTrail.delete() - person_count = person_count() |> Repo.all() - version_count = version_count() |> Repo.all() + person_count = + from(person in Person, select: count(person.id)) + |> Repo.all() + version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -147,18 +170,4 @@ defmodule PersonTest do meta: nil } end - - # Person related functions - def person_count(), do: (from person in Person, select: count(person.id)) - def first_person(), do: (first(Person, :id) |> preload(:company)) - def new_person(attrs), do: Person.changeset(%Person{}, attrs) - def update_person(person, attrs), do: Person.changeset(person, attrs) - - # Company related functions - def first_company(), do: (first(Company, :id) |> preload(:people)) - def new_company(attrs), do: Company.changeset(%Company{}, attrs) - def filter_company(opts), do: (from c in Company, where: c.name == ^opts[:name], limit: ^opts[:limit]) - - # Version related functions - def version_count(), do: (from version in PaperTrail.Version, select: count(version.id)) end From 64231d72c87165a42715e3a7915b5af0c605d074 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Wed, 9 Aug 2017 08:56:18 +0200 Subject: [PATCH 31/32] Propagate options to repo actions in delete functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow us to delete records with on cascade relations in the same schema (it’s not possible at this moment). --- lib/paper_trail.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index c0bcd857..4a428afa 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -200,12 +200,12 @@ defmodule PaperTrail do """ def delete(struct, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do transaction = Multi.new - |> Multi.delete(:model, struct) + |> Multi.delete(:model, struct, options) |> Multi.run(:version, fn %{} -> version = make_version_struct(%{event: "delete"}, struct, options) - @repo.insert(version) + @repo.insert(version, options) end) - |> @repo.transaction + |> @repo.transaction(options) case transaction do {:error, :model, changeset, %{}} -> {:error, Map.merge(changeset, %{repo: @repo})} @@ -218,9 +218,9 @@ defmodule PaperTrail do """ def delete!(struct, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do @repo.transaction(fn -> - model = @repo.delete!(struct) + model = @repo.delete!(struct, options) version_struct = make_version_struct(%{event: "delete"}, struct, options) - @repo.insert!(version_struct) + @repo.insert!(version_struct, options) model end) |> elem(1) end From 13590263c048cace75508091758bc063ffbc7d78 Mon Sep 17 00:00:00 2001 From: Ivan Gonzalez Date: Wed, 9 Aug 2017 09:51:49 +0200 Subject: [PATCH 32/32] Add some additional assertions in tests This additional assertions will allow us to compare results between regular behavior and the multi tenant one, and check if multi tenant generates some conflicts on the public schema/database. --- example/test/multi_tenant_company_test.exs | 12 ++++++++++++ example/test/multi_tenant_person_test.exs | 12 ++++++++++++ .../bang_functions_simple_mode_test.exs | 17 +++++++++++++++++ .../bang_functions_strict_mode_test.exs | 15 +++++++++++++++ test/paper_trail/paper_trail_version_test.exs | 3 +++ test/paper_trail/version_queries_test.exs | 2 ++ 6 files changed, 61 insertions(+) diff --git a/example/test/multi_tenant_company_test.exs b/example/test/multi_tenant_company_test.exs index b55ccf95..beb9b570 100644 --- a/example/test/multi_tenant_company_test.exs +++ b/example/test/multi_tenant_company_test.exs @@ -22,6 +22,9 @@ defmodule MultiTenantCompanyTest do from(version in PaperTrail.Version, select: count(version.id)) |> MultiTenantHelper.add_prefix_to_query() |> Repo.all() + regular_version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() first_company = first(Company, :id) |> preload(:people) @@ -33,6 +36,7 @@ defmodule MultiTenantCompanyTest do assert company_count == [1] assert version_count == [1] + assert regular_version_count == [0] assert company == %{ name: "Acme LLC", @@ -82,12 +86,16 @@ defmodule MultiTenantCompanyTest do from(version in PaperTrail.Version, select: count(version.id)) |> MultiTenantHelper.add_prefix_to_query() |> Repo.all() + regular_version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() company = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert company_count == [1] assert version_count == [2] + assert regular_version_count == [0] assert company == %{ name: "Acme LLC", @@ -131,12 +139,16 @@ defmodule MultiTenantCompanyTest do from(version in PaperTrail.Version, select: count(version.id)) |> MultiTenantHelper.add_prefix_to_query() |> Repo.all() + regular_version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() company_ref = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert company_count == [0] assert version_count == [3] + assert regular_version_count == [0] assert company_ref == %{ name: "Acme LLC", diff --git a/example/test/multi_tenant_person_test.exs b/example/test/multi_tenant_person_test.exs index 04a23280..c6fab082 100644 --- a/example/test/multi_tenant_person_test.exs +++ b/example/test/multi_tenant_person_test.exs @@ -39,6 +39,9 @@ defmodule MultiTenantPersonTest do from(version in PaperTrail.Version, select: count(version.id)) |> MultiTenantHelper.add_prefix_to_query() |> Repo.all() + regular_version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) @@ -51,6 +54,7 @@ defmodule MultiTenantPersonTest do assert person_count == [1] assert version_count == [1] + assert regular_version_count == [0] assert Map.drop(person, [:company]) == %{ first_name: "Izel", @@ -104,12 +108,16 @@ defmodule MultiTenantPersonTest do from(version in PaperTrail.Version, select: count(version.id)) |> MultiTenantHelper.add_prefix_to_query() |> Repo.all() + regular_version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() person = result[:model] |> Map.drop([:__meta__, :__struct__, :inserted_at, :updated_at, :id]) version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert person_count == [1] assert version_count == [2] + assert regular_version_count == [0] assert Map.drop(person, [:company]) == %{ company_id: target_company.id, @@ -157,11 +165,15 @@ defmodule MultiTenantPersonTest do from(version in PaperTrail.Version, select: count(version.id)) |> MultiTenantHelper.add_prefix_to_query() |> Repo.all() + regular_version_count = + from(version in PaperTrail.Version, select: count(version.id)) + |> Repo.all() version = result[:version] |> Map.drop([:__meta__, :__struct__, :inserted_at]) assert person_count == [0] assert version_count == [3] + assert regular_version_count == [0] assert Map.drop(version, [:id]) == %{ event: "delete", diff --git a/test/paper_trail/bang_functions_simple_mode_test.exs b/test/paper_trail/bang_functions_simple_mode_test.exs index 00831204..39a1ee79 100644 --- a/test/paper_trail/bang_functions_simple_mode_test.exs +++ b/test/paper_trail/bang_functions_simple_mode_test.exs @@ -384,6 +384,8 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do version = PaperTrail.get_version(company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 1 assert version_count == 1 assert company |> serialize |> Map.drop([:id, :inserted_at, :updated_at]) == %{ @@ -429,6 +431,8 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do version = PaperTrail.get_version(updated_company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 1 assert version_count == 2 assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ @@ -471,6 +475,8 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do version = PaperTrail.get_version(updated_company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 1 assert version_count == 2 assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ @@ -522,6 +528,8 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do company = deleted_company |> serialize version = PaperTrail.get_version(deleted_company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 0 assert version_count == 3 assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ @@ -600,6 +608,9 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do |> MultiTenant.add_prefix_to_changeset() |> PaperTrail.insert!(origin: "admin", meta: %{linkname: "izelnakri"}, prefix: tenant) + assert Person.count() == 0 + assert Company.count() == 0 + assert Version.count() == 0 person_count = Person.count(:multitenant) company_count = Company.count(:multitenant) version_count = Version.count(prefix: tenant) @@ -664,6 +675,9 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do person = updated_person |> serialize version = PaperTrail.get_version(updated_person, prefix: tenant) |> serialize + assert Person.count() == 0 + assert Company.count() == 0 + assert Version.count() == 0 assert person_count == 1 assert company_count == 2 assert version_count == 4 @@ -729,6 +743,9 @@ defmodule PaperTrailTest.SimpleModeBangFunctions do old_person = updated_person |> serialize version = PaperTrail.get_version(deleted_person, prefix: tenant) |> serialize + assert Person.count() == 0 + assert Company.count() == 0 + assert Version.count() == 0 assert person_count == 0 assert company_count == 2 assert version_count == 5 diff --git a/test/paper_trail/bang_functions_strict_mode_test.exs b/test/paper_trail/bang_functions_strict_mode_test.exs index e9fb16c2..a430cdf0 100644 --- a/test/paper_trail/bang_functions_strict_mode_test.exs +++ b/test/paper_trail/bang_functions_strict_mode_test.exs @@ -399,6 +399,8 @@ defmodule PaperTrailTest.StrictModeBangFunctions do version = PaperTrail.get_version(inserted_company, prefix: tenant) |> serialize() + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 1 assert version_count == 1 assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ @@ -436,6 +438,8 @@ defmodule PaperTrailTest.StrictModeBangFunctions do version = PaperTrail.get_version(inserted_company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 1 assert version_count == 1 assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ @@ -485,6 +489,8 @@ defmodule PaperTrailTest.StrictModeBangFunctions do updated_company_version = PaperTrail.get_version(updated_company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 1 assert version_count == 2 assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ @@ -543,6 +549,8 @@ defmodule PaperTrailTest.StrictModeBangFunctions do deleted_company_version = PaperTrail.get_version(deleted_company, prefix: tenant) |> serialize + assert Company.count() == 0 + assert Version.count() == 0 assert company_count == 0 assert version_count == 3 assert Map.drop(old_company, [:id, :inserted_at, :updated_at]) == %{ @@ -628,6 +636,8 @@ defmodule PaperTrailTest.StrictModeBangFunctions do person = inserted_person |> serialize version = PaperTrail.get_version(inserted_person, prefix: tenant) |> serialize + assert Person.count() == 0 + assert Version.count() == 0 assert person_count == 1 assert version_count == 3 assert Map.drop(person, [:id, :inserted_at, :updated_at]) == %{ @@ -689,6 +699,8 @@ defmodule PaperTrailTest.StrictModeBangFunctions do updated_person_version = PaperTrail.get_version(updated_person, prefix: tenant) |> serialize + assert Person.count() == 0 + assert Version.count() == 0 assert person_count == 1 assert company_count == 2 assert version_count == 4 @@ -759,6 +771,9 @@ defmodule PaperTrailTest.StrictModeBangFunctions do company_count = Company.count(:multitenant) version_count = Version.count(prefix: tenant) + assert Company.count() == 0 + assert Person.count() == 0 + assert Version.count() == 0 assert person_count == 0 assert company_count == 2 assert version_count == 5 diff --git a/test/paper_trail/paper_trail_version_test.exs b/test/paper_trail/paper_trail_version_test.exs index 0fa1a97e..2f4a2fc7 100644 --- a/test/paper_trail/paper_trail_version_test.exs +++ b/test/paper_trail/paper_trail_version_test.exs @@ -75,11 +75,13 @@ defmodule PaperTrailTest.Version do test "[multi tenant] count works" do versions = add_three_versions(MultiTenant.tenant()) Version.count(prefix: MultiTenant.tenant()) == length(versions) + Version.count() != length(versions) end test "[multi tenant] first works" do add_three_versions(MultiTenant.tenant()) Version.first(prefix: MultiTenant.tenant()) |> serialize == @valid_attrs + Version.first() |> serialize != @valid_attrs end test "[multi tenant] last works" do @@ -92,6 +94,7 @@ defmodule PaperTrailTest.Version do origin: "test", inserted_at: DateTime.from_naive!(~N[1965-04-14 01:00:00.000], "Etc/UTC") } + Version.last() == nil end def add_three_versions(prefix \\ nil) do diff --git a/test/paper_trail/version_queries_test.exs b/test/paper_trail/version_queries_test.exs index ecc35660..37b52ed9 100644 --- a/test/paper_trail/version_queries_test.exs +++ b/test/paper_trail/version_queries_test.exs @@ -99,6 +99,7 @@ defmodule PaperTrailTest.VersionQueries do assert PaperTrail.get_version(Person, last_person.id) == target_version assert PaperTrail.get_version(last_person_multi, prefix: tenant) == target_version_multi assert PaperTrail.get_version(Person, last_person_multi.id, prefix: tenant) == target_version_multi + assert target_version != target_version_multi end test "get_versions gives us the right versions" do @@ -120,6 +121,7 @@ defmodule PaperTrailTest.VersionQueries do assert PaperTrail.get_versions(Person, last_person.id) == target_versions assert PaperTrail.get_versions(last_person_multi, prefix: tenant) == target_versions_multi assert PaperTrail.get_versions(Person, last_person_multi.id, prefix: tenant) == target_versions_multi + assert target_versions != target_versions_multi end test "get_current_model/1 gives us the current record of a version" do