use crate::db::{execute_graph_operation, get_neo4j_graph, queries, OperationOutcome, RedisOps};
use crate::types::DynError;
use neo4rs::Relation;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use super::PostStream;
#[derive(Serialize, Deserialize, ToSchema, Default, Debug)]
pub struct Bookmark {
pub id: String,
pub indexed_at: i64,
}
impl RedisOps for Bookmark {}
impl Bookmark {
pub async fn put_to_graph(
author_id: &str,
post_id: &str,
user_id: &str,
bookmark_id: &str,
indexed_at: i64,
) -> Result<OperationOutcome, DynError> {
let query = queries::put::create_post_bookmark(
user_id,
author_id,
post_id,
bookmark_id,
indexed_at,
);
execute_graph_operation(query).await
}
pub async fn get_by_id(
author_id: &str,
post_id: &str,
viewer_id: Option<&str>,
) -> Result<Option<Bookmark>, DynError> {
let viewer_id = match viewer_id {
Some(viewer_id) => viewer_id,
None => return Ok(None),
};
match Self::get_from_index(author_id, post_id, viewer_id).await? {
Some(counts) => Ok(Some(counts)),
None => {
let graph_response = Self::get_from_graph(author_id, post_id, viewer_id).await?;
if let Some(bookmark) = graph_response {
bookmark.put_to_index(author_id, post_id, viewer_id).await?;
return Ok(Some(bookmark));
}
Ok(None)
}
}
}
pub async fn get_from_index(
author_id: &str,
post_id: &str,
viewer_id: &str,
) -> Result<Option<Bookmark>, DynError> {
if let Some(bookmark) =
Self::try_from_index_json(&[author_id, post_id, viewer_id], None).await?
{
return Ok(Some(bookmark));
}
Ok(None)
}
pub async fn get_from_graph(
author_id: &str,
post_id: &str,
viewer_id: &str,
) -> Result<Option<Bookmark>, DynError> {
let mut result;
{
let graph = get_neo4j_graph()?;
let query = queries::get::post_bookmark(author_id, post_id, viewer_id);
let graph = graph.lock().await;
result = graph.execute(query).await?;
}
if let Some(row) = result.next().await? {
let relation: Relation = match row.get("b") {
Ok(value) => value,
Err(_) => return Ok(None),
};
let bookmark = Self {
id: relation.get("id").unwrap_or_default(),
indexed_at: relation.get("indexed_at").unwrap_or_default(),
};
Ok(Some(bookmark))
} else {
Ok(None)
}
}
pub async fn put_to_index(
&self,
author_id: &str,
post_id: &str,
viewer_id: &str,
) -> Result<(), DynError> {
self.put_index_json(&[author_id, post_id, viewer_id], None, None)
.await?;
PostStream::add_to_bookmarks_sorted_set(self, viewer_id, post_id, author_id).await?;
Ok(())
}
pub async fn reindex(user_id: &str) -> Result<(), DynError> {
let mut result;
{
let graph = get_neo4j_graph()?;
let query = queries::get::user_bookmarks(user_id);
let graph = graph.lock().await;
result = graph.execute(query).await?;
}
while let Some(row) = result.next().await? {
if let Some(relation) = row.get::<Option<Relation>>("b")? {
let bookmark = Bookmark {
id: relation.get("id").unwrap_or_default(),
indexed_at: relation.get("indexed_at").unwrap_or_default(),
};
let author_id = row.get("author_id")?;
let post_id = row.get("post_id")?;
bookmark.put_to_index(author_id, post_id, user_id).await?;
}
}
Ok(())
}
pub async fn del_from_graph(
user_id: &str,
bookmark_id: &str,
) -> Result<Option<(String, String)>, DynError> {
let mut result;
{
let graph = get_neo4j_graph()?;
let query = queries::del::delete_bookmark(user_id, bookmark_id);
let graph = graph.lock().await;
result = graph.execute(query).await?;
}
while let Some(row) = result.next().await? {
let post_id: Option<String> = row.get("post_id").unwrap_or(None);
let author_id: Option<String> = row.get("author_id").unwrap_or(None);
if let (Some(post_id), Some(author_id)) = (post_id, author_id) {
return Ok(Some((post_id, author_id)));
}
}
Ok(None)
}
pub async fn del_from_index(
bookmarker_id: &str,
post_id: &str,
author_id: &str,
) -> Result<(), DynError> {
Self::remove_from_index_multiple_json(&[&[author_id, post_id, bookmarker_id]]).await?;
PostStream::remove_from_bookmarks_sorted_set(bookmarker_id, post_id, author_id).await?;
Ok(())
}
}