use crate::error::{Error, Result};
pub fn quote_ident(name: &str) -> Result<String> {
if name.is_empty() {
return Err(Error::invalid_ident("identifier is empty"));
}
for (i, ch) in name.chars().enumerate() {
let ok =
ch.is_ascii_alphabetic() || ch == '_' || ch.is_ascii_digit() || (ch == '-' && i != 0);
if !ok {
return Err(Error::invalid_ident(format!(
"identifier contains forbidden character {:?}",
ch
)));
}
}
Ok(name.to_string())
}
pub fn quote_string(s: &str) -> Result<String> {
for ch in s.chars() {
let c = ch as u32;
if c < 0x20 || c == 0x7f {
return Err(Error::invalid_string(
"string literal contains a control character",
));
}
}
let escaped = s.replace('\\', "\\\\").replace('\'', "''");
Ok(format!("'{}'", escaped))
}
pub fn sanitize_graph_name(name: &str) -> String {
name.chars()
.filter(|ch| ch.is_ascii_alphanumeric() || *ch == '_' || *ch == '-')
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Error;
#[test]
fn test_quote_ident_valid() {
for name in [
"abc",
"ABC",
"_foo",
"foo_bar",
"foo-bar",
"foo9",
"9starts",
"005_add_index",
] {
assert_eq!(quote_ident(name).unwrap(), name);
}
}
#[test]
fn test_quote_ident_invalid() {
for name in ["", "-starts", "has space", "has;semi", "has\0null"] {
assert!(
matches!(quote_ident(name), Err(Error::InvalidIdent(_))),
"name={:?}",
name
);
}
}
#[test]
fn test_quote_string_basic() {
assert_eq!(quote_string("hello").unwrap(), "'hello'");
assert_eq!(quote_string("it's").unwrap(), "'it''s'");
}
#[test]
fn test_quote_string_backslash_then_quote() {
assert_eq!(quote_string("back\\slash").unwrap(), "'back\\\\slash'");
assert_eq!(quote_string("back\\'quote").unwrap(), "'back\\\\''quote'");
}
#[test]
fn test_quote_string_rejects_control_chars() {
for s in ["a\nb", "a\rb", "a\tb", "a\0b", "a\x1fb", "a\x7fb"] {
assert!(
matches!(quote_string(s), Err(Error::InvalidString(_))),
"s={:?}",
s
);
}
}
#[test]
fn test_sanitize_graph_name() {
assert_eq!(sanitize_graph_name("myGraph"), "myGraph");
assert_eq!(sanitize_graph_name("my-graph_01"), "my-graph_01");
assert_eq!(sanitize_graph_name("bad name!"), "badname");
assert_eq!(sanitize_graph_name(""), "");
assert_eq!(sanitize_graph_name("有害"), "");
assert_eq!(sanitize_graph_name(" "), "");
}
}