Skip to content

Commit

Permalink
refactor: insert funcions receive struct or changeset
Browse files Browse the repository at this point in the history
  • Loading branch information
DanubioLima committed Aug 24, 2024
1 parent 60c25aa commit 95f5003
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 33 deletions.
50 changes: 38 additions & 12 deletions lib/swiss_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -565,26 +565,52 @@ defmodule SwissSchema do
get_by!.(__MODULE__, clauses, opts)
end

def insert(struct_or_changeset, opts \\ [])

@impl SwissSchema
def insert(%{} = params, opts \\ []) do
def insert(%Ecto.Changeset{data: %module{}} = changeset, opts) do
case module do
__MODULE__ -> perform_insert(changeset, opts)
_ -> {:error, :not_same_schema_module}
end
end

@impl SwissSchema
def insert(%module{} = struct, opts) when is_struct(struct) do
case module do
__MODULE__ -> perform_insert(struct, opts)
_ -> {:error, :not_same_schema_module}
end
end

defp perform_insert(source, opts) do
repo = Keyword.get(opts, :repo, unquote(repo))
insert = Function.capture(repo, :insert, 2)
changeset = Keyword.get(opts, :changeset, @_swiss_schema.default_changeset)
insert.(source, opts)
end

struct(__MODULE__)
|> changeset.(params)
|> insert.(opts)
def insert!(struct_or_changeset, opts \\ [])

@impl SwissSchema
def insert!(%Ecto.Changeset{data: %module{}} = changeset, opts) do
case module do
__MODULE__ -> perform_insert!(changeset, opts)
_ -> {:error, :not_same_schema_module}
end
end

@impl SwissSchema
def insert!(%{} = params, opts \\ []) do
repo = Keyword.get(opts, :repo, unquote(repo))
insert! = Function.capture(repo, :insert!, 2)
changeset = Keyword.get(opts, :changeset, @_swiss_schema.default_changeset)
def insert!(%module{} = struct, opts) when is_struct(struct) do
case module do
__MODULE__ -> perform_insert!(struct, opts)
_ -> {:error, :not_same_schema_module}
end
end

struct(__MODULE__)
|> changeset.(params)
|> insert!.(opts)
defp perform_insert!(source, opts) do
repo = Keyword.get(opts, :repo, unquote(repo))
insert = Function.capture(repo, :insert!, 2)
insert.(source, opts)
end

@impl SwissSchema
Expand Down
19 changes: 19 additions & 0 deletions test/support/book_schema.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule SwissSchemaTest.Book do
@moduledoc false

use Ecto.Schema
use SwissSchema, repo: SwissSchemaTest.Repo
import Ecto.Changeset

schema "users" do
field(:title, :string)
field(:description, :string)
end

@impl SwissSchema
def changeset(%SwissSchemaTest.Book{} = book, %{} = params) do
book
|> cast(params, [:title, :description])
|> validate_required([:title])
end
end
12 changes: 12 additions & 0 deletions test/support/create_books.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule SwissSchemaTest.CreateBooks do
@moduledoc false

use Ecto.Migration

def change do
create table(:books) do
add(:title, :string, null: false)
add(:description, :string)
end
end
end
File renamed without changes.
71 changes: 50 additions & 21 deletions test/swiss_schema_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule SwissSchemaTest do
use ExUnit.Case
alias SwissSchemaTest.Book
alias SwissSchemaTest.Repo
alias SwissSchemaTest.Repo2
alias SwissSchemaTest.User
Expand All @@ -16,6 +17,16 @@ defmodule SwissSchemaTest do
}
end

defp book_mock(opts \\ []) when is_list(opts) do
title = Keyword.get(opts, :title, "book-title-#{Ecto.UUID.generate()}")
description = Keyword.get(opts, :description, "book-description-long-#{Ecto.UUID.generate()}")

%Book{
title: title,
description: description
}
end

setup_all do
Enum.each([Repo, Repo2], fn repo ->
Ecto.Adapters.Postgres.storage_up(repo.config())
Expand Down Expand Up @@ -499,47 +510,65 @@ defmodule SwissSchemaTest do

describe "insert/2" do
test "inserts a row" do
user = user_mock() |> Map.from_struct()
user_changeset()
|> assert_user()
end

assert {:ok, %User{} = user} = User.insert(user)
assert ^user = Repo.get!(User, user.id)
test "accepts a struct" do
user_mock()
|> assert_user()
end

test "accepts a custom Ecto repo thru :repo opt" do
params = user_mock() |> Map.from_struct()
user_changeset()
|> assert_user(Repo2)
end

test "not accepts changeset from other schema" do
changeset = book_changeset()

assert {:ok, %User{id: uid}} = User.insert(params, repo: Repo2)
assert %User{} = Repo2.get!(User, uid)
assert {:error, :not_same_schema_module} = User.insert(changeset)
end

test "accepts a custom changeset function thru :changeset opt" do
params = user_mock() |> Map.take([:username, :email])
defp user_changeset() do
user_mock() |> Ecto.Changeset.cast(%{}, [:username, :email, :lucky_number])
end

assert {:ok, %User{} = user} = User.insert(params, changeset: &User.changeset_custom/2)
assert is_integer(user.lucky_number)
defp book_changeset() do
book_mock() |> Book.changeset(%{})
end

defp assert_user(changeset_or_struct, repo \\ Repo) do
assert {:ok, %User{id: uid}} = User.insert(changeset_or_struct, repo: repo)
assert %User{} = repo.get!(User, uid)
end
end

describe "insert!/2" do
test "inserts a row" do
user = user_mock() |> Map.from_struct()
user_changeset()
|> assert_user!()
end

assert %User{} = user = User.insert!(user)
assert ^user = Repo.get!(User, user.id)
test "accepts a struct" do
user_mock()
|> assert_user!()
end

test "accepts a custom Ecto repo thru :repo opt" do
params = user_mock() |> Map.from_struct()

assert %User{id: uid} = User.insert!(params, repo: Repo2)
assert %User{} = Repo2.get!(User, uid)
user_changeset()
|> assert_user!(Repo2)
end

test "accepts a custom changeset function thru :changeset opt" do
params = user_mock() |> Map.take([:username, :email])
test "not accepts changeset from other schema" do
changeset = book_changeset()

assert user = User.insert!(params, changeset: &User.changeset_custom/2)
assert is_integer(user.lucky_number)
assert {:error, :not_same_schema_module} = User.insert!(changeset)
end

defp assert_user!(changeset_or_struct, repo \\ Repo) do
assert %User{id: uid} = User.insert!(changeset_or_struct, repo: repo)
assert %User{} = repo.get!(User, uid)
end
end

Expand Down

0 comments on commit 95f5003

Please sign in to comment.