Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/ctxgraph-cli/src/commands/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ pub fn run(
_source: Option<String>,
) -> ctxgraph::Result<()> {
let graph = open_graph()?;
let results = graph.search(&text, limit)?;

let safe_query = super::query_universal::sanitize_query(&text);

let results = graph.search(&safe_query, limit)?;

if results.is_empty() {
println!("No results found for '{text}'");
Expand Down
46 changes: 18 additions & 28 deletions crates/ctxgraph-cli/src/commands/query_universal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,20 +170,7 @@ pub fn run(query_text: String, limit: usize) -> ctxgraph::Result<()> {
}

// ── Stage 3: fallback fused search ───────────────────────────
// FTS5 doesn't like punctuation. Strip everything except word chars.
let safe_query: String = query_text
.chars()
.map(|c| {
if c.is_alphanumeric() || c == ' ' || c == '_' {
c
} else {
' '
}
})
.collect::<String>()
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
let safe_query = sanitize_query(&query_text);

println!("\n FALLBACK fused search results:");
let entity_hits = graph.search_entities(&safe_query, limit.min(10))?;
Expand Down Expand Up @@ -300,20 +287,7 @@ fn split_verb_entity(
}

fn exact_entity_lookup(graph: &ctxgraph::Graph, name: &str) -> ctxgraph::Result<Option<Entity>> {
// Strip punctuation for FTS5 compatibility
let safe: String = name
.chars()
.map(|c| {
if c.is_alphanumeric() || c == ' ' || c == '_' {
c
} else {
' '
}
})
.collect::<String>()
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
let safe = sanitize_query(name);
if safe.is_empty() {
return Ok(None);
}
Expand All @@ -328,6 +302,22 @@ fn exact_entity_lookup(graph: &ctxgraph::Graph, name: &str) -> ctxgraph::Result<
Ok(None)
}

/// Sanitize a query string for FTS5 by stripping non-alphanumeric characters.
pub fn sanitize_query(text: &str) -> String {
text.chars()
.map(|c| {
if c.is_alphanumeric() || c == ' ' || c == '_' {
c
} else {
' '
}
})
.collect::<String>()
.split_whitespace()
.collect::<Vec<_>>()
.join(" ")
}

fn is_pure_stopwords(s: &str) -> bool {
const STOP: &[&str] = &[
"what", "who", "where", "when", "why", "how", "the", "a", "an", "is", "are", "was", "were",
Expand Down