use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Entity {
pub entity_id: String,
pub name: String,
pub aliases: Vec<String>,
pub classifications: Vec<Classification>,
pub definition: String,
pub status: String,
pub create_time: String,
pub update_time: String,
pub creator: String,
pub repo_id: String,
pub cover: Option<EntityCover>,
pub extra: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EntityCover {
pub file_token: String,
pub url: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Classification {
pub classification_id: String,
pub name: String,
pub parent_id: Option<String>,
pub level: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Repository {
pub repo_id: String,
pub name: String,
pub description: Option<String>,
pub entity_count: i32,
pub create_time: String,
pub update_time: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Draft {
pub draft_id: String,
pub title: String,
pub content: String,
pub status: String,
pub operation_type: String,
pub create_time: String,
pub update_time: String,
pub creator: String,
pub approval_status: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EntitySearchResult {
pub entity_id: String,
pub name: String,
pub aliases: Vec<String>,
pub definition: String,
pub score: f64,
pub highlights: Option<Vec<HighlightInfo>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct HighlightInfo {
pub field: String,
pub fragments: Vec<String>,
pub start_position: i32,
pub end_position: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EntityMatchResult {
pub entity_id: String,
pub name: String,
pub match_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct EntityExtractResult {
pub entity: String,
pub suggested_aliases: Vec<String>,
pub confidence: f64,
pub start_position: i32,
pub end_position: i32,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
pub struct FileUploadRequest {
pub file_name: String,
pub file_content: String,
pub file_size: i64,
pub content_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct FileUploadResult {
pub file_token: String,
pub url: String,
pub file_name: String,
pub file_size: i64,
pub content_type: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PageResponse<T> {
pub items: Vec<T>,
pub page: i32,
pub page_size: i32,
pub total: i32,
pub has_next: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ApiResponse<T> {
pub data: Option<T>,
pub code: i32,
pub msg: String,
pub request_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum EntityType {
Normal,
Professional,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DraftStatus {
Editing,
Pending,
Approved,
Rejected,
}
#[cfg(test)]
mod tests {
use super::*;
fn test_roundtrip<T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug>(
original: &T,
) {
let json = serde_json::to_string(original).expect("序列化失败");
let deserialized: T = serde_json::from_str(&json).expect("反序列化失败");
assert_eq!(original, &deserialized, "roundtrip 后数据不一致");
}
#[test]
fn test_entity_serialization() {
let entity = Entity {
entity_id: "entity123".to_string(),
name: "词条名称".to_string(),
aliases: vec!["别名1".to_string(), "别名2".to_string()],
classifications: vec![Classification {
classification_id: "class1".to_string(),
name: "分类1".to_string(),
parent_id: None,
level: 1,
}],
definition: "词条定义".to_string(),
status: "normal".to_string(),
create_time: "2024-01-01T00:00:00Z".to_string(),
update_time: "2024-01-02T00:00:00Z".to_string(),
creator: "user123".to_string(),
repo_id: "repo123".to_string(),
cover: None,
extra: None,
};
test_roundtrip(&entity);
}
#[test]
fn test_entity_cover_serialization() {
let cover = EntityCover {
file_token: "token123".to_string(),
url: "https://example.com/cover.jpg".to_string(),
};
test_roundtrip(&cover);
}
#[test]
fn test_classification_serialization() {
let class = Classification {
classification_id: "class123".to_string(),
name: "技术类".to_string(),
parent_id: Some("parent123".to_string()),
level: 2,
};
test_roundtrip(&class);
}
#[test]
fn test_repository_serialization() {
let repo = Repository {
repo_id: "repo123".to_string(),
name: "技术词典".to_string(),
description: Some("技术相关词条".to_string()),
entity_count: 100,
create_time: "2024-01-01T00:00:00Z".to_string(),
update_time: "2024-01-02T00:00:00Z".to_string(),
};
test_roundtrip(&repo);
}
#[test]
fn test_draft_serialization() {
let draft = Draft {
draft_id: "draft123".to_string(),
title: "草稿标题".to_string(),
content: "草稿内容".to_string(),
status: "editing".to_string(),
operation_type: "create".to_string(),
create_time: "2024-01-01T00:00:00Z".to_string(),
update_time: "2024-01-02T00:00:00Z".to_string(),
creator: "user123".to_string(),
approval_status: "pending".to_string(),
};
test_roundtrip(&draft);
}
#[test]
fn test_entity_search_result_serialization() {
let result = EntitySearchResult {
entity_id: "entity123".to_string(),
name: "搜索结果".to_string(),
aliases: vec!["别名".to_string()],
definition: "定义".to_string(),
score: 0.95,
highlights: None,
};
test_roundtrip(&result);
}
#[test]
fn test_highlight_info_serialization() {
let highlight = HighlightInfo {
field: "name".to_string(),
fragments: vec!["<em>高亮</em>".to_string()],
start_position: 0,
end_position: 10,
};
test_roundtrip(&highlight);
}
#[test]
fn test_entity_match_result_serialization() {
let result = EntityMatchResult {
entity_id: "entity123".to_string(),
name: "匹配结果".to_string(),
match_type: "name".to_string(),
};
test_roundtrip(&result);
}
#[test]
fn test_entity_extract_result_serialization() {
let result = EntityExtractResult {
entity: "提取词条".to_string(),
suggested_aliases: vec!["建议别名".to_string()],
confidence: 0.85,
start_position: 0,
end_position: 4,
};
test_roundtrip(&result);
}
#[test]
fn test_file_upload_request_serialization() {
let req = FileUploadRequest {
file_name: "test.pdf".to_string(),
file_content: "base64content".to_string(),
file_size: 1024,
content_type: "application/pdf".to_string(),
};
test_roundtrip(&req);
}
#[test]
fn test_file_upload_result_serialization() {
let result = FileUploadResult {
file_token: "token123".to_string(),
url: "https://example.com/file".to_string(),
file_name: "test.pdf".to_string(),
file_size: 1024,
content_type: "application/pdf".to_string(),
};
test_roundtrip(&result);
}
#[test]
fn test_page_response_serialization() {
let response: PageResponse<String> = PageResponse {
items: vec!["item1".to_string(), "item2".to_string()],
page: 1,
page_size: 20,
total: 100,
has_next: true,
};
test_roundtrip(&response);
}
#[test]
fn test_api_response_serialization() {
let response: ApiResponse<String> = ApiResponse {
data: Some("test data".to_string()),
code: 0,
msg: "success".to_string(),
request_id: Some("req123".to_string()),
};
test_roundtrip(&response);
}
#[test]
fn test_entity_type_serialization() {
test_roundtrip(&EntityType::Normal);
test_roundtrip(&EntityType::Professional);
test_roundtrip(&EntityType::Custom);
}
#[test]
fn test_draft_status_serialization() {
test_roundtrip(&DraftStatus::Editing);
test_roundtrip(&DraftStatus::Pending);
test_roundtrip(&DraftStatus::Approved);
test_roundtrip(&DraftStatus::Rejected);
}
}