nexus_common/models/user/
counts.rs1use crate::db::kv::JsonAction;
2use crate::db::{get_neo4j_graph, queries, RedisOps};
3use crate::models::tag::user::USER_TAGS_KEY_PARTS;
4use crate::types::DynError;
5use serde::{Deserialize, Serialize};
6use utoipa::ToSchema;
7
8use super::UserStream;
9
10#[derive(Serialize, Deserialize, ToSchema, Debug, Default)]
12pub struct UserCounts {
13 pub tagged: u32,
15 pub tags: u32,
17 pub unique_tags: u32,
19 pub posts: u32,
20 pub replies: u32,
21 pub following: u32,
22 pub followers: u32,
23 pub friends: u32,
24 pub bookmarks: u32,
25}
26
27impl RedisOps for UserCounts {}
28
29impl UserCounts {
30 pub async fn get_by_id(user_id: &str) -> Result<Option<UserCounts>, DynError> {
32 match Self::get_from_index(user_id).await? {
33 Some(counts) => Ok(Some(counts)),
34 None => {
35 let graph_response = Self::get_from_graph(user_id).await?;
36 if let Some(user_counts) = graph_response {
37 user_counts.put_to_index(user_id).await?;
38 return Ok(Some(user_counts));
39 }
40 Ok(None)
41 }
42 }
43 }
44
45 pub async fn get_from_graph(user_id: &str) -> Result<Option<UserCounts>, DynError> {
47 let mut result;
48 {
49 let graph = get_neo4j_graph()?;
50 let query = queries::get::user_counts(user_id);
51
52 let graph = graph.lock().await;
53 result = graph.execute(query).await?;
54 }
55
56 if let Some(row) = result.next().await? {
57 let user_exists: bool = row.get("exists").unwrap_or(false);
58 if user_exists {
59 match row.get("counts") {
60 Ok(user_counts) => return Ok(Some(user_counts)),
61 Err(_e) => return Ok(None),
65 }
66 }
67 }
68 Ok(None)
69 }
70
71 pub async fn get_from_index(user_id: &str) -> Result<Option<UserCounts>, DynError> {
72 if let Some(user_counts) = Self::try_from_index_json(&[user_id], None).await? {
73 return Ok(Some(user_counts));
74 }
75 Ok(None)
76 }
77
78 pub async fn put_to_index(&self, user_id: &str) -> Result<(), DynError> {
79 self.put_index_json(&[user_id], None, None).await?;
80 UserStream::add_to_most_followed_sorted_set(user_id, self).await?;
81 UserStream::add_to_influencers_sorted_set(user_id, self).await?;
82 Ok(())
83 }
84
85 pub async fn update_index_field(
86 author_id: &str,
87 field: &str,
88 action: JsonAction,
89 ) -> Result<(), DynError> {
90 Self::modify_json_field(&[author_id], field, action).await?;
91 Ok(())
92 }
93
94 pub async fn update(
110 user_id: &str,
111 field: &str,
112 action: JsonAction,
113 tag_label: Option<&str>,
114 ) -> Result<(), DynError> {
115 if let Some(label) = tag_label {
117 let index_parts = [&USER_TAGS_KEY_PARTS[..], &[user_id]].concat();
118 let score = Self::check_sorted_set_member(None, &index_parts, &[label]).await?;
119 match (score, &action) {
120 (Some(tag_value), _) if tag_value < 1 => (),
122
123 (None, JsonAction::Increment(_)) => (),
125
126 _ => return Ok(()),
128 }
129 }
130 Self::update_index_field(user_id, field, action).await?;
132 if field == "followers" || field == "tags" || field == "posts" {
134 let exist_count = Self::get_by_id(user_id).await?;
135 if let Some(user_counts) = exist_count {
136 UserStream::add_to_influencers_sorted_set(user_id, &user_counts).await?;
137 if field == "followers" {
139 UserStream::add_to_most_followed_sorted_set(user_id, &user_counts).await?
140 }
141 }
142 }
143 Ok(())
144 }
145
146 pub async fn reindex(author_id: &str) -> Result<(), DynError> {
147 match Self::get_from_graph(author_id).await? {
148 Some(counts) => counts.put_to_index(author_id).await?,
149 None => tracing::error!("{}: Could not found user counts in the graph", author_id),
150 }
151 Ok(())
152 }
153
154 pub async fn delete(user_id: &str) -> Result<(), DynError> {
155 Self::remove_from_index_multiple_json(&[&[user_id]]).await?;
157
158 Ok(())
159 }
160}