mirror of
https://github.com/perstarkse/minne.git
synced 2026-03-31 06:33:09 +02:00
feat: category filtering knowledge and content
This commit is contained in:
@@ -11,7 +11,7 @@ use tokio::fs::remove_dir_all;
|
||||
use tracing::info;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{storage::db::SurrealDbClient, stored_object};
|
||||
use crate::{error::AppError, storage::db::SurrealDbClient, stored_object};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FileError {
|
||||
@@ -221,15 +221,15 @@ impl FileInfo {
|
||||
///
|
||||
/// # Returns
|
||||
/// `Result<(), FileError>`
|
||||
pub async fn delete_by_id(id: &str, db_client: &SurrealDbClient) -> Result<(), FileError> {
|
||||
pub async fn delete_by_id(id: &str, db_client: &SurrealDbClient) -> Result<(), AppError> {
|
||||
// Get the FileInfo from the database
|
||||
let file_info = match db_client.get_item::<FileInfo>(id).await? {
|
||||
Some(info) => info,
|
||||
None => {
|
||||
return Err(FileError::FileNotFound(format!(
|
||||
return Err(AppError::from(FileError::FileNotFound(format!(
|
||||
"File with id {} was not found",
|
||||
id
|
||||
)))
|
||||
))))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -242,15 +242,15 @@ impl FileInfo {
|
||||
remove_dir_all(parent_dir).await?;
|
||||
info!("Removed directory {:?} and its contents", parent_dir);
|
||||
} else {
|
||||
return Err(FileError::FileNotFound(
|
||||
return Err(AppError::from(FileError::FileNotFound(
|
||||
"File has no parent directory".to_string(),
|
||||
));
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return Err(FileError::FileNotFound(format!(
|
||||
return Err(AppError::from(FileError::FileNotFound(format!(
|
||||
"File at path {:?} was not found",
|
||||
file_path
|
||||
)));
|
||||
))));
|
||||
}
|
||||
|
||||
// Delete the FileInfo from the database
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::{error::AppError, storage::types::file_info::FileInfo};
|
||||
use chrono::Utc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::info;
|
||||
use url::Url;
|
||||
|
||||
@@ -227,6 +227,50 @@ impl User {
|
||||
Ok(entities)
|
||||
}
|
||||
|
||||
pub async fn get_knowledge_entities_by_type(
|
||||
user_id: &str,
|
||||
entity_type: &str,
|
||||
db: &SurrealDbClient,
|
||||
) -> Result<Vec<KnowledgeEntity>, AppError> {
|
||||
let entities: Vec<KnowledgeEntity> = db
|
||||
.client
|
||||
.query("SELECT * FROM type::table($table) WHERE user_id = $user_id AND entity_type = $entity_type")
|
||||
.bind(("table", KnowledgeEntity::table_name()))
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("entity_type", entity_type.to_owned()))
|
||||
.await?
|
||||
.take(0)?;
|
||||
|
||||
Ok(entities)
|
||||
}
|
||||
|
||||
pub async fn get_entity_types(
|
||||
user_id: &str,
|
||||
db: &SurrealDbClient,
|
||||
) -> Result<Vec<String>, AppError> {
|
||||
#[derive(Deserialize)]
|
||||
struct EntityTypeResponse {
|
||||
entity_type: String,
|
||||
}
|
||||
|
||||
// Query to select distinct entity types for the user
|
||||
let response: Vec<EntityTypeResponse> = db
|
||||
.client
|
||||
.query("SELECT entity_type FROM type::table($table_name) WHERE user_id = $user_id GROUP BY entity_type")
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("table_name", KnowledgeEntity::table_name()))
|
||||
.await?
|
||||
.take(0)?;
|
||||
|
||||
// Extract the entity types from the response
|
||||
let entity_types: Vec<String> = response
|
||||
.into_iter()
|
||||
.map(|item| format!("{:?}", item.entity_type))
|
||||
.collect();
|
||||
|
||||
Ok(entity_types)
|
||||
}
|
||||
|
||||
pub async fn get_knowledge_relationships(
|
||||
user_id: &str,
|
||||
db: &SurrealDbClient,
|
||||
@@ -272,6 +316,23 @@ impl User {
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
pub async fn get_text_contents_by_category(
|
||||
user_id: &str,
|
||||
category: &str,
|
||||
db: &SurrealDbClient,
|
||||
) -> Result<Vec<TextContent>, AppError> {
|
||||
let items: Vec<TextContent> = db
|
||||
.client
|
||||
.query("SELECT * FROM type::table($table_name) WHERE user_id = $user_id AND category = $category ORDER BY created_at DESC")
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("category", category.to_owned()))
|
||||
.bind(("table_name", TextContent::table_name()))
|
||||
.await?
|
||||
.take(0)?;
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
pub async fn get_latest_knowledge_entities(
|
||||
user_id: &str,
|
||||
db: &SurrealDbClient,
|
||||
@@ -413,6 +474,34 @@ impl User {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_knowledge_entities_by_content_category(
|
||||
user_id: &str,
|
||||
category: &str,
|
||||
db: &SurrealDbClient,
|
||||
) -> Result<Vec<KnowledgeEntity>, AppError> {
|
||||
// First, find all text content items with the specified category
|
||||
let text_contents = Self::get_text_contents_by_category(user_id, category, db).await?;
|
||||
|
||||
if text_contents.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
// Extract source_ids
|
||||
let source_ids: Vec<String> = text_contents.iter().map(|tc| tc.id.clone()).collect();
|
||||
|
||||
// Find all knowledge entities with matching source_ids
|
||||
let entities: Vec<KnowledgeEntity> = db
|
||||
.client
|
||||
.query("SELECT * FROM type::table($table) WHERE user_id = $user_id AND source_id IN $source_ids")
|
||||
.bind(("table", KnowledgeEntity::table_name()))
|
||||
.bind(("user_id", user_id.to_owned()))
|
||||
.bind(("source_ids", source_ids))
|
||||
.await?
|
||||
.take(0)?;
|
||||
|
||||
Ok(entities)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user