A specialized drop-in replacement for use Ecto.Schema, tuned for the
Recall (Mnesia) adapter.
Ecto.Schema is built for SQL adapters: a query carries field names, and the
adapter resolves each name to a storage position at runtime. Recall stores
every Ecto field as a positional Mnesia attribute, so a field's position is
fixed the moment the schema is defined — there's nothing to discover at query
time. This module bakes that knowledge into dedicated, compiled functions on
the schema itself, so querying by a field dispatches straight to a function
that already knows its position. This is the only schema layout the adapter
understands; there is no runtime-lookup path for a plain Ecto.Schema.
Use it like Ecto.Schema, but name the table with an atom — a Mnesia
table is an atom, so that's the source of truth this adapter works in:
defmodule MyApp.User do
use Recall.Schema
schema :users do
field :name, :string
field :age, :integer
end
endEverything Ecto.Schema provides — the struct, __schema__/1, changesets,
associations — keeps working untouched; this only adds the compiled
accessors the adapter relies on. Defining a schema with this macro is
required: the adapter resolves every field through these baked accessors
and has no runtime fallback for a plain use Ecto.Schema schema.
Atom table names
Ecto.Schema's schema/2 requires a string source (it's built for SQL,
where the table name is text). Recall shadows it with a schema/2 that
requires an atom and forwards the equivalent string to Ecto.Schema — so
schema :users is what you write, while __schema__(:source) still returns
"users" for the rest of Ecto. Passing a string raises at compile time.
Physical layout lives in migrations, not the schema
The schema is purely logical — fields, types, struct, changesets. A table's physical layout (the table type and any secondary indexes) is owned by migrations, the same way a SQL adapter works:
create table(:users) do
add :name, :string
add :age, :integer
end
create index(:users, [:age]) # a secondary index the planners can useThe read and join planners serve an equality on the primary key, or on any
attribute the table physically indexes, with :mnesia.read/index_read
instead of a full scan; an equality on any other field runs correctly but takes
the scan path. Indexes are never created on the fly — only by a create index
migration — so an ad-hoc query can't silently grow a permanent index.
Generated functions
Given the schema above (fields == [:id, :name, :age], stored as
{:users, id, name, age}), the macro emits:
__recall__(:tag)— the Mnesia record tag (table name),:users.__recall__(:field_names)— fields in storage order (primary key first),[:id, :name, :age].__recall__(:field_indices)—%{id: 0, name: 1, age: 2}.__recall__(:field_count)— the match-spec arity,3.__recall__(:match_head)/:match_body— the prebuilt match-spec head tuple{:users, :"$1", :"$2", :"$3"}and body list[:"$1", :"$2", :"$3"].__recall_index__(field)— the field's 0-based position, one compiled clause per field (e.g.__recall_index__(:age)returns2).__recall_position__(field)— the field's 1-based Mnesia attribute position,index + 2(+1for the leading tag,+1for 1-based tuples).__recall__(:load_free?)—truewhen every field stores its native runtime term (so loading is the identity), lettingEcto.Adapters.Recall.FastReadassemble structs without per-field loaders.falsefor custom types, Ecto enums, embeds, associations.__recall__(:load_fields)—[{field, row_index}, ...]for the real (non-pad) struct fields in storage order, the recipeFastReaduses to stamp a stored row onto the loaded struct.
Both per-field accessors raise KeyError for an unknown field.
Summary
Functions
Like Ecto.Schema.schema/2, but the table name must be an atom (the form a
Mnesia table actually takes). Forwards the equivalent string to
Ecto.Schema.schema/2, so the rest of Ecto sees the source it expects.
Functions
Like Ecto.Schema.schema/2, but the table name must be an atom (the form a
Mnesia table actually takes). Forwards the equivalent string to
Ecto.Schema.schema/2, so the rest of Ecto sees the source it expects.