Skip to content

🐛 Bug: CLI truncates values containing spaces #76

@ElioNeto

Description

@ElioNeto

🐛 Bug Report: Values Containing Spaces are Truncated in the CLI

📋 Description

The ApexStore CLI parser stops reading the value at the first space character it encounters. When attempting to insert JSON data or a string containing spaces (e.g., {name: elio neto}), the engine only stores the first word, discarding the rest of the input.

🔄 Steps to Reproduce

  1. Open the ApexStore REPL:

    cargo run --bin cli
  2. Run the following command:

    lsm> SET user:1 { "nome": "Elio Neto" }
    
  3. Check the stored value:

    lsm> GET user:1
    

    or

    lsm> ALL
    

✅ Expected Behavior

lsm> GET user:1
✓ 'user:1' = '{ "nome": "Elio Neto" }'

❌ Actual Behavior

lsm> GET user:1
✓ 'user:1' = '{'

Only the first part before the space is stored.

🔍 Root Cause

Current Code (src/cli/mod.rs)

let parts: Vec<&str> = input.splitn(4, ' ').collect();
let command = parts[0].to_uppercase();

match command.as_str() {
    "SET" => {
        if parts.len() < 3 {
            println!("❌ Usage: SET <key> <value>");
            continue;
        }
        let key = parts[1].to_string();
        let value = parts[2].as_bytes().to_vec();  // ⚠️ Captures only parts[2]
        
        match engine.set(key.clone(), value) {
            Ok(_) => println!("✓ SET '{}' executed successfully", key),
            Err(e) => println!("❌ Error: {}", e),
        }
    }
}

The Problem

The code uses splitn(4, ' '), which splits the input into up to 4 parts separated by spaces. For the command SET user:1 { "nome": "Elio Neto" }, the resulting array is:

  • parts[0] = "SET"
  • parts[1] = "user:1"
  • parts[2] = "{"
  • parts[3] = "\"nome\": \"Elio Neto\" }"

However, the current code only captures parts[2], losing all the content stored in parts[3].

💡 Proposed Solution

Option 1: Concatenate the Remaining Parts (Simple and Direct)

"SET" => {
    if parts.len() < 3 {
        println!("❌ Usage: SET <key> <value>");
        continue;
    }
    let key = parts[1].to_string();
    // Concatenate all parts after the key
    let value = parts[2..].join(" ").as_bytes().to_vec();
    
    match engine.set(key.clone(), value) {
        Ok(_) => println!("✓ SET '{}' executed successfully", key),
        Err(e) => println!("❌ Error: {}", e),
    }
}

Pros:

  • Simple implementation
  • No extra dependencies
  • Solves the immediate issue

Cons:

  • Doesn't support quotes for values with leading/trailing spaces
  • Makes it harder to handle controlled spacing within values

Option 2: Parser with Quote Support (Robust)

Use a crate like shlex or implement a custom parser:

use shlex;

// At the beginning of the REPL loop
let parts = match shlex::split(&input) {
    Some(p) => p,
    None => {
        println!("❌ Error processing command (unbalanced quotes?)");
        continue;
    }
};

let command = parts[0].to_uppercase();

match command.as_str() {
    "SET" => {
        if parts.len() < 3 {
            println!("❌ Usage: SET <key> <value>");
            continue;
        }
        let key = parts[1].to_string();
        let value = parts[2].as_bytes().to_vec();
        
        // Now works with: SET user:1 "{ \"nome\": \"Elio Neto\" }"
        match engine.set(key.clone(), value) {
            Ok(_) => println!("✓ SET '{}' executed successfully", key),
            Err(e) => println!("❌ Error: {}", e),
        }
    }
}

Pros:

  • Supports single and double quotes
  • Consistent with Unix shell behavior
  • Allows escaping special characters
  • Professional-grade solution

Cons:

  • Adds an external dependency
  • Requires users to learn quoting syntax

📊 Impact

  • Severity: 🔴 High
  • Frequency: Common (any value containing a space)
  • Affected Use Cases:
    • JSON storage
    • Full names
    • Sentences and descriptions
    • Any multi-word text

🎯 Test Cases

After the fix, the following scenarios should work:

# Case 1: Simple JSON
lsm> SET user:1 {"nome": "Elio Neto"}
lsm> GET user:1
✓ 'user:1' = '{"nome": "Elio Neto"}'

# Case 2: Sentence with spaces
lsm> SET user:2 Alice Silva Santos
lsm> GET user:2
✓ 'user:2' = 'Alice Silva Santos'

# Case 3: Quoted value (Option 2)
lsm> SET user:3 "Name with    multiple spaces"
lsm> GET user:3
✓ 'user:3' = 'Name with    multiple spaces'

# Case 4: Complex JSON
lsm> SET product:1 {"id": 1, "name": "Laptop Dell", "price": 2500.00}
lsm> GET product:1
✓ 'product:1' = '{"id": 1, "name": "Laptop Dell", "price": 2500.00}'

📝 Recommendation

Phased Implementation:

Phase 1 (Quick Fix): Use Option 1 to solve the immediate problem.

  • Implementation time: ~15 minutes
  • Zero dependencies
  • Covers 90% of use cases

Phase 2 (Enhancement): Migrate to Option 2 in a future release.

  • Add shlex = "1.3" to Cargo.toml
  • Implement a robust parser
  • Update documentation with quoting examples

🔗 Affected Files

  • src/cli/mod.rs - main() function, SET command block
  • docs/CLI_GUIDE.md - Syntax documentation for the SET command
  • Possibly Cargo.toml - If Option 2 is chosen

📚 References

✅ Acceptance Criteria

  • Values with spaces are stored completely
  • JSON can be inserted without truncation
  • Manual tests pass for all the cases above
  • Documentation is updated with examples
  • Backward compatibility is maintained (simple commands keep working)

Priority: 🔴 High
Estimate: 1-2 hours (Option 1) or 3-4 hours (Option 2)
Labels: bug, cli, good first issue, priority: high

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions