diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index baa9e8d2..5083debb 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -422,63 +422,9 @@ pub enum Expression { UnaryPlus(Box), UnaryMinus(Box), UnaryNot(Box), - StrFunctionCall(Box), - LangFunctionCall(Box), - LangMatchesFunctionCall(Box, Box), - DatatypeFunctionCall(Box), - BoundFunctionCall(Variable), - IRIFunctionCall(Box), - BNodeFunctionCall(Option>), - RandFunctionCall(), - AbsFunctionCall(Box), - CeilFunctionCall(Box), - FloorFunctionCall(Box), - RoundFunctionCall(Box), - ConcatFunctionCall(Vec), - SubStrFunctionCall(Box, Box, Option>), - StrLenFunctionCall(Box), - ReplaceFunctionCall( - Box, - Box, - Box, - Option>, - ), - UCaseFunctionCall(Box), - LCaseFunctionCall(Box), - EncodeForURIFunctionCall(Box), - ContainsFunctionCall(Box, Box), - StrStartsFunctionCall(Box, Box), - StrEndsFunctionCall(Box, Box), - StrBeforeFunctionCall(Box, Box), - StrAfterFunctionCall(Box, Box), - YearFunctionCall(Box), - MonthFunctionCall(Box), - DayFunctionCall(Box), - HoursFunctionCall(Box), - MinutesFunctionCall(Box), - SecondsFunctionCall(Box), - TimezoneFunctionCall(Box), - TzFunctionCall(Box), - NowFunctionCall(), - UUIDFunctionCall(), - StrUUIDFunctionCall(), - MD5FunctionCall(Box), - SHA1FunctionCall(Box), - SHA256FunctionCall(Box), - SHA384FunctionCall(Box), - SHA512FunctionCall(Box), - CoalesceFunctionCall(Vec), - IfFunctionCall(Box, Box, Box), - StrLangFunctionCall(Box, Box), - StrDTFunctionCall(Box, Box), - SameTermFunctionCall(Box, Box), - IsIRIFunctionCall(Box), - IsBlankFunctionCall(Box), - IsLiteralFunctionCall(Box), - IsNumericFunctionCall(Box), - RegexFunctionCall(Box, Box, Option>), - CustomFunctionCall(NamedNode, Vec), - ExistsFunctionCall(Box), + FunctionCall(Function, Vec), + Exists(Box), + Bound(Variable), } impl fmt::Display for Expression { @@ -518,96 +464,20 @@ impl fmt::Display for Expression { Expression::UnaryPlus(e) => write!(f, "+{}", e), Expression::UnaryMinus(e) => write!(f, "-{}", e), Expression::UnaryNot(e) => write!(f, "!{}", e), - Expression::StrFunctionCall(e) => write!(f, "STR({})", e), - Expression::LangFunctionCall(e) => write!(f, "LANG({})", e), - Expression::LangMatchesFunctionCall(a, b) => write!(f, "LANGMATCHES({}, {})", a, b), - Expression::DatatypeFunctionCall(e) => write!(f, "DATATYPE({})", e), - Expression::BoundFunctionCall(v) => write!(f, "BOUND({})", v), - Expression::IRIFunctionCall(e) => write!(f, "IRI({})", e), - Expression::BNodeFunctionCall(v) => v - .as_ref() - .map(|id| write!(f, "BNODE({})", id)) - .unwrap_or_else(|| write!(f, "BNODE()")), - Expression::RandFunctionCall() => write!(f, "RAND()"), - Expression::AbsFunctionCall(e) => write!(f, "ABS({})", e), - Expression::CeilFunctionCall(e) => write!(f, "CEIL({})", e), - Expression::FloorFunctionCall(e) => write!(f, "FLOOR({})", e), - Expression::RoundFunctionCall(e) => write!(f, "ROUND({})", e), - Expression::ConcatFunctionCall(e) => write!( - f, - "CONCAT({})", - e.iter() - .map(|v| v.to_string()) - .collect::>() - .join(", ") - ), - Expression::SubStrFunctionCall(a, b, c) => c - .as_ref() - .map(|cv| write!(f, "SUBSTR({}, {}, {})", a, b, cv)) - .unwrap_or_else(|| write!(f, "SUBSTR({}, {})", a, b)), - Expression::StrLenFunctionCall(e) => write!(f, "STRLEN({})", e), - Expression::ReplaceFunctionCall(arg, pattern, replacement, flags) => match flags { - Some(flags) => write!( - f, - "REPLACE({}, {}, {}, {})", - arg, pattern, replacement, flags - ), - None => write!(f, "REPLACE({}, {}, {})", arg, pattern, replacement), - }, - Expression::UCaseFunctionCall(e) => write!(f, "UCASE({})", e), - Expression::LCaseFunctionCall(e) => write!(f, "LCASE({})", e), - Expression::EncodeForURIFunctionCall(e) => write!(f, "ENCODE_FOR_URI({})", e), - Expression::ContainsFunctionCall(a, b) => write!(f, "CONTAINS({}, {})", a, b), - Expression::StrStartsFunctionCall(a, b) => write!(f, "STRSTATS({}, {})", a, b), - Expression::StrEndsFunctionCall(a, b) => write!(f, "STRENDS({}, {})", a, b), - Expression::StrBeforeFunctionCall(a, b) => write!(f, "STRBEFORE({}, {})", a, b), - Expression::StrAfterFunctionCall(a, b) => write!(f, "STRAFTER({}, {})", a, b), - Expression::YearFunctionCall(e) => write!(f, "YEAR({})", e), - Expression::MonthFunctionCall(e) => write!(f, "MONTH({})", e), - Expression::DayFunctionCall(e) => write!(f, "DAY({})", e), - Expression::HoursFunctionCall(e) => write!(f, "HOURS({})", e), - Expression::MinutesFunctionCall(e) => write!(f, "MINUTES({})", e), - Expression::SecondsFunctionCall(e) => write!(f, "SECONDS({})", e), - Expression::TimezoneFunctionCall(e) => write!(f, "TIMEZONE({})", e), - Expression::TzFunctionCall(e) => write!(f, "TZ({})", e), - Expression::NowFunctionCall() => write!(f, "NOW()"), - Expression::UUIDFunctionCall() => write!(f, "UUID()"), - Expression::StrUUIDFunctionCall() => write!(f, "STRUUID()"), - Expression::MD5FunctionCall(e) => write!(f, "MD5({})", e), - Expression::SHA1FunctionCall(e) => write!(f, "SHA1({})", e), - Expression::SHA256FunctionCall(e) => write!(f, "SHA256({})", e), - Expression::SHA384FunctionCall(e) => write!(f, "SHA384({})", e), - Expression::SHA512FunctionCall(e) => write!(f, "SHA512({})", e), - Expression::CoalesceFunctionCall(e) => write!( - f, - "COALESCE({})", - e.iter() - .map(|v| v.to_string()) - .collect::>() - .join(", ") - ), - Expression::IfFunctionCall(a, b, c) => write!(f, "IF({}, {}, {})", a, b, c), - Expression::StrLangFunctionCall(a, b) => write!(f, "STRLANG({}, {})", a, b), - Expression::StrDTFunctionCall(a, b) => write!(f, "STRDT({}, {})", a, b), - Expression::SameTermFunctionCall(a, b) => write!(f, "sameTerm({}, {})", a, b), - Expression::IsIRIFunctionCall(e) => write!(f, "isIRI({})", e), - Expression::IsBlankFunctionCall(e) => write!(f, "isBLANK({})", e), - Expression::IsLiteralFunctionCall(e) => write!(f, "isLITERAL({})", e), - Expression::IsNumericFunctionCall(e) => write!(f, "isNUMERIC({})", e), - Expression::RegexFunctionCall(text, pattern, flags) => match flags { - Some(flags) => write!(f, "REGEX({}, {}, {})", text, pattern, flags), - None => write!(f, "REGEX({}, {})", text, pattern), - }, - Expression::CustomFunctionCall(iri, args) => write!( - f, - "{}({})", - iri, - args.iter() - .map(|v| v.to_string()) - .collect::>() - .join(", ") - ), - Expression::ExistsFunctionCall(p) => write!(f, "EXISTS {{ {} }}", p), + Expression::FunctionCall(function, parameters) => { + write!(f, "{}(", function)?; + let mut cont = false; + for p in parameters { + if cont { + write!(f, ", ")?; + } + p.fmt(f)?; + cont = true; + } + write!(f, ")") + } + Expression::Exists(p) => write!(f, "EXISTS {{ {} }}", p), + Expression::Bound(v) => write!(f, "BOUND({})", v), } } } @@ -708,195 +578,134 @@ impl<'a> fmt::Display for SparqlExpression<'a> { Expression::UnaryPlus(e) => write!(f, "+{}", SparqlExpression(&*e)), Expression::UnaryMinus(e) => write!(f, "-{}", SparqlExpression(&*e)), Expression::UnaryNot(e) => match e.as_ref() { - Expression::ExistsFunctionCall(p) => { - write!(f, "NOT EXISTS {{ {} }}", SparqlGraphPattern(&*p)) - } + Expression::Exists(p) => write!(f, "NOT EXISTS {{ {} }}", SparqlGraphPattern(&*p)), e => write!(f, "!{}", e), }, - Expression::StrFunctionCall(e) => write!(f, "STR({})", SparqlExpression(&*e)), - Expression::LangFunctionCall(e) => write!(f, "LANG({})", SparqlExpression(&*e)), - Expression::LangMatchesFunctionCall(a, b) => write!( - f, - "LANGMATCHES({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::DatatypeFunctionCall(e) => write!(f, "DATATYPE({})", SparqlExpression(&*e)), - Expression::BoundFunctionCall(v) => write!(f, "BOUND({})", v), - Expression::IRIFunctionCall(e) => write!(f, "IRI({})", SparqlExpression(&*e)), - Expression::BNodeFunctionCall(v) => v - .as_ref() - .map(|id| write!(f, "BOUND({})", SparqlExpression(&*id))) - .unwrap_or_else(|| write!(f, "BOUND()")), - Expression::RandFunctionCall() => write!(f, "RAND()"), - Expression::AbsFunctionCall(e) => write!(f, "ABS({})", SparqlExpression(&*e)), - Expression::CeilFunctionCall(e) => write!(f, "CEIL({})", SparqlExpression(&*e)), - Expression::FloorFunctionCall(e) => write!(f, "FLOOR({})", SparqlExpression(&*e)), - Expression::RoundFunctionCall(e) => write!(f, "ROUND({})", SparqlExpression(&*e)), - Expression::ConcatFunctionCall(e) => write!( - f, - "CONCAT({})", - e.iter() - .map(|v| SparqlExpression(v).to_string()) - .collect::>() - .join(", ") - ), - Expression::SubStrFunctionCall(a, b, c) => c - .as_ref() - .map(|cv| { - write!( - f, - "SUBSTR({}, {}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b), - SparqlExpression(cv) - ) - }) - .unwrap_or_else(|| { - write!( - f, - "SUBSTR({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ) - }), - Expression::StrLenFunctionCall(e) => write!(f, "STRLEN({})", SparqlExpression(&*e)), - Expression::ReplaceFunctionCall(arg, pattern, replacement, flags) => match flags { - Some(flags) => write!( - f, - "REPLACE({}, {}, {}, {})", - SparqlExpression(&*arg), - SparqlExpression(&*pattern), - SparqlExpression(&*replacement), - flags - ), - None => write!( - f, - "REPLACE({}, {}, {})", - SparqlExpression(&*arg), - SparqlExpression(&*pattern), - SparqlExpression(&*replacement) - ), - }, - Expression::UCaseFunctionCall(e) => write!(f, "UCASE({})", SparqlExpression(&*e)), - Expression::LCaseFunctionCall(e) => write!(f, "LCASE({})", SparqlExpression(&*e)), - Expression::EncodeForURIFunctionCall(e) => { - write!(f, "ENCODE_FOR_URI({})", SparqlExpression(&*e)) - } - Expression::ContainsFunctionCall(a, b) => write!( - f, - "CONTAINS({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::StrStartsFunctionCall(a, b) => write!( - f, - "STRSTATS({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::StrEndsFunctionCall(a, b) => write!( - f, - "STRENDS({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::StrBeforeFunctionCall(a, b) => write!( - f, - "STRBEFORE({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::StrAfterFunctionCall(a, b) => write!( - f, - "STRAFTER({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::YearFunctionCall(e) => write!(f, "YEAR({})", SparqlExpression(&*e)), - Expression::MonthFunctionCall(e) => write!(f, "MONTH({})", SparqlExpression(&*e)), - Expression::DayFunctionCall(e) => write!(f, "DAY({})", SparqlExpression(&*e)), - Expression::HoursFunctionCall(e) => write!(f, "HOURS({})", SparqlExpression(&*e)), - Expression::MinutesFunctionCall(e) => write!(f, "MINUTES({})", SparqlExpression(&*e)), - Expression::SecondsFunctionCall(e) => write!(f, "SECONDS({})", SparqlExpression(&*e)), - Expression::TimezoneFunctionCall(e) => write!(f, "TIMEZONE({})", SparqlExpression(&*e)), - Expression::TzFunctionCall(e) => write!(f, "TZ({})", SparqlExpression(&*e)), - Expression::NowFunctionCall() => write!(f, "NOW()"), - Expression::UUIDFunctionCall() => write!(f, "UUID()"), - Expression::StrUUIDFunctionCall() => write!(f, "STRUUID()"), - Expression::MD5FunctionCall(e) => write!(f, "MD5({})", SparqlExpression(&*e)), - Expression::SHA1FunctionCall(e) => write!(f, "SHA1({})", SparqlExpression(&*e)), - Expression::SHA256FunctionCall(e) => write!(f, "SHA256({})", SparqlExpression(&*e)), - Expression::SHA384FunctionCall(e) => write!(f, "SHA384({})", SparqlExpression(&*e)), - Expression::SHA512FunctionCall(e) => write!(f, "SHA512({})", SparqlExpression(&*e)), - Expression::CoalesceFunctionCall(e) => write!( - f, - "COALESCE({})", - e.iter() - .map(|v| SparqlExpression(&*v).to_string()) - .collect::>() - .join(", ") - ), - Expression::IfFunctionCall(a, b, c) => write!( - f, - "IF({}, {}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b), - SparqlExpression(&*c) - ), - Expression::StrLangFunctionCall(a, b) => write!( - f, - "STRLANG({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::StrDTFunctionCall(a, b) => write!( - f, - "STRDT({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::SameTermFunctionCall(a, b) => write!( - f, - "sameTerm({}, {})", - SparqlExpression(&*a), - SparqlExpression(&*b) - ), - Expression::IsIRIFunctionCall(e) => write!(f, "isIRI({})", SparqlExpression(&*e)), - Expression::IsBlankFunctionCall(e) => write!(f, "isBLANK({})", SparqlExpression(&*e)), - Expression::IsLiteralFunctionCall(e) => { - write!(f, "isLITERAL({})", SparqlExpression(&*e)) - } - Expression::IsNumericFunctionCall(e) => { - write!(f, "isNUMERIC({})", SparqlExpression(&*e)) - } - Expression::RegexFunctionCall(text, pattern, flags) => match flags { - Some(flags) => write!( - f, - "REGEX({}, {}, {})", - SparqlExpression(&*text), - SparqlExpression(&*pattern), - flags - ), - None => write!( - f, - "REGEX({}, {})", - SparqlExpression(&*text), - SparqlExpression(&*pattern) - ), - }, - Expression::CustomFunctionCall(iri, args) => write!( - f, - "{}({})", - iri, - args.iter() - .map(|v| SparqlExpression(v).to_string()) - .collect::>() - .join(", ") - ), - Expression::ExistsFunctionCall(p) => { - write!(f, "EXISTS {{ {} }}", SparqlGraphPattern(&*p)) + Expression::FunctionCall(function, parameters) => { + write!(f, "{}(", function)?; + let mut cont = false; + for p in parameters { + if cont { + write!(f, ", ")?; + } + SparqlExpression(&*p).fmt(f)?; + cont = true; + } + write!(f, ")") } + Expression::Bound(v) => write!(f, "BOUND({})", v), + Expression::Exists(p) => write!(f, "EXISTS {{ {} }}", SparqlGraphPattern(&*p)), + } + } +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] +pub enum Function { + Str, + Lang, + LangMatches, + Datatype, + IRI, + BNode, + Rand, + Abs, + Ceil, + Floor, + Round, + Concat, + SubStr, + StrLen, + Replace, + UCase, + LCase, + EncodeForURI, + Contains, + StrStarts, + StrEnds, + StrBefore, + StrAfter, + Year, + Month, + Day, + Hours, + Minutes, + Seconds, + Timezone, + Tz, + Now, + UUID, + StrUUID, + MD5, + SHA1, + SHA256, + SHA384, + SHA512, + Coalesce, + If, + StrLang, + StrDT, + SameTerm, + IsIRI, + IsBlank, + IsLiteral, + IsNumeric, + Regex, + Custom(NamedNode), +} + +impl fmt::Display for Function { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Function::Str => write!(f, "STR"), + Function::Lang => write!(f, "LANG"), + Function::LangMatches => write!(f, "LANGMATCHES"), + Function::Datatype => write!(f, "DATATYPE"), + Function::IRI => write!(f, "IRI"), + Function::BNode => write!(f, "BNODE"), + Function::Rand => write!(f, "RAND"), + Function::Abs => write!(f, "ABS"), + Function::Ceil => write!(f, "CEIL"), + Function::Floor => write!(f, "FLOOR"), + Function::Round => write!(f, "ROUND"), + Function::Concat => write!(f, "CONCAT"), + Function::SubStr => write!(f, "SUBSTR"), + Function::StrLen => write!(f, "STRLEN"), + Function::Replace => write!(f, "REPLACE"), + Function::UCase => write!(f, "UCASE"), + Function::LCase => write!(f, "LCASE"), + Function::EncodeForURI => write!(f, "ENCODE_FOR_URI"), + Function::Contains => write!(f, "CONTAINS"), + Function::StrStarts => write!(f, "STRSTATS"), + Function::StrEnds => write!(f, "STRENDS"), + Function::StrBefore => write!(f, "STRBEFORE"), + Function::StrAfter => write!(f, "STRAFTER"), + Function::Year => write!(f, "YEAR"), + Function::Month => write!(f, "MONTH"), + Function::Day => write!(f, "DAY"), + Function::Hours => write!(f, "HOURS"), + Function::Minutes => write!(f, "MINUTES"), + Function::Seconds => write!(f, "SECONDS"), + Function::Timezone => write!(f, "TIMEZONE"), + Function::Tz => write!(f, "TZ"), + Function::Now => write!(f, "NOW"), + Function::UUID => write!(f, "UUID"), + Function::StrUUID => write!(f, "STRUUID"), + Function::MD5 => write!(f, "MD5"), + Function::SHA1 => write!(f, "SHA1"), + Function::SHA256 => write!(f, "SHA256"), + Function::SHA384 => write!(f, "SHA384"), + Function::SHA512 => write!(f, "SHA512"), + Function::Coalesce => write!(f, "COALESCE"), + Function::If => write!(f, "IF"), + Function::StrLang => write!(f, "STRLANG"), + Function::StrDT => write!(f, "STRDT"), + Function::SameTerm => write!(f, "sameTerm"), + Function::IsIRI => write!(f, "isIRI"), + Function::IsBlank => write!(f, "isBLANK"), + Function::IsLiteral => write!(f, "isLITERAL"), + Function::IsNumeric => write!(f, "isNUMERIC"), + Function::Regex => write!(f, "REGEX"), + Function::Custom(iri) => iri.fmt(f), } } } diff --git a/lib/src/sparql/plan.rs b/lib/src/sparql/plan.rs index 8a2f016a..31df3da7 100644 --- a/lib/src/sparql/plan.rs +++ b/lib/src/sparql/plan.rs @@ -616,127 +616,140 @@ impl<'a, S: EncodedQuadsStore> PlanBuilder<'a, S> { Expression::UnaryNot(e) => { PlanExpression::UnaryNot(Box::new(self.build_for_expression(e, variables)?)) } - Expression::StrFunctionCall(e) => { - PlanExpression::Str(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::LangFunctionCall(e) => { - PlanExpression::Lang(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::LangMatchesFunctionCall(a, b) => PlanExpression::LangMatches( - Box::new(self.build_for_expression(a, variables)?), - Box::new(self.build_for_expression(b, variables)?), - ), - Expression::DatatypeFunctionCall(e) => { - PlanExpression::Datatype(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::BoundFunctionCall(v) => PlanExpression::Bound(variable_key(variables, v)), - Expression::IRIFunctionCall(e) => { - PlanExpression::IRI(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::BNodeFunctionCall(e) => PlanExpression::BNode(match e { - Some(e) => Some(Box::new(self.build_for_expression(e, variables)?)), - None => None, - }), - Expression::YearFunctionCall(e) => { - PlanExpression::Year(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::MonthFunctionCall(e) => { - PlanExpression::Month(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::DayFunctionCall(e) => { - PlanExpression::Day(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::HoursFunctionCall(e) => { - PlanExpression::Hours(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::MinutesFunctionCall(e) => { - PlanExpression::Minutes(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::SecondsFunctionCall(e) => { - PlanExpression::Seconds(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::UUIDFunctionCall() => PlanExpression::UUID(), - Expression::StrUUIDFunctionCall() => PlanExpression::StrUUID(), - Expression::CoalesceFunctionCall(l) => { - PlanExpression::Coalesce(self.expression_list(l, variables)?) - } - Expression::IfFunctionCall(a, b, c) => PlanExpression::If( - Box::new(self.build_for_expression(a, variables)?), - Box::new(self.build_for_expression(b, variables)?), - Box::new(self.build_for_expression(c, variables)?), - ), - Expression::StrLangFunctionCall(a, b) => PlanExpression::StrLang( - Box::new(self.build_for_expression(a, variables)?), - Box::new(self.build_for_expression(b, variables)?), - ), - Expression::SameTermFunctionCall(a, b) => PlanExpression::SameTerm( - Box::new(self.build_for_expression(a, variables)?), - Box::new(self.build_for_expression(b, variables)?), - ), - Expression::IsIRIFunctionCall(e) => { - PlanExpression::IsIRI(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::IsBlankFunctionCall(e) => { - PlanExpression::IsBlank(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::IsLiteralFunctionCall(e) => { - PlanExpression::IsLiteral(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::IsNumericFunctionCall(e) => { - PlanExpression::IsNumeric(Box::new(self.build_for_expression(e, variables)?)) - } - Expression::RegexFunctionCall(text, pattern, flags) => PlanExpression::Regex( - Box::new(self.build_for_expression(text, variables)?), - Box::new(self.build_for_expression(pattern, variables)?), - match flags { - Some(flags) => Some(Box::new(self.build_for_expression(flags, variables)?)), + Expression::FunctionCall(function, parameters) => match function { + Function::Str => PlanExpression::Str(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Lang => PlanExpression::Lang(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::LangMatches => PlanExpression::LangMatches( + Box::new(self.build_for_expression(¶meters[0], variables)?), + Box::new(self.build_for_expression(¶meters[1], variables)?), + ), + Function::Datatype => PlanExpression::Datatype(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::IRI => PlanExpression::IRI(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::BNode => PlanExpression::BNode(match parameters.get(0) { + Some(e) => Some(Box::new(self.build_for_expression(e, variables)?)), None => None, - }, - ), - Expression::CustomFunctionCall(name, parameters) => { - if *name == *xsd::BOOLEAN { - self.build_cast( - parameters, - PlanExpression::BooleanCast, - variables, - "boolean", - )? - } else if *name == *xsd::DOUBLE { - self.build_cast(parameters, PlanExpression::DoubleCast, variables, "double")? - } else if *name == *xsd::FLOAT { - self.build_cast(parameters, PlanExpression::FloatCast, variables, "float")? - } else if *name == *xsd::DECIMAL { - self.build_cast( - parameters, - PlanExpression::DecimalCast, - variables, - "decimal", - )? - } else if *name == *xsd::INTEGER { - self.build_cast( - parameters, - PlanExpression::IntegerCast, - variables, - "integer", - )? - } else if *name == *xsd::DATE { - self.build_cast(parameters, PlanExpression::DateCast, variables, "date")? - } else if *name == *xsd::TIME { - self.build_cast(parameters, PlanExpression::TimeCast, variables, "time")? - } else if *name == *xsd::DATE_TIME { - self.build_cast( - parameters, - PlanExpression::DateTimeCast, - variables, - "dateTime", - )? - } else if *name == *xsd::STRING { - self.build_cast(parameters, PlanExpression::StringCast, variables, "string")? - } else { - Err(format_err!("Not supported custom function {}", expression))? + }), + Function::Year => PlanExpression::Year(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Month => PlanExpression::Month(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Day => PlanExpression::Day(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Hours => PlanExpression::Hours(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Minutes => PlanExpression::Minutes(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Seconds => PlanExpression::Seconds(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::UUID => PlanExpression::UUID(), + Function::StrUUID => PlanExpression::StrUUID(), + Function::Coalesce => { + PlanExpression::Coalesce(self.expression_list(¶meters, variables)?) } - } - _ => unimplemented!(), + Function::If => PlanExpression::If( + Box::new(self.build_for_expression(¶meters[0], variables)?), + Box::new(self.build_for_expression(¶meters[1], variables)?), + Box::new(self.build_for_expression(¶meters[2], variables)?), + ), + Function::StrLang => PlanExpression::StrLang( + Box::new(self.build_for_expression(¶meters[0], variables)?), + Box::new(self.build_for_expression(¶meters[1], variables)?), + ), + Function::SameTerm => PlanExpression::SameTerm( + Box::new(self.build_for_expression(¶meters[0], variables)?), + Box::new(self.build_for_expression(¶meters[1], variables)?), + ), + Function::IsIRI => PlanExpression::IsIRI(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::IsBlank => PlanExpression::IsBlank(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::IsLiteral => PlanExpression::IsLiteral(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::IsNumeric => PlanExpression::IsNumeric(Box::new( + self.build_for_expression(¶meters[0], variables)?, + )), + Function::Regex => PlanExpression::Regex( + Box::new(self.build_for_expression(¶meters[0], variables)?), + Box::new(self.build_for_expression(¶meters[1], variables)?), + match parameters.get(2) { + Some(flags) => Some(Box::new(self.build_for_expression(flags, variables)?)), + None => None, + }, + ), + Function::Custom(name) => { + if *name == *xsd::BOOLEAN { + self.build_cast( + parameters, + PlanExpression::BooleanCast, + variables, + "boolean", + )? + } else if *name == *xsd::DOUBLE { + self.build_cast( + parameters, + PlanExpression::DoubleCast, + variables, + "double", + )? + } else if *name == *xsd::FLOAT { + self.build_cast(parameters, PlanExpression::FloatCast, variables, "float")? + } else if *name == *xsd::DECIMAL { + self.build_cast( + parameters, + PlanExpression::DecimalCast, + variables, + "decimal", + )? + } else if *name == *xsd::INTEGER { + self.build_cast( + parameters, + PlanExpression::IntegerCast, + variables, + "integer", + )? + } else if *name == *xsd::DATE { + self.build_cast(parameters, PlanExpression::DateCast, variables, "date")? + } else if *name == *xsd::TIME { + self.build_cast(parameters, PlanExpression::TimeCast, variables, "time")? + } else if *name == *xsd::DATE_TIME { + self.build_cast( + parameters, + PlanExpression::DateTimeCast, + variables, + "dateTime", + )? + } else if *name == *xsd::STRING { + self.build_cast( + parameters, + PlanExpression::StringCast, + variables, + "string", + )? + } else { + Err(format_err!("Not supported custom function {}", expression))? + } + } + _ => unimplemented!(), + }, + Expression::Bound(v) => PlanExpression::Bound(variable_key(variables, v)), + Expression::Exists(_) => unimplemented!(), }) } diff --git a/lib/src/sparql/sparql_grammar.rustpeg b/lib/src/sparql/sparql_grammar.rustpeg index 27445f68..03e2808b 100644 --- a/lib/src/sparql/sparql_grammar.rustpeg +++ b/lib/src/sparql/sparql_grammar.rustpeg @@ -354,7 +354,7 @@ Constraint -> Expression = BrackettedExpression / BuiltInCall / FunctionCall //[70] FunctionCall -> Expression = f: iri _ a: ArgList { - Expression::CustomFunctionCall(f, a) + Expression::FunctionCall(Function::Custom(f), a) } //[71] @@ -754,81 +754,81 @@ BrackettedExpression -> Expression = '(' _ e:Expression _ ')' { e } //[121] BuiltInCall -> Expression = a:Aggregate { state.new_aggregation(a).into() } / - "STR"i _ '(' _ e:Expression _ ')' { Expression::StrFunctionCall(Box::new(e)) } / - "LANG"i _ '(' _ e:Expression _ ')' { Expression::LangFunctionCall(Box::new(e)) } / - "LANGMATCHES"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::LangMatchesFunctionCall(Box::new(a), Box::new(b)) } / - "DATATYPE"i _ '(' _ e:Expression _ ')' { Expression::DatatypeFunctionCall(Box::new(e)) } / - "BOUND"i _ '(' _ v:Var _ ')' { Expression::BoundFunctionCall(v) } / - ("IRI"i / "URI"i) _ '(' _ e:Expression _ ')' { Expression::IRIFunctionCall(Box::new(e)) } / - "BNODE"i '(' _ e:Expression _ ')' { Expression::BNodeFunctionCall(Some(Box::new(e))) } / - "BNODE"i NIL { Expression::BNodeFunctionCall(None) } / - "RAND"i _ NIL { Expression::RandFunctionCall() } / - "ABS"i _ '(' _ e:Expression _ ')' { Expression::AbsFunctionCall(Box::new(e)) } / - "CEIL"i _ '(' _ e:Expression _ ')' { Expression::CeilFunctionCall(Box::new(e)) } / - "FLOOR"i _ '(' _ e:Expression _ ')' { Expression::FloorFunctionCall(Box::new(e)) } / - "ROUND"i _ '(' _ e:Expression _ ')' { Expression::RoundFunctionCall(Box::new(e)) } / - "CONCAT"i e:ExpressionList { Expression::ConcatFunctionCall(e) } / + "STR"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Str, vec![e]) } / + "LANG"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Lang, vec![e]) } / + "LANGMATCHES"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::LangMatches, vec![a, b]) } / + "DATATYPE"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Datatype, vec![e]) } / + "BOUND"i _ '(' _ v:Var _ ')' { Expression::Bound(v) } / + ("IRI"i / "URI"i) _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::IRI, vec![e]) } / + "BNODE"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::BNode, vec![e]) } / + "BNODE"i NIL { Expression::FunctionCall(Function::BNode, vec![]) } / + "RAND"i _ NIL { Expression::FunctionCall(Function::Rand, vec![]) } / + "ABS"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Abs, vec![e]) } / + "CEIL"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Ceil, vec![e]) } / + "FLOOR"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Floor, vec![e]) } / + "ROUND"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Round, vec![e]) } / + "CONCAT"i e:ExpressionList { Expression::FunctionCall(Function::Concat, e) } / SubstringExpression / - "STRLEN"i _ '(' _ e: Expression _ ')' { Expression::StrLenFunctionCall(Box::new(e)) } / + "STRLEN"i _ '(' _ e: Expression _ ')' { Expression::FunctionCall(Function::StrLen, vec![e]) } / StrReplaceExpression / - "UCASE"i _ '(' _ e:Expression _ ')' { Expression::UCaseFunctionCall(Box::new(e)) } / - "LCASE"i _ '(' _ e:Expression _ ')' { Expression::LCaseFunctionCall(Box::new(e)) } / - 'ENCODE_FOR_URI' '(' _ e: Expression _ ')' { Expression::EncodeForURIFunctionCall(Box::new(e)) } / - "CONTAINS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::ContainsFunctionCall(Box::new(a), Box::new(b)) } / - "STRSTARTS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrStartsFunctionCall(Box::new(a), Box::new(b)) } / - "STRENDS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrEndsFunctionCall(Box::new(a), Box::new(b)) } / - "STRBEFORE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrBeforeFunctionCall(Box::new(a), Box::new(b)) } / - "STRAFTER"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrAfterFunctionCall(Box::new(a), Box::new(b)) } / - "YEAR"i _ '(' _ e:Expression _ ')' { Expression::YearFunctionCall(Box::new(e)) } / - "MONTH"i _ '(' _ e:Expression _ ')' { Expression::MonthFunctionCall(Box::new(e)) } / - "DAY"i _ '(' _ e:Expression _ ')' { Expression::DayFunctionCall(Box::new(e)) } / - "HOURS"i _ '(' _ e:Expression _ ')' { Expression::HoursFunctionCall(Box::new(e)) } / - "MINUTES"i _ '(' _ e:Expression _ ')' { Expression::MinutesFunctionCall(Box::new(e)) } / - "SECONDS"i _ '(' _ e:Expression _ ')' { Expression::SecondsFunctionCall(Box::new(e)) } / - "TIMEZONE"i _ '(' _ e:Expression _ ')' { Expression::TimezoneFunctionCall(Box::new(e)) } / - "TZ"i _ '(' _ e:Expression _ ')' { Expression::TzFunctionCall(Box::new(e)) } / - "NOW"i _ NIL { Expression::NowFunctionCall() } / - "UUID"i _ NIL { Expression::UUIDFunctionCall() }/ - "STRUUID"i _ NIL { Expression::StrUUIDFunctionCall() } / - "MD5"i '(' _ e:Expression _ ')' { Expression::MD5FunctionCall(Box::new(e)) } / - "SHA1"i '(' _ e:Expression _ ')' { Expression::SHA1FunctionCall(Box::new(e)) } / - "SHA256"i '(' _ e:Expression _ ')' { Expression::SHA256FunctionCall(Box::new(e)) } / - "SHA384"i '(' _ e:Expression _ ')' { Expression::SHA384FunctionCall(Box::new(e)) } / - "SHA512"i '(' _ e:Expression _ ')' { Expression::SHA512FunctionCall(Box::new(e)) } / - "COALESCE"i e:ExpressionList { Expression::CoalesceFunctionCall(e) } / - "IF"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::IfFunctionCall(Box::new(a), Box::new(b), Box::new(c)) } / - "STRLANG"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrLangFunctionCall(Box::new(a), Box::new(b)) } / - "STRDT"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::StrDTFunctionCall(Box::new(a), Box::new(b)) } / - "sameTerm"i '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::SameTermFunctionCall(Box::new(a), Box::new(b)) } / - ("isIRI"i / "isURI"i) _ '(' _ e:Expression _ ')' { Expression::IsIRIFunctionCall(Box::new(e)) } / - "isBLANK"i '(' _ e:Expression _ ')' { Expression::IsBlankFunctionCall(Box::new(e)) } / - "isLITERAL"i '(' _ e:Expression _ ')' { Expression::IsLiteralFunctionCall(Box::new(e)) } / - "isNUMERIC"i '(' _ e:Expression _ ')' { Expression::IsNumericFunctionCall(Box::new(e)) } / + "UCASE"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::UCase, vec![e]) } / + "LCASE"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::LCase, vec![e]) } / + 'ENCODE_FOR_URI' '(' _ e: Expression _ ')' { Expression::FunctionCall(Function::EncodeForURI, vec![e]) } / + "CONTAINS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::Contains, vec![a, b]) } / + "STRSTARTS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::StrStarts, vec![a, b]) } / + "STRENDS"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::StrEnds, vec![a, b]) } / + "STRBEFORE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::StrBefore, vec![a, b]) } / + "STRAFTER"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::StrAfter, vec![a, b]) } / + "YEAR"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Year, vec![e]) } / + "MONTH"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Month, vec![e]) } / + "DAY"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Day, vec![e]) } / + "HOURS"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Hours, vec![e]) } / + "MINUTES"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Minutes, vec![e]) } / + "SECONDS"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Seconds, vec![e]) } / + "TIMEZONE"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Timezone, vec![e]) } / + "TZ"i _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::Tz, vec![e]) } / + "NOW"i _ NIL { Expression::FunctionCall(Function::Now, vec![]) } / + "UUID"i _ NIL { Expression::FunctionCall(Function::UUID, vec![]) }/ + "STRUUID"i _ NIL { Expression::FunctionCall(Function::StrUUID, vec![]) } / + "MD5"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::MD5, vec![e]) } / + "SHA1"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::SHA1, vec![e]) } / + "SHA256"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::SHA256, vec![e]) } / + "SHA384"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::SHA384, vec![e]) } / + "SHA512"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::SHA512, vec![e]) } / + "COALESCE"i e:ExpressionList { Expression::FunctionCall(Function::Coalesce, e) } / + "IF"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::FunctionCall(Function::If, vec![a, b, c]) } / + "STRLANG"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::StrLang, vec![a, b]) } / + "STRDT"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::StrDT, vec![a, b]) } / + "sameTerm"i '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::SameTerm, vec![a, b]) } / + ("isIRI"i / "isURI"i) _ '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::IsIRI, vec![e]) } / + "isBLANK"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::IsBlank, vec![e]) } / + "isLITERAL"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::IsLiteral, vec![e]) } / + "isNUMERIC"i '(' _ e:Expression _ ')' { Expression::FunctionCall(Function::IsNumeric, vec![e]) } / RegexExpression / ExistsFunc / NotExistsFunc //[122] RegexExpression -> Expression = - "REGEX"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::RegexFunctionCall(Box::new(a), Box::new(b), Some(Box::new(c))) } / - "REGEX"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::RegexFunctionCall(Box::new(a), Box::new(b), None) } + "REGEX"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::FunctionCall(Function::Regex, vec![a, b, c]) } / + "REGEX"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::Regex, vec![a, b]) } SubstringExpression -> Expression = - "SUBSTR"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::SubStrFunctionCall(Box::new(a), Box::new(b), Some(Box::new(c))) } / - "SUBSTR"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::SubStrFunctionCall(Box::new(a), Box::new(b), None) } + "SUBSTR"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::FunctionCall(Function::SubStr, vec![a, b, c]) } / + "SUBSTR"i _ '(' _ a:Expression _ ',' _ b:Expression _ ')' { Expression::FunctionCall(Function::SubStr, vec![a, b]) } //[124] StrReplaceExpression -> Expression = - "REPLACE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ',' _ d:Expression _ ')' { Expression::ReplaceFunctionCall(Box::new(a), Box::new(b), Box::new(c), Some(Box::new(d))) } / - "REPLACE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::ReplaceFunctionCall(Box::new(a), Box::new(b), Box::new(c), None) } + "REPLACE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ',' _ d:Expression _ ')' { Expression::FunctionCall(Function::Replace, vec![a, b, c, d]) } / + "REPLACE"i _ '(' _ a:Expression _ ',' _ b:Expression _ ',' _ c:Expression _ ')' { Expression::FunctionCall(Function::Replace, vec![a, b, c]) } //[125] -ExistsFunc -> Expression = "EXISTS"i _ p:GroupGraphPattern { Expression::ExistsFunctionCall(Box::new(p)) } +ExistsFunc -> Expression = "EXISTS"i _ p:GroupGraphPattern { Expression::Exists(Box::new(p)) } //[126] -NotExistsFunc -> Expression = "NOT"i _ "EXISTS"i _ p:GroupGraphPattern { Expression::UnaryNot(Box::new(Expression::ExistsFunctionCall(Box::new(p)))) } +NotExistsFunc -> Expression = "NOT"i _ "EXISTS"i _ p:GroupGraphPattern { Expression::UnaryNot(Box::new(Expression::Exists(Box::new(p)))) } //[127] Aggregate -> Aggregation = @@ -854,7 +854,7 @@ Aggregate -> Aggregation = //[128] iriOrFunction -> Expression = i: iri _ a: ArgList? { match a { - Some(a) => Expression::CustomFunctionCall(i, a), + Some(a) => Expression::FunctionCall(Function::Custom(i), a), None => Expression::Constant(i.into()) } }