Ecto.Schema

Parsed documentation:
View on GitHub
Defines a schema for a model.

A schema is a struct with associated metadata that is persisted to a
repository. Every schema model is also a struct, that means that you work
with models just like you would work with structs.

## Example

    defmodule User do
      use Ecto.Schema

      schema "users" do
        field :name, :string
        field :age, :integer, default: 0
        has_many :posts, Post
      end
    end

By default, a schema will generate both a primary key named `id`
of type `:integer` and `belongs_to` associations will generate
foreign keys of type `:integer` too. Those setting can be configured
below.

## Schema attributes

The schema supports some attributes to be set before hand,
configuring the defined schema.

Those attributes are:

  * `@primary_key` - configures the schema primary key. It expects
    a tuple with the primary key name, type and options. Defaults
    to `{:id, :integer, []}`. When set to false, does not define
    a primary key in the model;

  * `@foreign_key_type` - configures the default foreign key type
    used by `belongs_to` associations. Defaults to `:integer`;

  * `@timestamps_type` - configures the default timestamps type
    used by `timestamps`. Defaults to `Ecto.DateTime`;

  * `@derive` - the same as `@derive` available in `Kernel.defstruct/1`
    as the schema defines a struct behind the scenes;

The advantage of defining configure the schema via those attributes
is that they can be set with a macro to configure application wide
defaults. For example, if you would like to use `uuid`'s in all of
your application models, you can do:

    # Define a module to be used as base
    defmodule MyApp.Model do
      defmacro __using__(_) do
        quote do
          use Ecto.Model
          @primary_key {:id, :uuid, []}
          @foreign_key_type :uuid
        end
      end
    end

    # Now use MyApp.Model to define new models
    defmodule MyApp.Comment do
      use MyApp.Model

      schema "comments" do
        belongs_to :post, MyApp.Post
      end
    end

Any models using `MyApp.Model` will get the `:id` field with type
`:uuid` as primary key.

The `belongs_to` association on `MyApp.Comment` will also define
a `:post_id` field with `:uuid` type that references the `:id` of
the `MyApp.Post` model.

## Types and casting

When defining the schema, types need to be given. Types are split
in two categories, primitive types and custom types.

### Primitive types

The primitive types are:

Ecto type               | Elixir type             | Literal syntax in query
:---------------------- | :---------------------- | :---------------------
`:integer`              | `integer`               | 1, 2, 3
`:float`                | `float`                 | 1.0, 2.0, 3.0
`:boolean`              | `boolean`               | true, false
`:string`               | UTF-8 encoded `string`  | "hello"
`:binary`               | `binary`                | `<<int, int, int, ...>>`
`:uuid`                 | 16 byte `binary`        | `uuid(binary_or_string)`
`{:array, inner_type}`  | `list`                  | `[value, value, value, ...]`
`:decimal`              | [`Decimal`](https://github.com/ericmj/decimal)
`:datetime`             | `{{year, month, day}, {hour, min, sec}}`
`:date`                 | `{year, month, day}`
`:time`                 | `{hour, min, sec}`

### Custom types

Sometimes the primitive types in Ecto are too primitive. For example,
`:uuid` relies on the underling binary representation instead of
representing itself as a readable string. That's when `Ecto.UUID`
comes in.

`Ecto.UUID` is a  custom type. A custom type is a module that
implements the `Ecto.Type` behaviour. By default, Ecto provides the
following custom types:

Custom type             | Ecto type               | Elixir type
:---------------------- | :---------------------- | :---------------------
`Ecto.UUID`             | `:uuid`                 | "uuid-string"
`Ecto.DateTime`         | `:datetime`             | `%Ecto.DateTime{}`
`Ecto.Date`             | `:date`                 | `%Ecto.Date{}`
`Ecto.Time`             | `:time`                 | `%Ecto.Time{}`

Ecto allow developers to provide their own types too. Read the
`Ecto.Type` documentation for more information.

### Casting

When directly manipulating the struct, it is the responsibility of
the developer to ensure the field values have the proper type. For
example, you can create a weather struct with an invalid value
for `temp_lo`:

    iex> weather = %Weather{temp_lo: "0"}
    iex> weather.temp_lo
    "0"

However, if you attempt to persist the struct above, an error will
be raised since Ecto validates the types when building the query.

Therefore, when working and manipulating external data, it is
recommended the usage of `Ecto.Changeset`'s that are able to filter
and properly cast external data. In fact, `Ecto.Changeset` and custom
types provide a powerful combination to extend Ecto types and queries.

Finally, models can also have virtual fields by passing the
`virtual: true` option. These fields are not persisted to the database
and can optionally not be type checked by declaring type `:any`.

## Reflection

Any schema module will generate the `__schema__` function that can be
used for runtime introspection of the schema:

* `__schema__(:source)` - Returns the source as given to `schema/2`;
* `__schema__(:primary_key)` - Returns the field that is the primary
  key or `nil` if there is none;

* `__schema__(:fields)` - Returns a list of all non-virtual field names;
* `__schema__(:field, field)` - Returns the type of the given non-virtual field;

* `__schema__(:associations)` - Returns a list of all association field names;
* `__schema__(:association, assoc)` - Returns the association reflection of the given assoc;

* `__schema__(:read_after_writes)` - Non-virtual fields that must be read back
  from the database after every write (insert or update);

* `__schema__(:load, struct \\ __struct__(), fields_or_idx, values)` - Loads a
  new model struct from a tuple of non-virtual field values starting at the given
  index or defined by the given fields;

Furthermore, both `__struct__` and `__changeset__` functions are
defined so structs and changeset functionalities are available.
No suggestions.
Please help! Open an issue on GitHub if this assessment is incorrect.