Skip to content

Commit

Permalink
feat: impl fn relations to Anime and Manga
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrielFR committed Jan 11, 2025
1 parent 098af2a commit 544882f
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 20 deletions.
2 changes: 2 additions & 0 deletions queries/search_anime.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ query($search: String, $page: Int = 1, $per_page: Int = 10) {
color
}
bannerImage
averageScore
meanScore
siteUrl
}
}
Expand Down
2 changes: 2 additions & 0 deletions queries/search_manga.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ query($search: String, $page: Int = 1, $per_page: Int = 10) {
color
}
bannerImage
averageScore
meanScore
siteUrl
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ impl Client {
description: media["description"].as_str().unwrap().to_string(),
cover: Cover::deserialize(&media["coverImage"]).unwrap(),
banner: media["bannerImage"].as_str().map(String::from),
average_score: media["averageScore"].as_u64().map(|x| x as u8),
mean_score: media["meanScore"].as_u64().map(|x| x as u8),
url: media["siteUrl"].as_str().unwrap().to_string(),

client: self.clone(),
Expand Down Expand Up @@ -448,6 +450,8 @@ impl Client {
description: media["description"].as_str().unwrap().to_string(),
cover: Cover::deserialize(&media["coverImage"]).unwrap(),
banner: media["bannerImage"].as_str().map(String::from),
average_score: media["averageScore"].as_u64().map(|x| x as u8),
mean_score: media["meanScore"].as_u64().map(|x| x as u8),
url: media["siteUrl"].as_str().unwrap().to_string(),

client: self.clone(),
Expand Down
21 changes: 17 additions & 4 deletions src/models/anime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright (c) 2022-2025 Andriel Ferreira <https://github.com/AndrielFR>

use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::{
Character, Cover, Date, Format, Link, Person, Relation, Season, Source, Status, Studio, Tag,
Expand Down Expand Up @@ -48,7 +49,6 @@ use crate::{Client, Result};
/// * `trending` - The trending of the anime.
/// * `favourites` - The number of favourites of the anime.
/// * `tags` - The tags of the anime.
/// * `relations` - The relations of the anime.
/// * `characters` - The characters of the anime.
/// * `staff` - The staff of the anime.
/// * `studios` - The studios of the anime.
Expand Down Expand Up @@ -123,8 +123,7 @@ pub struct Anime {
/// The tags of the anime.
pub tags: Option<Vec<Tag>>,
/// The relations of the anime.
#[serde(skip)]
pub relations: Option<Vec<Relation>>,
pub(crate) relations: Value,
/// The characters of the anime.
#[serde(skip)]
pub characters: Option<Vec<Character>>,
Expand Down Expand Up @@ -186,6 +185,20 @@ impl Anime {
panic!("This anime is already full loaded!")
}
}

/// Returns the relations of the anime.
pub fn relations(&self) -> Vec<Relation> {
self.relations
.as_object()
.unwrap()
.get("edges")
.unwrap()
.as_array()
.unwrap()
.iter()
.map(|r| serde_json::from_value(r.clone()).unwrap())
.collect()
}
}

/// Represents the airing schedule of an anime.
Expand All @@ -206,7 +219,7 @@ pub struct AiringSchedule {
pub id: u32,
/// The airing date.
#[serde(rename = "airingAt")]
pub at: u64,
pub at: i64,
/// Time until the airing.
#[serde(rename = "timeUntilAiring")]
pub time_until: u64,
Expand Down
18 changes: 16 additions & 2 deletions src/models/manga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! This module contains the `Manga` struct and its related types.
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::{
Character, Cover, Date, Format, Link, Person, Relation, Source, Status, Studio, Tag, Title,
Expand Down Expand Up @@ -113,8 +114,7 @@ pub struct Manga {
/// The tags of the manga.
pub tags: Option<Vec<Tag>>,
/// The relations of the manga.
#[serde(skip)]
pub relations: Option<Vec<Relation>>,
pub(crate) relations: Value,
/// The characters of the manga.
#[serde(skip)]
pub characters: Option<Vec<Character>>,
Expand Down Expand Up @@ -172,4 +172,18 @@ impl Manga {
panic!("This manga is already full loaded")
}
}

/// Returns the relations of the manga.
pub fn relations(&self) -> Vec<Relation> {
self.relations
.as_object()
.unwrap()
.get("edges")
.unwrap()
.as_array()
.unwrap()
.iter()
.map(|r| serde_json::from_value(r.clone()).unwrap())
.collect()
}
}
2 changes: 2 additions & 0 deletions src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod image;
mod language;
mod link;
mod manga;
mod media;

Check failure on line 17 in src/models/mod.rs

View workflow job for this annotation

GitHub Actions / test

file not found for module `media`

Check failure on line 17 in src/models/mod.rs

View workflow job for this annotation

GitHub Actions / check

file not found for module `media`
mod name;
mod notification;
mod person;
Expand All @@ -37,6 +38,7 @@ pub use image::Image;
pub use language::Language;
pub use link::{Link, LinkType};
pub use manga::Manga;
pub use media::Media;

Check failure on line 41 in src/models/mod.rs

View workflow job for this annotation

GitHub Actions / test

unresolved import `media::Media`

Check failure on line 41 in src/models/mod.rs

View workflow job for this annotation

GitHub Actions / check

unresolved import `media::Media`
pub use name::Name;
pub use notification::{Notification, NotificationOption, NotificationType};
pub use person::Person;
Expand Down
62 changes: 48 additions & 14 deletions src/models/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,27 @@
//! This module contains the `Relation` struct and its related types.
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::{Anime, Manga, MediaType};
use super::{Anime, Cover, Format, Manga, Media, Status, Title};

/// Represents a relation between different media types.
///
/// The `Relation` struct contains information about the relationship
/// between different media types, such as anime and manga, including
/// the media type, related anime or manga, relation ID, relation type,
/// and whether it is the main studio.
/// the related media, relation ID, relation type, and whether it is
/// the main studio.
///
/// # Fields
///
/// * `media_type` - The type of media (e.g., anime, manga).
/// * `anime` - An optional related anime.
/// * `manga` - An optional related manga.
/// * `id` - The ID of the relation.
/// * `relation_type` - The type of relation (e.g., adaptation, sequel).
/// * `is_main_studio` - Whether the relation is the main studio.
// TODO: Use generic type
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all(deserialize = "camelCase"))]
pub struct Relation {
/// The type of media (e.g., anime, manga).
pub media_type: MediaType,
/// An optional related anime.
pub anime: Option<Anime>,
/// An optional related manga.
pub manga: Option<Manga>,
/// The related media.
pub(crate) node: Value,
/// The ID of the relation.
pub id: i64,
/// The type of relation (e.g., adaptation, sequel).
Expand All @@ -40,6 +33,47 @@ pub struct Relation {
pub is_main_studio: bool,
}

impl Relation {
/// Returns the related media.
pub fn media(&self) -> Media {
let media = self.node.clone();

match self.node["type"].as_str() {
Some("ANIME") => Media::Anime(Anime {
id: media["id"].as_i64().unwrap(),
id_mal: media["idMal"].as_i64(),
title: Title::deserialize(&media["title"]).unwrap(),
format: Format::deserialize(&media["format"]).unwrap(),
status: Status::deserialize(&media["status"]).unwrap(),
description: media["description"].as_str().unwrap().to_string(),
cover: Cover::deserialize(&media["coverImage"]).unwrap(),
banner: media["bannerImage"].as_str().map(String::from),
average_score: media["averageScore"].as_u64().map(|x| x as u8),
mean_score: media["meanScore"].as_u64().map(|x| x as u8),
url: media["siteUrl"].as_str().unwrap().to_string(),

..Default::default()
}),
Some("MANGA") => Media::Manga(Manga {
id: media["id"].as_i64().unwrap(),
id_mal: media["idMal"].as_i64(),
title: Title::deserialize(&media["title"]).unwrap(),
format: Format::deserialize(&media["format"]).unwrap(),
status: Status::deserialize(&media["status"]).unwrap(),
description: media["description"].as_str().unwrap().to_string(),
cover: Cover::deserialize(&media["coverImage"]).unwrap(),
banner: media["bannerImage"].as_str().map(String::from),
average_score: media["averageScore"].as_u64().map(|x| x as u8),
mean_score: media["meanScore"].as_u64().map(|x| x as u8),
url: media["siteUrl"].as_str().unwrap().to_string(),

..Default::default()
}),
_ => Media::Unknown,
}
}
}

/// Represents the type of relation between different media.
///
/// The `RelationType` enum defines various types of relationships that
Expand All @@ -62,7 +96,7 @@ pub struct Relation {
/// * `Compilation` - The media is a compilation of another work.
/// * `Contains` - The media contains another work.
#[derive(Debug, Default, Clone, Eq, Hash, PartialEq, Deserialize, Serialize)]
#[serde(rename_all(deserialize = "UPPERCASE"))]
#[serde(rename_all(deserialize = "SCREAMING_SNAKE_CASE"))]
pub enum RelationType {
/// The media is an adaptation of another work.
Adaptation,
Expand Down

0 comments on commit 544882f

Please sign in to comment.