refactor(structure): reorganize codebase into domain-focused modules
This commit is contained in:
119
src/documents/extractor/mrs.rs
Normal file
119
src/documents/extractor/mrs.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
pub fn extract_mr_document(conn: &Connection, mr_id: i64) -> Result<Option<DocumentData>> {
|
||||
let row = conn.query_row(
|
||||
"SELECT m.id, m.iid, m.title, m.description, m.state, m.author_username,
|
||||
m.source_branch, m.target_branch,
|
||||
m.created_at, m.updated_at, m.web_url,
|
||||
p.path_with_namespace, p.id AS project_id
|
||||
FROM merge_requests m
|
||||
JOIN projects p ON p.id = m.project_id
|
||||
WHERE m.id = ?1",
|
||||
rusqlite::params![mr_id],
|
||||
|row| {
|
||||
Ok((
|
||||
row.get::<_, i64>(0)?,
|
||||
row.get::<_, i64>(1)?,
|
||||
row.get::<_, Option<String>>(2)?,
|
||||
row.get::<_, Option<String>>(3)?,
|
||||
row.get::<_, Option<String>>(4)?,
|
||||
row.get::<_, Option<String>>(5)?,
|
||||
row.get::<_, Option<String>>(6)?,
|
||||
row.get::<_, Option<String>>(7)?,
|
||||
row.get::<_, Option<i64>>(8)?,
|
||||
row.get::<_, Option<i64>>(9)?,
|
||||
row.get::<_, Option<String>>(10)?,
|
||||
row.get::<_, String>(11)?,
|
||||
row.get::<_, i64>(12)?,
|
||||
))
|
||||
},
|
||||
);
|
||||
|
||||
let (
|
||||
id,
|
||||
iid,
|
||||
title,
|
||||
description,
|
||||
state,
|
||||
author_username,
|
||||
source_branch,
|
||||
target_branch,
|
||||
created_at,
|
||||
updated_at,
|
||||
web_url,
|
||||
path_with_namespace,
|
||||
project_id,
|
||||
) = match row {
|
||||
Ok(r) => r,
|
||||
Err(rusqlite::Error::QueryReturnedNoRows) => return Ok(None),
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
let mut label_stmt = conn.prepare_cached(
|
||||
"SELECT l.name FROM mr_labels ml
|
||||
JOIN labels l ON l.id = ml.label_id
|
||||
WHERE ml.merge_request_id = ?1
|
||||
ORDER BY l.name",
|
||||
)?;
|
||||
let labels: Vec<String> = label_stmt
|
||||
.query_map(rusqlite::params![id], |row| row.get(0))?
|
||||
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||
|
||||
let labels_json = serde_json::to_string(&labels).unwrap_or_else(|_| "[]".to_string());
|
||||
|
||||
let display_title = title.as_deref().unwrap_or("(untitled)");
|
||||
let display_state = state.as_deref().unwrap_or("unknown");
|
||||
let mut content = format!(
|
||||
"[[MergeRequest]] !{}: {}\nProject: {}\n",
|
||||
iid, display_title, path_with_namespace
|
||||
);
|
||||
if let Some(ref url) = web_url {
|
||||
let _ = writeln!(content, "URL: {}", url);
|
||||
}
|
||||
let _ = writeln!(content, "Labels: {}", labels_json);
|
||||
let _ = writeln!(content, "State: {}", display_state);
|
||||
if let Some(ref author) = author_username {
|
||||
let _ = writeln!(content, "Author: @{}", author);
|
||||
}
|
||||
if let (Some(src), Some(tgt)) = (&source_branch, &target_branch) {
|
||||
let _ = writeln!(content, "Source: {} -> {}", src, tgt);
|
||||
}
|
||||
|
||||
if let Some(ref desc) = description {
|
||||
content.push_str("\n--- Description ---\n\n");
|
||||
// Pre-truncate to avoid unbounded memory allocation for huge descriptions
|
||||
let pre_trunc = pre_truncate_description(desc, MAX_DOCUMENT_BYTES_HARD);
|
||||
if pre_trunc.was_truncated {
|
||||
warn!(
|
||||
iid,
|
||||
original_bytes = pre_trunc.original_bytes,
|
||||
"MR description truncated (oversized)"
|
||||
);
|
||||
}
|
||||
content.push_str(&pre_trunc.content);
|
||||
}
|
||||
|
||||
let labels_hash = compute_list_hash(&labels);
|
||||
let paths_hash = compute_list_hash(&[]);
|
||||
|
||||
let hard_cap = truncate_hard_cap(&content);
|
||||
let content_hash = compute_content_hash(&hard_cap.content);
|
||||
|
||||
Ok(Some(DocumentData {
|
||||
source_type: SourceType::MergeRequest,
|
||||
source_id: id,
|
||||
project_id,
|
||||
author_username,
|
||||
labels,
|
||||
paths: Vec::new(),
|
||||
labels_hash,
|
||||
paths_hash,
|
||||
created_at: created_at.unwrap_or(0),
|
||||
updated_at: updated_at.unwrap_or(0),
|
||||
url: web_url,
|
||||
title: Some(display_title.to_string()),
|
||||
content_text: hard_cap.content,
|
||||
content_hash,
|
||||
is_truncated: hard_cap.is_truncated,
|
||||
truncated_reason: hard_cap.reason.map(|r| r.as_str().to_string()),
|
||||
}))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user