eliminate use of miette!

main
Ziyang Hu 2 years ago
parent d7004097eb
commit 963e09d620

@ -1,7 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use miette::{miette, bail, ensure, Result};
use miette::{bail as bail_out, ensure as ensure_that, miette as gen_err, Result};
use crate::data::value::DataValue;
@ -71,7 +71,7 @@ impl NormalAggrObj for AggrAnd {
fn set(&mut self, value: &DataValue) -> Result<()> {
match value {
DataValue::Bool(v) => self.accum &= *v,
v => bail!("cannot compute 'and' for {:?}", v),
v => bail_out!("cannot compute 'and' for {:?}", v),
}
Ok(())
}
@ -91,7 +91,7 @@ impl MeetAggrObj for MeetAggrAnd {
*l &= *r;
Ok(old == *l)
}
(u, v) => bail!("cannot compute 'and' for {:?} and {:?}", u, v),
(u, v) => bail_out!("cannot compute 'and' for {:?} and {:?}", u, v),
}
}
}
@ -107,7 +107,7 @@ impl NormalAggrObj for AggrOr {
fn set(&mut self, value: &DataValue) -> Result<()> {
match value {
DataValue::Bool(v) => self.accum |= *v,
v => bail!("cannot compute 'or' for {:?}", v),
v => bail_out!("cannot compute 'or' for {:?}", v),
}
Ok(())
}
@ -127,7 +127,7 @@ impl MeetAggrObj for MeetAggrOr {
*l |= *r;
Ok(old == *l)
}
(u, v) => bail!("cannot compute 'or' for {:?} and {:?}", u, v),
(u, v) => bail_out!("cannot compute 'or' for {:?} and {:?}", u, v),
}
}
}
@ -207,7 +207,7 @@ impl NormalAggrObj for AggrUnion {
fn set(&mut self, value: &DataValue) -> Result<()> {
match value {
DataValue::List(v) => self.accum.extend(v.iter().cloned()),
v => bail!("cannot compute 'union' for value {:?}", v),
v => bail_out!("cannot compute 'union' for value {:?}", v),
}
Ok(())
}
@ -242,7 +242,7 @@ impl MeetAggrObj for MeetAggrUnion {
}
inserted
}
(_, v) => bail!("cannot compute 'union' for value {:?}", v),
(_, v) => bail_out!("cannot compute 'union' for value {:?}", v),
});
}
}
@ -263,7 +263,7 @@ impl NormalAggrObj for AggrIntersection {
self.accum.remove(el);
}
}
v => bail!("cannot compute 'intersection' for value {:?}", v),
v => bail_out!("cannot compute 'intersection' for value {:?}", v),
}
Ok(())
}
@ -298,7 +298,7 @@ impl MeetAggrObj for MeetAggrIntersection {
}
removed
}
(_, v) => bail!("cannot compute 'union' for value {:?}", v),
(_, v) => bail_out!("cannot compute 'union' for value {:?}", v),
});
}
}
@ -332,7 +332,7 @@ impl NormalAggrObj for AggrStrJoin {
self.accum.push_str(s);
Ok(())
} else {
bail!("cannot apply 'str_join' to {:?}", value)
bail_out!("cannot apply 'str_join' to {:?}", value)
}
}
@ -410,7 +410,7 @@ impl NormalAggrObj for AggrVariance {
self.sum_sq += f * f;
self.count += 1;
}
v => bail!("cannot compute 'variance': encountered value {:?}", v),
v => bail_out!("cannot compute 'variance': encountered value {:?}", v),
}
Ok(())
}
@ -441,7 +441,7 @@ impl NormalAggrObj for AggrStdDev {
self.sum_sq += f * f;
self.count += 1;
}
v => bail!("cannot compute 'std_dev': encountered value {:?}", v),
v => bail_out!("cannot compute 'std_dev': encountered value {:?}", v),
}
Ok(())
}
@ -468,7 +468,7 @@ impl NormalAggrObj for AggrMean {
self.sum += n.get_float();
self.count += 1;
}
v => bail!("cannot compute 'mean': encountered value {:?}", v),
v => bail_out!("cannot compute 'mean': encountered value {:?}", v),
}
Ok(())
}
@ -491,7 +491,7 @@ impl NormalAggrObj for AggrSum {
DataValue::Num(n) => {
self.sum += n.get_float();
}
v => bail!("cannot compute 'sum': encountered value {:?}", v),
v => bail_out!("cannot compute 'sum': encountered value {:?}", v),
}
Ok(())
}
@ -514,7 +514,7 @@ impl NormalAggrObj for AggrProduct {
DataValue::Num(n) => {
self.product *= n.get_float();
}
v => bail!("cannot compute 'product': encountered value {:?}", v),
v => bail_out!("cannot compute 'product': encountered value {:?}", v),
}
Ok(())
}
@ -620,7 +620,7 @@ impl NormalAggrObj for AggrChoice {
}
fn get(&self) -> Result<DataValue> {
self.found.clone().ok_or_else(|| miette!("empty choice"))
self.found.clone().ok_or_else(|| gen_err!("empty choice"))
}
}
@ -690,7 +690,7 @@ impl NormalAggrObj for AggrMinCost {
fn set(&mut self, value: &DataValue) -> Result<()> {
match value {
DataValue::List(l) => {
ensure!(
ensure_that!(
l.len() == 2,
"'min_cost' requires a list of exactly two items as argument"
);
@ -701,7 +701,7 @@ impl NormalAggrObj for AggrMinCost {
}
Ok(())
}
v => bail!("cannot compute 'min_cost' on {:?}", v),
v => bail_out!("cannot compute 'min_cost' on {:?}", v),
}
}
@ -716,7 +716,7 @@ impl MeetAggrObj for MeetAggrMinCost {
fn update(&self, left: &mut DataValue, right: &DataValue) -> Result<bool> {
Ok(match (left, right) {
(DataValue::List(prev), DataValue::List(l)) => {
ensure!(
ensure_that!(
l.len() == 2 && prev.len() == 2,
"'min_cost' requires a list of length 2 as argument, got {:?}, {:?}",
prev,
@ -732,7 +732,7 @@ impl MeetAggrObj for MeetAggrMinCost {
true
}
}
(u, v) => bail!("cannot compute 'min_cost' on {:?}, {:?}", u, v),
(u, v) => bail_out!("cannot compute 'min_cost' on {:?}, {:?}", u, v),
})
}
}
@ -757,7 +757,7 @@ impl NormalAggrObj for AggrMaxCost {
fn set(&mut self, value: &DataValue) -> Result<()> {
match value {
DataValue::List(l) => {
ensure!(
ensure_that!(
l.len() == 2,
"'max_cost' requires a list of exactly two items as argument"
);
@ -768,7 +768,7 @@ impl NormalAggrObj for AggrMaxCost {
}
Ok(())
}
v => bail!("cannot compute 'max_cost' on {:?}", v),
v => bail_out!("cannot compute 'max_cost' on {:?}", v),
}
}
@ -783,7 +783,7 @@ impl MeetAggrObj for MeetAggrMaxCost {
fn update(&self, left: &mut DataValue, right: &DataValue) -> Result<bool> {
Ok(match (left, right) {
(DataValue::List(prev), DataValue::List(l)) => {
ensure!(
ensure_that!(
l.len() == 2 && prev.len() == 2,
"'max_cost' requires a list of length 2 as argument, got {:?}, {:?}",
prev,
@ -799,7 +799,7 @@ impl MeetAggrObj for MeetAggrMaxCost {
true
}
}
(u, v) => bail!("cannot compute 'max_cost' on {:?}, {:?}", u, v),
(u, v) => bail_out!("cannot compute 'max_cost' on {:?}, {:?}", u, v),
})
}
}
@ -825,7 +825,7 @@ impl NormalAggrObj for AggrShortest {
}
Ok(())
}
v => bail!("cannot compute 'shortest' on {:?}", v),
v => bail_out!("cannot compute 'shortest' on {:?}", v),
}
}
@ -848,7 +848,7 @@ impl MeetAggrObj for MeetAggrShortest {
} else {
false
}),
(l, v) => bail!("cannot compute 'shortest' on {:?} and {:?}", l, v),
(l, v) => bail_out!("cannot compute 'shortest' on {:?} and {:?}", l, v),
}
}
}
@ -907,7 +907,7 @@ impl NormalAggrObj for AggrBitAnd {
if self.res.is_empty() {
self.res = bs.to_vec();
} else {
ensure!(
ensure_that!(
self.res.len() == bs.len(),
"operands of 'bit_and' must have the same lengths, got {:x?} and {:x?}",
self.res,
@ -919,7 +919,7 @@ impl NormalAggrObj for AggrBitAnd {
}
Ok(())
}
v => bail!("cannot apply 'bit_and' to {:?}", v),
v => bail_out!("cannot apply 'bit_and' to {:?}", v),
}
}
@ -937,7 +937,7 @@ impl MeetAggrObj for MeetAggrBitAnd {
if left == right {
return Ok(false);
}
ensure!(
ensure_that!(
left.len() == right.len(),
"operands of 'bit_and' must have the same lengths, got {:x?} and {:x?}",
left,
@ -949,7 +949,7 @@ impl MeetAggrObj for MeetAggrBitAnd {
Ok(true)
}
v => bail!("cannot apply 'bit_and' to {:?}", v),
v => bail_out!("cannot apply 'bit_and' to {:?}", v),
}
}
}
@ -968,7 +968,7 @@ impl NormalAggrObj for AggrBitOr {
if self.res.is_empty() {
self.res = bs.to_vec();
} else {
ensure!(
ensure_that!(
self.res.len() == bs.len(),
"operands of 'bit_or' must have the same lengths, got {:x?} and {:x?}",
self.res,
@ -980,7 +980,7 @@ impl NormalAggrObj for AggrBitOr {
}
Ok(())
}
v => bail!("cannot apply 'bit_or' to {:?}", v),
v => bail_out!("cannot apply 'bit_or' to {:?}", v),
}
}
@ -998,7 +998,7 @@ impl MeetAggrObj for MeetAggrBitOr {
if left == right {
return Ok(false);
}
ensure!(
ensure_that!(
left.len() == right.len(),
"operands of 'bit_or' must have the same lengths, got {:x?} and {:x?}",
left,
@ -1010,7 +1010,7 @@ impl MeetAggrObj for MeetAggrBitOr {
Ok(true)
}
v => bail!("cannot apply 'bit_or' to {:?}", v),
v => bail_out!("cannot apply 'bit_or' to {:?}", v),
}
}
}
@ -1029,7 +1029,7 @@ impl NormalAggrObj for AggrBitXor {
if self.res.is_empty() {
self.res = bs.to_vec();
} else {
ensure!(
ensure_that!(
self.res.len() == bs.len(),
"operands of 'bit_xor' must have the same lengths, got {:x?} and {:x?}",
self.res,
@ -1041,7 +1041,7 @@ impl NormalAggrObj for AggrBitXor {
}
Ok(())
}
v => bail!("cannot apply 'bit_xor' to {:?}", v),
v => bail_out!("cannot apply 'bit_xor' to {:?}", v),
}
}
@ -1124,7 +1124,7 @@ impl Aggregation {
AggrStrJoin::default()
} else {
let arg = args[0].get_string().ok_or_else(|| {
miette!(
gen_err!(
"the argument to 'str_join' must be a string, got {:?}",
args[0]
)
@ -1137,12 +1137,12 @@ impl Aggregation {
AggrCollect::default()
} else {
let arg = args[0].get_int().ok_or_else(|| {
miette!(
gen_err!(
"the argument to 'collect' must be an integer, got {:?}",
args[0]
)
})?;
ensure!(
ensure_that!(
arg > 0,
"argument to 'collect' must be positive, got {}",
arg

@ -2,17 +2,20 @@ use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
use log::error;
use miette::{bail, ensure, miette, Result};
use miette::{bail, Diagnostic, ensure, Result};
use rmp_serde::Serializer;
use serde::Serialize;
use smallvec::SmallVec;
use smartstring::{LazyCompact, SmartString};
use thiserror::Error;
use crate::data::encode::EncodedVec;
use crate::data::id::{AttrId, EntityId, TxId, Validity};
use crate::data::triple::StoreOp;
use crate::data::value::{DataValue, Num};
use crate::runtime::transact::SessionTx;
use crate::transact::meta::AttrNotFoundError;
use crate::transact::triple::EntityNotFound;
// use crate::parse::triple::TempIdCtx;
@ -106,53 +109,50 @@ impl Display for AttributeTyping {
}
impl AttributeTyping {
fn type_err(&self, val: DataValue) -> miette::Error {
miette!("cannot coerce {:?} to {:?}", val, self)
}
pub(crate) fn coerce_value(&self, val: DataValue) -> Result<DataValue> {
pub(crate) fn coerce_value(&self, val: DataValue) -> Result<DataValue, DataValue> {
match self {
AttributeTyping::Ref => match val {
DataValue::Num(Num::I(s)) if s > 0 => Ok(DataValue::Num(Num::I(s))),
val => Err(self.type_err(val)),
val => Err(val),
},
AttributeTyping::Bool => {
if matches!(val, DataValue::Bool(_)) {
Ok(val)
} else {
Err(self.type_err(val))
Err(val)
}
}
AttributeTyping::Int => {
if matches!(val, DataValue::Num(Num::I(_))) {
Ok(val)
} else {
Err(self.type_err(val))
Err(val)
}
}
AttributeTyping::Float => match val {
v @ DataValue::Num(Num::F(_)) => Ok(v),
DataValue::Num(Num::I(i)) => Ok(DataValue::Num(Num::F(i as f64))),
val => Err(self.type_err(val)),
val => Err(val),
},
AttributeTyping::String => {
if matches!(val, DataValue::Str(_)) {
Ok(val)
} else {
Err(self.type_err(val))
Err(val)
}
}
AttributeTyping::Bytes => {
if matches!(val, DataValue::Bytes(_)) {
Ok(val)
} else {
Err(self.type_err(val))
Err(val)
}
}
AttributeTyping::List => {
if matches!(val, DataValue::List(_)) {
Ok(val)
} else {
Err(self.type_err(val))
Err(val)
}
}
}
@ -265,35 +265,98 @@ impl Attribute {
if self.val_type.is_ref_type() {
match &value {
DataValue::Str(s) => {
#[derive(Debug, Error, Diagnostic)]
#[error("Cannot find triple with temp ID '{temp_id}'")]
#[diagnostic(code(eval::temp_id_not_found))]
#[diagnostic(help(
"As the attribute {attr_name} is of type 'ref', \
the given value is interpreted as a temp id, \
but it cannot be found in the input triples."
))]
struct TempIdNotFoundError {
attr_name: String,
temp_id: String,
}
return Ok(temp_ids
.get(s)
.ok_or_else(|| miette!("required tempid {} not found", s))?
.ok_or_else(|| TempIdNotFoundError {
attr_name: self.name.to_string(),
temp_id: s.to_string(),
})?
.as_datavalue());
}
DataValue::List(ls) => {
#[derive(Debug, Diagnostic, Error)]
#[error("Cannot interpret the list {data:?} as a keyed entity")]
#[diagnostic(code(eval::bad_keyed_entity))]
#[diagnostic(help("As the attribute {attr_name} is of type 'ref', \
the list value is interpreted as a keyed entity, with the first element a string \
representing the attribute name, and the second element the keyed value."))]
struct BadUniqueKeySpecifierError {
data: Vec<DataValue>,
attr_name: String,
}
#[derive(Debug, Diagnostic, Error)]
#[error("The attribute {attr_name} is not uniquely indexed")]
#[diagnostic(code(eval::non_unique_keyed_entity))]
#[diagnostic(help("As the attribute {attr_name} is of type 'ref', and the list \
{data:?} is specified as the value, the attribute is required to have a unique index."))]
struct NonUniqueKeySpecifierError {
data: Vec<DataValue>,
attr_name: String,
}
ensure!(
ls.len() == 2,
"list specifier for ref types must have length 2"
BadUniqueKeySpecifierError {
data: ls.clone(),
attr_name: self.name.to_string()
}
);
let attr_name = ls[0]
let attr_name = ls.get(0).unwrap()
.get_string()
.ok_or_else(|| miette!("list specifier requires first argument string"))?;
.ok_or_else(|| BadUniqueKeySpecifierError {
data: ls.clone(),
attr_name: self.name.to_string()
})?;
let attr = tx
.attr_by_name(attr_name)?
.ok_or_else(|| miette!("attribute not found: {}", attr_name))?;
.ok_or_else(|| AttrNotFoundError(attr_name.to_string()))?;
ensure!(
attr.indexing.is_unique_index(),
"ref type list specifier requires unique index"
NonUniqueKeySpecifierError {
data: ls.clone(),
attr_name: self.name.to_string()
}
);
let val = attr.coerce_value(ls[1].clone(), temp_ids, tx, vld)?;
let eid = tx.eid_by_unique_av(&attr, &val, vld)?.ok_or_else(|| {
miette!("entity not found for attr val {} {:?}", attr_name, val)
})?;
let eid = tx
.eid_by_unique_av(&attr, &val, vld)?
.ok_or_else(|| EntityNotFound(format!("{}: {:?}", attr_name, val)))?;
return Ok(eid.as_datavalue());
}
_ => {}
}
}
self.val_type.coerce_value(value)
self.val_type.coerce_value(value).map_err(|value| {
ValueCoercionError {
value,
typing: self.val_type,
attr_name: self.name.to_string(),
}
.into()
})
}
}
#[derive(Debug, Diagnostic, Error)]
#[error("Cannot coerce value {value:?} to type {typing:?}")]
#[diagnostic(code(eval::type_coercion))]
#[diagnostic(help("This is required by the attribute {attr_name}"))]
struct ValueCoercionError {
value: DataValue,
typing: AttributeTyping,
attr_name: String,
}

@ -4,11 +4,12 @@ use std::fmt::{Debug, Formatter};
use std::mem;
use itertools::Itertools;
use miette::{bail, miette, Diagnostic, Result};
use miette::{bail, Diagnostic, Result};
use smartstring::SmartString;
use thiserror::Error;
use crate::data::functions::*;
use crate::data::id::EntityId;
use crate::data::symb::Symbol;
use crate::data::tuple::Tuple;
use crate::data::value::{DataValue, LARGEST_UTF_CHAR};
@ -31,7 +32,33 @@ pub(crate) enum Expr {
},
}
#[derive(Debug, Error, Diagnostic)]
#[error("Cannot build entity ID from {0:?}")]
#[diagnostic(code(parser::bad_eid))]
#[diagnostic(help("Entity ID should be an integer satisfying certain constraints"))]
struct BadEntityId(DataValue, #[label] SourceSpan);
#[derive(Error, Diagnostic, Debug)]
#[error("Evaluation of expression failed")]
#[diagnostic(code(eval::throw))]
struct EvalRaisedError(#[label] SourceSpan, #[help] String);
impl Expr {
pub(crate) fn build_perm_eid(self) -> Result<EntityId> {
let span = self.span();
let value = self.eval_to_const()?;
match value.get_non_neg_int() {
Some(i) => {
let eid = EntityId(i);
if !eid.is_perm() {
Err(BadEntityId(value, span).into())
} else {
Ok(eid)
}
}
None => Err(BadEntityId(value, span).into()),
}
}
pub(crate) fn span(&self) -> SourceSpan {
match self {
Expr::Binding { var, .. } => var.span,
@ -85,9 +112,15 @@ impl Expr {
) -> Result<()> {
match self {
Expr::Binding { var, tuple_pos, .. } => {
let found_idx = *binding_map.get(var).ok_or_else(|| {
miette!("cannot find binding {}, this indicates a system error", var)
})?;
#[derive(Debug, Error, Diagnostic)]
#[error("Cannot find binding {0}")]
#[diagnostic(code(eval::bad_binding))]
#[diagnostic(help("This could indicate a system problem"))]
struct BadBindingError(String, #[label] SourceSpan);
let found_idx = *binding_map
.get(var)
.ok_or_else(|| BadBindingError(var.to_string(), var.span))?;
*tuple_pos = Some(found_idx)
}
Expr::Const { .. } => {}
@ -211,13 +244,13 @@ impl Expr {
args,
span: *span,
},
Some(args) => {
let res = (op.inner)(&args)?;
Expr::Const {
Some(args) => match (op.inner)(&args) {
Ok(res) => Expr::Const {
val: res,
span: *span,
}
}
},
Err(msg) => bail!(EvalRaisedError(self.span(), msg.to_string())),
},
}
}
})
@ -249,11 +282,6 @@ impl Expr {
},
Expr::Const { val, .. } => Ok(val.clone()),
Expr::Apply { op, args, .. } => {
#[derive(Error, Diagnostic, Debug)]
#[error("Evaluation of expression failed")]
#[diagnostic(code(eval::throw))]
struct EvalRaisedError(#[label] SourceSpan, #[help] String);
let args: Box<[DataValue]> = args.iter().map(|v| v.eval(bindings)).try_collect()?;
Ok((op.inner)(&args)
.map_err(|err| EvalRaisedError(self.span(), err.to_string()))?)
@ -309,7 +337,13 @@ impl Expr {
if let Some(val) = args[1].get_const() {
if target == symb {
let s = val.get_string().ok_or_else(|| {
miette!("unexpected arg {:?} for OP_STARTS_WITH", val)
#[derive(Debug, Error, Diagnostic)]
#[error("Cannot prefix scan with {0:?}")]
#[diagnostic(code(eval::bad_string_range_scan))]
#[diagnostic(help("A string argument is required"))]
struct StrRangeScanError(DataValue, #[label] SourceSpan);
StrRangeScanError(val.clone(), symb.span)
})?;
let lower = DataValue::Str(SmartString::from(s));
// let lower = DataValue::Str(s.to_string());

@ -2,7 +2,7 @@ use std::ops::{Div, Rem};
use std::str::FromStr;
use itertools::Itertools;
use miette::{bail, ensure, miette, Result};
use miette::{bail as bail_out, ensure as ensure_that, miette as gen_err, Result};
use num_traits::FloatConst;
use rand::prelude::*;
use smartstring::SmartString;
@ -41,7 +41,7 @@ pub(crate) fn op_is_in(args: &[DataValue]) -> Result<DataValue> {
let left = &args[0];
let right = args[1]
.get_list()
.ok_or_else(|| miette!("right hand side of 'is_in' must be a list"))?;
.ok_or_else(|| gen_err!("right hand side of 'is_in' must be a list"))?;
Ok(DataValue::Bool(right.contains(left)))
}
@ -56,7 +56,7 @@ pub(crate) fn op_neq(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_GT, 2, false);
pub(crate) fn op_gt(args: &[DataValue]) -> Result<DataValue> {
ensure!(
ensure_that!(
same_value_type(&args[0], &args[1]),
"comparison can only be done between the same datatypes"
);
@ -69,7 +69,7 @@ pub(crate) fn op_gt(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_GE, 2, false);
pub(crate) fn op_ge(args: &[DataValue]) -> Result<DataValue> {
ensure!(
ensure_that!(
same_value_type(&args[0], &args[1]),
"comparison can only be done between the same datatypes"
);
@ -82,7 +82,7 @@ pub(crate) fn op_ge(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_LT, 2, false);
pub(crate) fn op_lt(args: &[DataValue]) -> Result<DataValue> {
ensure!(
ensure_that!(
same_value_type(&args[0], &args[1]),
"comparison can only be done between the same datatypes"
);
@ -95,7 +95,7 @@ pub(crate) fn op_lt(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_LE, 2, false);
pub(crate) fn op_le(args: &[DataValue]) -> Result<DataValue> {
ensure!(
ensure_that!(
same_value_type(&args[0], &args[1]),
"comparison can only be done between the same datatypes"
);
@ -114,7 +114,7 @@ pub(crate) fn op_add(args: &[DataValue]) -> Result<DataValue> {
match arg {
DataValue::Num(Num::I(i)) => i_accum += i,
DataValue::Num(Num::F(f)) => f_accum += f,
_ => bail!("addition requires numbers"),
_ => bail_out!("addition requires numbers"),
}
}
if f_accum == 0.0f64 {
@ -131,7 +131,7 @@ pub(crate) fn op_max(args: &[DataValue]) -> Result<DataValue> {
.try_fold(None, |accum, nxt| match (accum, nxt) {
(None, d @ DataValue::Num(_)) => Ok(Some(d.clone())),
(Some(DataValue::Num(a)), DataValue::Num(b)) => Ok(Some(DataValue::Num(a.max(*b)))),
_ => bail!("'max can only be applied to numbers'"),
_ => bail_out!("'max can only be applied to numbers'"),
})?;
match res {
None => Ok(DataValue::Num(Num::F(f64::NEG_INFINITY))),
@ -146,7 +146,7 @@ pub(crate) fn op_min(args: &[DataValue]) -> Result<DataValue> {
.try_fold(None, |accum, nxt| match (accum, nxt) {
(None, d @ DataValue::Num(_)) => Ok(Some(d.clone())),
(Some(DataValue::Num(a)), DataValue::Num(b)) => Ok(Some(DataValue::Num(a.min(*b)))),
_ => bail!("'min' can only be applied to numbers"),
_ => bail_out!("'min' can only be applied to numbers"),
})?;
match res {
None => Ok(DataValue::Num(Num::F(f64::INFINITY))),
@ -165,7 +165,7 @@ pub(crate) fn op_sub(args: &[DataValue]) -> Result<DataValue> {
(DataValue::Num(Num::F(a)), DataValue::Num(Num::I(b))) => {
DataValue::Num(Num::F(a - (*b as f64)))
}
_ => bail!("subtraction requires numbers"),
_ => bail_out!("subtraction requires numbers"),
})
}
@ -177,7 +177,7 @@ pub(crate) fn op_mul(args: &[DataValue]) -> Result<DataValue> {
match arg {
DataValue::Num(Num::I(i)) => i_accum *= i,
DataValue::Num(Num::F(f)) => f_accum *= f,
_ => bail!("multiplication requires numbers"),
_ => bail_out!("multiplication requires numbers"),
}
}
if f_accum == 1.0f64 {
@ -200,7 +200,7 @@ pub(crate) fn op_div(args: &[DataValue]) -> Result<DataValue> {
(DataValue::Num(Num::F(a)), DataValue::Num(Num::I(b))) => {
DataValue::Num(Num::F(a / (*b as f64)))
}
_ => bail!("division requires numbers"),
_ => bail_out!("division requires numbers"),
})
}
@ -209,7 +209,7 @@ pub(crate) fn op_minus(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Num(Num::I(i)) => DataValue::Num(Num::I(-(*i))),
DataValue::Num(Num::F(f)) => DataValue::Num(Num::F(-(*f))),
_ => bail!("minus can only be applied to numbers"),
_ => bail_out!("minus can only be applied to numbers"),
})
}
@ -218,7 +218,7 @@ pub(crate) fn op_abs(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Num(Num::I(i)) => DataValue::Num(Num::I(i.abs())),
DataValue::Num(Num::F(f)) => DataValue::Num(Num::F(f.abs())),
_ => bail!("'abs' requires numbers"),
_ => bail_out!("'abs' requires numbers"),
})
}
@ -237,7 +237,7 @@ pub(crate) fn op_signum(args: &[DataValue]) -> Result<DataValue> {
DataValue::from(f64::NAN)
}
}
_ => bail!("'signum' requires numbers"),
_ => bail_out!("'signum' requires numbers"),
})
}
@ -246,7 +246,7 @@ pub(crate) fn op_floor(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Num(Num::I(i)) => DataValue::Num(Num::I(*i)),
DataValue::Num(Num::F(f)) => DataValue::Num(Num::F(f.floor())),
_ => bail!("'floor' requires numbers"),
_ => bail_out!("'floor' requires numbers"),
})
}
@ -255,7 +255,7 @@ pub(crate) fn op_ceil(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Num(Num::I(i)) => DataValue::Num(Num::I(*i)),
DataValue::Num(Num::F(f)) => DataValue::Num(Num::F(f.ceil())),
_ => bail!("'ceil' requires numbers"),
_ => bail_out!("'ceil' requires numbers"),
})
}
@ -264,7 +264,7 @@ pub(crate) fn op_round(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] {
DataValue::Num(Num::I(i)) => DataValue::Num(Num::I(*i)),
DataValue::Num(Num::F(f)) => DataValue::Num(Num::F(f.round())),
_ => bail!("'round' requires numbers"),
_ => bail_out!("'round' requires numbers"),
})
}
@ -273,7 +273,7 @@ pub(crate) fn op_exp(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'exp' requires numbers"),
_ => bail_out!("'exp' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.exp())))
}
@ -283,7 +283,7 @@ pub(crate) fn op_exp2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'exp2' requires numbers"),
_ => bail_out!("'exp2' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.exp2())))
}
@ -293,7 +293,7 @@ pub(crate) fn op_ln(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'ln' requires numbers"),
_ => bail_out!("'ln' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.ln())))
}
@ -303,7 +303,7 @@ pub(crate) fn op_log2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'log2' requires numbers"),
_ => bail_out!("'log2' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.log2())))
}
@ -313,7 +313,7 @@ pub(crate) fn op_log10(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'log10' requires numbers"),
_ => bail_out!("'log10' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.log10())))
}
@ -323,7 +323,7 @@ pub(crate) fn op_sin(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'sin' requires numbers"),
_ => bail_out!("'sin' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.sin())))
}
@ -333,7 +333,7 @@ pub(crate) fn op_cos(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'cos' requires numbers"),
_ => bail_out!("'cos' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.cos())))
}
@ -343,7 +343,7 @@ pub(crate) fn op_tan(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'tan' requires numbers"),
_ => bail_out!("'tan' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.tan())))
}
@ -353,7 +353,7 @@ pub(crate) fn op_asin(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'asin' requires numbers"),
_ => bail_out!("'asin' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.asin())))
}
@ -363,7 +363,7 @@ pub(crate) fn op_acos(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'acos' requires numbers"),
_ => bail_out!("'acos' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.acos())))
}
@ -373,7 +373,7 @@ pub(crate) fn op_atan(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'atan' requires numbers"),
_ => bail_out!("'atan' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.atan())))
}
@ -383,12 +383,12 @@ pub(crate) fn op_atan2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'atan2' requires numbers"),
_ => bail_out!("'atan2' requires numbers"),
};
let b = match &args[1] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'atan2' requires numbers"),
_ => bail_out!("'atan2' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.atan2(b))))
@ -399,7 +399,7 @@ pub(crate) fn op_sinh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'sinh' requires numbers"),
_ => bail_out!("'sinh' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.sinh())))
}
@ -409,7 +409,7 @@ pub(crate) fn op_cosh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'cosh' requires numbers"),
_ => bail_out!("'cosh' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.cosh())))
}
@ -419,7 +419,7 @@ pub(crate) fn op_tanh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'tanh' requires numbers"),
_ => bail_out!("'tanh' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.tanh())))
}
@ -429,7 +429,7 @@ pub(crate) fn op_asinh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'asinh' requires numbers"),
_ => bail_out!("'asinh' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.asinh())))
}
@ -439,7 +439,7 @@ pub(crate) fn op_acosh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'acosh' requires numbers"),
_ => bail_out!("'acosh' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.acosh())))
}
@ -449,7 +449,7 @@ pub(crate) fn op_atanh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'atanh' requires numbers"),
_ => bail_out!("'atanh' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.atanh())))
}
@ -459,12 +459,12 @@ pub(crate) fn op_pow(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'pow' requires numbers"),
_ => bail_out!("'pow' requires numbers"),
};
let b = match &args[1] {
DataValue::Num(Num::I(i)) => *i as f64,
DataValue::Num(Num::F(f)) => *f,
_ => bail!("'pow' requires numbers"),
_ => bail_out!("'pow' requires numbers"),
};
Ok(DataValue::Num(Num::F(a.powf(b))))
}
@ -480,7 +480,7 @@ pub(crate) fn op_mod(args: &[DataValue]) -> Result<DataValue> {
(DataValue::Num(Num::F(a)), DataValue::Num(Num::I(b))) => {
DataValue::Num(Num::F(a.rem(*b as f64)))
}
_ => bail!("'mod' requires numbers"),
_ => bail_out!("'mod' requires numbers"),
})
}
@ -492,7 +492,7 @@ pub(crate) fn op_and(args: &[DataValue]) -> Result<DataValue> {
return Ok(DataValue::Bool(false));
}
} else {
bail!("'and' requires booleans");
bail_out!("'and' requires booleans");
}
}
Ok(DataValue::Bool(true))
@ -506,7 +506,7 @@ pub(crate) fn op_or(args: &[DataValue]) -> Result<DataValue> {
return Ok(DataValue::Bool(true));
}
} else {
bail!("'or' requires booleans");
bail_out!("'or' requires booleans");
}
}
Ok(DataValue::Bool(false))
@ -517,7 +517,7 @@ pub(crate) fn op_negate(args: &[DataValue]) -> Result<DataValue> {
if let DataValue::Bool(b) = &args[0] {
Ok(DataValue::Bool(!*b))
} else {
bail!("'negate' requires booleans");
bail_out!("'negate' requires booleans");
}
}
@ -525,7 +525,7 @@ define_op!(OP_BIT_AND, 2, false);
pub(crate) fn op_bit_and(args: &[DataValue]) -> Result<DataValue> {
match (&args[0], &args[1]) {
(DataValue::Bytes(left), DataValue::Bytes(right)) => {
ensure!(
ensure_that!(
left.len() == right.len(),
"operands of 'bit_and' must have the same lengths"
);
@ -535,7 +535,7 @@ pub(crate) fn op_bit_and(args: &[DataValue]) -> Result<DataValue> {
}
Ok(DataValue::Bytes(ret))
}
_ => bail!("'bit_and' requires bytes"),
_ => bail_out!("'bit_and' requires bytes"),
}
}
@ -543,7 +543,7 @@ define_op!(OP_BIT_OR, 2, false);
pub(crate) fn op_bit_or(args: &[DataValue]) -> Result<DataValue> {
match (&args[0], &args[1]) {
(DataValue::Bytes(left), DataValue::Bytes(right)) => {
ensure!(
ensure_that!(
left.len() == right.len(),
"operands of 'bit_or' must have the same lengths",
);
@ -553,7 +553,7 @@ pub(crate) fn op_bit_or(args: &[DataValue]) -> Result<DataValue> {
}
Ok(DataValue::Bytes(ret))
}
_ => bail!("'bit_or' requires bytes"),
_ => bail_out!("'bit_or' requires bytes"),
}
}
@ -567,7 +567,7 @@ pub(crate) fn op_bit_not(args: &[DataValue]) -> Result<DataValue> {
}
Ok(DataValue::Bytes(ret))
}
_ => bail!("'bit_not' requires bytes"),
_ => bail_out!("'bit_not' requires bytes"),
}
}
@ -575,7 +575,7 @@ define_op!(OP_BIT_XOR, 2, false);
pub(crate) fn op_bit_xor(args: &[DataValue]) -> Result<DataValue> {
match (&args[0], &args[1]) {
(DataValue::Bytes(left), DataValue::Bytes(right)) => {
ensure!(
ensure_that!(
left.len() == right.len(),
"operands of 'bit_xor' must have the same lengths"
);
@ -585,7 +585,7 @@ pub(crate) fn op_bit_xor(args: &[DataValue]) -> Result<DataValue> {
}
Ok(DataValue::Bytes(ret))
}
_ => bail!("'bit_xor' requires bytes"),
_ => bail_out!("'bit_xor' requires bytes"),
}
}
@ -607,7 +607,7 @@ pub(crate) fn op_unpack_bits(args: &[DataValue]) -> Result<DataValue> {
ret.into_iter().map(DataValue::Bool).collect_vec(),
))
} else {
bail!("'unpack_bits' requires bytes")
bail_out!("'unpack_bits' requires bytes")
}
}
@ -636,12 +636,12 @@ pub(crate) fn op_pack_bits(args: &[DataValue]) -> Result<DataValue> {
}
}
}
_ => bail!("'pack_bits' requires list of booleans"),
_ => bail_out!("'pack_bits' requires list of booleans"),
}
}
Ok(DataValue::Bytes(res.into()))
} else {
bail!("'pack_bits' requires list of booleans")
bail_out!("'pack_bits' requires list of booleans")
}
}
@ -654,7 +654,7 @@ pub(crate) fn op_concat(args: &[DataValue]) -> Result<DataValue> {
if let DataValue::Str(s) = arg {
ret += s;
} else {
bail!("'concat' requires strings, or lists");
bail_out!("'concat' requires strings, or lists");
}
}
Ok(DataValue::Str(SmartString::from(ret)))
@ -665,12 +665,12 @@ pub(crate) fn op_concat(args: &[DataValue]) -> Result<DataValue> {
if let DataValue::List(l) = arg {
ret.extend_from_slice(l);
} else {
bail!("'concat' requires strings, or lists");
bail_out!("'concat' requires strings, or lists");
}
}
Ok(DataValue::List(ret.into()))
}
_ => bail!("'concat' requires strings, or lists"),
_ => bail_out!("'concat' requires strings, or lists"),
}
}
@ -678,7 +678,7 @@ define_op!(OP_STR_INCLUDES, 2, false);
pub(crate) fn op_str_includes(args: &[DataValue]) -> Result<DataValue> {
match (&args[0], &args[1]) {
(DataValue::Str(l), DataValue::Str(r)) => Ok(DataValue::Bool(l.find(r as &str).is_some())),
_ => bail!("'str_includes' requires strings"),
_ => bail_out!("'str_includes' requires strings"),
}
}
@ -686,7 +686,7 @@ define_op!(OP_LOWERCASE, 1, false);
pub(crate) fn op_lowercase(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Str(s) => Ok(DataValue::Str(SmartString::from(s.to_lowercase()))),
_ => bail!("'lowercase' requires strings"),
_ => bail_out!("'lowercase' requires strings"),
}
}
@ -694,7 +694,7 @@ define_op!(OP_UPPERCASE, 1, false);
pub(crate) fn op_uppercase(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Str(s) => Ok(DataValue::Str(SmartString::from(s.to_uppercase()))),
_ => bail!("'uppercase' requires strings"),
_ => bail_out!("'uppercase' requires strings"),
}
}
@ -702,7 +702,7 @@ define_op!(OP_TRIM, 1, false);
pub(crate) fn op_trim(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Str(s) => Ok(DataValue::Str(SmartString::from(s.trim()))),
_ => bail!("'trim' requires strings"),
_ => bail_out!("'trim' requires strings"),
}
}
@ -710,7 +710,7 @@ define_op!(OP_TRIM_START, 1, false);
pub(crate) fn op_trim_start(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Str(s) => Ok(DataValue::Str(SmartString::from(s.trim_start()))),
_ => bail!("'trim_start' requires strings"),
_ => bail_out!("'trim_start' requires strings"),
}
}
@ -718,7 +718,7 @@ define_op!(OP_TRIM_END, 1, false);
pub(crate) fn op_trim_end(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Str(s) => Ok(DataValue::Str(SmartString::from(s.trim_end()))),
_ => bail!("'trim_end' requires strings"),
_ => bail_out!("'trim_end' requires strings"),
}
}
@ -726,11 +726,11 @@ define_op!(OP_STARTS_WITH, 2, false);
pub(crate) fn op_starts_with(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Str(s) => s,
_ => bail!("'starts_with' requires strings"),
_ => bail_out!("'starts_with' requires strings"),
};
let b = match &args[1] {
DataValue::Str(s) => s,
_ => bail!("'starts_with' requires strings"),
_ => bail_out!("'starts_with' requires strings"),
};
Ok(DataValue::Bool(a.starts_with(b as &str)))
}
@ -739,11 +739,11 @@ define_op!(OP_ENDS_WITH, 2, false);
pub(crate) fn op_ends_with(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] {
DataValue::Str(s) => s,
_ => bail!("'ends_with' requires strings"),
_ => bail_out!("'ends_with' requires strings"),
};
let b = match &args[1] {
DataValue::Str(s) => s,
_ => bail!("'ends_with' requires strings"),
_ => bail_out!("'ends_with' requires strings"),
};
Ok(DataValue::Bool(a.ends_with(b as &str)))
}
@ -754,10 +754,10 @@ pub(crate) fn op_regex(args: &[DataValue]) -> Result<DataValue> {
r @ DataValue::Regex(_) => r.clone(),
DataValue::Str(s) => {
DataValue::Regex(RegexWrapper(regex::Regex::new(s).map_err(|err| {
miette!("The string cannot be interpreted as regex: {}", err)
gen_err!("The string cannot be interpreted as regex: {}", err)
})?))
}
_ => bail!("'regex' requires strings"),
_ => bail_out!("'regex' requires strings"),
})
}
@ -765,7 +765,7 @@ define_op!(OP_REGEX_MATCHES, 2, false);
pub(crate) fn op_regex_matches(args: &[DataValue]) -> Result<DataValue> {
match (&args[0], &args[1]) {
(DataValue::Str(s), DataValue::Regex(r)) => Ok(DataValue::Bool(r.0.is_match(s))),
_ => bail!("'regex_matches' requires strings"),
_ => bail_out!("'regex_matches' requires strings"),
}
}
@ -775,7 +775,7 @@ pub(crate) fn op_regex_replace(args: &[DataValue]) -> Result<DataValue> {
(DataValue::Str(s), DataValue::Regex(r), DataValue::Str(rp)) => {
Ok(DataValue::Str(r.0.replace(s, rp as &str).into()))
}
_ => bail!("'regex_replace' requires strings"),
_ => bail_out!("'regex_replace' requires strings"),
}
}
@ -785,7 +785,7 @@ pub(crate) fn op_regex_replace_all(args: &[DataValue]) -> Result<DataValue> {
(DataValue::Str(s), DataValue::Regex(r), DataValue::Str(rp)) => {
Ok(DataValue::Str(r.0.replace_all(s, rp as &str).into()))
}
_ => bail!("'regex_replace' requires strings"),
_ => bail_out!("'regex_replace' requires strings"),
}
}
@ -799,7 +799,7 @@ pub(crate) fn op_regex_extract(args: &[DataValue]) -> Result<DataValue> {
.collect_vec();
Ok(DataValue::List(found))
}
_ => bail!("'regex_extract' requires strings"),
_ => bail_out!("'regex_extract' requires strings"),
}
}
@ -812,7 +812,7 @@ pub(crate) fn op_regex_extract_first(args: &[DataValue]) -> Result<DataValue> {
.map(|v| DataValue::Str(SmartString::from(v.as_str())));
Ok(found.unwrap_or(DataValue::Null))
}
_ => bail!("'regex_extract_first' requires strings"),
_ => bail_out!("'regex_extract_first' requires strings"),
}
}
@ -888,7 +888,7 @@ pub(crate) fn op_append(args: &[DataValue]) -> Result<DataValue> {
l.push(args[1].clone());
Ok(DataValue::List(l))
}
_ => bail!("'append' requires first argument to be a list"),
_ => bail_out!("'append' requires first argument to be a list"),
}
}
@ -900,7 +900,7 @@ pub(crate) fn op_prepend(args: &[DataValue]) -> Result<DataValue> {
l.extend_from_slice(pl);
Ok(DataValue::List(l))
}
_ => bail!("'prepend' requires first argument to be a list"),
_ => bail_out!("'prepend' requires first argument to be a list"),
}
}
@ -916,7 +916,7 @@ pub(crate) fn op_length(args: &[DataValue]) -> Result<DataValue> {
DataValue::List(l) => l.len() as i64,
DataValue::Str(s) => s.chars().count() as i64,
DataValue::Bytes(b) => b.len() as i64,
_ => bail!("'length' requires lists"),
_ => bail_out!("'length' requires lists"),
}))
}
@ -928,9 +928,9 @@ pub(crate) fn op_unicode_normalize(args: &[DataValue]) -> Result<DataValue> {
"nfd" => s.nfd().collect(),
"nfkc" => s.nfkc().collect(),
"nfkd" => s.nfkd().collect(),
u => bail!("unknown normalization {} for 'unicode_normalize'", u),
u => bail_out!("unknown normalization {} for 'unicode_normalize'", u),
})),
_ => bail!("'unicode_normalize' requires strings"),
_ => bail_out!("'unicode_normalize' requires strings"),
}
}
@ -938,7 +938,7 @@ define_op!(OP_SORTED, 1, false);
pub(crate) fn op_sorted(args: &[DataValue]) -> Result<DataValue> {
let mut arg = args[0]
.get_list()
.ok_or_else(|| miette!("'sort' requires lists"))?
.ok_or_else(|| gen_err!("'sort' requires lists"))?
.to_vec();
arg.sort();
Ok(DataValue::List(arg))
@ -948,7 +948,7 @@ define_op!(OP_REVERSE, 1, false);
pub(crate) fn op_reverse(args: &[DataValue]) -> Result<DataValue> {
let mut arg = args[0]
.get_list()
.ok_or_else(|| miette!("'reverse' requires lists"))?
.ok_or_else(|| gen_err!("'reverse' requires lists"))?
.to_vec();
arg.reverse();
Ok(DataValue::List(arg))
@ -956,7 +956,7 @@ pub(crate) fn op_reverse(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_HAVERSINE, 4, false);
pub(crate) fn op_haversine(args: &[DataValue]) -> Result<DataValue> {
let gen_err = || miette!("'haversine' requires numbers");
let gen_err = || gen_err!("'haversine' requires numbers");
let lat1 = args[0].get_float().ok_or_else(gen_err)?;
let lon1 = args[1].get_float().ok_or_else(gen_err)?;
let lat2 = args[2].get_float().ok_or_else(gen_err)?;
@ -971,7 +971,7 @@ pub(crate) fn op_haversine(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_HAVERSINE_DEG_INPUT, 4, false);
pub(crate) fn op_haversine_deg_input(args: &[DataValue]) -> Result<DataValue> {
let gen_err = || miette!("'haversine_deg_input' requires numbers");
let gen_err = || gen_err!("'haversine_deg_input' requires numbers");
let lat1 = args[0].get_float().ok_or_else(gen_err)? * f64::PI() / 180.;
let lon1 = args[1].get_float().ok_or_else(gen_err)? * f64::PI() / 180.;
let lat2 = args[2].get_float().ok_or_else(gen_err)? * f64::PI() / 180.;
@ -988,7 +988,7 @@ define_op!(OP_DEG_TO_RAD, 1, false);
pub(crate) fn op_deg_to_rad(args: &[DataValue]) -> Result<DataValue> {
let x = args[0]
.get_float()
.ok_or_else(|| miette!("'deg_to_rad' requires numbers"))?;
.ok_or_else(|| gen_err!("'deg_to_rad' requires numbers"))?;
Ok(DataValue::from(x * f64::PI() / 180.))
}
@ -996,7 +996,7 @@ define_op!(OP_RAD_TO_DEG, 1, false);
pub(crate) fn op_rad_to_deg(args: &[DataValue]) -> Result<DataValue> {
let x = args[0]
.get_float()
.ok_or_else(|| miette!("'rad_to_deg' requires numbers"))?;
.ok_or_else(|| gen_err!("'rad_to_deg' requires numbers"))?;
Ok(DataValue::from(x * 180. / f64::PI()))
}
@ -1004,7 +1004,7 @@ define_op!(OP_FIRST, 1, false);
pub(crate) fn op_first(args: &[DataValue]) -> Result<DataValue> {
Ok(args[0]
.get_list()
.ok_or_else(|| miette!("'first' requires lists"))?
.ok_or_else(|| gen_err!("'first' requires lists"))?
.first()
.cloned()
.unwrap_or(DataValue::Null))
@ -1014,7 +1014,7 @@ define_op!(OP_LAST, 1, false);
pub(crate) fn op_last(args: &[DataValue]) -> Result<DataValue> {
Ok(args[0]
.get_list()
.ok_or_else(|| miette!("'last' requires lists"))?
.ok_or_else(|| gen_err!("'last' requires lists"))?
.last()
.cloned()
.unwrap_or(DataValue::Null))
@ -1024,11 +1024,11 @@ define_op!(OP_CHUNKS, 2, false);
pub(crate) fn op_chunks(args: &[DataValue]) -> Result<DataValue> {
let arg = args[0]
.get_list()
.ok_or_else(|| miette!("first argument of 'chunks' must be a list"))?;
.ok_or_else(|| gen_err!("first argument of 'chunks' must be a list"))?;
let n = args[1]
.get_int()
.ok_or_else(|| miette!("second argument of 'chunks' must be an integer"))?;
ensure!(n > 0, "second argument to 'chunks' must be positive");
.ok_or_else(|| gen_err!("second argument of 'chunks' must be an integer"))?;
ensure_that!(n > 0, "second argument to 'chunks' must be positive");
let res = arg
.chunks(n as usize)
.map(|el| DataValue::List(el.to_vec()))
@ -1040,11 +1040,11 @@ define_op!(OP_CHUNKS_EXACT, 2, false);
pub(crate) fn op_chunks_exact(args: &[DataValue]) -> Result<DataValue> {
let arg = args[0]
.get_list()
.ok_or_else(|| miette!("first argument of 'chunks_exact' must be a list"))?;
.ok_or_else(|| gen_err!("first argument of 'chunks_exact' must be a list"))?;
let n = args[1]
.get_int()
.ok_or_else(|| miette!("second argument of 'chunks_exact' must be an integer"))?;
ensure!(n > 0, "second argument to 'chunks_exact' must be positive");
.ok_or_else(|| gen_err!("second argument of 'chunks_exact' must be an integer"))?;
ensure_that!(n > 0, "second argument to 'chunks_exact' must be positive");
let res = arg
.chunks_exact(n as usize)
.map(|el| DataValue::List(el.to_vec()))
@ -1056,11 +1056,11 @@ define_op!(OP_WINDOWS, 2, false);
pub(crate) fn op_windows(args: &[DataValue]) -> Result<DataValue> {
let arg = args[0]
.get_list()
.ok_or_else(|| miette!("first argument of 'windows' must be a list"))?;
.ok_or_else(|| gen_err!("first argument of 'windows' must be a list"))?;
let n = args[1]
.get_int()
.ok_or_else(|| miette!("second argument of 'windows' must be an integer"))?;
ensure!(n > 0, "second argument to 'windows' must be positive");
.ok_or_else(|| gen_err!("second argument of 'windows' must be an integer"))?;
ensure_that!(n > 0, "second argument to 'windows' must be positive");
let res = arg
.windows(n as usize)
.map(|el| DataValue::List(el.to_vec()))
@ -1075,12 +1075,12 @@ fn get_index(mut i: i64, total: usize) -> Result<usize> {
Ok(if i >= 0 {
let i = i as usize;
if i >= total {
bail!("index {} out of bound", i)
bail_out!("index {} out of bound", i)
} else {
i
}
} else {
bail!("index {} out of bound", i)
bail_out!("index {} out of bound", i)
})
}
@ -1088,10 +1088,10 @@ define_op!(OP_GET, 2, false);
pub(crate) fn op_get(args: &[DataValue]) -> Result<DataValue> {
let l = args[0]
.get_list()
.ok_or_else(|| miette!("first argument to 'get' mut be a list"))?;
.ok_or_else(|| gen_err!("first argument to 'get' mut be a list"))?;
let n = args[1]
.get_int()
.ok_or_else(|| miette!("second argument to 'get' mut be an integer"))?;
.ok_or_else(|| gen_err!("second argument to 'get' mut be an integer"))?;
let idx = get_index(n, l.len())?;
Ok(l[idx].clone())
}
@ -1100,10 +1100,10 @@ define_op!(OP_MAYBE_GET, 2, false);
pub(crate) fn op_maybe_get(args: &[DataValue]) -> Result<DataValue> {
let l = args[0]
.get_list()
.ok_or_else(|| miette!("first argument to 'maybe_get' mut be a list"))?;
.ok_or_else(|| gen_err!("first argument to 'maybe_get' mut be a list"))?;
let n = args[1]
.get_int()
.ok_or_else(|| miette!("second argument to 'maybe_get' mut be an integer"))?;
.ok_or_else(|| gen_err!("second argument to 'maybe_get' mut be an integer"))?;
if let Ok(idx) = get_index(n, l.len()) {
Ok(l[idx].clone())
} else {
@ -1115,13 +1115,13 @@ define_op!(OP_SLICE, 3, false);
pub(crate) fn op_slice(args: &[DataValue]) -> Result<DataValue> {
let l = args[0]
.get_list()
.ok_or_else(|| miette!("first argument to 'slice' mut be a list"))?;
.ok_or_else(|| gen_err!("first argument to 'slice' mut be a list"))?;
let m = args[1]
.get_int()
.ok_or_else(|| miette!("second argument to 'slice' mut be an integer"))?;
.ok_or_else(|| gen_err!("second argument to 'slice' mut be an integer"))?;
let n = args[2]
.get_int()
.ok_or_else(|| miette!("third argument to 'slice' mut be an integer"))?;
.ok_or_else(|| gen_err!("third argument to 'slice' mut be an integer"))?;
let m = get_index(m, l.len())?;
let n = get_index(n, l.len())?;
Ok(DataValue::List(l[m..n].to_vec()))
@ -1132,7 +1132,7 @@ pub(crate) fn op_chars(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::List(
args[0]
.get_string()
.ok_or_else(|| miette!("'chars' requires strings"))?
.ok_or_else(|| gen_err!("'chars' requires strings"))?
.chars()
.map(|c| {
let mut s = SmartString::new();
@ -1152,11 +1152,11 @@ pub(crate) fn op_from_substrings(args: &[DataValue]) -> Result<DataValue> {
if let DataValue::Str(s) = arg {
ret.push_str(s);
} else {
bail!("'from_substring' requires a list of strings")
bail_out!("'from_substring' requires a list of strings")
}
}
}
_ => bail!("'from_substring' requires a list of strings"),
_ => bail_out!("'from_substring' requires a list of strings"),
}
Ok(DataValue::Str(SmartString::from(ret)))
}
@ -1168,7 +1168,7 @@ pub(crate) fn op_encode_base64(args: &[DataValue]) -> Result<DataValue> {
let s = base64::encode(b);
Ok(DataValue::Str(SmartString::from(s)))
}
_ => bail!("'encode_base64' requires bytes"),
_ => bail_out!("'encode_base64' requires bytes"),
}
}
@ -1176,10 +1176,10 @@ define_op!(OP_DECODE_BASE64, 1, false);
pub(crate) fn op_decode_base64(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Str(s) => {
let b = base64::decode(s).map_err(|_| miette!("Data is not properly encoded"))?;
let b = base64::decode(s).map_err(|_| gen_err!("Data is not properly encoded"))?;
Ok(DataValue::Bytes(b.into()))
}
_ => bail!("'decode_base64' requires strings"),
_ => bail_out!("'decode_base64' requires strings"),
}
}
@ -1194,10 +1194,10 @@ pub(crate) fn op_to_float(args: &[DataValue]) -> Result<DataValue> {
"INF" => f64::INFINITY.into(),
"NEG_INF" => f64::NEG_INFINITY.into(),
s => f64::from_str(s)
.map_err(|_| miette!("The string cannot be interpreted as float"))?
.map_err(|_| gen_err!("The string cannot be interpreted as float"))?
.into(),
},
v => bail!("'to_float' does not recognize {:?}", v),
v => bail_out!("'to_float' does not recognize {:?}", v),
})
}
@ -1211,13 +1211,13 @@ pub(crate) fn op_rand_bernoulli(args: &[DataValue]) -> Result<DataValue> {
let prob = match &args[0] {
DataValue::Num(n) => {
let f = n.get_float();
ensure!(
ensure_that!(
f >= 0. && f <= 1.,
"'rand_bernoulli' requires number between 0. and 1."
);
f
}
_ => bail!("'rand_bernoulli' requires number between 0. and 1."),
_ => bail_out!("'rand_bernoulli' requires number between 0. and 1."),
};
Ok(DataValue::Bool(thread_rng().gen_bool(prob)))
}
@ -1226,10 +1226,10 @@ define_op!(OP_RAND_INT, 2, false);
pub(crate) fn op_rand_int(args: &[DataValue]) -> Result<DataValue> {
let lower = &args[0]
.get_int()
.ok_or_else(|| miette!("'rand_int' requires integers"))?;
.ok_or_else(|| gen_err!("'rand_int' requires integers"))?;
let upper = &args[1]
.get_int()
.ok_or_else(|| miette!("'rand_int' requires integers"))?;
.ok_or_else(|| gen_err!("'rand_int' requires integers"))?;
Ok(thread_rng().gen_range(*lower..=*upper).into())
}
@ -1240,7 +1240,7 @@ pub(crate) fn op_rand_choose(args: &[DataValue]) -> Result<DataValue> {
.choose(&mut thread_rng())
.cloned()
.unwrap_or(DataValue::Null)),
_ => bail!("'rand_choice' requires lists"),
_ => bail_out!("'rand_choice' requires lists"),
}
}
@ -1248,6 +1248,6 @@ define_op!(OP_ASSERT, 1, true);
pub(crate) fn op_assert(args: &[DataValue]) -> Result<DataValue> {
match &args[0] {
DataValue::Bool(true) => Ok(DataValue::Bool(true)),
_ => bail!("assertion failed: {:?}", args),
_ => bail_out!("assertion failed: {:?}", args),
}
}

@ -1,9 +1,7 @@
use miette::{miette};
use serde_json::json;
pub(crate) use serde_json::Value as JsonValue;
use smartstring::SmartString;
use crate::data::id::{AttrId, EntityId, TxId};
use crate::data::value::{DataValue, Num};
impl From<JsonValue> for DataValue {
@ -97,57 +95,6 @@ impl From<DataValue> for JsonValue {
}
}
impl From<AttrId> for JsonValue {
fn from(id: AttrId) -> Self {
JsonValue::Number(id.0.into())
}
}
impl TryFrom<&'_ JsonValue> for AttrId {
type Error = miette::Error;
fn try_from(value: &'_ JsonValue) -> Result<Self, Self::Error> {
let v = value
.as_u64()
.ok_or_else(|| miette!("cannot convert {} to attr id", value))?;
Ok(AttrId(v))
}
}
impl From<EntityId> for JsonValue {
fn from(id: EntityId) -> Self {
JsonValue::Number(id.0.into())
}
}
impl TryFrom<&'_ JsonValue> for EntityId {
type Error = miette::Error;
fn try_from(value: &'_ JsonValue) -> Result<Self, Self::Error> {
let v = value
.as_u64()
.ok_or_else(|| miette!("cannot convert {} to entity id", value))?;
Ok(EntityId(v))
}
}
impl From<TxId> for JsonValue {
fn from(id: TxId) -> Self {
JsonValue::Number(id.0.into())
}
}
impl TryFrom<&'_ JsonValue> for TxId {
type Error = miette::Error;
fn try_from(value: &'_ JsonValue) -> Result<Self, Self::Error> {
let v = value
.as_u64()
.ok_or_else(|| miette!("cannot convert {} to tx id", value))?;
Ok(TxId(v))
}
}
#[cfg(test)]
mod tests {
use serde_json::json;

@ -3,13 +3,12 @@ use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use either::{Left, Right};
use miette::Result;
use miette::{ensure, Diagnostic};
use miette::{ensure, Diagnostic, Result};
use smallvec::SmallVec;
use smartstring::{LazyCompact, SmartString};
use thiserror::Error;
use crate::algo::AlgoHandle;
use crate::algo::{AlgoHandle, AlgoNotFoundError};
use crate::data::aggr::Aggregation;
use crate::data::attr::Attribute;
use crate::data::expr::Expr;
@ -99,6 +98,15 @@ pub(crate) enum InputRulesOrAlgo {
Algo { algo: AlgoApply },
}
impl InputRulesOrAlgo {
pub(crate) fn first_span(&self) -> SourceSpan {
match self {
InputRulesOrAlgo::Rules { rules, .. } => rules[0].span,
InputRulesOrAlgo::Algo { algo, .. } => algo.span,
}
}
}
#[derive(Clone)]
pub(crate) struct AlgoApply {
pub(crate) algo: AlgoHandle,
@ -466,32 +474,64 @@ pub(crate) struct InputProgram {
pub(crate) out_opts: QueryOutOptions,
}
#[derive(Debug, Diagnostic, Error)]
#[error("Entry head not found")]
#[diagnostic(code(parser::no_entry_head))]
#[diagnostic(help("You need to explicitly name your entry arguments"))]
struct EntryHeadNotExplicitlyDefinedError(#[label] SourceSpan);
#[derive(Debug, Diagnostic, Error)]
#[error("Program has no entry")]
#[diagnostic(code(parser::no_entry))]
#[diagnostic(help("You need to have one rule named '?'"))]
pub(crate) struct NoEntryError;
impl InputProgram {
pub(crate) fn get_entry_head(&self) -> Option<&[Symbol]> {
pub(crate) fn get_entry_arity(&self) -> Result<usize> {
if let Some(entry) = self.prog.get(&Symbol::new(PROG_ENTRY, SourceSpan(0, 0))) {
return match entry {
InputRulesOrAlgo::Rules { rules } => Ok(rules.last().unwrap().head.len()),
InputRulesOrAlgo::Algo { algo: algo_apply } => {
algo_apply.arity().ok_or_else(|| {
AlgoNotFoundError(algo_apply.algo.name.to_string(), algo_apply.span).into()
})
}
};
}
if let Some(ConstRule { data, .. }) = self.const_rules.get(&MagicSymbol::Muggle {
inner: Symbol::new(PROG_ENTRY, SourceSpan(0, 0)),
}) {
return Ok(data.get(0).map(|row| row.0.len()).unwrap_or(0))
}
Err(NoEntryError.into())
}
pub(crate) fn get_entry_head(&self) -> Result<&[Symbol]> {
if let Some(entry) = self.prog.get(&Symbol::new(PROG_ENTRY, SourceSpan(0, 0))) {
return match entry {
InputRulesOrAlgo::Rules { rules } => Some(&rules.last().unwrap().head),
InputRulesOrAlgo::Rules { rules } => Ok(&rules.last().unwrap().head),
InputRulesOrAlgo::Algo { algo: algo_apply } => {
if algo_apply.head.is_empty() {
None
Err(EntryHeadNotExplicitlyDefinedError(entry.first_span()).into())
} else {
Some(&algo_apply.head)
Ok(&algo_apply.head)
}
}
};
}
if let Some(ConstRule { bindings, .. }) = self.const_rules.get(&MagicSymbol::Muggle {
if let Some(ConstRule { bindings, span, .. }) = self.const_rules.get(&MagicSymbol::Muggle {
inner: Symbol::new(PROG_ENTRY, SourceSpan(0, 0)),
}) {
return if bindings.is_empty() {
None
Err(EntryHeadNotExplicitlyDefinedError(*span).into())
} else {
Some(bindings)
Ok(bindings)
};
}
None
Err(NoEntryError.into())
}
pub(crate) fn to_normalized_program(
&self,

@ -60,275 +60,3 @@ fn parse_pull_field(pair: Pair<'_>) -> Result<OutPullSpec> {
subfields,
})
}
// use std::cmp::max;
//
// use miette::{miette, bail, Result};
// use itertools::Itertools;
// use serde_json::Map;
//
// use crate::data::attr::AttributeCardinality;
// use crate::data::json::JsonValue;
// use crate::data::symb::Symbol;
// use crate::data::value::DataValue;
// use crate::query::pull::{AttrPullSpec, PullSpec, PullSpecs};
// use crate::runtime::transact::SessionTx;
//
// impl SessionTx {
// pub(crate) fn parse_pull(&mut self, desc: &JsonValue, depth: usize) -> Result<PullSpecs> {
// if let Some(inner) = desc.as_array() {
// let mut ret: PullSpecs = inner
// .iter()
// .map(|v| self.parse_pull_element(v, depth))
// .try_collect()?;
// // the sort is necessary to put recursive queries last
// ret.sort();
// Ok(ret)
// } else {
// bail!("pull definition: expect array, got {}", desc);
// }
// }
// pub(crate) fn parse_pull_element(
// &mut self,
// desc: &JsonValue,
// depth: usize,
// ) -> Result<PullSpec> {
// match desc {
// JsonValue::String(s) if s == "*" => Ok(PullSpec::PullAll),
// JsonValue::String(s) if s == "_id" => Ok(PullSpec::PullId("_id".into())),
// JsonValue::String(s) => {
// let input_symb = Symbol::new(s.as_ref());
// let reverse = input_symb.0.starts_with('<');
// let symb = if reverse {
// Symbol::new(input_symb.0.strip_prefix('<').unwrap())
// } else {
// input_symb.clone()
// };
// let attr = self
// .attr_by_name(&symb)?
// .ok_or_else(|| miette!("attribute {} not found", symb))?;
// let cardinality = attr.cardinality;
// Ok(PullSpec::Attr(AttrPullSpec {
// attr,
// default_val: DataValue::Null,
// reverse,
// name: input_symb,
// cardinality,
// take: None,
// nested: vec![],
// recursive: false,
// recursion_limit: None,
// recursion_depth: 0,
// }))
// }
// JsonValue::Object(m) => self.parse_pull_obj(m, depth),
// v => bail!("pull element: expect string or object, got {}", v),
// }
// }
// pub(crate) fn parse_pull_obj(
// &mut self,
// desc: &Map<String, JsonValue>,
// depth: usize,
// ) -> Result<PullSpec> {
// let mut default_val = DataValue::Null;
// let mut as_override = None;
// let mut take = None;
// let mut cardinality_override = None;
// let mut input_symb = None;
// let mut sub_target = vec![];
// let mut recursive = false;
// let mut recursion_limit = None;
// let mut pull_id = false;
// let mut recursion_depth = 0;
//
// for (k, v) in desc {
// match k as &str {
// "as" => {
// as_override =
// Some(Symbol::new(v.as_str().ok_or_else(|| {
// miette!("expect 'as' field to be string, got {}", v)
// })?))
// }
// "limit" => {
// take = Some(v.as_u64().ok_or_else(|| {
// miette!("expect 'limit field to be non-negative integer, got {}", v)
// })? as usize)
// }
// "cardinality" => {
// cardinality_override =
// Some(AttributeCardinality::try_from(v.as_str().ok_or_else(
// || miette!("expect 'cardinality' field to be string, got {}", v),
// )?)?)
// }
// "default" => default_val = DataValue::from(v),
// "pull" => {
// let v = v
// .as_str()
// .ok_or_else(|| miette!("expect 'pull' field to be string, got {}", v))?;
// if v == "_id" {
// pull_id = true
// } else {
// input_symb = Some(Symbol::new(v));
// }
// }
// "recurse" => {
// if let Some(u) = v.as_u64() {
// recursion_limit = Some(u as usize);
// } else if let Some(b) = v.as_bool() {
// if !b {
// continue;
// }
// } else {
// bail!(
// "expect 'recurse' field to be non-negative integer or boolean, got {}",
// v
// );
// }
// recursive = true;
// }
// "depth" => {
// recursion_depth = v.as_u64().ok_or_else(|| {
// miette!("expect 'depth' field to be non-negative integer, got {}", v)
// })? as usize
// }
// "spec" => {
// sub_target = {
// if let Some(arr) = v.as_array() {
// arr.clone()
// } else {
// bail!("expect 'spec' field to be an array, got {}", v);
// }
// };
// }
// v => {
// bail!("unexpected pull spec key {}", v);
// }
// }
// }
//
// if pull_id {
// return Ok(PullSpec::PullId(
// as_override.unwrap_or_else(|| "_id".into()),
// ));
// }
//
// if input_symb.is_none() {
// bail!("no target key in pull definition");
// }
//
// let input_symb = input_symb.unwrap();
//
// let reverse = input_symb.0.starts_with('<');
// let symb = if reverse {
// Symbol::new(input_symb.0.strip_prefix('<').unwrap())
// } else {
// input_symb.clone()
// };
// let attr = self
// .attr_by_name(&symb)?
// .ok_or_else(|| miette!("attribute not found: {}", symb))?;
// let cardinality = cardinality_override.unwrap_or(attr.cardinality);
// let nested = self.parse_pull(&JsonValue::Array(sub_target), depth + 1)?;
//
// if recursive {
// recursion_depth = max(recursion_depth, 1);
// }
//
// let default_val = if default_val == DataValue::Null {
// default_val
// } else {
// attr.val_type.coerce_value(default_val)?
// };
//
// Ok(PullSpec::Attr(AttrPullSpec {
// attr,
// default_val,
// reverse,
// name: as_override.unwrap_or(input_symb),
// cardinality,
// take,
// nested,
// recursive,
// recursion_limit,
// recursion_depth,
// }))
// }
// }
// fn parse_pull_spec(src: Pair<'_>) -> Result<JsonValue> {
// let mut src = src.into_inner();
// let name = src.next().unwrap().as_str();
// let args: Vec<_> = src
// .next()
// .unwrap()
// .into_inner()
// .map(parse_pull_arg)
// .try_collect()?;
// Ok(json!({"pull": name, "spec": args}))
// }
//
// fn parse_pull_arg(src: Pair<'_>) -> Result<JsonValue> {
// let mut src = src.into_inner();
// let pull_def = src.next().unwrap();
// let mut ret = match pull_def.as_rule() {
// Rule::pull_all => {
// json!("*")
// }
// Rule::pull_id => {
// json!("_id")
// }
// Rule::pull_attr => {
// let mut pull_def = pull_def.into_inner();
// let mut ret = json!(pull_def.next().unwrap().as_str());
// if let Some(args) = pull_def.next() {
// let args: Vec<_> = args.into_inner().map(parse_pull_arg).try_collect()?;
// if !args.is_empty() {
// if !ret.is_object() {
// ret = json!({ "pull": ret });
// }
// ret.as_object_mut()
// .unwrap()
// .insert("spec".to_string(), json!(args));
// }
// }
// ret
// }
// _ => unreachable!(),
// };
// for modifier in src {
// if !ret.is_object() {
// ret = json!({ "pull": ret });
// }
// let inner_map = ret.as_object_mut().unwrap();
// match modifier.as_rule() {
// Rule::pull_as => {
// inner_map.insert(
// "as".to_string(),
// json!(modifier.into_inner().next().unwrap().as_str()),
// );
// }
// Rule::pull_limit => {
// let n = modifier.into_inner().next().unwrap().as_str();
// inner_map.insert("limit".to_string(), json!(str2usize(n)?));
// }
// Rule::pull_offset => {
// let n = modifier.into_inner().next().unwrap().as_str();
// inner_map.insert("offset".to_string(), json!(str2usize(n)?));
// }
// Rule::pull_default => {
// let d = build_expr::<NoWrapConst>(modifier.into_inner().next().unwrap())?;
// inner_map.insert("default".to_string(), d);
// }
// Rule::pull_recurse => {
// let d = build_expr::<NoWrapConst>(modifier.into_inner().next().unwrap())?;
// inner_map.insert("recurse".to_string(), d);
// }
// Rule::pull_depth => {
// let n = modifier.into_inner().next().unwrap().as_str();
// inner_map.insert("depth".to_string(), json!(str2usize(n)?));
// }
// _ => unreachable!(),
// }
// }
// Ok(json!(ret))
// }

@ -6,7 +6,7 @@ use std::fmt::{Display, Formatter};
use either::Left;
use itertools::Itertools;
use miette::{bail, ensure, miette, Diagnostic, LabeledSpan, Report, Result};
use miette::{bail, ensure, Diagnostic, LabeledSpan, Report, Result};
use smartstring::{LazyCompact, SmartString};
use thiserror::Error;
@ -19,7 +19,7 @@ use crate::data::program::{
InputRelationApplyAtom, InputRule, InputRuleApplyAtom, InputRulesOrAlgo, InputTerm,
MagicSymbol, QueryOutOptions, RelationOp, SortDir, TripleDir, Unification,
};
use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::data::symb::Symbol;
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::expr::build_expr;
@ -290,33 +290,31 @@ pub(crate) fn parse_query(
}
}
if let Some((meta, _)) = out_opts.store_relation.borrow_mut() {
meta.arity = get_entry_arity(&progs).ok_or_else(|| miette!("bad"))?;
}
let prog = InputProgram {
let mut prog = InputProgram {
prog: progs,
const_rules,
out_opts,
};
let head_args = prog.get_entry_head().unwrap_or(&[]);
for key in prog.out_opts.out_spec.keys() {
ensure!(
head_args.contains(key),
"the pull target {} is not found",
key
);
let head_arity = prog.get_entry_arity()?;
if let Some((meta, _)) = prog.out_opts.store_relation.borrow_mut() {
meta.arity = head_arity;
}
Ok(prog)
}
if !prog.out_opts.out_spec.is_empty() {
let head_args = prog.get_entry_head().unwrap_or(&[]);
fn get_entry_arity(prog: &BTreeMap<Symbol, InputRulesOrAlgo>) -> Option<usize> {
match prog.get(&Symbol::new(PROG_ENTRY, SourceSpan(0, 0)))? {
InputRulesOrAlgo::Rules { rules } => Some(rules[0].head.len()),
InputRulesOrAlgo::Algo { algo } => algo.arity(),
for key in prog.out_opts.out_spec.keys() {
ensure!(
head_args.contains(key),
"the pull target {} is not found",
key
);
}
}
Ok(prog)
}
fn parse_rule(
@ -376,7 +374,10 @@ fn parse_atom(src: Pair<'_>, param_pool: &BTreeMap<String, DataValue>) -> Result
.into_inner()
.map(|v| parse_disjunction(v, param_pool))
.try_collect()?;
InputAtom::Conjunction { inner: grouped, span }
InputAtom::Conjunction {
inner: grouped,
span,
}
}
Rule::disjunction => parse_disjunction(src, param_pool)?,
Rule::triple => parse_triple(src, param_pool)?,
@ -385,7 +386,7 @@ fn parse_atom(src: Pair<'_>, param_pool: &BTreeMap<String, DataValue>) -> Result
let inner = parse_atom(src.into_inner().next().unwrap(), param_pool)?;
InputAtom::Negation {
inner: inner.into(),
span
span,
}
}
Rule::expr => {
@ -434,7 +435,7 @@ fn parse_atom(src: Pair<'_>, param_pool: &BTreeMap<String, DataValue>) -> Result
inner: InputRuleApplyAtom {
name: Symbol::new(name.as_str(), name.extract_span()),
args,
span
span,
},
}
}
@ -452,7 +453,7 @@ fn parse_atom(src: Pair<'_>, param_pool: &BTreeMap<String, DataValue>) -> Result
inner: InputRelationApplyAtom {
name: Symbol::new(&name.as_str()[1..], name.extract_span()),
args,
span
span,
},
}
}
@ -471,7 +472,7 @@ fn parse_triple(src: Pair<'_>, param_pool: &BTreeMap<String, DataValue>) -> Resu
attr: Symbol::new(attr_p.as_str(), attr_p.extract_span()),
entity: parse_rule_arg(e_p, param_pool)?,
value: parse_rule_arg(v_p, param_pool)?,
span
span,
},
})
}
@ -592,7 +593,7 @@ fn parse_algo_rule(
rule_args.push(AlgoRuleArg::InMem {
name: Symbol::new(name.as_str(), name.extract_span()),
bindings,
span
span,
})
}
Rule::algo_relation_rel => {
@ -607,7 +608,7 @@ fn parse_algo_rule(
name.extract_span(),
),
bindings,
span
span,
})
}
Rule::algo_triple_rel => {
@ -631,7 +632,7 @@ fn parse_algo_rule(
Symbol::new(snd.as_str(), snd.extract_span()),
],
dir,
span
span,
});
}
_ => unreachable!(),

@ -1,8 +1,9 @@
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
use miette::{bail, ensure, miette, Result};
use miette::{bail, ensure, Diagnostic, Result};
use smartstring::{LazyCompact, SmartString};
use thiserror::Error;
use crate::data::id::{EntityId, Validity};
use crate::data::program::InputProgram;
@ -10,7 +11,7 @@ use crate::data::symb::Symbol;
use crate::data::value::{DataValue, LARGEST_UTF_CHAR};
use crate::parse::expr::{build_expr, parse_string};
use crate::parse::query::parse_query;
use crate::parse::{ExtractSpan, Pair, Pairs, Rule};
use crate::parse::{ExtractSpan, Pair, Pairs, Rule, SourceSpan};
#[repr(u8)]
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
@ -136,6 +137,12 @@ fn parse_tx_clause(
Ok(())
}
#[derive(Debug, Error, Diagnostic)]
#[error("Duplicate specification of key in tx map")]
#[diagnostic(code(parser::tx_dup_key))]
#[diagnostic(help("'_id' or '_tid' can appear only once"))]
struct DupKeySpecError(#[label] SourceSpan);
fn parse_tx_map(
map_p: Pair<'_>,
op: TxAction,
@ -145,32 +152,33 @@ fn parse_tx_map(
coll: &mut Vec<Quintuple>,
) -> Result<EntityRep> {
let mut identifier = None;
let whole_span = map_p.extract_span();
for pair in map_p.clone().into_inner() {
let mut src = pair.into_inner();
let fst = src.next().unwrap();
match fst.as_rule() {
Rule::tx_ident_id => {
ensure!(identifier.is_none(), "duplicate specification of key");
ensure!(identifier.is_none(), DupKeySpecError(whole_span));
let expr = build_expr(src.next().unwrap(), param_pool)?;
let c = expr.eval_to_const()?;
let c = c
.get_non_neg_int()
.ok_or_else(|| miette!("integer id required, got {:?}", c))?;
let eid = EntityId(c);
ensure!(eid.is_perm(), "entity id invalid: {:?}", eid);
let eid = expr.build_perm_eid()?;
identifier = Some(EntityRep::Id(eid))
}
Rule::tx_ident_temp_id => {
ensure!(identifier.is_none(), "duplicate specification of key");
#[derive(Debug, Diagnostic, Error)]
#[error("Bad temp id specified")]
#[diagnostic(code(parser::bad_temp_id))]
#[diagnostic(help("Temp ID must be given as a string"))]
struct BadTempId(DataValue, #[label] SourceSpan);
ensure!(identifier.is_none(), DupKeySpecError(whole_span));
let expr = build_expr(src.next().unwrap(), param_pool)?;
let span = expr.span();
let c = expr.eval_to_const()?;
let c = c
.get_string()
.ok_or_else(|| miette!("tid requires string, got {:?}", c))?;
let c = c.get_string().ok_or_else(|| BadTempId(c.clone(), span))?;
identifier = Some(EntityRep::UserTempId(SmartString::from(c)))
}
Rule::tx_ident_key => {
ensure!(identifier.is_none(), "duplicate specification of key");
ensure!(identifier.is_none(), DupKeySpecError(whole_span));
let expr = build_expr(src.next().unwrap(), param_pool)?;
let c = expr.eval_to_const()?;
let c = match c {

@ -1,7 +1,8 @@
use std::collections::{BTreeMap, BTreeSet};
use itertools::Itertools;
use miette::{ensure, miette, Context, Result};
use miette::{ensure, Context, Diagnostic, Result};
use thiserror::Error;
use crate::algo::AlgoNotFoundError;
use crate::data::aggr::Aggregation;
@ -12,6 +13,7 @@ use crate::data::program::{
};
use crate::data::symb::Symbol;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::query::relation::RelAlgebra;
use crate::runtime::derived::DerivedRelStore;
use crate::runtime::transact::SessionTx;
@ -70,6 +72,11 @@ pub(crate) struct CompiledRule {
pub(crate) contained_rules: BTreeSet<MagicSymbol>,
}
#[derive(Debug, Error, Diagnostic)]
#[error("Requested rule {0} not found")]
#[diagnostic(code(eval::rule_not_found))]
struct RuleNotFound(String, #[label] SourceSpan);
impl SessionTx {
pub(crate) fn stratified_magic_compile(
&mut self,
@ -201,7 +208,12 @@ impl SessionTx {
MagicAtom::Rule(rule_app) => {
let store = stores
.get(&rule_app.name)
.ok_or_else(|| miette!("undefined rule '{:?}' encountered", rule_app.name))?
.ok_or_else(|| {
RuleNotFound(
rule_app.name.symbol().to_string(),
rule_app.name.symbol().span,
)
})?
.clone();
ensure!(
store.arity == rule_app.args.len(),
@ -300,7 +312,10 @@ impl SessionTx {
let store = stores
.get(&rule_app.name)
.ok_or_else(|| {
miette!("undefined rule encountered: '{:?}'", rule_app.name)
RuleNotFound(
rule_app.name.symbol().to_string(),
rule_app.name.symbol().span,
)
})?
.clone();
ensure!(
@ -398,7 +413,7 @@ impl SessionTx {
}
} else {
seen_variables.insert(u.binding.clone());
ret = ret.unify(u.binding.clone(), u.expr.clone(), u.one_many_unif);
ret = ret.unify(u.binding.clone(), u.expr.clone(), u.one_many_unif, u.span);
}
}
}

@ -2,9 +2,9 @@ use std::collections::{BTreeMap, BTreeSet};
use std::mem;
use log::{debug, log_enabled, trace, Level};
use miette::{miette, Result};
use miette::Result;
use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::program::{MagicAlgoApply, MagicSymbol, NoEntryError};
use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::parse::SourceSpan;
use crate::query::compile::{AggrKind, CompiledProgram, CompiledRule, CompiledRuleSet};
@ -40,7 +40,7 @@ impl SessionTx {
.get(&MagicSymbol::Muggle {
inner: Symbol::new(PROG_ENTRY, SourceSpan(0, 0)),
})
.ok_or_else(|| miette!("program entry not found in rules"))?
.ok_or_else(|| NoEntryError)?
.clone();
for (idx, cur_prog) in strata.iter().enumerate() {
@ -145,9 +145,7 @@ impl SessionTx {
poison: Poison,
) -> Result<()> {
let mut algo_impl = algo_apply.algo.get_impl()?;
let out = stores
.get(rule_symb)
.ok_or_else(|| miette!("cannot find algo store {:?}", rule_symb))?;
let out = stores.get(rule_symb).unwrap();
algo_impl.run(self, &algo_apply, stores, out, poison)
}
fn initial_rule_eval(

@ -1,7 +1,7 @@
use std::collections::BTreeSet;
use itertools::Itertools;
use miette::{bail, miette, Result};
use miette::{bail, Result};
use crate::data::expr::Expr;
use crate::data::program::{
@ -10,6 +10,7 @@ use crate::data::program::{
TempSymbGen, Unification,
};
use crate::runtime::transact::SessionTx;
use crate::transact::meta::AttrNotFoundError;
#[derive(Debug)]
pub(crate) struct Disjunction {
@ -233,7 +234,7 @@ impl InputAttrTripleAtom {
) -> Result<Disjunction> {
let attr = tx
.attr_by_name(&self.attr.name)?
.ok_or_else(|| miette!("attribute {} not found", self.attr))?;
.ok_or_else(|| AttrNotFoundError(self.attr.name.to_string()))?;
let wrap = |atom| {
if is_negated {
NormalFormAtom::NegatedAttrTriple(atom)
@ -422,6 +423,6 @@ impl InputRelationApplyAtom {
span: self.span,
})
});
Disjunction::conj(ret )
Disjunction::conj(ret)
}
}

@ -2,7 +2,7 @@ use std::collections::BTreeSet;
use std::mem;
use itertools::Itertools;
use miette::{miette, Result};
use miette::{Result};
use smallvec::SmallVec;
use crate::data::id::Validity;
@ -15,6 +15,7 @@ use crate::data::program::{
use crate::data::symb::{Symbol, PROG_ENTRY};
use crate::parse::SourceSpan;
use crate::runtime::transact::SessionTx;
use crate::transact::meta::AttrNotFoundError;
impl NormalFormProgram {
pub(crate) fn exempt_aggr_rules_for_magic_sets(&self, exempt_rules: &mut BTreeSet<Symbol>) {
@ -351,11 +352,10 @@ impl NormalFormProgram {
dir,
span,
} => {
let attr = tx
.attr_by_name(&name.name)?
.ok_or_else(|| {
miette!("cannot find attribute {}", name)
})?;
let attr =
tx.attr_by_name(&name.name)?.ok_or_else(
|| AttrNotFoundError(name.to_string()),
)?;
MagicAlgoRuleArg::Triple {
attr: attr,
bindings: bindings.clone(),

@ -1,8 +1,9 @@
use std::collections::BTreeMap;
use itertools::Itertools;
use miette::{ensure, miette, Result};
use miette::{ensure, Diagnostic, Result};
use serde_json::{json, Map};
use thiserror::Error;
use cozorocks::CfHandle::Snd;
@ -12,9 +13,12 @@ use crate::data::json::JsonValue;
use crate::data::program::RelationOp;
use crate::data::symb::Symbol;
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::pull::OutPullSpec;
use crate::runtime::transact::SessionTx;
use crate::parse::SourceSpan;
use crate::runtime::relation::RelationMetadata;
use crate::runtime::transact::SessionTx;
use crate::transact::meta::AttrNotFoundError;
struct OutPullSpecWithAttr {
attr: Attribute,
@ -27,7 +31,7 @@ impl OutPullSpec {
fn hydrate(&self, tx: &SessionTx, vld: Validity) -> Result<OutPullSpecWithAttr> {
let attr = tx
.attr_by_name(&self.attr.name)?
.ok_or_else(|| miette!("required attribute not found: {}", self.attr))?;
.ok_or_else(|| AttrNotFoundError(self.attr.to_string()))?;
Ok(OutPullSpecWithAttr {
attr,
reverse: self.reverse,
@ -183,16 +187,17 @@ impl SessionTx {
.map_ok(|tuple| tuple.0.into_iter().map(JsonValue::from).collect())
.try_collect()?)
} else {
let headers = headers.ok_or_else(|| miette!("pull requires headers"))?;
let mut idx2pull: Vec<Option<Vec<_>>> = Vec::with_capacity(headers.len());
let headers = headers.unwrap_or(&[]);
let mut idx2pull: Vec<Option<(Vec<_>, _)>> = Vec::with_capacity(headers.len());
for head in headers.iter() {
match out_spec.get(head) {
None => idx2pull.push(None),
Some((os, vld)) => idx2pull.push(Some(
Some((os, vld)) => idx2pull.push(Some((
os.iter()
.map(|o| o.hydrate(self, vld.unwrap_or(default_vld)))
.try_collect()?,
)),
head.clone(),
))),
}
}
let mut collected = vec![];
@ -200,12 +205,20 @@ impl SessionTx {
let tuple = tuple?.0;
let mut row_collected = Vec::with_capacity(tuple.len());
for (idx, item) in tuple.into_iter().enumerate() {
if let Some(specs) = &idx2pull[idx] {
let id = EntityId(
item.get_int()
.ok_or_else(|| miette!("pull requires integer, got {:?}", item))?
as u64,
);
if let Some((specs, symb)) = &idx2pull[idx] {
#[derive(Debug, Diagnostic, Error)]
#[error("Cannot interpret {0:?} as an entity")]
#[diagnostic(code(eval::bad_pull_id))]
#[diagnostic(help(
"You specified pull operation for the variable '{1}', but the value in the output \
stream cannot be interpreted as an entity ID (must be an integer)."
))]
struct BadPullInputError(DataValue, String, #[label] SourceSpan);
let id =
EntityId(item.get_int().ok_or_else(|| {
BadPullInputError(item, symb.to_string(), symb.span)
})? as u64);
let res = self.run_pull_on_item(id, specs)?;
row_collected.push(res);
} else {

@ -5,7 +5,8 @@ use std::iter;
use either::{Left, Right};
use itertools::Itertools;
use log::error;
use miette::{bail, miette, Context, Result};
use miette::{bail, Context, Diagnostic, Result};
use thiserror::Error;
use crate::data::attr::Attribute;
use crate::data::expr::{compute_bounds, compute_single_bound, Expr};
@ -36,6 +37,7 @@ pub(crate) struct UnificationRA {
expr: Expr,
is_multi: bool,
pub(crate) to_eliminate: BTreeSet<Symbol>,
span: SourceSpan,
}
fn eliminate_from_tuple(mut ret: Tuple, eliminate_indices: &BTreeSet<usize>) -> Tuple {
@ -96,7 +98,13 @@ impl UnificationRA {
.map_ok(move |tuple| -> Result<Vec<Tuple>> {
let result_list = self.expr.eval(&tuple)?;
let result_list = result_list.get_list().ok_or_else(|| {
miette!("multi unification encountered non-list {:?}", result_list)
#[derive(Debug, Error, Diagnostic)]
#[error("Invalid spread unification")]
#[diagnostic(code(eval::invalid_spread_unif))]
#[diagnostic(help("Spread unification requires a list at the right"))]
struct BadSpreadUnification(#[label] SourceSpan);
BadSpreadUnification(self.span)
})?;
let mut coll = vec![];
for result in result_list {
@ -394,13 +402,20 @@ impl RelAlgebra {
to_eliminate: Default::default(),
})
}
pub(crate) fn unify(self, binding: Symbol, expr: Expr, is_multi: bool) -> Self {
pub(crate) fn unify(
self,
binding: Symbol,
expr: Expr,
is_multi: bool,
span: SourceSpan,
) -> Self {
RelAlgebra::Unification(UnificationRA {
parent: Box::new(self),
binding,
expr,
is_multi,
to_eliminate: Default::default(),
span,
})
}
pub(crate) fn join(

@ -179,77 +179,3 @@ impl NormalFormRule {
})
}
}
// fn reorder_rule_body_for_negations(clauses: Vec<Atom>) -> Result<Vec<Atom>> {
// let (negations, others): (Vec<_>, _) = clauses.into_iter().partition(|a| a.is_negation());
// let mut seen_bindings = BTreeSet::new();
// for a in &others {
// a.collect_bindings(&mut seen_bindings);
// }
// let mut negations_with_meta = negations
// .into_iter()
// .map(|p| {
// let p = p.into_negated().unwrap();
// let mut bindings = Default::default();
// p.collect_bindings(&mut bindings);
// let valid_bindings: BTreeSet<_> =
// bindings.intersection(&seen_bindings).cloned().collect();
// (Some(p), valid_bindings)
// })
// .collect_vec();
// let mut ret = vec![];
// seen_bindings.clear();
// for a in others {
// a.collect_bindings(&mut seen_bindings);
// ret.push(a);
// for (negated, pred_bindings) in negations_with_meta.iter_mut() {
// if negated.is_none() {
// continue;
// }
// if seen_bindings.is_superset(pred_bindings) {
// let negated = negated.take().unwrap();
// ret.push(Atom::Negation(Box::new(negated)));
// }
// }
// }
// Ok(ret)
// }
//
// fn reorder_rule_body_for_predicates(clauses: Vec<Atom>) -> Result<Vec<Atom>> {
// let (predicates, others): (Vec<_>, _) = clauses.into_iter().partition(|a| a.is_predicate());
// let mut predicates_with_meta = predicates
// .into_iter()
// .map(|p| {
// let p = p.into_predicate().unwrap();
// let bindings = p.bindings();
// (Some(p), bindings)
// })
// .collect_vec();
// let mut seen_bindings = BTreeSet::new();
// let mut ret = vec![];
// for a in others {
// a.collect_bindings(&mut seen_bindings);
// ret.push(a);
// for (pred, pred_bindings) in predicates_with_meta.iter_mut() {
// if pred.is_none() {
// continue;
// }
// if seen_bindings.is_superset(pred_bindings) {
// let pred = pred.take().unwrap();
// ret.push(Atom::Predicate(pred));
// }
// }
// }
// for (p, bindings) in predicates_with_meta {
// ensure!(
// p.is_none(),
// "unsafe bindings {:?} found in predicate {:?}",
// bindings
// .difference(&seen_bindings)
// .cloned()
// .collect::<BTreeSet<_>>(),
// p.unwrap()
// );
// }
// Ok(ret)
// }

@ -9,7 +9,7 @@ use std::{fs, thread};
use either::{Left, Right};
use itertools::Itertools;
use log::debug;
use miette::{bail, ensure, miette, Diagnostic, Result, WrapErr};
use miette::{bail, ensure, Diagnostic, Result, WrapErr};
use serde_json::json;
use smartstring::SmartString;
use thiserror::Error;
@ -383,14 +383,11 @@ impl Db {
poison,
)?;
let json_headers = match input_program.get_entry_head() {
None => JsonValue::Null,
Some(headers) => headers.iter().map(|v| json!(v.name)).collect(),
Err(_) => JsonValue::Null,
Ok(headers) => headers.iter().map(|v| json!(v.name)).collect(),
};
if !input_program.out_opts.sorters.is_empty() {
let entry_head = input_program
.get_entry_head()
.ok_or_else(|| miette!("program entry head must be defined for sorters to work"))?
.to_vec();
let entry_head = input_program.get_entry_head()?.to_vec();
let sorted_result =
tx.sort_and_collect(result, &input_program.out_opts.sorters, &entry_head)?;
let sorted_iter = if let Some(offset) = input_program.out_opts.offset {
@ -412,7 +409,7 @@ impl Db {
} else {
let ret: Vec<_> = tx.run_pull_on_query_results(
sorted_iter,
input_program.get_entry_head(),
input_program.get_entry_head().ok(),
&input_program.out_opts.out_spec,
default_vld,
)?;
@ -438,7 +435,7 @@ impl Db {
} else {
let ret: Vec<_> = tx.run_pull_on_query_results(
scan,
input_program.get_entry_head(),
input_program.get_entry_head().ok(),
&input_program.out_opts.out_spec,
default_vld,
)?;
@ -529,6 +526,12 @@ impl Db {
match self.it.pair()? {
None => Ok(None),
Some((k_slice, v_slice)) => {
#[derive(Debug, Error, Diagnostic)]
#[error("Encountered corrupt key in meta store")]
#[diagnostic(code(db::corrupt_meta_key))]
#[diagnostic(help("This is an internal error. Please file a bug."))]
struct CorruptKeyInMetaStoreError;
let encoded = EncodedTuple(k_slice).decode()?;
let ks: Vec<_> = encoded
.0
@ -537,7 +540,7 @@ impl Db {
.map(|v| {
v.get_string()
.map(|s| s.to_string())
.ok_or_else(|| miette!("bad key in meta store"))
.ok_or(CorruptKeyInMetaStoreError)
})
.try_collect()?;
Ok(Some((ks, v_slice.to_vec())))

@ -5,8 +5,8 @@ use std::ops::Bound::Included;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, RwLock};
use miette::{miette, Result};
use itertools::Itertools;
use miette::Result;
use cozorocks::DbIter;
@ -381,7 +381,7 @@ impl Iterator for SortedIter {
self.it.next();
}
match self.it.pair() {
Err(e) => Some(Err(miette!(e))),
Err(e) => Some(Err(e.into())),
Ok(None) => None,
Ok(Some((_, v_slice))) => match EncodedTuple(v_slice).decode() {
Ok(res) => Some(Ok(res)),

@ -1,17 +1,18 @@
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use log::error;
use miette::{miette, Result};
use miette::{Diagnostic, Result};
use rmp_serde::Serializer;
use serde::Serialize;
use smallvec::SmallVec;
use smartstring::{LazyCompact, SmartString};
use thiserror::Error;
use cozorocks::CfHandle::{Pri, Snd};
use cozorocks::{DbIter, Tx};
use cozorocks::CfHandle::{Pri, Snd};
use crate::data::attr::Attribute;
use crate::data::encode::{
@ -164,8 +165,13 @@ impl SessionTx {
}
pub(crate) fn get_write_tx_id(&self) -> Result<TxId> {
self.w_tx_id
.ok_or_else(|| miette!("attempting to write in read-only transaction"))
#[derive(Error, Diagnostic, Debug)]
#[error("Attempting to write in read-only mode")]
#[diagnostic(code(query::readonly_violation))]
#[diagnostic(help("This indicates a bug. Please report it."))]
struct WriteInReadOnlyModeError;
Ok(self.w_tx_id.ok_or_else(|| WriteInReadOnlyModeError)?)
}
pub(crate) fn bounded_scan_first(&self, lower: &[u8], upper: &[u8]) -> DbIter {
// this is tricky, must be written like this!

@ -1,10 +1,11 @@
use std::sync::atomic::Ordering;
use miette::{bail, ensure, miette, Result};
use miette::{bail, ensure, Diagnostic, Result};
use smartstring::SmartString;
use thiserror::Error;
use cozorocks::{DbIter, IterBuilder};
use cozorocks::CfHandle::Pri;
use cozorocks::{DbIter, IterBuilder};
use crate::data::attr::Attribute;
use crate::data::encode::{
@ -56,7 +57,9 @@ impl SessionTx {
let attr = Attribute::decode(&data[VEC_SIZE_8..])?;
if op.is_retract() {
self.attr_by_id_cache.borrow_mut().insert(attr.id, None);
self.attr_by_kw_cache.borrow_mut().insert(attr.name.into(), None);
self.attr_by_kw_cache
.borrow_mut()
.insert(attr.name.into(), None);
None
} else {
self.attr_by_id_cache
@ -136,7 +139,7 @@ impl SessionTx {
pub(crate) fn amend_attr(&mut self, attr: Attribute) -> Result<AttrId> {
let existing = self
.attr_by_id(attr.id)?
.ok_or_else(|| miette!("expected attribute id {:?} not found", attr.id))?;
.ok_or_else(|| AttrNotFoundError(attr.id.0.to_string()))?;
let tx_id = self.get_write_tx_id()?;
if existing.name != attr.name {
ensure!(
@ -185,11 +188,16 @@ impl SessionTx {
pub(crate) fn retract_attr_by_name(&mut self, kw: &str) -> Result<AttrId> {
let attr = self
.attr_by_name(kw)?
.ok_or_else(|| miette!("attribute not found: {}", kw))?;
.ok_or_else(|| AttrNotFoundError(kw.to_string()))?;
self.retract_attr(attr.id)
}
}
#[derive(Debug, Error, Diagnostic)]
#[error("Required attribute identified by {0} not found")]
#[diagnostic(code(eval::attr_not_found))]
pub(crate) struct AttrNotFoundError(pub(crate) String);
struct AttrIter {
it: DbIter,
started: bool,

@ -1,8 +1,9 @@
use std::collections::BTreeMap;
use std::sync::atomic::Ordering;
use miette::{bail, ensure, miette, Result};
use miette::{bail, ensure, Diagnostic, Result};
use smartstring::{LazyCompact, SmartString};
use thiserror::Error;
use cozorocks::CfHandle::Pri;
use cozorocks::{DbIter, IterBuilder};
@ -19,8 +20,14 @@ use crate::data::triple::StoreOp;
use crate::data::value::DataValue;
use crate::parse::tx::{EntityRep, Quintuple, TxAction};
use crate::runtime::transact::SessionTx;
use crate::transact::meta::AttrNotFoundError;
use crate::utils::swap_option_result;
#[derive(Debug, Diagnostic, Error)]
#[error("Required entity identified by {0} not found")]
#[diagnostic(code(eval::entity_not_found))]
pub(crate) struct EntityNotFound(pub(crate) String);
impl SessionTx {
pub(crate) fn tx_triples(
&mut self,
@ -49,7 +56,7 @@ impl SessionTx {
TxAction::Put => {
let attr = self
.attr_by_name(&payload.attr_name.name)?
.ok_or_else(|| miette!("attribute {} not found", payload.attr_name))?;
.ok_or_else(|| AttrNotFoundError(payload.attr_name.name.to_string()))?;
let val =
attr.coerce_value(payload.value, &mut str_temp_to_perm_ids, self, vld)?;
match payload.entity {
@ -73,11 +80,11 @@ impl SessionTx {
EntityRep::PullByKey(symb, val) => {
let attr = self
.attr_by_name(&symb)?
.ok_or_else(|| miette!("required attribute {} not found", symb))?;
.ok_or_else(|| AttrNotFoundError(symb.to_string()))?;
let eid =
self.eid_by_unique_av(&attr, &val, vld)?.ok_or_else(|| {
miette!("requried entity not found: {}: {:?}", symb, val)
EntityNotFound(format!("{}: {:?}", attr.name, val))
})?;
ret.push((self.new_triple(eid, &attr, &val, vld)?, 1));
@ -95,11 +102,11 @@ impl SessionTx {
let vld = payload.validity.unwrap_or(default_vld);
let attr = self
.attr_by_name(&symb)?
.ok_or_else(|| miette!("required attribute {} not found", symb))?;
.ok_or_else(|| AttrNotFoundError(symb.to_string()))?;
let eid =
self.eid_by_unique_av(&attr, &val, vld)?.ok_or_else(|| {
miette!("requried entity not found: {}: {:?}", symb, val)
EntityNotFound(format!("{}: {:?}", attr.name, val))
})?;
eid
}

Loading…
Cancel
Save