Class: SPARQL::Algebra::Operator::PathRange

Inherits:
Ternary show all
Includes:
Query
Defined in:
lib/sparql/algebra/operator/path_range.rb

Overview

The SPARQL Property Path pathRange (NonCountingPath) operator.

Property path ranges allow specific path lenghts to be queried. The minimum range describes the minimum path length that will yield solutions, and the maximum range the maximum path that will be returned. A minumum of zero is similar to the path? operator. The maximum range of * is similar to the path* or path+ operators.

For example, the two queries are functionally equivalent:

SELECT * WHERE {:a :p{1,2} :b}

SELECT * WHERE {:a (:p/:p?) :b}

[91] PathElt ::= PathPrimary PathMod? [93] PathMod ::= ‘*’ | ‘?’ | ‘+’ | ‘INTEGER? (‘,’ INTEGER?)? ‘’

Examples:

SPARQL Grammar range with fixed length

PREFIX : <http://example/> 
SELECT * WHERE {
  :a :p{2} ?z
} 

SSE range with fixed length only

(prefix ((: <http://example/>))
 (path :a (pathRange 2 2 :p) ?z))

SPARQL Grammar range with min only

PREFIX : <http://example/> 
SELECT * WHERE {
  :a :p{1,} ?z
} 

SSE range with min only

(prefix ((: <http://example/>))
 (path :a (pathRange 1 * :p) ?z))

SPARQL Grammar range with max only

PREFIX : <http://example/> 
SELECT * WHERE {
  :a :p{,2} ?z
} 

SSE range with max only

(prefix ((: <http://example/>))
 (path :a (pathRange 0 2 :p) ?z))

SPARQL Grammar range with min and max

PREFIX : <http://example/> 
SELECT * WHERE {
  :a :p{1,2} ?z
} 

SSE range with min and max

(prefix ((: <http://example/>))
 (path :a (pathRange 1 2 :p) ?z))

Constant Summary collapse

NAME =
:"pathRange"

Constants inherited from Ternary

Ternary::ARITY

Constants inherited from SPARQL::Algebra::Operator

ARITY, IsURI, URI

Constants included from Expression

Expression::PATTERN_PARENTS

Instance Attribute Summary

Attributes included from Query

#solutions

Attributes inherited from SPARQL::Algebra::Operator

#operands

Instance Method Summary collapse

Methods included from Query

#each_solution, #empty?, #failed?, #graph_name=, #matched?, #query_yields_boolean?, #query_yields_solutions?, #query_yields_statements?, #unshift, #variables

Methods inherited from SPARQL::Algebra::Operator

#aggregate?, arity, #base_uri, base_uri, base_uri=, #bind, #boolean, #constant?, #deep_dup, #each_descendant, #eql?, #evaluatable?, evaluate, #executable?, #first_ancestor, for, #inspect, #ndvars, #node?, #operand, #optimize, #optimize!, #parent, #parent=, #prefixes, prefixes, prefixes=, #rewrite, #to_binary, to_sparql, #to_sxp, #to_sxp_bin, #validate!, #variable?, #variables, #vars

Methods included from Expression

cast, #constant?, #evaluate, extension, extension?, extensions, for, #invalid?, new, #node?, open, #optimize, #optimize!, parse, register_extension, #to_sxp_bin, #valid?, #validate!, #variable?

Constructor Details

#initialize(min, max, path, **options) ⇒ PathRange

Initializes a new operator instance.

Parameters:

  • max (RDF::Literal::Integer)

    the range minimum

  • min (RDF::Literal::Integer, Symbol)

    the range maximum (may be *)

  • path (SPARQL::Operator)

    the query

  • options (Hash{Symbol => Object})

    any additional options (see SPARQL::Algebra::Operator#initialize)

Raises:

  • (TypeError)

    if any operand is invalid

  • (ArgumentError)

    range element is invalid



75
76
77
78
79
# File 'lib/sparql/algebra/operator/path_range.rb', line 75

def initialize(min, max, path, **options)
  raise ArgumentError, "expect min <= max {#{min},#{max}}" if
    max.is_a?(RDF::Literal::Integer) && max < min
  super
end

Instance Method Details

#execute(queryable, accumulator: RDF::Query::Solutions.new, index: RDF::Literal(0), **options) {|solution| ... } ⇒ Object

Path with lower and upper bounds on lenghts:

(path :a (pathRange 1 2 :p) :b) => (path)

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to query

  • accumulator (RDF::Query::Solutions) (defaults to: RDF::Query::Solutions.new)

    (RDF::Query::Solutions.new) For previous solutions to avoid duplicates.

  • options (Hash{Symbol => Object})

    any additional keyword options

Options Hash (**options):

Yields:

  • (solution)

    each matching solution

Yield Parameters:

Yield Returns:

  • (void)

    ignored

See Also:



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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/sparql/algebra/operator/path_range.rb', line 100

def execute(queryable,
            accumulator: RDF::Query::Solutions.new,
            index: RDF::Literal(0),
            **options,
            &block)

  min, max, op = *operands
  subject, object = options[:subject], options[:object]
  debug(options) {"Path{#{min},#{max}} #{[subject, op, object].to_sse}"}

  path_mm = if min.zero? && max.is_a?(RDF::Literal::Integer) && max.zero?
    PathZero.new(op, **options)
  else
    # Build up a sequence
    path_opt = nil
    seq_len = min.to_i
    if max.is_a?(RDF::Literal::Integer)
      # min to max is a sequence of optional sequences
      opt_len = (max - min).to_i
      while opt_len > 0 do
        path_opt = PathOpt.new(path_opt ? Seq.new(op, path_opt, **options) : op, **options)
        opt_len -= 1
      end
    elsif seq_len > 0
      path_opt = PathPlus.new(op, **options)
      seq_len -= 1
    else
      path_opt = PathStar.new(op, **options)
    end

    # sequence ending in op, op+, op*, or path_opt
    path_seq = nil
    while seq_len > 0 do
      path_seq = if path_opt
        opt, path_opt = path_opt, nil
        Seq.new(op, opt, **options)
      elsif path_seq
        Seq.new(op, path_seq, **options)
      else
        op
      end
      seq_len -= 1
    end
    path_seq || path_opt || op
  end
  debug(options) {"=> #{path_mm.to_sse}"}

  # After this, path_mm may just be the original op, which can be a term, not an operator.
  if path_mm.is_a?(RDF::Term)
    path_mm = RDF::Query.new do |q|
      q.pattern [subject, path_mm, object]
    end
  end

  solutions = path_mm.execute(queryable, **options.merge(depth: options[:depth].to_i + 1)).uniq
  debug(options) {"(path{#{min},#{max}})=> #{solutions.to_sxp}"}
  solutions.each(&block) if block_given?
  solutions
end

#to_sparql(**options) ⇒ String

Returns a partial SPARQL grammar for this operator.

Returns:

  • (String)


165
166
167
168
169
170
171
172
173
174
175
# File 'lib/sparql/algebra/operator/path_range.rb', line 165

def to_sparql(**options)
  min, max, path = operands
  "(#{path.to_sparql(**options)})" +
  if max == :*
    "{#{min},}"
  elsif min == max
    "{#{min}}"
  else
    "{#{min},#{max}}"
  end
end