Packages
ecto
0.13.0
3.14.1
3.14.0
3.13.6
3.13.5
3.13.4
3.13.3
3.13.2
3.13.1
3.13.0
3.12.6
3.12.5
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.2
3.11.1
3.11.0
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.4
3.8.3
3.8.2
3.8.1
3.8.0
3.7.2
3.7.1
3.7.0
3.6.2
3.6.1
3.6.0
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.5.0-rc.1
3.5.0-rc.0
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.1
3.0.0-rc.0
2.2.12
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.2.0-rc.1
2.2.0-rc.0
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.1.0-rc.5
2.1.0-rc.4
2.1.0-rc.3
2.1.0-rc.2
2.1.0-rc.1
2.1.0-rc.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-beta.2
2.0.0-beta.1
2.0.0-beta.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.16.0
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.12.0-rc
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
A toolkit for data mapping and language integrated query for Elixir
Current section
Files
Jump to
Current section
Files
lib/ecto/model.ex
defmodule Ecto.Model do
@moduledoc """
Provides convenience functions for defining and working
with models.
## Using
When used, `Ecto.Model` works as an "umbrella" module that adds
common functionality to your module:
* `use Ecto.Schema` - provides the API necessary to define schemas
* `import Ecto.Changeset` - functions for building and manipulating changesets
* `import Ecto.Model` - functions for working with models and their associations
* `import Ecto.Query, only: [from: 2]` - for generating and manipulating queries
Plus all the modules existing in `Ecto.Model.*` are brought in
too:
* `use Ecto.Model.Callbacks` - provides lifecycle callbacks
* `use Ecto.Model.Timestamps` - automatically set `inserted_at` and
`updated_at` fields declared via `Ecto.Schema.timestamps/1`
* `use Ecto.Model.OptimisticLock` - makes the `optimistic_lock/1` macro
available
However, you can avoid using `Ecto.Model` altogether in favor
of cherry-picking any of the functionality above.
## Importing
You may want to import this module in contexts where you are
working with different models. For example, in a web application,
you may want to import this module into your plugs to provide
conveniences for building and accessing model information.
"""
@doc false
defmacro __using__(_opts) do
quote do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query, only: [from: 2]
import Ecto.Model
use Ecto.Model.OptimisticLock
use Ecto.Model.Timestamps
use Ecto.Model.Callbacks
end
end
@type t :: %{__struct__: atom}
@doc """
Returns the model primary keys as a keyword list.
"""
@spec primary_key(t) :: Keyword.t
def primary_key(%{__struct__: model} = struct) do
Enum.map model.__schema__(:primary_key), fn(field) ->
{field, Map.fetch!(struct, field)}
end
end
@doc """
Returns the model primary keys as a keyword list.
Raises `Ecto.NoPrimaryKeyError` if the model has no
primary key field.
"""
@spec primary_key!(t) :: Keyword.t | no_return
def primary_key!(struct) do
case primary_key(struct) do
[] -> raise Ecto.NoPrimaryKeyError, model: struct
pk -> pk
end
end
@doc """
Builds a struct from the given `assoc` in `model`.
## Examples
If the relationship is a `has_one` or `has_many` and
the key is set in the given model, the key will automatically
be set in the built association:
iex> post = Repo.get(Post, 13)
%Post{id: 13}
iex> build(post, :comments)
%Comment{id: nil, post_id: 13}
Note though it doesn't happen with belongs to cases, as the
key is often the primary key and such is usually generated
dynamically:
iex> comment = Repo.get(Post, 13)
%Comment{id: 13, post_id: 25}
iex> build(comment, :post)
%Post{id: nil}
You can also pass the attributes, which can be a map or
a keyword list, to set the struct's fields except the
association key.
iex> build(post, :comments, text: "cool")
%Comment{id: nil, post_id: 13, text: "cool"}
iex> build(post, :comments, %{text: "cool"})
%Comment{id: nil, post_id: 13, text: "cool"}
iex> build(post, :comments, post_id: 1)
%Comment{id: nil, post_id: 13}
"""
def build(%{__struct__: model} = struct, assoc, attributes \\ %{}) do
assoc = Ecto.Association.association_from_model!(model, assoc)
assoc.__struct__.build(assoc, struct, attributes)
end
@doc """
Builds a query for the association in the given model or models.
## Examples
In the example below, we get all comments associated to the given
post:
post = Repo.get Post, 1
Repo.all assoc(post, :comments)
`assoc/2` can also receive a list of posts, as long as the posts are
not empty:
posts = Repo.all from p in Post, where: is_nil(p.published_at)
Repo.all assoc(posts, :comments)
"""
def assoc(model_or_models, assoc) do
structs = List.wrap(model_or_models)
if structs == [] do
raise ArgumentError, "cannot retrieve association #{inspect assoc} for empty list"
end
model = hd(structs).__struct__
assoc = %{owner_key: owner_key} =
Ecto.Association.association_from_model!(model, assoc)
values =
for struct <- structs,
assert_struct!(model, struct),
key = Map.fetch!(struct, owner_key),
do: key
assoc.__struct__.assoc_query(assoc, values)
end
@doc """
Update the database source of the model
## Examples
post = Repo.get Post, 1
new_post = Ecto.Model.put_source(post, "user_posts")
"""
def put_source(model, new_source) do
put_in model.__meta__.source, new_source
end
defp assert_struct!(model, %{__struct__: struct}) do
if struct != model do
raise ArgumentError, "expected a homogeneous list containing the same struct, " <>
"got: #{inspect model} and #{inspect struct}"
else
true
end
end
end