roadforest 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/examples/file-management.rb +7 -1
- data/lib/roadforest/application.rb +0 -2
- data/lib/roadforest/application/dispatcher.rb +20 -1
- data/lib/roadforest/model.rb +4 -4
- data/lib/roadforest/rdf/{context-fascade.rb → access-manager.rb} +96 -42
- data/lib/roadforest/rdf/focus-list.rb +1 -1
- data/lib/roadforest/rdf/graph-copier.rb +10 -5
- data/lib/roadforest/rdf/graph-focus.rb +222 -32
- data/lib/roadforest/rdf/graph-store.rb +1 -12
- data/lib/roadforest/rdf/investigation.rb +3 -1
- data/lib/roadforest/rdf/post-focus.rb +7 -15
- data/lib/roadforest/remote-host.rb +20 -8
- data/lib/roadforest/resource/rdf/read-only.rb +5 -2
- data/lib/roadforest/test-support/matchers.rb +40 -9
- data/lib/roadforest/utility/class-registry.rb +8 -1
- data/spec/focus-list.rb +7 -1
- data/spec/graph-copier.rb +27 -43
- data/spec/graph-store.rb +41 -15
- data/spec/update-focus.rb +10 -8
- metadata +63 -12
- data/lib/roadforest/rdf/graph-reading.rb +0 -200
- data/lib/roadforest/rdf/update-focus.rb +0 -18
- data/lib/roadforest/resource/handlers.rb +0 -43
data/examples/file-management.rb
CHANGED
@@ -56,7 +56,7 @@ module FileManagementExample
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def add_child(graph)
|
59
|
-
services.logger.debug(graph.source_graph.dump(:nquads))
|
59
|
+
services.logger.debug(graph.access_manager.source_graph.dump(:nquads))
|
60
60
|
new_file = FileRecord.new(graph.first(:lc, "name"), false)
|
61
61
|
services.file_records << new_file
|
62
62
|
end
|
@@ -65,6 +65,12 @@ module FileManagementExample
|
|
65
65
|
graph.add_list(:lc, "needs") do |list|
|
66
66
|
services.file_records.each do |record|
|
67
67
|
if !record.resolved
|
68
|
+
# need = copy_from(:need, '*' => record.name)
|
69
|
+
# list.add_node(need.url) do |node|
|
70
|
+
# need.target = node
|
71
|
+
# need[:lc, :name]
|
72
|
+
# need[:lc, :digest]
|
73
|
+
# end
|
68
74
|
list << path_for(:need, '*' => record.name)
|
69
75
|
end
|
70
76
|
end
|
@@ -3,7 +3,6 @@ module RoadForest
|
|
3
3
|
class Application < Webmachine::Application; end
|
4
4
|
end
|
5
5
|
|
6
|
-
require 'roadforest/resource/handlers'
|
7
6
|
require 'roadforest/application/dispatcher'
|
8
7
|
require 'roadforest/application/path-provider'
|
9
8
|
require 'roadforest/application/services-host'
|
@@ -14,7 +13,6 @@ require 'roadforest/rdf/normalization'
|
|
14
13
|
module RoadForest
|
15
14
|
class Application
|
16
15
|
include RDF::Normalization
|
17
|
-
include Resource::Handlers
|
18
16
|
|
19
17
|
def initialize(canonical_host, services = nil, configuration = nil, dispatcher = nil)
|
20
18
|
@canonical_host = normalize_resource(canonical_host)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'webmachine'
|
2
|
+
require 'roadforest/application/route-adapter'
|
2
3
|
|
3
4
|
module RoadForest
|
4
5
|
class Dispatcher < Webmachine::Dispatcher
|
5
|
-
include Resource::Handlers
|
6
6
|
def initialize(services)
|
7
7
|
super(method(:create_resource))
|
8
8
|
@services = services
|
@@ -11,6 +11,25 @@ module RoadForest
|
|
11
11
|
end
|
12
12
|
attr_accessor :services, :trace_by_default
|
13
13
|
|
14
|
+
def bundle(resource_class, &block)
|
15
|
+
Application::RouteAdapter.new(resource_class, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def bundle_typed_resource(resource_type, model_class, route_name)
|
19
|
+
resource_class = Resource.get(resource_type)
|
20
|
+
bundle(resource_class) do |resource, request, response|
|
21
|
+
resource.model = model_class.new(route_name, resource.params, services)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def bundle_traced_resource(resource_type, model_class, route_name)
|
26
|
+
resource_class = Resource.get(resource_type)
|
27
|
+
bundle(resource_class) do |resource, request, response|
|
28
|
+
resource.model = model_class.new(route_name, resource.params, services)
|
29
|
+
resource.trace = true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
14
33
|
def resource_route(resource, name, path_spec, bindings)
|
15
34
|
route = Route.new(path_spec, resource, bindings || {})
|
16
35
|
yield route if block_given?
|
data/lib/roadforest/model.rb
CHANGED
@@ -133,9 +133,9 @@ module RoadForest
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def start_focus(graph, resource_url=nil)
|
136
|
-
|
137
|
-
|
138
|
-
focus
|
136
|
+
access = RDF::WriteManager.new
|
137
|
+
access.source_graph = graph
|
138
|
+
focus = RDF::GraphFocus.new(access, resource_url || my_url)
|
139
139
|
|
140
140
|
yield focus if block_given?
|
141
141
|
return focus
|
@@ -158,7 +158,7 @@ module RoadForest
|
|
158
158
|
graph = ::RDF::Graph.new
|
159
159
|
focus = start_focus(graph, my_url)
|
160
160
|
fill_graph(focus)
|
161
|
-
self.response_data =
|
161
|
+
self.response_data = graph
|
162
162
|
end
|
163
163
|
end
|
164
164
|
end
|
@@ -2,19 +2,16 @@ require 'rdf'
|
|
2
2
|
require 'roadforest/rdf/resource-query'
|
3
3
|
require 'roadforest/rdf/resource-pattern'
|
4
4
|
require 'roadforest/rdf/normalization'
|
5
|
+
require 'roadforest/rdf/parcel'
|
5
6
|
|
6
7
|
module RoadForest::RDF
|
7
|
-
class
|
8
|
+
class ReadOnlyManager
|
8
9
|
include ::RDF::Countable
|
9
10
|
include ::RDF::Enumerable
|
10
11
|
include ::RDF::Queryable
|
11
12
|
include Normalization
|
12
13
|
|
13
|
-
attr_accessor :resource, :rigor, :source_graph
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
@copied_contexts = {}
|
17
|
-
end
|
14
|
+
attr_accessor :resource, :rigor, :source_graph
|
18
15
|
|
19
16
|
def resource=(resource)
|
20
17
|
@resource = normalize_context(resource)
|
@@ -24,33 +21,14 @@ module RoadForest::RDF
|
|
24
21
|
other = self.class.allocate
|
25
22
|
other.resource = self.resource
|
26
23
|
other.rigor = self.rigor
|
27
|
-
|
28
|
-
other.copied_contexts = self.copied_contexts
|
29
24
|
other.source_graph = self.source_graph
|
30
|
-
|
25
|
+
|
31
26
|
return other
|
32
27
|
end
|
33
28
|
|
34
|
-
|
35
|
-
|
36
|
-
begin
|
37
|
-
parceller = Parcel.new
|
38
|
-
parceller.graph = source_graph
|
39
|
-
parceller
|
40
|
-
end
|
41
|
-
end
|
29
|
+
alias origin_graph source_graph
|
30
|
+
alias destination_graph source_graph
|
42
31
|
|
43
|
-
def copy_context
|
44
|
-
return if copied_contexts[resource]
|
45
|
-
return if target_graph.nil? or source_graph == target_graph
|
46
|
-
parceller.graph_for(resource).each_statement do |statement|
|
47
|
-
statement.context = resource
|
48
|
-
target_graph << statement
|
49
|
-
end
|
50
|
-
copied_contexts[resource] = true
|
51
|
-
end
|
52
|
-
|
53
|
-
#superfluous?
|
54
32
|
def build_query
|
55
33
|
ResourceQuery.new([], {}) do |query|
|
56
34
|
query.subject_context = resource
|
@@ -59,6 +37,10 @@ module RoadForest::RDF
|
|
59
37
|
end
|
60
38
|
end
|
61
39
|
|
40
|
+
def relevant_prefixes
|
41
|
+
relevant_prefixes_for_graph(origin_graph)
|
42
|
+
end
|
43
|
+
|
62
44
|
def query_execute(query, &block)
|
63
45
|
query = ResourceQuery.from(query, resource, rigor)
|
64
46
|
execute_search(query, &block)
|
@@ -69,32 +51,104 @@ module RoadForest::RDF
|
|
69
51
|
execute_search(pattern, &block)
|
70
52
|
end
|
71
53
|
|
72
|
-
def
|
73
|
-
|
74
|
-
enum = search.execute(target_graph)
|
75
|
-
if enum.any?{ true }
|
76
|
-
enum.each(&block)
|
77
|
-
return enum
|
78
|
-
end
|
79
|
-
end
|
80
|
-
search.execute(source_graph, &block)
|
54
|
+
def each(&block)
|
55
|
+
origin_graph.each(&block)
|
81
56
|
end
|
82
57
|
|
83
|
-
def
|
84
|
-
|
58
|
+
def execute_search(search, &block)
|
59
|
+
search.execute(origin_graph, &block)
|
85
60
|
end
|
61
|
+
end
|
86
62
|
|
63
|
+
class WriteManager < ReadOnlyManager
|
87
64
|
def insert(statement)
|
88
|
-
copy_context
|
89
65
|
statement[3] = resource
|
90
|
-
|
66
|
+
destination_graph.insert(statement)
|
91
67
|
end
|
92
68
|
|
93
69
|
def delete(statement)
|
94
70
|
statement = RDF::Query::Pattern.from(statement)
|
95
71
|
statement.context = resource
|
72
|
+
destination_graph.delete(statement)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class PostManager < WriteManager
|
77
|
+
end
|
78
|
+
|
79
|
+
class SplitManager < WriteManager
|
80
|
+
attr_accessor :target_graph
|
81
|
+
|
82
|
+
alias destination_graph target_graph
|
83
|
+
|
84
|
+
def dup
|
85
|
+
other = super
|
86
|
+
other.target_graph = self.target_graph
|
87
|
+
return other
|
88
|
+
end
|
89
|
+
|
90
|
+
def relevant_prefixes
|
91
|
+
super.merge(relevant_prefixes_for_graph(destination_graph))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class UpdateManager < SplitManager
|
96
|
+
def initialize
|
97
|
+
@copied_contexts = {}
|
98
|
+
end
|
99
|
+
|
100
|
+
attr_accessor :copied_contexts
|
101
|
+
|
102
|
+
def dup
|
103
|
+
other = super
|
104
|
+
other.copied_contexts = self.copied_contexts
|
105
|
+
return other
|
106
|
+
end
|
107
|
+
|
108
|
+
def execute_search(search, &block)
|
109
|
+
enum = search.execute(destination_graph)
|
110
|
+
if enum.any?{ true }
|
111
|
+
enum.each(&block)
|
112
|
+
return enum
|
113
|
+
end
|
114
|
+
search.execute(origin_graph, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
def insert(statement)
|
118
|
+
copy_context
|
119
|
+
super
|
120
|
+
end
|
121
|
+
|
122
|
+
def delete(statement)
|
96
123
|
copy_context
|
97
|
-
|
124
|
+
super
|
125
|
+
end
|
126
|
+
|
127
|
+
def parceller
|
128
|
+
@parceller ||=
|
129
|
+
begin
|
130
|
+
parceller = Parcel.new
|
131
|
+
parceller.graph = source_graph
|
132
|
+
parceller
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def copy_context
|
137
|
+
return if copied_contexts[resource]
|
138
|
+
parceller.graph_for(resource).each_statement do |statement|
|
139
|
+
statement.context = resource
|
140
|
+
destination_graph << statement
|
141
|
+
end
|
142
|
+
copied_contexts[resource] = true
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class CopyManager < SplitManager
|
147
|
+
def execute_search(search, &block)
|
148
|
+
super(search) do |statement|
|
149
|
+
destination_graph.insert(statement)
|
150
|
+
yield statement
|
151
|
+
end
|
98
152
|
end
|
99
153
|
end
|
100
154
|
end
|
@@ -37,7 +37,7 @@ module RoadForest::RDF
|
|
37
37
|
|
38
38
|
if empty?
|
39
39
|
new_subject = subject
|
40
|
-
graph.insert([new_subject, RDF.type, RDF.List])
|
40
|
+
#graph.insert([new_subject, RDF.type, RDF.List])
|
41
41
|
else
|
42
42
|
old_subject, new_subject = last_subject, RDF::Node.new
|
43
43
|
graph.delete([old_subject, RDF.rest, RDF.nil])
|
@@ -3,12 +3,17 @@ require 'roadforest/rdf/graph-focus'
|
|
3
3
|
|
4
4
|
module RoadForest
|
5
5
|
module RDF
|
6
|
-
class GraphCopier <
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
class GraphCopier < GraphFocus
|
7
|
+
def query_value(query)
|
8
|
+
#This isn't the most efficient way to do this (the query essentially
|
9
|
+
#happens twice) but the intended use of GC is to copy small numbers of
|
10
|
+
#patterns between small graphs, so the n is small
|
11
|
+
query.patterns.each do |pattern|
|
12
|
+
pattern.execute(@access_manager) do |statement|
|
13
|
+
@access_manager.insert(statement)
|
14
|
+
end
|
15
|
+
end
|
10
16
|
super
|
11
|
-
@target_graph = ::RDF::Graph.new
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
@@ -1,39 +1,94 @@
|
|
1
1
|
require 'rdf'
|
2
|
-
require '
|
3
|
-
require 'roadforest/rdf
|
2
|
+
require 'rdf/model/node'
|
3
|
+
require 'roadforest/rdf'
|
4
|
+
require 'roadforest/rdf/focus-list'
|
5
|
+
require 'roadforest/rdf/normalization'
|
6
|
+
require 'roadforest/rdf/resource-query'
|
7
|
+
require 'roadforest/rdf/access-manager'
|
8
|
+
|
4
9
|
|
5
10
|
module RoadForest::RDF
|
6
|
-
class
|
7
|
-
|
11
|
+
class NullFocus < ::BasicObject
|
12
|
+
def initialize(focus, pattern, callsite)
|
13
|
+
@focus, @pattern, @callsite = focus, pattern, callsite
|
14
|
+
end
|
15
|
+
|
16
|
+
def __callsite__
|
17
|
+
@callsite
|
18
|
+
end
|
19
|
+
|
20
|
+
def subject
|
21
|
+
@focus.subject
|
22
|
+
end
|
23
|
+
|
24
|
+
def nil?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def blank?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def empty?
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def length
|
37
|
+
0
|
38
|
+
end
|
39
|
+
alias count length
|
40
|
+
alias size length
|
41
|
+
|
42
|
+
def method_missing(method, *args, &block)
|
43
|
+
::Kernel.raise ::NoMethodError, "No method '#{method}' on NullFocus. " +
|
44
|
+
"NullFocus returned because there were no results at \n#{@focus.subject}\n for \n#{@pattern.inspect}\n" +
|
45
|
+
"Search was attempted at #{@callsite[0]}"
|
46
|
+
end
|
8
47
|
end
|
9
48
|
|
10
|
-
class
|
11
|
-
|
12
|
-
|
13
|
-
|
49
|
+
class GraphFocus
|
50
|
+
#XXX Any changes to this class heirarchy or to ContextFascade should start
|
51
|
+
#with a refactor like:
|
52
|
+
# Reduce this to the single-node API ([] []=)
|
53
|
+
# Change the ContextFascade into a family of classes (RO, RW, Update)
|
54
|
+
include Normalization
|
55
|
+
|
56
|
+
#attr_accessor :source_graph, :target_graph, :subject, :root_url,
|
57
|
+
#:source_rigor
|
58
|
+
|
59
|
+
attr_accessor :subject, :access_manager
|
60
|
+
|
61
|
+
alias rdf subject
|
62
|
+
|
63
|
+
def initialize(access_manager, subject = nil)
|
64
|
+
@access_manager = access_manager
|
65
|
+
self.subject = subject unless subject.nil?
|
14
66
|
end
|
15
67
|
|
16
|
-
def
|
17
|
-
|
68
|
+
def root_url
|
69
|
+
@access_manager.resource
|
18
70
|
end
|
19
71
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
else
|
27
|
-
values.each
|
72
|
+
def subject=(*value)
|
73
|
+
@subject = normalize_resource(value)
|
74
|
+
case @subject
|
75
|
+
when ::RDF::URI
|
76
|
+
@access_manager.resource = @subject
|
28
77
|
end
|
29
78
|
end
|
30
79
|
|
31
|
-
def
|
32
|
-
|
80
|
+
def inspect
|
81
|
+
"#<#{self.class.name}:0x#{"%x" % object_id} (#{subject.to_s}) #{forward_properties.inspect}>"
|
82
|
+
end
|
83
|
+
alias to_s inspect
|
84
|
+
|
85
|
+
def dup
|
86
|
+
other = self.class.new(access_manager.dup)
|
87
|
+
other.subject = subject
|
88
|
+
other
|
33
89
|
end
|
34
|
-
end
|
35
90
|
|
36
|
-
|
91
|
+
### Begin old GraphFocus
|
37
92
|
def normalize_triple(property, value, extra=nil)
|
38
93
|
if not extra.nil?
|
39
94
|
property = [property, value]
|
@@ -71,6 +126,7 @@ module RoadForest::RDF
|
|
71
126
|
end
|
72
127
|
value
|
73
128
|
end
|
129
|
+
alias first_or_add find_or_add
|
74
130
|
|
75
131
|
def set_node(property, url=nil)
|
76
132
|
create_node(url) do |node|
|
@@ -100,20 +156,154 @@ module RoadForest::RDF
|
|
100
156
|
yield list if block_given?
|
101
157
|
return list
|
102
158
|
end
|
103
|
-
|
159
|
+
#### End of old GraphFocus
|
160
|
+
|
161
|
+
def wrap_node(value)
|
162
|
+
next_step = dup
|
163
|
+
if ::RDF::Node === value
|
164
|
+
next_step.root_url = self.root_url
|
165
|
+
else
|
166
|
+
next_step.root_url = normalize_context(value)
|
167
|
+
end
|
168
|
+
next_step.subject = value
|
169
|
+
next_step
|
170
|
+
end
|
171
|
+
|
172
|
+
def unwrap_value(value)
|
173
|
+
return nil if value.nil?
|
174
|
+
if value.respond_to? :object
|
175
|
+
value.object
|
176
|
+
else
|
177
|
+
wrap_node(value)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_context
|
182
|
+
normalize_context(subject)
|
183
|
+
end
|
184
|
+
|
185
|
+
def root_url=(*value) #XXX curies?
|
186
|
+
@root_url = normalize_resource(value)
|
187
|
+
end
|
104
188
|
|
105
|
-
|
106
|
-
def
|
107
|
-
|
189
|
+
#XXX This probably wants to be handled completely in the MediaType handler
|
190
|
+
def relevant_prefixes
|
191
|
+
access_manager.relevant_prefixes
|
108
192
|
end
|
109
193
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
194
|
+
def get(prefix, property = nil)
|
195
|
+
return maybe_null( prefix, property,
|
196
|
+
single_or_enum(forward_query_value( prefix, property))
|
197
|
+
)
|
113
198
|
end
|
114
|
-
|
199
|
+
alias_method :[], :get
|
115
200
|
|
116
|
-
|
117
|
-
|
201
|
+
def first(prefix, property = nil)
|
202
|
+
return maybe_null( prefix, property,
|
203
|
+
forward_query_value( prefix, property ).first
|
204
|
+
)
|
205
|
+
end
|
206
|
+
|
207
|
+
def all(prefix, property = nil)
|
208
|
+
return maybe_null( prefix, property,
|
209
|
+
forward_query_value( prefix, property )
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
#XXX Maybe rev should return a decorator, so it looks like:
|
214
|
+
#focus.rev.get(...) or focus.rev.all(...)
|
215
|
+
def rev(prefix, property = nil)
|
216
|
+
return maybe_null( prefix, property,
|
217
|
+
single_or_enum(reverse_query_value( prefix, property))
|
218
|
+
)
|
219
|
+
end
|
220
|
+
|
221
|
+
def rev_first(prefix, property = nil)
|
222
|
+
return maybe_null( prefix, property,
|
223
|
+
reverse_query_value(prefix, property).first
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
def rev_all(prefix, property = nil)
|
228
|
+
return maybe_null( prefix, property,
|
229
|
+
reverse_query_value(prefix, property)
|
230
|
+
)
|
231
|
+
end
|
232
|
+
|
233
|
+
def as_list
|
234
|
+
list = FocusList.new(subject, access_manager)
|
235
|
+
list.base_node = self
|
236
|
+
list
|
237
|
+
end
|
238
|
+
|
239
|
+
def forward_properties
|
240
|
+
query_properties( build_query{|q| q.pattern([ normalize_resource(subject), :property, :value ])} )
|
241
|
+
end
|
242
|
+
|
243
|
+
def reverse_properties
|
244
|
+
query_properties( build_query{|q| q.pattern([ :value, :property, normalize_resource(subject)])} )
|
245
|
+
end
|
246
|
+
|
247
|
+
protected
|
248
|
+
|
249
|
+
STRIP_TRACE = %r{\A#{File::expand_path("../../..", __FILE__)}}
|
250
|
+
def maybe_null(prefix, property, result)
|
251
|
+
if not result.nil?
|
252
|
+
if result.respond_to? :empty?
|
253
|
+
return result unless result.empty?
|
254
|
+
else
|
255
|
+
return result
|
256
|
+
end
|
257
|
+
end
|
258
|
+
return NullFocus.new(self, normalize_property(prefix, property), caller(0).drop_while{|line| line =~ STRIP_TRACE})
|
259
|
+
end
|
260
|
+
|
261
|
+
def single_or_enum(values)
|
262
|
+
case values.length
|
263
|
+
when 0
|
264
|
+
return nil
|
265
|
+
when 1
|
266
|
+
return values.first
|
267
|
+
else
|
268
|
+
return values.enum_for(:each)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def reverse_query_value(prefix, property=nil)
|
273
|
+
query_value(build_query{|q|
|
274
|
+
q.pattern([ :value, normalize_property(prefix, property), normalize_resource(subject)])
|
275
|
+
})
|
276
|
+
end
|
277
|
+
|
278
|
+
def forward_query_value(prefix, property=nil)
|
279
|
+
query_value(build_query{|q|
|
280
|
+
q.pattern([ normalize_resource(subject), normalize_property(prefix, property), :value])
|
281
|
+
})
|
282
|
+
end
|
283
|
+
|
284
|
+
def build_query(&block)
|
285
|
+
access_manager.build_query(&block)
|
286
|
+
end
|
287
|
+
|
288
|
+
def execute_query(query)
|
289
|
+
query.execute(access_manager)
|
290
|
+
end
|
291
|
+
|
292
|
+
def query_value(query)
|
293
|
+
solutions = execute_query(query)
|
294
|
+
solutions.map do |solution|
|
295
|
+
unwrap_value(solution.value)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def query_properties(query)
|
300
|
+
Hash[execute_query(query).map do |solution|
|
301
|
+
prop = solution.property
|
302
|
+
if qname = prop.qname
|
303
|
+
prop = qname
|
304
|
+
end
|
305
|
+
[prop, solution.value]
|
306
|
+
end]
|
307
|
+
end
|
118
308
|
end
|
119
309
|
end
|