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 a primary key named `id`
of type `:integer` and `belongs_to` associations in the schema will generate
foreign keys of type `:integer`. 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, autogenerate: true}`. 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_opts` - configures the default timestamps type
    used by `timestamps`. Defaults to `[type: Ecto.DateTime, usec: false]`;

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

The advantage of configuring 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 `binary_id`'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, :binary_id, autogenerate: true}
          @foreign_key_type :binary_id
        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
:---------------------- | :---------------------- | :---------------------
`:id`                   | `integer`               | 1, 2, 3
`:binary_id`            | `binary`                | `<<int, int, int, ...>>`
`: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, ...>>`
`{: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}`

**Note:** Although Ecto provides `:date`, `:time` and `:datetime`, you
likely want to use `Ecto.Date`, `Ecto.Time` and `Ecto.DateTime` respectively.
See the Custom types sections below about types that enhance the primitive
ones.

### ID types

In the table above, you may have noticed that Elixir supports two ID
types: `:id` and `:binary_id`. Those types are equivalent to `:id`
and `:binary_id` with the difference their semantics is specified by
the underlying adapter/database.

For example, if you use the `:id` type with `:autogenerate`, it means
the database will be responsible for auto-generation the id.

Similarly, `:binary_id` means the adapter/database will auto-generate
an ID in binary format, which may be `Ecto.UUID` for databases like
PostgreSQL and MySQL, or some specific ObjectID or RecordID often
imposed by NoSQL databases.

For those reasons, it is recommended to use those types for primary
keys and associations.

### Custom types

Sometimes the primitive types in Ecto are too primitive. For example,
`:datetime` relies on the underling tuple representation instead of
representing itself as something nicer like a map/struct. That's where
`Ecto.DateTime` comes in.

`Ecto.DateTime` 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             | Database type           | Elixir type
:---------------------- | :---------------------- | :---------------------
`Ecto.DateTime`         | `:datetime`             | `%Ecto.DateTime{}`
`Ecto.Date`             | `:date`                 | `%Ecto.Date{}`
`Ecto.Time`             | `:time`                 | `%Ecto.Time{}`
`Ecto.UUID`             | `:uuid`                 | "uuid-string"

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 sending them to the
adapter/database.

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 a list of the field that is the primary
  key or [] 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__(:autogenerate)` - Non-virtual fields that are auto generated on insert;

* `__schema__(:autogenerate_id)` - Primary key that is auto generated on insert;

* `__schema__(:load, source, idx, values, id_types)` - Loads a new model from a tuple of non-virtual
  field values starting at the given index. Typically used by adapters;

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.