Skip to content

Commit

Permalink
fix: support numbers and underscores anywhere in service name and keys
Browse files Browse the repository at this point in the history
  • Loading branch information
amunra committed Jan 31, 2024
1 parent 13b3fc9 commit 35aaace
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 21 deletions.
7 changes: 3 additions & 4 deletions questdb-confstr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ service::key1=value1;key2=value2;key3=value3;
A few rules:
* The last semicolon is mandatory.
* Service name and keys are case-insensitive.
* Keys are ASCII alphanumeric and start with a letter.
* Keys are ASCII alphanumeric and can contain underscores.
* Values are case-sensitive unicode strings which can contain any characters,
* Except control characters (`0x00..=0x1f` and `0x7f..=0x9f`).
* If semicolons `;` appears in a value, these are escaped as double semicolon `;;`.
Expand All @@ -29,9 +29,8 @@ param ::= key "=" value
key ::= identifier
value ::= { value_char }
identifier ::= alpha { alphanumeric }
alpha ::= "a".."z" | "A".."Z"
alphanumeric ::= "a".."z" | "A".."Z" | "0".."9"
identifier ::= alpha_num_under { alpha_num_under }
alpha_num_under ::= "a".."z" | "A".."Z" | "0".."9" | "_"
value_char ::= non_semicolon_char | escaped_semicolon
escaped_semicolon ::= ";;"
non_semicolon_char ::= ? any unicode character except ';', 0x00..=0x1f and 0x7f..=0x9f ?
Expand Down
10 changes: 3 additions & 7 deletions questdb-confstr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,21 +174,17 @@ fn parse_ident(
let mut token = String::new();
while let Some((pos, c)) = iter.peek0() {
*next_pos = *pos;
let take = if token.is_empty() {
c.is_ascii_alphabetic()
if c.is_ascii_alphanumeric() || *c == '_' {
token.push(c.to_ascii_lowercase());
iter.next();
} else {
c.is_ascii_alphanumeric()
};
if !take {
if token.is_empty() {
return Err(parse_err(ErrorKind::ExpectedIdentifierNot(*c), *next_pos));
} else if !c.is_ascii() || matches!(c, '\0'..=' ') {
return Err(parse_err(ErrorKind::MustBeAlphanumeric(*c), *next_pos));
}
break;
}
token.push(c.to_ascii_lowercase());
iter.next();
}

if token.is_empty() {
Expand Down
28 changes: 18 additions & 10 deletions questdb-confstr/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*
******************************************************************************/

use std::collections::HashMap;
use questdb_confstr::{parse_conf_str, ErrorKind, ParsingError};

#[test]
Expand Down Expand Up @@ -75,17 +76,24 @@ fn duplicate_key() {
}

#[test]
fn key_must_start_with_letter() {
fn key_can_start_with_number() -> Result<(), ParsingError> {
let input = "https::123=456;";
let config = parse_conf_str(input);
assert!(config.is_err());
let err = config.unwrap_err();
assert_eq!(err.kind().clone(), ErrorKind::ExpectedIdentifierNot('1'));
assert_eq!(err.position(), 7);
assert_eq!(
err.to_string(),
"expected identifier to start with ascii letter, not '1' at position 7"
);
let config = parse_conf_str(input)?;
assert_eq!(config.service(), "https");
let mut expected = HashMap::new();
expected.insert("123".to_string(), "456".to_string());
assert_eq!(config.params(), &expected);
Ok(())
}

#[test]
fn identifiers_can_contain_underscores() -> Result<(), ParsingError> {
let input = "_A_::__x_Y__=42;";
let config = parse_conf_str(input)?;
assert_eq!(config.service(), "_a_");
let mut expected = HashMap::new();
expected.insert("__x_y__".to_string(), "42".to_string());
Ok(())
}

#[test]
Expand Down

0 comments on commit 35aaace

Please sign in to comment.