1use crate::{FieldSet, NodeEntity, NodeId, StampMode};
2use neo4rs::{Query, Relation, UnboundedRelation};
3
4pub trait RelationEntity: FieldSet + TryFrom<Relation> + TryFrom<UnboundedRelation> {
6 type Id: RelationId<T = Self>;
7
8 fn identifier(&self) -> Self::Id;
16
17 fn into_identifier(self) -> Self::Id {
19 self.into()
20 }
21
22 fn create<S: NodeEntity, E: NodeEntity>(
23 &self,
24 start: RelationBound<S>,
25 end: RelationBound<E>,
26 ) -> Query {
27 let q = format!(
28 r###"
29 {}
30 {}
31 CREATE (s)-[:{}]->(e)
32 "###,
33 start.to_query_clause("s"),
34 end.to_query_clause("e"),
35 Self::to_query_obj(None, StampMode::Create)
36 );
37 let mut q = Query::new(q);
39 q = start.add_params(q, "s");
40 q = end.add_params(q, "e");
41 self.add_values_to_params(q, None, StampMode::Create)
42 }
43
44 fn update(&self) -> Query {
52 assert!(!Self::Id::field_names().is_empty());
53 let q = Query::new(format!(
54 "MATCH ()-[r:{}]-()
55 SET r += {{ {} }}",
56 Self::Id::to_query_obj(None, StampMode::Read),
57 Self::to_query_fields(None, StampMode::Update),
58 ));
59 self.add_values_to_params(q, None, StampMode::Update)
60 }
61
62 fn update_from<T: NodeId>(&self, from: &T) -> Query {
66 let mut q = Query::new(format!(
67 "MATCH (n:{})-[r:{}]-()
68 SET r += {{ {} }}",
69 T::to_query_obj(Some("n"), StampMode::Read),
70 Self::Id::to_query_obj(None, StampMode::Read),
71 Self::to_query_fields(None, StampMode::Update),
72 ));
73 q = from.add_values_to_params(q, Some("n"), StampMode::Read);
74 self.add_values_to_params(q, None, StampMode::Update)
75 }
76
77 fn update_between<S: NodeId, E: NodeId>(&self, start: &S, end: &E) -> Query {
81 let mut q = Query::new(format!(
82 "MATCH (s:{})-[r:{}]-(e:{})
83 SET r += {{ {} }}",
84 S::to_query_obj(Some("s"), StampMode::Read),
85 Self::Id::to_query_obj(None, StampMode::Read),
86 E::to_query_obj(Some("e"), StampMode::Read),
87 Self::to_query_fields(None, StampMode::Update),
88 ));
89 q = start.add_values_to_params(q, Some("s"), StampMode::Read);
90 q = end.add_values_to_params(q, Some("e"), StampMode::Read);
91 self.add_values_to_params(q, None, StampMode::Update)
92 }
93}
94
95pub trait RelationId:
97 FieldSet + From<Self::T> + TryFrom<Relation> + TryFrom<UnboundedRelation>
98{
99 type T: RelationEntity<Id = Self>;
100
101 fn read(&self) -> Query {
105 assert!(!Self::field_names().is_empty());
106 let q = Query::new(format!(
107 "MATCH [r:{}] RETURN r",
108 Self::to_query_obj(None, StampMode::Read)
109 ));
110 self.add_values_to_params(q, None, StampMode::Read)
111 }
112 fn read_from<T: NodeId>(&self, from: &T) -> Query {
114 let mut q = Query::new(format!(
115 "MATCH (n:{})-[r:{}]-()
116 RETURN r",
117 T::to_query_obj(Some("n"), StampMode::Read),
118 Self::to_query_obj(None, StampMode::Read)
119 ));
120 q = from.add_values_to_params(q, Some("n"), StampMode::Read);
121 self.add_values_to_params(q, None, StampMode::Read)
122 }
123 fn read_between<S: NodeId, E: NodeId>(&self, start: &S, end: &E) -> Query {
125 let mut q = Query::new(format!(
126 "MATCH (s:{})-[r:{}]-(e:{})
127 RETURN r",
128 S::to_query_obj(Some("s"), StampMode::Read),
129 Self::to_query_obj(None, StampMode::Read),
130 E::to_query_obj(Some("e"), StampMode::Read),
131 ));
132 q = start.add_values_to_params(q, Some("s"), StampMode::Read);
133 q = end.add_values_to_params(q, Some("e"), StampMode::Read);
134 self.add_values_to_params(q, None, StampMode::Read)
135 }
136 fn delete(&self) -> Query {
140 assert!(!Self::field_names().is_empty());
141 let q = Query::new(format!(
142 "MATCH [r:{}] DELETE r",
143 Self::to_query_obj(None, StampMode::Read)
144 ));
145 self.add_values_to_params(q, None, StampMode::Read)
146 }
147 fn delete_from<T: NodeId>(&self, from: &T) -> Query {
149 let mut q = Query::new(format!(
150 "MATCH (n:{})-[r:{}]-()
151 DELETE r",
152 T::to_query_obj(Some("n"), StampMode::Read),
153 Self::to_query_obj(None, StampMode::Read)
154 ));
155 q = from.add_values_to_params(q, Some("n"), StampMode::Read);
156 self.add_values_to_params(q, None, StampMode::Read)
157 }
158 fn delete_between<S: NodeId, E: NodeId>(&self, start: &S, end: &E) -> Query {
160 let mut q = Query::new(format!(
161 "MATCH (s:{})-[r:{}]-(e:{})
162 DELETE r",
163 S::to_query_obj(Some("s"), StampMode::Read),
164 Self::to_query_obj(None, StampMode::Read),
165 E::to_query_obj(Some("e"), StampMode::Read),
166 ));
167 q = start.add_values_to_params(q, Some("s"), StampMode::Read);
168 q = end.add_values_to_params(q, Some("e"), StampMode::Read);
169 self.add_values_to_params(q, None, StampMode::Read)
170 }
171}
172
173pub enum RelationBound<'a, T: NodeEntity> {
176 Create(&'a T),
177 Match(&'a T::Id),
178 }
181impl<'a, T: NodeEntity> RelationBound<'a, T> {
182 pub fn to_query_clause(&self, prefix: &str) -> String {
184 match self {
185 RelationBound::Create(_) => format!(
186 "CREATE ({}:{})",
187 prefix,
188 T::to_query_obj(Some(prefix), StampMode::Create)
189 ),
190 RelationBound::Match(_) => format!(
191 "MATCH ({}:{})",
192 prefix,
193 T::Id::to_query_obj(Some(prefix), StampMode::Read)
194 ),
195 }
209 }
210 pub fn add_params(&self, q: Query, prefix: &str) -> Query {
211 match self {
212 RelationBound::Create(t) => t.add_values_to_params(q, Some(prefix), StampMode::Create),
213 RelationBound::Match(id) => id.add_values_to_params(q, Some(prefix), StampMode::Read),
214 }
219 }
220}