Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Many to Many Relationship

This document describes how to define and manage Many to Many relationships in Biyard Rust projects using the api_model macro.

Overview

A Many to Many relationship occurs when multiple entities can relate to multiple entities through a join (pivot) table.

For example, multiple Post entities can have multiple associated Tag entities, and vice versa.

Basic Usage

Many to Many relationships are clearly defined using attributes provided by the api_model macro.

Example

Here's a practical example where a Post can have multiple related Tag entities:

#![allow(unused)]
fn main() {
use bdk::prelude::*;

#[api_model(base = "/v1/posts", table = posts)]
pub struct Post {
    #[api_model(primary_key)]
    pub id: i64,

    pub title: String,

    // Define Many to Many relationship: a post has multiple tags
    #[api_model(
        many_to_many = posts_tags,
        foreign_table_name = tags,
        foreign_primary_key = tag_id,
        foreign_reference_key = post_id
    )]
    pub tags: Vec<Tag>,
}

#[api_model(base = "/v1/tags", table = tags)]
pub struct Tag {
    #[api_model(primary_key)]
    pub id: i64,

    #[api_model(unique)]
    pub tag: String,

    // Define Many to Many relationship: a tag has multiple posts
    #[api_model(
        many_to_many = posts_tags,
        foreign_table_name = posts,
        foreign_primary_key = post_id,
        foreign_reference_key = tag_id
    )]
    pub posts: Vec<Post>,
}
}

Attribute Descriptions

AttributeDescriptionExample
many_to_manyName of the join (pivot) table managing the relationshipmany_to_many = posts_tags
foreign_table_nameName of the related entity's tableforeign_table_name = tags
foreign_primary_keyPrimary key of the related entity in the join tableforeign_primary_key = tag_id
foreign_reference_keyPrimary key of the current entity in the join tableforeign_reference_key = post_id
target_tableDetermines source of relationship data (join or foreign)target_table = join

In the example above, the join table posts_tags manages the association between Post and Tag.

Using target_table

You can specify the source table for retrieving relationship data using the target_table attribute. Setting target_table to join retrieves data from the join table, while foreign retrieves data directly from the related entity's table.

Example

#![allow(unused)]
fn main() {
#[api_model(
    many_to_many = test_mtm_votes,
    type = JSONB,
    foreign_table_name = test_mtm_users,
    foreign_primary_key = user_id,
    foreign_reference_key = model_id,
    target_table = join
)]
pub user_votes: Vec<Vote>,

#[api_model(
    many_to_many = test_mtm_votes,
    type = JSONB,
    foreign_table_name = test_mtm_users,
    foreign_primary_key = user_id,
    foreign_reference_key = model_id,
    target_table = foreign
)]
pub users: Vec<User>,
}

In this example:

  • user_votes retrieves data from the join table (test_mtm_votes).
  • users retrieves data from the foreign table (test_mtm_users).

Automatically Generated Features

  • Automatic JOINs
    Queries retrieving related data will automatically perform JOIN operations across the pivot table, simplifying complex relational data retrieval.

  • Intuitive API Client and Repository
    The api_model macro generates intuitive methods within API clients and repositories, making the handling of many-to-many relationships effortless.

Recommendations and Best Practices

  • Clearly define join tables (many_to_many) and related keys to avoid ambiguity.
  • Be cautious about performance implications of many-to-many relations; optimize your queries to reduce database load.
  • Consider explicitly defining and maintaining the join table structure to enhance clarity and control.

Following these guidelines will ensure clear, maintainable, and efficient management of Many to Many relationships in your Biyard Rust projects.