Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions nemo/src/io/format_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::{
},
error::{ValidationReport, hint::Hint, info::Info, validation_error::ValidationError},
substitution::Substitution,
translation::directive::FormatContext,
},
syntax::import_export::attribute,
};
Expand All @@ -47,7 +48,11 @@ pub(crate) trait FormatParameter<Tag>:
FromStr<Err = ()> + Debug + ToString + IntoEnumIterator + Copy + Eq + Hash
{
fn required_for(&self, tag: Tag) -> bool;
fn is_value_valid(&self, value: AnyDataValue) -> Result<(), ValidationError>;
fn is_value_valid(
&self,
value: AnyDataValue,
format_context: FormatContext,
) -> Result<(), ValidationError>;
}

pub(super) fn value_type_matches(
Expand Down Expand Up @@ -234,7 +239,11 @@ impl<Tag> FormatParameter<Tag> for StandardParameter {
false
}

fn is_value_valid(&self, value: AnyDataValue) -> Result<(), ValidationError> {
fn is_value_valid(
&self,
value: AnyDataValue,
_format_context: FormatContext,
) -> Result<(), ValidationError> {
value_type_matches(self, &value, self.supported_types())?;

match self {
Expand Down Expand Up @@ -269,6 +278,7 @@ pub(crate) trait FormatBuilder: Debug + Sized + Into<AnyImportExportBuilder> {
tag: Self::Tag,
parameters: &Parameters<Self>,
direction: Direction,
format_context: FormatContext,
) -> Result<Self, ValidationError>;

fn expected_arity(&self) -> Option<usize>;
Expand Down Expand Up @@ -357,6 +367,7 @@ impl<B: FormatBuilder> Parameters<B> {
_filter_rules: &[Rule],
direction: Direction,
report: &mut ValidationReport,
formate_context: FormatContext,
) -> Option<Self> {
let Ok(format_tag) = B::Tag::from_str(spec.format().name()) else {
report.add(
Expand Down Expand Up @@ -420,7 +431,7 @@ impl<B: FormatBuilder> Parameters<B> {
}
};

if let Err(error) = parameter.is_value_valid(value.clone()) {
if let Err(error) = parameter.is_value_valid(value.clone(), formate_context.clone()) {
report.add(value_term, error);
has_errors = true;
continue;
Expand Down Expand Up @@ -505,6 +516,7 @@ impl ImportExportBuilder {
self.resource.clone()
}

#[allow(clippy::too_many_arguments)]
fn new_with_tag<B: FormatBuilder>(
predicate: Tag,
tag: B::Tag,
Expand All @@ -513,10 +525,18 @@ impl ImportExportBuilder {
filter_rules: &[Rule],
direction: Direction,
report: &mut ValidationReport,
format_context: FormatContext,
) -> Option<ImportExportBuilder> {
let origin = spec.origin();
let parameters =
Parameters::<B>::validate(predicate, spec, bindings, filter_rules, direction, report)?;
let parameters = Parameters::<B>::validate(
predicate,
spec,
bindings,
filter_rules,
direction,
report,
format_context.clone(),
)?;
Comment thread
mmarx marked this conversation as resolved.

let resource_builder =
if let Some(value) = parameters.get_optional(StandardParameter::Resource.into()) {
Expand All @@ -538,7 +558,7 @@ impl ImportExportBuilder {
})
.unwrap_or_else(|| CompressionFormat::from_resource_builder(&resource_builder));

let inner = match B::new(tag, &parameters, direction) {
let inner = match B::new(tag, &parameters, direction, format_context.clone()) {
Ok(b) => b,
Err(error) => {
report.add_source(origin.clone(), error);
Expand Down Expand Up @@ -629,6 +649,7 @@ impl ImportExportBuilder {
filter_rules: &[Rule],
direction: Direction,
report: &mut ValidationReport,
format_context: FormatContext,
) -> Option<Self> {
let format_tag = spec.format().name().to_owned();
let Ok(tag) = format_tag.parse::<SupportedFormatTag>() else {
Expand All @@ -651,6 +672,7 @@ impl ImportExportBuilder {
filter_rules,
direction,
report,
format_context,
),
SupportedFormatTag::Rdf(tag) => Self::new_with_tag::<RdfHandler>(
predicate,
Expand All @@ -660,6 +682,7 @@ impl ImportExportBuilder {
filter_rules,
direction,
report,
format_context,
),
SupportedFormatTag::Json(tag) => Self::new_with_tag::<JsonHandler>(
predicate,
Expand All @@ -669,6 +692,7 @@ impl ImportExportBuilder {
filter_rules,
direction,
report,
format_context,
),
SupportedFormatTag::Sparql(tag) => Self::new_with_tag::<SparqlBuilder>(
predicate,
Expand All @@ -678,6 +702,7 @@ impl ImportExportBuilder {
filter_rules,
direction,
report,
format_context,
),
}
}
Expand Down
12 changes: 9 additions & 3 deletions nemo/src/io/formats/dsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
rule_model::{
components::{import_export::Direction, term::value_type::ValueType},
error::validation_error::ValidationError,
translation::directive::FormatContext,
},
syntax::import_export::{attribute, file_format},
};
Expand Down Expand Up @@ -178,12 +179,16 @@ impl FormatParameter<DsvTag> for DsvParameter {
}
}

fn is_value_valid(&self, value: AnyDataValue) -> Result<(), ValidationError> {
fn is_value_valid(
&self,
value: AnyDataValue,
format_context: FormatContext,
) -> Result<(), ValidationError> {
value_type_matches(self, &value, self.supported_types())?;

match self {
DsvParameter::BaseParamType(base) => {
FormatParameter::<DsvTag>::is_value_valid(base, value)
DsvParameter::BaseParamType(base_param) => {
FormatParameter::<DsvTag>::is_value_valid(base_param, value, format_context)
}
DsvParameter::Limit => value
.to_u64()
Expand Down Expand Up @@ -238,6 +243,7 @@ impl FormatBuilder for DsvBuilder {
tag: Self::Tag,
parameters: &Parameters<DsvBuilder>,
_direction: Direction,
_format_context: FormatContext,
) -> Result<Self, ValidationError> {
let value_formats = parameters.get_optional(DsvParameter::Format).map(|value| {
DsvValueFormats::try_from(value).expect("value formats have already been validated")
Expand Down
6 changes: 5 additions & 1 deletion nemo/src/io/formats/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ use crate::{
AnyImportExportBuilder, FormatBuilder, Parameters, StandardParameter, SupportedFormatTag,
format_tag,
},
rule_model::{components::import_export::Direction, error::validation_error::ValidationError},
rule_model::{
components::import_export::Direction, error::validation_error::ValidationError,
translation::directive::FormatContext,
},
syntax::import_export::file_format,
};

Expand Down Expand Up @@ -71,6 +74,7 @@ impl FormatBuilder for JsonHandler {
_tag: Self::Tag,
_parameters: &Parameters<Self>,
direction: Direction,
_format_context: FormatContext,
) -> Result<Self, ValidationError> {
if matches!(direction, Direction::Export) {
return Err(ValidationError::UnsupportedJsonExport);
Expand Down
12 changes: 9 additions & 3 deletions nemo/src/io/formats/rdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::{
rule_model::{
components::{import_export::Direction, term::value_type::ValueType},
error::validation_error::ValidationError,
translation::directive::FormatContext,
},
syntax::import_export::{attribute, file_format},
};
Expand Down Expand Up @@ -187,12 +188,16 @@ impl FormatParameter<RdfTag> for RdfParameter {
)
}

fn is_value_valid(&self, value: AnyDataValue) -> Result<(), ValidationError> {
fn is_value_valid(
&self,
value: AnyDataValue,
format_context: FormatContext,
) -> Result<(), ValidationError> {
value_type_matches(self, &value, self.supported_types())?;

match self {
RdfParameter::BaseParamType(base) => {
FormatParameter::<RdfTag>::is_value_valid(base, value)
RdfParameter::BaseParamType(base_param) => {
FormatParameter::<RdfTag>::is_value_valid(base_param, value, format_context)
}
RdfParameter::Limit => value
.to_u64()
Expand Down Expand Up @@ -222,6 +227,7 @@ impl FormatBuilder for RdfHandler {
tag: Self::Tag,
parameters: &Parameters<RdfHandler>,
_direction: Direction,
_format_context: FormatContext,
) -> Result<Self, ValidationError> {
let variant = match tag {
RdfTag::Rdf => {
Expand Down
79 changes: 62 additions & 17 deletions nemo/src/io/formats/sparql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
rule_model::{
components::{import_export::Direction, term::value_type::ValueType},
error::validation_error::ValidationError,
translation::directive::FormatContext,
},
syntax::import_export::{
attribute,
Expand Down Expand Up @@ -67,12 +68,16 @@ impl FormatParameter<SparqlTag> for SparqlParameter {
matches!(tag, SparqlTag::Sparql) && matches!(self, Self::Endpoint)
}

fn is_value_valid(&self, value: AnyDataValue) -> Result<(), ValidationError> {
fn is_value_valid(
&self,
value: AnyDataValue,
format_context: FormatContext,
) -> Result<(), ValidationError> {
value_type_matches(self, &value, self.supported_types())?;

match self {
SparqlParameter::BaseParamType(base) => {
FormatParameter::<SparqlTag>::is_value_valid(base, value)
SparqlParameter::BaseParamType(base_param) => {
FormatParameter::<SparqlTag>::is_value_valid(base_param, value, format_context)
}
SparqlParameter::Base => Ok(()),
SparqlParameter::Format => DsvValueFormats::try_from(value).and(Ok(())).map_err(|_| {
Expand All @@ -93,13 +98,33 @@ impl FormatParameter<SparqlTag> for SparqlParameter {
}
SparqlParameter::Query => {
let query = value.to_plain_string_unchecked();
SparqlParser::new() // TODO(mam): inject prefixes and base here, cf. #647
.parse_query(query.as_str())
.and(Ok(()))
.map_err(|e| ValidationError::InvalidSparqlQuery {

let mut parser = SparqlParser::new();

if let Some(base) = format_context.base() {
parser = parser.with_base_iri(base.to_string()).map_err(|e| {
ValidationError::InvalidSparqlQuery {
query: query.clone(),
oxi_error: e.to_string(),
}
})?
}

for (prefix_name, prefix_iri) in format_context.prefixes() {
parser = parser
.with_prefix(prefix_name, prefix_iri.to_string())
.map_err(|e| ValidationError::InvalidSparqlQuery {
query: query.clone(),
oxi_error: e.to_string(),
})?
}

parser.parse_query(query.as_str()).and(Ok(())).map_err(|e| {
ValidationError::InvalidSparqlQuery {
query,
oxi_error: e.to_string(),
})
}
})
}
}
}
Expand Down Expand Up @@ -144,6 +169,7 @@ impl FormatBuilder for SparqlBuilder {
_tag: Self::Tag,
parameters: &Parameters<SparqlBuilder>,
_direction: Direction,
format_context: FormatContext,
) -> Result<Self, ValidationError> {
let value_formats = parameters
.get_optional(SparqlParameter::Format)
Expand All @@ -164,7 +190,9 @@ impl FormatBuilder for SparqlBuilder {
.map(|value| value.to_plain_string_unchecked())
.unwrap_or(QUERY_DEFAULT.to_string());

let query = SparqlParser::new() // TODO(mam): inject prefixes and base here, cf. #647
let parser = format_context.into_sparql_parser();

let query = parser
.parse_query(query.as_str())
.expect("query has already been validated");

Expand Down Expand Up @@ -268,10 +296,14 @@ impl ImportHandler for SparqlHandler {

#[cfg(test)]
mod test {
use crate::parser::{
ParserState,
ast::{ProgramAST, directive::import::Import},
input::ParserInput,

use crate::{
parser::{
ParserState,
ast::{ProgramAST, directive::import::Import},
input::ParserInput,
},
rule_model::translation::directive::FormatContext,
};
use nom::combinator::all_consuming;

Expand All @@ -282,10 +314,19 @@ mod test {

#[test]
fn parse_query() {
let mut format_context = FormatContext::default();
format_context.add_base("http://www.wikidata.org/".to_string());
// PREFIX wikibase: <http://wikiba.se/ontology#>
format_context.add_prefix(
"wikibase".to_string(),
"http://wikiba.se/ontology#".to_string(),
);
// PREFIX wdt: <http://www.wikidata.org/prop/direct/>
format_context.add_prefix("wdt".to_string(), "prop/direct/".to_string());

let valid_query = AnyDataValue::new_plain_string(String::from("
PREFIX wikibase: <http://wikiba.se/ontology#>
PREFIX wikibase: <http://wikiba.se/ontology#>
Comment thread
mmarx marked this conversation as resolved.
PREFIX bd: <http://www.bigdata.com/rdf#>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX p: <http://www.wikidata.org/prop/>
Expand All @@ -300,9 +341,12 @@ mod test {
);

let query_param = SparqlParameter::Query;
let result = query_param.is_value_valid(valid_query);
let result = query_param.is_value_valid(valid_query, format_context);
assert!(result.is_ok());
}

#[test]
fn parse_invalid_query() {
// Invalid because no prefixes are specified
let invalid_query = AnyDataValue::new_plain_string(String::from("
SELECT ?item ?itemLabel
Expand All @@ -313,7 +357,8 @@ mod test {
}
LIMIT 10")
);
let result = query_param.is_value_valid(invalid_query);
let query_param = SparqlParameter::Query;
let result = query_param.is_value_valid(invalid_query, FormatContext::default());
assert!(result.is_err());
}

Expand Down
Loading