Elixir Structs :
Elixir provides Structs.Structs define a set of fields.
A Struct will be referenced by the name of the module where it is defined
defmodule User do
defstruct [:name, :email]
end
user = %User{name: "John Doe", email: "john@example.com"}
Once a user Struct is created, we can access its email via user.email.
Relational Mappers :
An Object Relational Mapper manage the translation of objects in to relational database, and vice versa
Similarly Ecto provides schemas that maps any Data source(Database Tables) in to Elixir Struct.When applied to your Database, Elixir schemas are Relational Mappers.
Therefore while Ecto is not a Relational Mapper, it contains a Relational Mapper as a part of the many different tools it offers.
For
example, the schema below ties the fields name, email, inserted_at and updated_at to fields similarly named in the users table:
defmodule MyApp.User do
use Ecto.Schema
schema "users" do
field :name
field :email
timestamps()
end
end
The appeal behind schemas is that you define the shape of the data once and you can use
this shape to retrieve data from the database as well as coordinate changes happening on
the data
MyApp.User
|> MyApp.Repo.get!(13)
|> Ecto.Changeset.cast([name: "new name"], [:name, :email])
|> MyApp.Repo.update!
By relying on the schema information, Ecto knows how to read and write data without extra
input from the developer.
Schemaless Queries :
Most queries in Ecto are written using schemas. For example, to retrieve all posts in a
database, one may write:
MyApp.Repo.all(Post)
When writing schemaless queries, the select expression must be explicitly written with all the
desired fields.
Inserts, updates and deletes can be done without schemas via insert_all ,
update_all and delete_all respectively:
MyApp.Repo.insert_all(Post, [[title: "hello", body: "world"],
[title: "another", body: "post"]])
If you are writing a reporting view, it may be counter-productive to think how your existing
application schemas relate to the report being generated. It is often simpler to write a query
that returns only the data you need, without trying to fit the data into existing schemas:
import Ecto.Query
def running_activities(start_at, end_at)
MyApp.Repo.all(
from u in "users",
join: a in "activities",
on: a.user_id == u.id,
where: a.start_at > type(^start_at, :naive_datetime) and
a.end_at < type(^end_at, :naive_datetime),
group_by: a.user_id,
select: %{user_id: a.user_id, interval: a.end_at - a.start_at, count: count(u.id
)}
)
end
The function above does not rely on schemas. It returns only the data that matters for
building the report.
Notice how we use the type/2 function to specify what is the expected
type of the argument we are interpolating, benefiting from the same type casting guarantees
a schema would give.
Ecto 2.0 also makes regular schemaless queries more expressive.
In early versions, you would have to write verbose select expressions such as:
from p in "posts", select: %{title: p.title, body: p.body}
With Ecto 2.0 you can simply pass the desired list of fields directly:
from "posts", select: [:title, :body]
The two queries above are equivalent.Ecto will automatically convert the list of fields to a map or a struct.
Support for passing a list of fields or keyword lists has been added to almost all query
constructs in Ecto 2.0. For example, we can use an update query to change the title of a
given post without a schema:
def update_title(post, new_title) do
query = from "posts", where: [id: ^post.id], update: [set: [title: ^new_title]]
MyApp.Repo.update_all(query)
end
The update construct supports four commands:
- :set - sets the given column to the given values
- :inc - increments the given column by the given value
- :push - pushes (appends) the given value to the end of an array column
- :pull - pulls (removes) the given value from an array column
:inc Example:
def increment_page_views(post) do
query = from "posts", where: [id: ^post.id], update: [inc: [page_views: 1]]
MyApp.Repo.update_all(query)
end
Comments
Post a Comment