View Source LibEcto (lib_ecto v0.3.10)
LibEcto is a simple wrapper for ecto, make it much easier for daily use.
Why LibEcto
Ecto is a great library, but it's a little bit verbose for daily use.
For example, imaging you have a schema like this:
defmodule Sample.Schema do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, LibEcto.KsuidType, autogenerate: true}
schema "test" do
field :name, :string
field :value, :string
timestamps()
end
def changeset(m, params) do
m
|> cast(params, [:name, :value])
end
end
For most common use case, you need to write a lot of boilerplate code to do simple CRUD operation:
defmodule Sample.DB do
alias Sample.Schema
alias Sample.Repo
import Ecto.Changeset
def insert_one(params) do
Schema.changeset(%Schema{}, params)
|> Repo.insert()
end
def update_one(m, params) do
m
|> change(params)
|> Repo.update()
end
def delete_one(m) do
Repo.delete(m)
end
def get_by_id(id) do
Repo.get(Schema, id, select: [:id, :name, :value])
end
def get_by_id_array(id_array) do
Repo.all(from m in Schema, where: m.id in ^id_array, select: [:id, :name, :value])
end
def get_by_name(name) do
Repo.get_by(Schema, name: name, select: [:id, :name, :value])
end
#... more boilerplate code
# - get by name array
# - get by page
# - get by prefix
end
But!!!!!! With LibEcto, you can code like this:
defmodule Sample.DB do
use LibEcto,
repo: Sample.Repo,
schema: Sample.Schema,
columns: [
:id,
:name,
:value
],
filters: [
:id,
:name
]
def filter(:id, dynamic, %{"id" => value}) when is_bitstring(value),
do: {:ok, dynamic([m], ^dynamic and m.id == ^value)}
def filter(:id, dynamic, %{"id" => value}) when is_list(value),
do: {:ok, dynamic([m], ^dynamic and m.id in ^value)}
def filter(:name, dynamic, %{"name" => value}) when is_bitstring(value),
do: {:ok, dynamic([m], ^dynamic and m.name == ^value)}
def filter(:name, dynamic, %{"name" => {"like", value}}) when is_bitstring(value),
do: {:ok, dynamic([m], ^dynamic and like(m.name, ^value))}
def filter(:name, dynamic, %{"name" => value}) when is_list(value),
do: {:ok, dynamic([m], ^dynamic and m.name in ^value)}
def filter(_, dynamic, _), do: {:ok, dynamic}
def init_filter, do: dynamic([m], true)
# you can use ecto's ability to build complicate query or update or transaction if GenericDB can't satisfy your need
def other_complicated_query_or_update() do
# do something
end
end
LibEcto will generate all the boilerplate code for you, and you can focus on your business logic:
iex> Sample.DB.create_one(%{name: "test", value: "testv"})
{:ok, %Simple.Schema{id: "2JIebKci1ZgKenvhllJa3PMbydB", name: "test", value: "testv"}}
iex> Sample.DB.get_one(%{"name" => "test"})
{:ok, %Simple.Schema{id: "2JIebKci1ZgKenvhllJa3PMbydB", name: "test", value: "testv"}}
iex> Sample.DB.get_one(%{"name" => "not-exists"})
{:ok, nil}
iex> Sample.DB.get_one!(%{"name" => "not-exists"})
{:error, 404}
iex> {:ok, m} = Sample.DB.get_one(%{"name" => "test"})
iex> Sample.DB.update_one(m, name: "test2")
{:ok, %Simple.Schema{id: "2JIebKci1ZgKenvhllJa3PMbydB", name: "test2", value: "testv"}}
All supported functions:
- create_one/1
- get_one/1
- get_one!/1
- get_all/2
- get_limit/4
- count/1
- exists?/1
- get_by_page/5
- update_one/2
- delete_one/1
- delete_all/1
For more usage details, please check the test cases, which covers all the supported functions.
V2
V2 is a complete rewrite of LibEcto, it's much more powerful and flexible. It simply breaks down the original complex macros into more reasonable ones. The only difference with LibEcto is the DB layer, Here's how to use it:
defmodule Test.DB do
@moduledoc false
use LibEctoV2
@repo Repo
@schema Test.Schema
@columns [:id, :name, :value]
@filters [:id, :name]
def filter(:id, dynamic, %{"id" => value}) when is_bitstring(value),
do: {:ok, dynamic([m], ^dynamic and m.id == ^value)}
def filter(:id, dynamic, %{"id" => value}) when is_list(value), do: {:ok, dynamic([m], ^dynamic and m.id in ^value)}
def filter(:name, dynamic, %{"name" => value}) when is_bitstring(value),
do: {:ok, dynamic([m], ^dynamic and m.name == ^value)}
def filter(:name, dynamic, %{"name" => {"like", value}}) when is_bitstring(value),
do: {:ok, dynamic([m], ^dynamic and like(m.name, ^value))}
def filter(:name, dynamic, %{"name" => value}) when is_list(value),
do: {:ok, dynamic([m], ^dynamic and m.name in ^value)}
def filter(_, dynamic, _), do: {:ok, dynamic}
def init_filter, do: dynamic([m], m.removed_at == 0)
end
Installation
The package can be installed by adding lib_ecto
to your list of dependencies in mix.exs
:
def deps do
[
{:lib_ecto, "~> 0.3"}
]
end
Test
Test cases use ecto_sqlite3 as database.
Finished in 1.5 seconds (0.00s async, 1.5s sync)
17 tests, 0 failures
Randomized with seed 336538
Generating cover results ...
Percentage | Module
-----------|--------------------------
40.00% | LibEcto.KsuidType
78.95% | LibEcto.Ksuid
100.00% | LibEcto
100.00% | LibEcto.Base62
-----------|--------------------------
76.19% | Total
Coverage test failed, threshold not met:
Coverage: 76.19%
Threshold: 90.00%
Generated HTML coverage results in "cover" directory