Skip to content

Commit

Permalink
rename to ecto_clone
Browse files Browse the repository at this point in the history
  • Loading branch information
grantwest committed Dec 2, 2023
1 parent aaa31f7 commit 35c1200
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ erl_crash.dump
*.ez

# Ignore package tarball (built via "mix hex.build").
ecto_graf-*.tar
ecto_clone-*.tar

# Temporary files, for example, from tests.
/tmp/
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# EctoGraf
# EctoClone

[![Build Status](https://github.com/grantwest/ecto_graf/actions/workflows/ci.yml/badge.svg)](https://github.com/grantwest/ecto_graf/actions/workflows/ci.yml)
[![Version](https://img.shields.io/hexpm/v/ecto_graf.svg)](https://hex.pm/packages/ecto_graf)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/ecto_graf/)
[![Download](https://img.shields.io/hexpm/dt/ecto_graf.svg)](https://hex.pm/packages/ecto_graf)
[![Build Status](https://github.com/grantwest/ecto_clone/actions/workflows/ci.yml/badge.svg)](https://github.com/grantwest/ecto_clone/actions/workflows/ci.yml)
[![Version](https://img.shields.io/hexpm/v/ecto_clone.svg)](https://hex.pm/packages/ecto_clone)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/ecto_clone/)
[![Download](https://img.shields.io/hexpm/dt/ecto_clone.svg)](https://hex.pm/packages/ecto_clone)
[![License](https://img.shields.io/badge/License-0BSD-blue.svg)](https://opensource.org/licenses/0bsd)
[![Last Updated](https://img.shields.io/github/last-commit/grantwest/ecto_graf.svg)](https://github.com/grantwest/ecto_graf/commits/master)
[![Last Updated](https://img.shields.io/github/last-commit/grantwest/ecto_clone.svg)](https://github.com/grantwest/ecto_clone/commits/master)

Take advantage of Ecto associations to deep clone data in your database.

To clone a post with it's comments and tags:

```elixir
{:ok, cloned_post_id} = EctoGraf.clone(%Post{id: 5}, Repo, %{title: "new title"}, [Comment, PostTag])
{:ok, cloned_post_id} = EctoClone.clone(%Post{id: 5}, Repo, %{title: "new title"}, [Comment, PostTag])
```

See [clone docs](https://hexdocs.pm/ecto_graf/EctoGraf.html#clone/4) for more information and examples.
See [clone docs](https://hexdocs.pm/ecto_clone/EctoClone.html#clone/4) for more information and examples.

### Todo

Expand Down
10 changes: 5 additions & 5 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import Config

config :logger, level: :warning

config :ecto_graf, EctoGraf.Repo,
config :ecto_clone, EctoClone.Repo,
username: "postgres",
password: "postgres",
hostname: System.get_env("DB_HOSTNAME", "localhost"),
database: "ecto_graf_test#{System.get_env("MIX_TEST_PARTITION")}",
database: "ecto_clone_test#{System.get_env("MIX_TEST_PARTITION")}",
pool: Ecto.Adapters.SQL.Sandbox,
priv: "test/support",
pool_size: 10

config :ecto_graf,
ecto_repos: [EctoGraf.Repo]
config :ecto_clone,
ecto_repos: [EctoClone.Repo]

config :ecto_graf, :sandbox, Ecto.Adapters.SQL.Sandbox
config :ecto_clone, :sandbox, Ecto.Adapters.SQL.Sandbox
16 changes: 8 additions & 8 deletions lib/ecto_graf.ex → lib/ecto_clone.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule EctoGraf do
defmodule EctoClone do
@moduledoc """
Documentation for `EctoGraf`.
Documentation for `EctoClone`.
"""

import Ecto.Query
Expand All @@ -22,7 +22,7 @@ defmodule EctoGraf do
`new_attrs` is a map that will override values on the clone of the target.
`related_schemas_with_options` is the list of schemas to clone in relation to the target.
The order of schemas does not matter, EctoGraf determines clone order by associations.
The order of schemas does not matter, EctoClone determines clone order by associations.
See examples for setting options per schema. Suppored options include:
`map` - a function that takes the source row fields as a map and returns the cloned row fields
Expand All @@ -35,32 +35,32 @@ defmodule EctoGraf do
To clone a post with it's comments:
post = Repo.insert!(%Post{title: "hello"})
Repo.insert!(%Comment{body: "p", post_id: post.id})
{:ok, clone_id} = EctoGraf.clone(post, Repo, %{title: "New Title"}, [Comment])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{title: "New Title"}, [Comment])
To clone a post with it's tags, comments, comment edits:
EctoGraf.clone(post, Repo, %{}, [
EctoClone.clone(post, Repo, %{}, [
PostTag,
Comment,
CommentEdit
])
Options on schemas allow chaning values of cloned records:
EctoGraf.clone(post, Repo, %{}, [
EctoClone.clone(post, Repo, %{}, [
PostTag,
[Comment, map: fn comment -> Map.put(comment, :likes, 0) end],
CommentEdit
])
The where option allows selective cloning at the schema level:
EctoGraf.clone(post, Repo, %{}, [
EctoClone.clone(post, Repo, %{}, [
PostTag,
[Comment, where: fn query -> where(query, [comment], comment.likes >= 0) end],
CommentEdit
])
If you use the ecto timestamps and want to set inserted_at on all of your cloned records, you can use the map option globally:
now = your_get_timestamp_function()
EctoGraf.clone(
EctoClone.clone(
post,
Repo,
%{},
Expand Down
13 changes: 6 additions & 7 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
defmodule EctoGraf.MixProject do
defmodule EctoClone.MixProject do
use Mix.Project

@version "0.2.0"
@description "Leverage Ecto associations to deep clone db records & do other helpful stuff"
@source_url "https://github.com/grantwest/ecto_graf"
@source_url "https://github.com/grantwest/ecto_clone"

def project do
[
app: :ecto_graf,
app: :ecto_clone,
version: @version,
elixir: "~> 1.13",
elixirc_paths: elixirc_paths(Mix.env()),
Expand All @@ -19,7 +19,7 @@ defmodule EctoGraf.MixProject do
preferred_cli_env: [
"test.watch": :test
],
name: "EctoGraf",
name: "EctoClone",
docs: docs()
]
end
Expand All @@ -30,7 +30,7 @@ defmodule EctoGraf.MixProject do
]

case Mix.env() do
:test -> always ++ [mod: {EctoGraf.Test.Application, []}]
:test -> always ++ [mod: {EctoClone.Test.Application, []}]
_ -> always
end
end
Expand All @@ -40,7 +40,7 @@ defmodule EctoGraf.MixProject do

defp deps do
[
{:ecto, ">= 3.9.0", optional: true},
{:ecto, ">= 3.9.0"},
{:ecto_sql, ">= 3.9.0", only: [:test]},
{:postgrex, ">= 0.16.0", only: [:test]},
{:mix_test_watch, "~> 1.0", only: [:dev, :test], runtime: false},
Expand Down Expand Up @@ -70,7 +70,6 @@ defmodule EctoGraf.MixProject do
source_url: @source_url,
extras: ["README.md"],
main: "readme"
# main: "readme",
]
end
end
58 changes: 30 additions & 28 deletions test/clone_test.exs → test/ecto_clone_test.exs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
defmodule EctoGraf.CloneTest do
defmodule EctoClone.CloneTest do
use ExUnit.Case, async: true
import Ecto.Query
alias EctoGraf.Repo
alias EctoGraf.Schemas.Comment
alias EctoGraf.Schemas.CommentEdit
alias EctoGraf.Schemas.CommentPair
alias EctoGraf.Schemas.Post
alias EctoGraf.Schemas.PostTag
alias EctoGraf.Schemas.Tag
alias EctoGraf.Schemas.User
alias EctoClone.Repo
alias EctoClone.Schemas.Comment
alias EctoClone.Schemas.CommentEdit
alias EctoClone.Schemas.CommentPair
alias EctoClone.Schemas.Post
alias EctoClone.Schemas.PostTag
alias EctoClone.Schemas.Tag
alias EctoClone.Schemas.User

doctest EctoClone

test "clone simplest post" do
post = Repo.insert!(%Post{title: "hello"})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [])

assert %{
posts: [%Post{id: ^clone_id, title: "hello", author_id: nil}],
Expand All @@ -31,7 +33,7 @@ defmodule EctoGraf.CloneTest do
post = Repo.insert!(%Post{title: "hello", author_id: user.id})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [])

user_id = user.id

Expand All @@ -49,7 +51,7 @@ defmodule EctoGraf.CloneTest do
post = Repo.insert!(%Post{title: "hello"})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{title: "newtitle"}, [])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{title: "newtitle"}, [])

assert %{
posts: [%Post{id: ^clone_id, title: "newtitle"}],
Expand All @@ -66,7 +68,7 @@ defmodule EctoGraf.CloneTest do
Repo.insert!(%Comment{body: "first", post_id: post.id})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [Comment])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [Comment])

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand All @@ -84,7 +86,7 @@ defmodule EctoGraf.CloneTest do
Repo.insert!(%Comment{body: "c", post_id: post.id, parent_id: comment.id})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [Comment])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [Comment])

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand All @@ -105,7 +107,7 @@ defmodule EctoGraf.CloneTest do
Repo.insert!(%CommentEdit{diff: "d", comment_id: comment.id})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [Comment, CommentEdit])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [Comment, CommentEdit])

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand All @@ -123,7 +125,7 @@ defmodule EctoGraf.CloneTest do
Repo.insert!(%PostTag{post_id: post.id, tag_id: tag.id})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [PostTag])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [PostTag])

tag_id = tag.id

Expand All @@ -144,7 +146,7 @@ defmodule EctoGraf.CloneTest do
Repo.insert!(%CommentPair{comment_a_id: comment_a.id, comment_b_id: comment_b.id})
before = all_entires()

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [Comment, CommentPair])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [Comment, CommentPair])

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand Down Expand Up @@ -174,7 +176,7 @@ defmodule EctoGraf.CloneTest do
{^count, nil} = Repo.insert_all(Comment, comments)
end)

{:ok, clone_id} = EctoGraf.clone(post, Repo, %{}, [Comment])
{:ok, clone_id} = EctoClone.clone(post, Repo, %{}, [Comment])

count = Repo.aggregate(from(c in Comment, where: c.post_id == ^clone_id), :count)
assert count == comment_count
Expand All @@ -186,7 +188,7 @@ defmodule EctoGraf.CloneTest do
before = all_entires()

{:ok, clone_id} =
EctoGraf.clone(post, Repo, %{}, [[Comment, map: fn c -> Map.put(c, :body, "new") end]])
EctoClone.clone(post, Repo, %{}, [[Comment, map: fn c -> Map.put(c, :body, "new") end]])

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand All @@ -204,7 +206,7 @@ defmodule EctoGraf.CloneTest do
before = all_entires()

{:ok, clone_id} =
EctoGraf.clone(post, Repo, %{}, [Comment], map: fn c -> Map.put(c, :body, "new") end)
EctoClone.clone(post, Repo, %{}, [Comment], map: fn c -> Map.put(c, :body, "new") end)

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand All @@ -222,7 +224,7 @@ defmodule EctoGraf.CloneTest do
before = all_entires()

{:ok, clone_id} =
EctoGraf.clone(
EctoClone.clone(
post,
Repo,
%{},
Expand All @@ -246,7 +248,7 @@ defmodule EctoGraf.CloneTest do
before = all_entires()

{:ok, clone_id} =
EctoGraf.clone(
EctoClone.clone(
post,
Repo,
%{},
Expand All @@ -271,7 +273,7 @@ defmodule EctoGraf.CloneTest do
before = all_entires()

{:ok, clone_id} =
EctoGraf.clone(post, Repo, %{}, [[Comment, where: &where(&1, [c], c.body == "1")]])
EctoClone.clone(post, Repo, %{}, [[Comment, where: &where(&1, [c], c.body == "1")]])

assert %{
posts: [%Post{id: ^clone_id, title: "hello"}],
Expand All @@ -285,17 +287,17 @@ defmodule EctoGraf.CloneTest do

test "target not found error" do
post = %Post{id: -1}
assert EctoGraf.clone(post, Repo, %{}, []) == {:error, "target not found"}
assert EctoClone.clone(post, Repo, %{}, []) == {:error, "target not found"}
end

test "no association to target error" do
user = Repo.insert!(%User{name: "alice"})
post = Repo.insert!(%Post{title: "hello", author_id: user.id})

assert_raise RuntimeError,
"Elixir.EctoGraf.Schemas.User has no belongs_to or has_one association to Elixir.EctoGraf.Schemas.Post",
"Elixir.EctoClone.Schemas.User has no belongs_to or has_one association to Elixir.EctoClone.Schemas.Post",
fn ->
EctoGraf.clone(post, Repo, %{}, [User])
EctoClone.clone(post, Repo, %{}, [User])
end
end

Expand All @@ -306,9 +308,9 @@ defmodule EctoGraf.CloneTest do
Repo.insert!(%CommentEdit{diff: "d", comment_id: comment.id})

assert_raise RuntimeError,
"Elixir.EctoGraf.Schemas.Comment missing from schemas to clone",
"Elixir.EctoClone.Schemas.Comment missing from schemas to clone",
fn ->
EctoGraf.clone(post, Repo, %{}, [CommentEdit])
EctoClone.clone(post, Repo, %{}, [CommentEdit])
end
end

Expand Down
4 changes: 0 additions & 4 deletions test/ecto_graf_test.exs

This file was deleted.

6 changes: 3 additions & 3 deletions test/support/application.ex
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
defmodule EctoGraf.Test.Application do
defmodule EctoClone.Test.Application do
use Application

@impl true
def start(_type, _args) do
children = [
EctoGraf.Repo
EctoClone.Repo
]

opts = [strategy: :one_for_one, name: EctoGraf.Supervisor]
opts = [strategy: :one_for_one, name: EctoClone.Supervisor]
Supervisor.start_link(children, opts)
end
end
Loading

0 comments on commit 35c1200

Please sign in to comment.