rust_anilist/models/
relation.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>
3
4//! This module contains the `Relation` struct and its related types.
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9use super::{Anime, Cover, Format, Manga, Media, Status, Title};
10
11/// Represents a relation between different media types.
12///
13/// The `Relation` struct contains information about the relationship
14/// between different media types, such as anime and manga, including
15/// the related media, relation ID, relation type, and whether it is
16/// the main studio.
17///
18/// # Fields
19///
20/// * `id` - The ID of the relation.
21/// * `relation_type` - The type of relation (e.g., adaptation, sequel).
22/// * `is_main_studio` - Whether the relation is the main studio.
23#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
24#[serde(rename_all(deserialize = "camelCase"))]
25pub struct Relation {
26    /// The related media.
27    pub(crate) node: Value,
28    /// The ID of the relation.
29    pub id: i64,
30    /// The type of relation (e.g., adaptation, sequel).
31    pub relation_type: RelationType,
32    /// Whether the relation is the main studio.
33    pub is_main_studio: bool,
34}
35
36impl Relation {
37    /// Returns the related media.
38    pub fn media(&self) -> Media {
39        let media = self.node.clone();
40
41        match self.node["type"].as_str() {
42            Some("ANIME") => Media::Anime(Anime {
43                id: media["id"].as_i64().unwrap(),
44                id_mal: media["idMal"].as_i64(),
45                title: Title::deserialize(&media["title"]).unwrap(),
46                format: Format::deserialize(&media["format"]).unwrap(),
47                status: Status::deserialize(&media["status"]).unwrap(),
48                description: media["description"].as_str().unwrap().to_string(),
49                cover: Cover::deserialize(&media["coverImage"]).unwrap(),
50                banner: media["bannerImage"].as_str().map(String::from),
51                average_score: media["averageScore"].as_u64().map(|x| x as u8),
52                mean_score: media["meanScore"].as_u64().map(|x| x as u8),
53                url: media["siteUrl"].as_str().unwrap().to_string(),
54
55                ..Default::default()
56            }),
57            Some("MANGA") => Media::Manga(Manga {
58                id: media["id"].as_i64().unwrap(),
59                id_mal: media["idMal"].as_i64(),
60                title: Title::deserialize(&media["title"]).unwrap(),
61                format: Format::deserialize(&media["format"]).unwrap(),
62                status: Status::deserialize(&media["status"]).unwrap(),
63                description: media["description"].as_str().unwrap().to_string(),
64                cover: Cover::deserialize(&media["coverImage"]).unwrap(),
65                banner: media["bannerImage"].as_str().map(String::from),
66                average_score: media["averageScore"].as_u64().map(|x| x as u8),
67                mean_score: media["meanScore"].as_u64().map(|x| x as u8),
68                url: media["siteUrl"].as_str().unwrap().to_string(),
69
70                ..Default::default()
71            }),
72            _ => Media::Unknown,
73        }
74    }
75}
76
77/// Represents the type of relation between different media.
78///
79/// The `RelationType` enum defines various types of relationships that
80/// can exist between different media, such as adaptations, sequels,
81/// prequels, and more.
82///
83/// # Variants
84///
85/// * `Adaptation` - The media is an adaptation of another work.
86/// * `Prequel` - The media is a prequel to another work.
87/// * `Sequel` - The media is a sequel to another work.
88/// * `Parent` - The media is a parent story to another work.
89/// * `SideStory` - The media is a side story to another work.
90/// * `Character` - The media shares characters with another work.
91/// * `Summary` - The media is a summary of another work.
92/// * `Alternative` - The media is an alternative version of another work.
93/// * `SpinOff` - The media is a spin-off of another work.
94/// * `Other` - The media has some other type of relation to another work.
95/// * `Source` - The media is the source material for another work.
96/// * `Compilation` - The media is a compilation of another work.
97/// * `Contains` - The media contains another work.
98#[derive(Debug, Default, Clone, Eq, Hash, PartialEq, Deserialize, Serialize)]
99#[serde(rename_all(deserialize = "SCREAMING_SNAKE_CASE"))]
100pub enum RelationType {
101    /// The media is an adaptation of another work.
102    Adaptation,
103    /// The media is a prequel to another work.
104    Prequel,
105    /// The media is a sequel to another work.
106    Sequel,
107    /// The media is a parent story to another work.
108    Parent,
109    /// The media is a side story to another work.
110    SideStory,
111    /// The media shares characters with another work.
112    Character,
113    /// The media is a summary of another work.
114    Summary,
115    /// The media is an alternative version of another work.
116    Alternative,
117    /// The media is a spin-off of another work.
118    SpinOff,
119    /// The media has some other type of relation to another work.
120    #[default]
121    Other,
122    /// The media is the source material for another work.
123    Source,
124    /// The media is a compilation of another work.
125    Compilation,
126    /// The media contains another work.
127    Contains,
128}
129
130impl RelationType {
131    /// Returns a summary of the relation type.
132    pub fn summary(&self) -> &str {
133        match self {
134            RelationType::Adaptation => "An adaption of this media into a different format",
135            RelationType::Prequel => "Released before the relation",
136            RelationType::Sequel => "Released after the relation",
137            RelationType::Parent => "The media a side story is from",
138            RelationType::SideStory => "A side story of the parent media",
139            RelationType::Character => "Shares at least 1 character",
140            RelationType::Summary => "A shortened and summarized version",
141            RelationType::Alternative => "An alternative version of the same media",
142            RelationType::SpinOff => {
143                "An alternative version of the media with a different primary focus"
144            }
145            RelationType::Other => "Other",
146            RelationType::Source => "The source material the media was adapted from",
147            RelationType::Compilation => "A compilation of the media",
148            RelationType::Contains => "A media that contains the relation",
149        }
150    }
151}