Class: SHACL::Algebra::SPARQLConstraintComponent
- Inherits:
-
ConstraintComponent
- Object
- SPARQL::Algebra::Operator
- Operator
- ConstraintComponent
- SHACL::Algebra::SPARQLConstraintComponent
- Defined in:
- lib/shacl/algebra/sparql_constraint.rb
Constant Summary collapse
- NAME =
:sparql
- UNSUPPORTED_SPARQL_OPERATORS =
SPARQL Operators prohibited from being used in expression.
[ SPARQL::Algebra::Operator::Minus, SPARQL::Algebra::Operator::Service, SPARQL::Algebra::Operator::Table, ]
- PRE_BOUND =
Potentially pre-bound variables.
%i(currentShape shapesGraph PATH this value)
- BUILTIN_KEYS =
All keys associated with shapes which are set in options
%i( type label name comment description deactivated severity message path ask select declare namespace prefix prefixes select ask ).freeze
Constants inherited from Operator
Instance Attribute Summary
Attributes inherited from Operator
#graph, #options, #shapes_graph
Class Method Summary collapse
-
.from_json(operator, **options) ⇒ Operator
Creates an operator instance from a parsed SHACL representation.
Instance Method Summary collapse
-
#conforms(node, path: nil, depth: 0, **options) ⇒ Array<SHACL::ValidationResult>
Validates the specified
property
withingraph
, a list of ValidationResult.
Methods inherited from ConstraintComponent
Methods inherited from Operator
add_component, apply_op, #comment, component_params, #deactivated?, from_expanded_value, #id, iri, #iri, #label, #not_satisfied, params, parse_path, #satisfy, to_rdf, #to_sxp_bin, #type
Class Method Details
.from_json(operator, **options) ⇒ Operator
Creates an operator instance from a parsed SHACL representation.
Special case for SPARQLComponenet due to general recursion.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/shacl/algebra/sparql_constraint.rb', line 92 def from_json(operator, **) prefixes, query = [], "" operands = [] node_opts = .dup operator.each do |k, v| next if v.nil? case k # List properties when 'path' then node_opts[:path] = parse_path(v, **) when 'prefixes' prefixes = extract_prefixes(v) when 'severity' then node_opts[:severity] = iri(v, **) when 'type' then node_opts[:type] = as_array(v).map {|vv| iri(vv, **)} if v else node_opts[k.to_sym] = to_rdf(k.to_sym, v, **) if BUILTIN_KEYS.include?(k.to_sym) end end query_string = prefixes.join("\n") + node_opts[:select] || node_opts[:ask] query = SPARQL.parse(query_string) [:logger].info("#{NAME} SXP: #{query.to_sxp}") if [:logger] # Queries have restrictions operators = query.descendants.to_a.unshift(query) if node_opts[:ask] && !operators.any? {|op| op.is_a?(SPARQL::Algebra::Operator::Ask)} raise SHACL::Error, "Ask query must have ask operator" elsif node_opts[:select] && !operators.any? {|op| op.is_a?(SPARQL::Algebra::Operator::Project)} raise SHACL::Error, "Select query must have project operator" end uh_oh = (operators.map(&:class) & UNSUPPORTED_SPARQL_OPERATORS).map {|c| c.const_get(:NAME)} unless uh_oh.empty? raise SHACL::Error, "Query must not include operators #{uh_oh.to_sxp}: #{query_string}" end # Additionally, queries must not bind to special variables operators.select {|op| op.is_a?(SPARQL::Algebra::Operator::Extend)}.each do |extend| if extend.operands.first.any? {|v, e| PRE_BOUND.include?(v.to_sym)} raise SHACL::Error, "Query must not bind pre-bound variables: #{query_string}" end end operands << query new(*operands, **node_opts) end |
Instance Method Details
#conforms(node, path: nil, depth: 0, **options) ⇒ Array<SHACL::ValidationResult>
Validates the specified property
within graph
, a list of ValidationResult.
A property conforms the nodes found by evaluating it’s path
all conform.
Last operand is the parsed query. Bound variables are added as a table entry joined to the query.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/shacl/algebra/sparql_constraint.rb', line 31 def conforms(node, path: nil, depth: 0, **) return [] if deactivated? = {severity: RDF::Vocab::SHACL.Violation}.merge() log_debug(NAME, depth: depth) {SXP::Generator.string({node: node}.to_sxp_bin)} # Aggregate repo containing both data-graph (as the default) and shapes-graph, named by it's IRI aggregate = RDF::AggregateRepo.new(graph.data, shapes_graph.data) do |ag| ag.default false ag.named shapes_graph.graph_name if shapes_graph.graph_name end aggregate.default_graph bindings = RDF::Query::Solution.new({ currentShape: [:shape], shapesGraph: shapes_graph.graph_name, PATH: path, this: node, }.compact) solutions = operands.last.execute(aggregate, bindings: bindings, depth: depth + 1, logger: (@logger || @options[:logger]), **) if solutions.empty? satisfy(focus: node, path: path, message: @options.fetch(:message, "node conforms to SPARQL component"), component: RDF::Vocab::SHACL.SPARQLConstraintComponent, depth: depth, **) else solutions.map do |solution| not_satisfied(focus: node, path: (path || solution[:path]), value: (solution[:value] || node), message: @options.fetch(:message, "node does not coform to SPARQL component"), resultSeverity: .fetch(:severity), component: RDF::Vocab::SHACL.SPARQLConstraintComponent, depth: depth, **) end end end |