Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: make insert/2 and insert!/2 receive struct or changeset #26

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading