Return the single primary-key field name for a schema module.
Convenience over key/1 for the common single-key case; raises
{composite_primary_key, Mod, Keys} on a composite key.
Behaviour for defining database-backed schemas.
Implement the table/0 and fields/0 callbacks to define a schema module.
Mark one field with primary_key = true. Optionally implement timestamps/0
and associations/0.
-module(my_user).
-behaviour(kura_schema).
-include_lib("kura/include/kura.hrl").
table() -> <<"users">>.
fields() ->
[#kura_field{name = id, type = id, primary_key = true},
#kura_field{name = name, type = string},
#kura_field{name = email, type = string}].For a composite primary key, implement the optional key/0 callback
returning the ordered key columns; primary_key = true markers are then
unnecessary. When key/0 is absent the key is derived from the
primary_key = true fields, so existing single-key schemas are unchanged.
-module(membership).
-behaviour(kura_schema).
-include_lib("kura/include/kura.hrl").
table() -> <<"memberships">>.
key() -> [org_id, user_id].
fields() ->
[#kura_field{name = org_id, type = uuid, nullable = false},
#kura_field{name = user_id, type = uuid, nullable = false},
#kura_field{name = role, type = string}].
Return the foreign-key column(s) of an association as an ordered list.
Return a many_to_many association's join-table columns as
{OwnerCols, RelatedCols}, each an ordered list. A single-column
join_keys = {owner, related} is the one-element-list case.
Return the target schema module of an association.
Return the explicit referenced key column(s) on the target side, or
undefined to mean "default to the target schema's key". Only a
#kura_ref{} can carry this; legacy associations always return
undefined.
Look up a single association by name.
Return all associations defined on a schema module.
Return map of field name to column name (binary), excluding virtual fields.
Return all table-level constraints defined on a schema module.
Look up a single embed by name.
Return all embeds defined on a schema module.
Return list of field names for a schema module.
Return map of field name to kura type for a schema module.
Generate a primary key value if the schema defines generate_id/0.
Check if a schema module has an after_* hook for the given action.
Return all indexes defined on a schema module.
Return the ordered primary-key column names for a schema module.
Return the ordered primary-key field records for a schema module.
Return list of non-virtual field names.
Return the single primary-key field name for a schema module.
Return the single primary-key field record, or undefined if the
schema has no primary key. Raises on a composite key.
Run after_delete hook if defined. Returns ok or {error, Reason}.
Run after_insert hook if defined. Returns {ok, Record} or {error, Reason}.
Run after_update hook if defined. Returns {ok, Record} or {error, Reason}.
Run before_delete hook if defined. Returns ok or {error, Reason}.
Run before_insert hook if defined. Returns {ok, CS} or {error, CS}.
Run before_update hook if defined. Returns {ok, CS} or {error, CS}.
-callback associations() -> [#kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}].
-callback before_insert(#kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}) -> {ok, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}} | {error, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}}.
-callback before_update(#kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}) -> {ok, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}} | {error, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}}.
-callback constraints() -> [kura_migration:table_constraint()].
-callback generate_id() -> term().
-callback indexes() -> [kura_migration:index_def()].
-callback key() -> [atom()].
-callback table() -> binary().
-callback timestamps() -> [{atom(), kura_types:kura_type()}].
-spec assoc_fields(#kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}) -> [atom()].
Return the foreign-key column(s) of an association as an ordered list.
A #kura_ref{}'s fields win; a legacy single foreign_key lowers to
a one-element list, so single-column associations are the arity-1 case
of the same list. Returns [] if neither is set.
-spec assoc_join_keys(#kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}) -> {[atom()], [atom()]}.
Return a many_to_many association's join-table columns as
{OwnerCols, RelatedCols}, each an ordered list. A single-column
join_keys = {owner, related} is the one-element-list case.
-spec assoc_target(#kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}) -> module() | undefined.
Return the target schema module of an association.
A #kura_ref{}'s target wins; otherwise the legacy schema field.
-spec assoc_target_key(#kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}) -> [atom()] | undefined.
Return the explicit referenced key column(s) on the target side, or
undefined to mean "default to the target schema's key". Only a
#kura_ref{} can carry this; legacy associations always return
undefined.
-spec association(module(), atom()) -> {ok, #kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}} | {error, not_found}.
Look up a single association by name.
-spec associations(module()) -> [#kura_assoc{name :: atom(), type :: belongs_to | has_one | has_many | many_to_many, schema :: module(), foreign_key :: atom() | undefined, ref :: #kura_ref{fields :: [atom()] | undefined, target :: module() | undefined, target_key :: [atom()] | undefined} | undefined, join_through :: binary() | module() | undefined, join_keys :: {atom() | [atom()], atom() | [atom()]} | undefined, through :: [atom()] | undefined}].
Return all associations defined on a schema module.
Return map of field name to column name (binary), excluding virtual fields.
-spec constraints(module()) -> [kura_migration:table_constraint()].
Return all table-level constraints defined on a schema module.
-spec embed(module(), atom()) -> {ok, #kura_embed{name :: atom(), type :: embeds_one | embeds_many, schema :: module()}} | {error, not_found}.
Look up a single embed by name.
-spec embeds(module()) -> [#kura_embed{name :: atom(), type :: embeds_one | embeds_many, schema :: module()}].
Return all embeds defined on a schema module.
Return list of field names for a schema module.
-spec field_types(module()) -> #{atom() => kura_types:kura_type()}.
Return map of field name to kura type for a schema module.
Generate a primary key value if the schema defines generate_id/0.
Check if a schema module has an after_* hook for the given action.
-spec indexes(module()) -> [kura_migration:index_def()].
Return all indexes defined on a schema module.
Return the ordered primary-key column names for a schema module.
A schema declares its key with the optional key/0 callback (an ordered
list, arity 1 or more for composite keys). When key/0 is not
implemented, the key is derived from the fields marked
primary_key = true, so existing single-key schemas need no change.
-spec key_fields(module()) -> [#kura_field{name :: atom(), type :: kura_types:kura_type(), column :: binary() | undefined, default :: term(), primary_key :: boolean(), nullable :: boolean(), virtual :: boolean()}].
Return the ordered primary-key field records for a schema module.
Return list of non-virtual field names.
Return the single primary-key field name for a schema module.
Convenience over key/1 for the common single-key case; raises
{composite_primary_key, Mod, Keys} on a composite key.
-spec primary_key_field(module()) -> #kura_field{name :: atom(), type :: kura_types:kura_type(), column :: binary() | undefined, default :: term(), primary_key :: boolean(), nullable :: boolean(), virtual :: boolean()} | undefined.
Return the single primary-key field record, or undefined if the
schema has no primary key. Raises on a composite key.
Run after_delete hook if defined. Returns ok or {error, Reason}.
Run after_insert hook if defined. Returns {ok, Record} or {error, Reason}.
Run after_update hook if defined. Returns {ok, Record} or {error, Reason}.
Run before_delete hook if defined. Returns ok or {error, Reason}.
-spec run_before_insert(module(), #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}) -> {ok, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}} | {error, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}}.
Run before_insert hook if defined. Returns {ok, CS} or {error, CS}.
-spec run_before_update(module(), #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}) -> {ok, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}} | {error, #kura_changeset{valid :: boolean(), schema :: module() | undefined, data :: map(), params :: map(), changes :: map(), errors :: [{atom(), binary()}], types :: #{atom() => kura_types:kura_type()}, required :: [atom()], action :: atom() | undefined, constraints :: [#kura_constraint{type :: unique | foreign_key | check | exclusion, constraint :: binary(), field :: atom(), message :: binary()}], assoc_changes :: #{atom() => #kura_changeset{} | [#kura_changeset{}]}, prepare :: [fun((#kura_changeset{}) -> #kura_changeset{})], optimistic_lock :: atom() | undefined}}.
Run before_update hook if defined. Returns {ok, CS} or {error, CS}.