-
Notifications
You must be signed in to change notification settings - Fork 14
/
minus.rb
129 lines (123 loc) · 4.47 KB
/
minus.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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
module SPARQL; module Algebra
class Operator
##
# The SPARQL GraphPattern `minus` operator.
#
# [66] MinusGraphPattern ::= 'MINUS' GroupGraphPattern
#
# @example SPARQL Grammar
# SELECT * { ?s ?p ?o MINUS { ?s ?q ?v } }
#
# @example SSE
# (minus
# (bgp
# (triple ?s ?p ?o))
# (bgp (triple ?s ?q ?v)))
#
# @example SPARQL Grammar (inline filter)
# PREFIX : <http://example/>
# SELECT (?s1 AS ?subset) (?s2 AS ?superset)
# WHERE {
# ?s2 a :Set .
# ?s1 a :Set .
# FILTER(?s1 != ?s2)
# MINUS {
# ?s1 a :Set .
# ?s2 a :Set .
# FILTER(?s1 != ?s2)
# }
# }
#
# @example SSE (inline filter)
# (prefix ((: <http://example/>))
# (project (?subset ?superset)
# (extend ((?subset ?s1) (?superset ?s2))
# (filter (!= ?s1 ?s2)
# (minus
# (bgp (triple ?s2 a :Set) (triple ?s1 a :Set))
# (filter (!= ?s1 ?s2)
# (bgp
# (triple ?s1 a :Set)
# (triple ?s2 a :Set))))))))
#
# @see https://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
class Minus < Operator::Binary
include Query
NAME = :minus
##
# Executes each operand with `queryable` and performs the `join` operation
# by creating a new solution set containing the `merge` of all solutions
# from each set that are `compatible` with each other.
#
# @param [RDF::Queryable] queryable
# the graph or repository to query
# @param [Hash{Symbol => Object}] options
# any additional keyword options
# @yield [solution]
# each matching solution
# @yieldparam [RDF::Query::Solution] solution
# @yieldreturn [void] ignored
# @return [RDF::Query::Solutions]
# the resulting solution sequence
# @see https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#defn_algMinus
# @see https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#negation
def execute(queryable, **options, &block)
# Let Ω1 and Ω2 be multisets of solution mappings. We define:
#
# Minus(Ω1, Ω2) = { μ | μ in Ω1 . ∀ μ' in Ω2, either μ and μ' are not compatible or dom(μ) and dom(μ') are disjoint }
#
# card[Minus(Ω1, Ω2)](μ) = card[Ω1](μ)
debug(options) {"Minus"}
left = queryable.query(operand(0), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"(minus left) #{left.inspect}"}
right = queryable.query(operand(1), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"(minus right) #{right.inspect}"}
@solutions = left.minus(right)
@solutions.each(&block) if block_given?
@solutions
end
##
# Optimizes this query.
#
# Groups of one graph pattern (not a filter) become join(Z, A) and can be replaced by A.
# The empty graph pattern Z is the identity for join:
# Replace join(Z, A) by A
# Replace join(A, Z) by A
#
# @return [self]
# @see SPARQL::Algebra::Expression#optimize!
def optimize!(**options)
ops = operands.map {|o| o.optimize(**options) }.select {|o| o.respond_to?(:empty?) && !o.empty?}
@operands = ops
self
end
##
#
# Returns a partial SPARQL grammar for this operator.
#
# @param [Hash{String => Operator}] extensions
# Variable bindings
# @param [Array<Operator>] filter_ops ([])
# Filter Operations
# @param [Boolean] top_level (true)
# Treat this as a top-level, generating SELECT ... WHERE {}
# @return [String]
def to_sparql(top_level: true, filter_ops: [], extensions: {}, **options)
lhs, *rhs = operands
str = "{\n" + lhs.to_sparql(top_level: false, extensions: {}, **options)
# Any accrued filters go here.
filter_ops.each do |op|
str << "\nFILTER (#{op.to_sparql(**options)}) ."
end
rhs.each do |minus|
str << "\nMINUS {\n"
str << minus.to_sparql(top_level: false, extensions: {}, **options)
str << "\n}"
end
str << "}"
top_level ? Operator.to_sparql(str, extensions: extensions, **options) : str
end
end # Minus
end # Operator
end; end # SPARQL::Algebra