use crate::ast::data_sources::{DataSourceDecl, QueryDecl};
use crate::error::{Result, ShapeError};
use pest::iterators::Pair;
use super::expressions;
use super::types::parse_type_annotation;
use super::{Rule, pair_location, pair_span};
pub fn parse_datasource_def(pair: Pair<Rule>) -> Result<DataSourceDecl> {
let pair_loc = pair_location(&pair);
let mut inner = pair.into_inner();
let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected datasource name".to_string(),
location: Some(pair_loc.clone()),
})?;
let name_span = pair_span(&name_pair);
let name = name_pair.as_str().to_string();
let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected type annotation after ':'".to_string(),
location: Some(pair_loc.clone()),
})?;
let schema = parse_type_annotation(type_pair)?;
let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected provider expression after '='".to_string(),
location: Some(pair_loc),
})?;
let provider_expr = expressions::parse_expression(expr_pair)?;
Ok(DataSourceDecl {
name,
name_span,
schema,
provider_expr,
})
}
pub fn parse_query_decl(pair: Pair<Rule>) -> Result<QueryDecl> {
let pair_loc = pair_location(&pair);
let mut inner = pair.into_inner();
let name_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected query name".to_string(),
location: Some(pair_loc.clone()),
})?;
let name_span = pair_span(&name_pair);
let name = name_pair.as_str().to_string();
let type_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected type annotation after ':'".to_string(),
location: Some(pair_loc.clone()),
})?;
let type_ann = parse_type_annotation(type_pair)?;
let (output_schema, params_schema) = match &type_ann {
crate::ast::TypeAnnotation::Generic { args, .. } if args.len() == 2 => {
(args[0].clone(), args[1].clone())
}
_ => {
(type_ann, crate::ast::TypeAnnotation::Object(vec![]))
}
};
let expr_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
message: "expected expression after '='".to_string(),
location: Some(pair_loc.clone()),
})?;
let init_expr = expressions::parse_expression(expr_pair)?;
let (source_name, sql, sql_span) = extract_query_parts(&init_expr, &pair_loc)?;
Ok(QueryDecl {
name,
name_span,
output_schema,
params_schema,
source_name,
sql,
sql_span,
})
}
fn extract_query_parts(
expr: &crate::ast::Expr,
loc: &crate::error::SourceLocation,
) -> Result<(String, String, crate::ast::Span)> {
if let crate::ast::Expr::FunctionCall {
name, args, span, ..
} = expr
{
if name == "sql" && args.len() == 2 {
let source = if let crate::ast::Expr::Identifier(src, _) = &args[0] {
src.clone()
} else {
return Err(ShapeError::ParseError {
message: "expected data source identifier as first argument to sql()"
.to_string(),
location: Some(loc.clone()),
});
};
let sql_str = if let crate::ast::Expr::Literal(crate::ast::Literal::String(s), _) =
&args[1]
{
s.clone()
} else {
return Err(ShapeError::ParseError {
message: "expected SQL string literal as second argument to sql()".to_string(),
location: Some(loc.clone()),
});
};
return Ok((source, sql_str, *span));
}
}
Ok((String::new(), String::new(), crate::ast::Span::new(0, 0)))
}