1use serde::Deserialize;
2use url::Url;
3
4use crate::api::{Client, Projection};
5use crate::error::Result;
6use crate::instance::InstanceUrl;
7
8#[derive(Clone, Debug, PartialEq, Eq)]
10pub enum Parent {
11 Issue(String),
12 Article(String),
13}
14
15impl Parent {
16 pub fn id(&self) -> &str {
17 match self {
18 Self::Issue(id) | Self::Article(id) => id,
19 }
20 }
21
22 pub fn path(&self) -> String {
24 match self {
25 Self::Issue(id) => format!("issues/{id}"),
26 Self::Article(id) => format!("articles/{id}"),
27 }
28 }
29
30 pub fn url(&self, instance: &InstanceUrl) -> Url {
31 match self {
32 Self::Issue(id) => instance.issue_url(id),
33 Self::Article(id) => instance.article_url(id),
34 }
35 }
36
37 pub fn noun(&self) -> &'static str {
38 match self {
39 Self::Issue(_) => "issue",
40 Self::Article(_) => "article",
41 }
42 }
43}
44
45#[derive(Deserialize)]
46struct Found {}
47
48impl Projection for Found {
49 const FIELDS: &'static str = "id";
50}
51
52pub async fn exists(client: &Client, parent: &Parent) -> Result<()> {
54 client.get::<Found>(&parent.path(), &[]).await.map(drop)
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn parents_name_their_paths_and_pages() {
63 let instance = InstanceUrl::parse("https://acme.youtrack.cloud").unwrap();
64 let issue = Parent::Issue("WEB-1".into());
65 let article = Parent::Article("KB-A-1".into());
66 assert_eq!(issue.path(), "issues/WEB-1");
67 assert_eq!(article.path(), "articles/KB-A-1");
68 assert_eq!(article.id(), "KB-A-1");
69 assert_eq!(issue.noun(), "issue");
70 assert_eq!(
71 article.url(&instance).as_str(),
72 "https://acme.youtrack.cloud/articles/KB-A-1"
73 );
74 }
75}