nexus_common/models/
traits.rs1use crate::db::{exec_single_row, get_neo4j_graph, RedisOps};
2use crate::types::DynError;
3use async_trait::async_trait;
4use core::fmt;
5use neo4rs::Query;
6use std::fmt::Debug;
7
8pub trait CollectionId {
9 fn to_string_id(self) -> String;
10}
11
12impl CollectionId for &str {
13 fn to_string_id(self) -> String {
14 String::from(self)
15 }
16}
17
18impl CollectionId for &[&str] {
19 fn to_string_id(self) -> String {
20 self.join(":")
21 }
22}
23
24#[async_trait]
25pub trait Collection<T>
26where
27 Self: RedisOps + Clone + Debug + Default,
28 T: CollectionId + fmt::Debug + Sync + Send + Copy,
29{
30 async fn get_by_ids(ids: &[T]) -> Result<Vec<Option<Self>>, DynError> {
43 let key_parts_list: Vec<String> = ids.iter().map(|id| id.to_string_id()).collect();
44
45 let keys_refs: Vec<Vec<&str>> = key_parts_list.iter().map(|id| vec![id.as_str()]).collect();
46
47 let keys: Vec<&[&str]> = keys_refs.iter().map(|arr| &arr[..]).collect();
48
49 let mut collection = Self::get_from_index(keys).await?;
50
51 let mut missing_ids: Vec<(usize, T)> = Vec::new();
52 for (i, details) in collection.iter().enumerate() {
53 if details.is_none() {
54 missing_ids.push((i, ids[i]));
55 }
56 }
57
58 if !missing_ids.is_empty() {
59 let flat_missing_ids: Vec<T> = missing_ids.iter().map(|&(_, id)| id).collect();
60 let fetched_details = Self::get_from_graph(&flat_missing_ids).await?;
61
62 if !fetched_details.is_empty() {
63 for (i, (original_index, _)) in missing_ids.iter().enumerate() {
64 collection[*original_index].clone_from(&fetched_details[i]);
65 }
66 Self::put_to_index(&flat_missing_ids, fetched_details).await?;
67 }
68 }
69
70 Ok(collection)
71 }
72
73 async fn get_from_graph(ids: &[T]) -> Result<Vec<Option<Self>>, DynError> {
84 let mut result;
85 {
86 let graph = get_neo4j_graph()?;
87 let query = Self::collection_details_graph_query(ids);
88
89 let graph = graph.lock().await;
90 result = graph.execute(query).await?;
91 }
92
93 let mut records = Vec::with_capacity(ids.len());
94
95 while let Some(row) = result.next().await? {
96 let record: Option<Self> = row.get("record").ok();
97 records.push(record);
98 }
99 Ok(records)
100 }
101
102 async fn get_from_index(keys: Vec<&[&str]>) -> Result<Vec<Option<Self>>, DynError> {
103 Self::try_from_index_multiple_json(&keys).await
104 }
105
106 async fn put_to_index(ids: &[T], records: Vec<Option<Self>>) -> Result<(), DynError> {
119 let mut found_records = Vec::with_capacity(records.len());
120 let mut found_record_ids = Vec::with_capacity(records.len());
121
122 for (detail, id) in records.iter().zip(ids.iter()) {
123 if let Some(value) = detail {
124 found_records.push(Some(value.clone()));
125 found_record_ids.push(*id);
126 }
127 }
128 let key_parts_list: Vec<String> = found_record_ids
129 .iter()
130 .map(|id| id.to_string_id())
131 .collect();
132
133 let keys_refs: Vec<Vec<&str>> = key_parts_list.iter().map(|id| vec![id.as_str()]).collect();
134
135 let keys: Vec<&[&str]> = keys_refs.iter().map(|arr| &arr[..]).collect();
136
137 Self::put_multiple_json_indexes(&keys, found_records).await?;
138 Self::extend_on_index_miss(&records).await?;
139 Ok(())
140 }
141
142 async fn put_to_graph(&self) -> Result<(), DynError> {
144 exec_single_row(self.put_graph_query()?).await
145 }
146
147 async fn reindex(collection_ids: &[T]) -> Result<(), DynError> {
148 match Self::get_from_graph(collection_ids).await {
149 Ok(collection_details_list) => {
150 if !collection_details_list.is_empty() {
151 Self::put_to_index(collection_ids, collection_details_list).await?;
152 }
153 }
154 Err(e) => tracing::error!("Error: Could not find any element of the collection: {}", e),
155 }
156 Ok(())
157 }
158
159 fn collection_details_graph_query(id_list: &[T]) -> Query;
162
163 fn put_graph_query(&self) -> Result<Query, DynError>;
165
166 async fn extend_on_index_miss(elements: &[std::option::Option<Self>]) -> Result<(), DynError>;
167}