Repodb.Assoc

repodb · API reference

Association definitions for schema relationships.

Ecto-like associations: has_many, has_one, belongs_to, many_to_many.

Example usage:

(* In Post schema *)
let comments = has_many "comments" ~foreign_key:"post_id"

let author =
  belongs_to "author" ~references:User.table ~foreign_key:"author_id"

(* In Comment schema *)
let post = belongs_to "post" ~references:Post.table ~foreign_key:"post_id"
type cardinality = 
  | One
  | Many

Association cardinality

type assoc_type = 
  | BelongsTo (* Foreign key is on this schema *)
  | HasOne (* Foreign key is on the related schema, singular *)
  | HasMany (* Foreign key is on the related schema, plural *)
  | ManyToMany of {
    join_table : string;
    join_keys : string * string;
  } (* Uses a join table *)

Association type - which side holds the foreign key

type 'related t = {
  name : string;
  assoc_type : assoc_type;
  cardinality : cardinality;
  related_table : string;
  foreign_key : string;
  owner_key : string; (* Usually "id" *)
  on_delete : on_delete option;
  on_replace : on_replace option;
}

An association definition

and on_delete = 
  | Nilify (* Set foreign key to NULL *)
  | DeleteAll (* Delete all associated records *)
  | Nothing (* Do nothing (may cause constraint error) *)
and on_replace = 
  | Raise (* Raise if trying to replace *)
  | Mark_as_invalid (* Mark changeset as invalid *)
  | Nilify_assoc (* Set foreign keys to NULL *)
  | Update_assoc (* Update existing, insert new *)
  | Delete_assoc (* Delete and replace *)
type 'a load_state = 
  | NotLoaded
  | Loaded of 'a

Not loaded sentinel - associations start in this state

type 'a has_one_loaded = 'a option load_state

Wrapper for optional singular associations

type 'a has_many_loaded = 'a list load_state

Wrapper for plural associations

val belongs_to : 
  string ->
  related_table:string ->
  foreign_key:string ->
  ?owner_key:string ->
  ?on_delete:on_delete ->
  ?on_replace:on_replace ->
  unit ->
  'a t

Create a belongs_to association. The foreign key is on this schema, pointing to the related schema's primary key.

Example: A Comment belongs_to a Post, where Comment has post_id column.

val has_one : 
  string ->
  related_table:string ->
  foreign_key:string ->
  ?owner_key:string ->
  ?on_delete:on_delete ->
  ?on_replace:on_replace ->
  unit ->
  'a t

Create a has_one association. The foreign key is on the related schema, pointing to this schema's primary key.

Example: A User has_one Profile, where Profile has user_id column.

val has_many : 
  string ->
  related_table:string ->
  foreign_key:string ->
  ?owner_key:string ->
  ?on_delete:on_delete ->
  ?on_replace:on_replace ->
  unit ->
  'a t

Create a has_many association. The foreign key is on the related schema, pointing to this schema's primary key.

Example: A Post has_many Comments, where Comment has post_id column.

val many_to_many : 
  string ->
  related_table:string ->
  join_table:string ->
  join_keys:(string * string) ->
  ?on_delete:on_delete ->
  ?on_replace:on_replace ->
  unit ->
  'a t

Create a many_to_many association. Uses a join table to connect two schemas.

Example: Posts and Tags through post_tags join table.

let tags =
  many_to_many "tags" ~related_table:"tags" ~join_table:"post_tags"
    ~join_keys:("post_id", "tag_id") ()
val name : 'a t -> string

Get the association name

Get the related table name

val foreign_key : 'a t -> string

Get the foreign key column name

val owner_key : 'a t -> string

Get the owner key column name (usually "id")

val is_singular : 'a t -> bool

Check if this is a singular association

val is_plural : 'a t -> bool

Check if this is a plural association

val owner_has_fk : 'a t -> bool

Check if the foreign key is on this schema (belongs_to)

val build_placeholders : dialect:Driver.dialect -> int -> string
val belongs_to_query_params : 
  dialect:Driver.dialect ->
  'a t ->
  int ->
  string * Driver.Value.t array
val has_query_params : 
  dialect:Driver.dialect ->
  'a t ->
  int ->
  string * Driver.Value.t array
val many_to_many_query_params : 
  dialect:Driver.dialect ->
  'a t ->
  int ->
  string * Driver.Value.t array
val build_query_params : 
  dialect:Driver.dialect ->
  'a t ->
  int ->
  string * Driver.Value.t array
val build_batch_query_params : 
  dialect:Driver.dialect ->
  'a t ->
  int list ->
  string * Driver.Value.t array
type assoc_meta = {
  meta_name : string;
  meta_type : assoc_type;
  meta_cardinality : cardinality;
  meta_related_table : string;
  meta_foreign_key : string;
  meta_owner_key : string;
}

Association metadata for runtime reflection

val to_meta : 'a t -> assoc_meta

Extract metadata from an association

type wrapped_assoc = 
  | Assoc : 'a t -> wrapped_assoc

Wrapped association for heterogeneous lists

type schema_assocs = {
  assocs : wrapped_assoc list;
}

Schema associations container

val empty_assocs : schema_assocs
val add_assoc : 'a t -> schema_assocs -> schema_assocs
val find_assoc : string -> schema_assocs -> wrapped_assoc option
val assoc_names : schema_assocs -> string list