pub mod ast;
pub mod lexer;
mod lower;
pub mod parser;
pub mod token;
use anyhow::{Result, bail, ensure};
use reblessive::Stack;
pub use self::lower::PreparedGqlQuery;
use crate::cnf::CommonConfig;
use crate::dbs::Capabilities;
use crate::dbs::capabilities::ExperimentalTarget;
use crate::err::Error;
use crate::syn::error::{SyntaxError, syntax_error};
use crate::syn::token::Span;
const TARGET: &str = "surrealdb::core::gql";
pub fn parse_str(input: &str) -> Result<ast::GqlQuery, SyntaxError> {
parse_with_settings(input, GqlParserSettings::default())
}
pub fn parse_with_settings(
input: &str,
settings: GqlParserSettings,
) -> Result<ast::GqlQuery, SyntaxError> {
if input.len() > u32::MAX as usize {
return Err(syntax_error!(
"Cannot parse query, the query exceeded the maximum size of 4GB",
@Span::empty()
));
}
let mut parser = parser::Parser::new_with_settings(input, settings);
let mut stack = Stack::new();
stack.enter(|stk| parser.parse_query(stk)).finish()
}
pub fn lower(query: ast::GqlQuery) -> Result<PreparedGqlQuery, SyntaxError> {
Ok(PreparedGqlQuery(lower::lower(query)?))
}
pub fn parse_to_plan_with_settings(
input: &str,
settings: GqlParserSettings,
) -> Result<PreparedGqlQuery, SyntaxError> {
let query = parse_with_settings(input, settings)?;
lower(query)
}
pub fn settings_from_capabilities_config(
_capabilities: &Capabilities,
config: &CommonConfig,
) -> 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: &CommonConfig,
) -> Result<PreparedGqlQuery> {
trace!(target: TARGET, "Parsing GQL query");
if !capabilities.allows_experimental(&ExperimentalTarget::Gql) {
bail!("Experimental capability `gql` is not enabled");
}
ensure!(input.len() <= u32::MAX as usize, Error::QueryTooLarge);
parse_to_plan_with_settings(input, settings_from_capabilities_config(capabilities, config))
.map_err(|e| e.render_on(input))
.map_err(Error::InvalidQuery)
.map_err(anyhow::Error::new)
}
#[derive(Clone, Debug)]
pub struct GqlParserSettings {
pub object_recursion_limit: usize,
pub expr_recursion_limit: usize,
}
impl Default for GqlParserSettings {
fn default() -> Self {
GqlParserSettings {
object_recursion_limit: 100,
expr_recursion_limit: 128,
}
}
}