use anyhow::{Result, ensure};
pub(crate) use surrealdb_gql::{GqlParserSettings, PreparedGqlQuery, parse_to_plan_with_settings};
use crate::dbs::Capabilities;
use crate::syn::{ParseError, ParserConfig};
const TARGET: &str = "surrealdb::core::gql";
pub fn settings_from_capabilities_config(
_capabilities: &Capabilities,
config: &ParserConfig,
) -> GqlParserSettings {
GqlParserSettings {
object_recursion_limit: config.max_object_parsing_depth as usize,
expr_recursion_limit: config.max_expression_parsing_depth as usize,
}
}
#[instrument(level = "trace", target = "surrealdb::core::gql", fields(length = input.len()))]
pub fn parse_with_capabilities(
input: &str,
capabilities: &Capabilities,
config: &ParserConfig,
) -> Result<PreparedGqlQuery> {
trace!(target: TARGET, "Parsing GQL query");
ensure!(input.len() <= u32::MAX as usize, ParseError::QueryTooLarge);
parse_to_plan_with_settings(input, settings_from_capabilities_config(capabilities, config))
.map_err(|e| e.render_on(input))
.map_err(ParseError::InvalidQuery)
.map_err(anyhow::Error::new)
}
#[cfg(test)]
mod tests {
#[test]
fn parse_with_capabilities_renders_errors_like_surrealql() {
use crate::dbs::Capabilities;
use crate::dbs::capabilities::Targets;
use crate::syn::ParserConfig;
let error = crate::gql::parse_with_capabilities(
"MATCH (n:person) RETURN m",
&Capabilities::all().with_experimental(Targets::All),
&ParserConfig::default(),
)
.expect_err("should fail");
let rendered = format!("{error}");
assert!(rendered.contains("Parse error"), "unexpected error: {rendered}");
assert!(rendered.contains("Unknown variable `m`"), "unexpected error: {rendered}");
}
#[test]
fn parse_with_capabilities_available_without_experimental_flag() {
use crate::dbs::Capabilities;
use crate::syn::ParserConfig;
crate::gql::parse_with_capabilities(
"MATCH (n:person) RETURN n AS n",
&Capabilities::all(),
&ParserConfig::default(),
)
.expect("GQL should lower without an experimental capability");
}
}