Skip to content

Commit

Permalink
Merge pull request #918 from schungx/master
Browse files Browse the repository at this point in the history
Fix Scope deserialization lifetime
  • Loading branch information
schungx authored Sep 27, 2024
2 parents ef3df63 + 5107a6a commit a42efec
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/serde/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl<'de> Deserialize<'de> for ImmutableString {
}
}

impl<'de> Deserialize<'de> for Scope<'de> {
impl<'de> Deserialize<'de> for Scope<'_> {
#[inline(always)]
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Debug, Clone, Hash, Deserialize)]
Expand Down
69 changes: 67 additions & 2 deletions tests/custom_syntax.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![cfg(not(feature = "no_custom_syntax"))]

use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, LexError, ParseErrorType, Position, Scope, INT};
use rhai::{Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, Scope, INT};

#[test]
fn test_custom_syntax() {
Expand Down Expand Up @@ -432,3 +431,69 @@ fn test_custom_syntax_raw2() {
assert_eq!(engine.eval::<INT>("#42/2").unwrap(), 21);
assert_eq!(engine.eval::<INT>("sign(#1)").unwrap(), 1);
}

#[test]
fn test_custom_syntax_raw_sql() {
let mut engine = Engine::new();

engine.register_custom_syntax_with_state_raw(
"SELECT",
|symbols, lookahead, state| {
// Build a SQL statement as the state
let mut sql: String = if state.is_unit() { Default::default() } else { state.take().cast::<ImmutableString>().into() };

// At every iteration, the last symbol is the new one
let r = match symbols.last().unwrap().as_str() {
// Terminate parsing when we see `;`
";" => None,
// Variable substitution -- parse the following as a block
"$" => Some("$block$".into()),
// Block parsed, replace it with `?` as SQL parameter
"$block$" => {
if !sql.is_empty() {
sql.push(' ');
}
sql.push('?');
Some(lookahead.into()) // Always accept the next token
}
// Otherwise simply concat the tokens
_ => {
if !sql.is_empty() {
sql.push(' ');
}
sql.push_str(symbols.last().unwrap().as_str());
Some(lookahead.into()) // Always accept the next token
}
};

// SQL statement done!
*state = sql.into();

match lookahead {
// End of script?
"{EOF}" => Ok(None),
_ => Ok(r),
}
},
false,
|context, inputs, state| {
// Our SQL statement
let sql = state.as_immutable_string_ref().unwrap();
let mut output = sql.to_string();

// Inputs will be parameters
for input in inputs {
let value = context.eval_expression_tree(input).unwrap();
output.push('\n');
output.push_str(&value.to_string());
}

Ok(output.into())
},
);

let mut scope = Scope::new();
scope.push("id", 123 as INT);

assert_eq!(engine.eval_with_scope::<String>(&mut scope, "SELECT * FROM table WHERE id = ${id}").unwrap(), "SELECT * FROM table WHERE id = ?\n123");
}

0 comments on commit a42efec

Please sign in to comment.