devhub_sdk/
link_base.rs

1use crate::{
2    hdk,
3    hdk_extensions,
4};
5
6use hdk::prelude::*;
7use hdk_extensions::{
8    agent_id,
9};
10
11
12pub struct LinkBase<LT>(pub AnyLinkableHash, pub LT)
13where
14    LT: LinkTypeFilterExt + Copy,
15    ScopedLinkType: TryFrom<LT, Error = WasmError>,
16;
17
18
19impl<LT,T> TryFrom<(T, LT)> for LinkBase<LT>
20where
21    LT: LinkTypeFilterExt + Copy,
22    ScopedLinkType: TryFrom<LT, Error = WasmError>,
23    AnyLinkableHash: TryFrom<T, Error = WasmError>,
24{
25    type Error = WasmError;
26
27    fn try_from(input: (T, LT)) -> ExternResult<Self> {
28        Ok(
29            Self( AnyLinkableHash::try_from(input.0)?, input.1 )
30        )
31    }
32}
33
34
35impl<LT> LinkBase<LT>
36where
37    LT: LinkTypeFilterExt + Copy,
38    ScopedLinkType: TryFrom<LT, Error = WasmError>,
39{
40    pub fn new<T>(input: T, link_type: LT) -> Self
41    where
42        T: Into<AnyLinkableHash>,
43    {
44        Self( input.into(), link_type )
45    }
46
47    pub fn hash(&self) -> AnyLinkableHash {
48        self.0.clone()
49    }
50
51    pub fn link_type(&self) -> LT {
52        self.1
53    }
54
55    pub fn get_links(&self, tag: Option<LinkTag>) ->
56        ExternResult<Vec<Link>>
57    {
58        get_links( self.hash(), self.link_type(), tag )
59    }
60
61    pub fn create_link<T>(
62        &self,
63        target: &T,
64        tag: impl Into<LinkTag>
65    ) -> ExternResult<ActionHash>
66    where
67        T: Into<AnyLinkableHash> + Clone,
68    {
69        create_link( self.hash(), target.to_owned(), self.link_type(), tag )
70    }
71
72    pub fn links_exist<T>(&self, target: &T, tag: impl Into<LinkTag>) ->
73        ExternResult<Option<Link>>
74    where
75        T: Into<AnyLinkableHash> + Clone,
76    {
77        let tag : LinkTag = tag.into();
78
79        Ok(
80            self.get_links( Some(tag.clone()) )?.into_iter()
81                .find( |link| {
82                    link.target == target.to_owned().into()
83                        && link.tag == tag
84                })
85        )
86    }
87
88    pub fn create_link_if_not_exists<T>(
89        &self,
90        target: &T,
91        tag: impl Into<LinkTag>
92    ) -> ExternResult<Option<ActionHash>>
93    where
94        T: Into<AnyLinkableHash> + Clone,
95    {
96        let target : AnyLinkableHash = target.to_owned().into();
97        let tag : LinkTag = tag.into();
98
99        for link in self.get_links( Some(tag.clone()) )? {
100            // We still have to check the tag because we only consider it to exist when the tags are
101            // an exact match
102            if link.target == target
103                && link.tag == tag
104            {
105                debug!("Target ({}) already exists for anchor {}", target, self.hash() );
106                return Ok( None );
107            }
108        }
109
110        Ok( Some( self.create_link( &target, tag )? ) )
111    }
112
113    pub fn delete_all_my_links_to_target<T>(
114        &self,
115        target: &T,
116        tag: Option<LinkTag>,
117    ) -> ExternResult<Vec<ActionHash>>
118    where
119        T: Into<AnyLinkableHash> + Clone,
120    {
121        let agent_id = agent_id()?;
122        let target : AnyLinkableHash = target.to_owned().into();
123        let mut deleted_links = vec![];
124
125        for link in self.get_links( tag.clone() )? {
126            if link.target == target
127                && ( tag == None
128                     || Some(link.tag) == tag )
129                && link.author == agent_id
130            {
131                debug!("Deleting link ({}): {} => {}", link.create_link_hash, self.hash(), target );
132                let delete_action = delete_link( link.create_link_hash )?;
133                deleted_links.push( delete_action );
134            }
135        }
136
137        Ok( deleted_links )
138    }
139}