tripod 0.3.1 → 0.3.2
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/README.md +4 -2
- data/lib/tripod/criteria.rb +14 -0
- data/lib/tripod/criteria/execution.rb +9 -54
- data/lib/tripod/finders.rb +70 -0
- data/lib/tripod/sparql_query.rb +7 -3
- data/lib/tripod/version.rb +1 -1
- data/spec/tripod/criteria_execution_spec.rb +24 -8
- data/spec/tripod/criteria_spec.rb +7 -0
- metadata +19 -19
data/README.md
CHANGED
@@ -103,9 +103,9 @@ Note: Tripod doesn't supply a database. You need to install one. I recommend [Fu
|
|
103
103
|
# It doesn't actually do anything against the DB until you run resources, first, or count on it.
|
104
104
|
# (from Tripod::CriteriaExecution)
|
105
105
|
|
106
|
-
Person.all #=> returns a Tripod::Criteria object which selects all resources of rdf_type http://person
|
106
|
+
Person.all #=> returns a Tripod::Criteria object which selects all resources of rdf_type http://person, in the http://people graph
|
107
107
|
|
108
|
-
Resource.all #=> returns a criteria object to return resources in the database (as no rdf_type specified at class level)
|
108
|
+
Resource.all #=> returns a criteria object to return resources in the database (as no rdf_type or graph_uri specified at class level)
|
109
109
|
|
110
110
|
Person.all.resources #=> returns all the actual resources for the criteria object, as an array
|
111
111
|
|
@@ -116,6 +116,8 @@ Note: Tripod doesn't supply a database. You need to install one. I recommend [Fu
|
|
116
116
|
# note that you need to use ?uri as the variable for the subject.
|
117
117
|
Person.where("?uri <http://name> 'Joe'") #=> returns a Tripod::Criteria object
|
118
118
|
|
119
|
+
Resource.graph("http://mygraph") #=> Retruns a criteria object with a graph restriction (note: if graph_uri set on the class, it will default to using this)
|
120
|
+
|
119
121
|
## Chainable criteria
|
120
122
|
|
121
123
|
Person.all.where("?uri <http://name> 'Ric'").where("?uri <http://knows> <http://asa>).first
|
data/lib/tripod/criteria.rb
CHANGED
@@ -17,6 +17,7 @@ module Tripod
|
|
17
17
|
attr_accessor :limit_clause
|
18
18
|
attr_accessor :order_clause
|
19
19
|
attr_accessor :offset_clause
|
20
|
+
attr_accessor :graph_uri
|
20
21
|
|
21
22
|
def initialize(resource_class)
|
22
23
|
self.resource_class = resource_class
|
@@ -28,6 +29,8 @@ module Tripod
|
|
28
29
|
else
|
29
30
|
self.where("?uri ?p ?o")
|
30
31
|
end
|
32
|
+
|
33
|
+
self.graph_uri = resource_class._GRAPH_URI.to_s if resource_class._GRAPH_URI
|
31
34
|
end
|
32
35
|
|
33
36
|
# they're equal if they return the same query
|
@@ -73,5 +76,16 @@ module Tripod
|
|
73
76
|
self
|
74
77
|
end
|
75
78
|
|
79
|
+
# Restrict htis query to the graph uri passed in
|
80
|
+
#
|
81
|
+
# @example .graph(RDF::URI.new('http://graphoid')
|
82
|
+
# @example .graph('http://graphoid')
|
83
|
+
#
|
84
|
+
# @param [ Stirng, RDF::URI ] The graph uri
|
85
|
+
#
|
86
|
+
# @return [ Tripod::Criteria ] A criteria object
|
87
|
+
def graph(graph_uri)
|
88
|
+
self.graph_uri = graph_uri.to_s
|
89
|
+
end
|
76
90
|
end
|
77
91
|
end
|
@@ -33,8 +33,8 @@ module Tripod
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def resources_from_sparql(sparql)
|
36
|
-
uris_and_graphs =
|
37
|
-
|
36
|
+
uris_and_graphs = self.resource_class._select_uris_and_graphs(sparql)
|
37
|
+
self.resource_class._create_and_hydrate_resources(uris_and_graphs)
|
38
38
|
end
|
39
39
|
|
40
40
|
def build_select_query
|
@@ -44,64 +44,19 @@ module Tripod
|
|
44
44
|
extras(limit_clause)
|
45
45
|
extras(offset_clause)
|
46
46
|
|
47
|
-
|
48
|
-
|
47
|
+
if graph_uri
|
48
|
+
select_query = "SELECT ?uri (<#{graph_uri}> as ?graph) WHERE { GRAPH <#{graph_uri}> "
|
49
|
+
else
|
50
|
+
select_query = "SELECT ?uri ?graph WHERE { GRAPH ?graph "
|
51
|
+
end
|
52
|
+
|
53
|
+
select_query += "{ "
|
49
54
|
select_query += self.where_clauses.join(" . ")
|
50
55
|
select_query += " } } "
|
51
56
|
select_query += self.extra_clauses.join(" ")
|
52
57
|
select_query.strip
|
53
58
|
end
|
54
59
|
|
55
|
-
# create and hydrate the resources identified in uris_and_graphs.
|
56
|
-
# Note: if any of the graphs are not set, those resources can still be constructed, but not persisted back to DB.
|
57
|
-
def create_and_hydrate_resources(uris_and_graphs)
|
58
|
-
|
59
|
-
graph = self.resource_class.describe_uris(uris_and_graphs.keys) #uses the resource_class on the criteria object
|
60
|
-
repo = self.resource_class.add_data_to_repository(graph)
|
61
|
-
|
62
|
-
resources = []
|
63
|
-
|
64
|
-
uris_and_graphs.each_pair do |u,g|
|
65
|
-
|
66
|
-
# instantiate a new resource
|
67
|
-
r = self.resource_class.new(u,g)
|
68
|
-
|
69
|
-
# make a graph of data for this resource's uri
|
70
|
-
data_graph = RDF::Graph.new
|
71
|
-
repo.query( [RDF::URI.new(u), :predicate, :object] ) do |statement|
|
72
|
-
data_graph << statement
|
73
|
-
end
|
74
|
-
|
75
|
-
# use it to hydrate this resource
|
76
|
-
r.hydrate!(:graph => data_graph)
|
77
|
-
r.new_record = false
|
78
|
-
resources << r
|
79
|
-
end
|
80
|
-
|
81
|
-
resources
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
# based on the query passed in, build a hash of uris->graphs
|
86
|
-
# @param [ String] sparql. The sparql query
|
87
|
-
# @param [ Hash ] opts. A hash of options.
|
88
|
-
#
|
89
|
-
# @option options [ String ] uri_variable The name of the uri variable in the query, if not 'uri'
|
90
|
-
# @option options [ String ] graph_variable The name of the uri variable in thh query, if not 'graph'
|
91
|
-
def select_uris_and_graphs(sparql, opts={})
|
92
|
-
select_results = Tripod::SparqlClient::Query.select(sparql)
|
93
|
-
|
94
|
-
uris_and_graphs = {}
|
95
|
-
|
96
|
-
select_results.each do |r|
|
97
|
-
uri_variable = opts[:uri_variable] || 'uri'
|
98
|
-
graph_variable = opts[:graph_variable] || 'graph'
|
99
|
-
uris_and_graphs[ r[uri_variable]["value"] ] = r[graph_variable]["value"]
|
100
|
-
end
|
101
|
-
|
102
|
-
uris_and_graphs
|
103
|
-
end
|
104
|
-
|
105
60
|
end
|
106
61
|
|
107
62
|
end
|
data/lib/tripod/finders.rb
CHANGED
@@ -48,6 +48,24 @@ module Tripod::Finders
|
|
48
48
|
resource
|
49
49
|
end
|
50
50
|
|
51
|
+
# Find a collection of +Resource+s by a SPARQL select statement which returns their uris.
|
52
|
+
# Under the hood, this only executes two queries: a select, then a describe.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# Person.find_by_sparql('SELECT ?uri ?graph WHERE { GRAPH ?graph { ?uri ?p ?o } } LIMIT 3')
|
56
|
+
#
|
57
|
+
# @param [ String ] sparql_query. A sparql query which returns a list of uris of the objects.
|
58
|
+
# @param [ Hash ] opts. A hash of options.
|
59
|
+
#
|
60
|
+
# @option options [ String ] uri_variable The name of the uri variable in thh query, if not 'uri'
|
61
|
+
# @option options [ String ] graph_variable The name of the uri variable in thh query, if not 'graph'
|
62
|
+
#
|
63
|
+
# @return [ Array ] An array of hydrated resources of this class's type.
|
64
|
+
def find_by_sparql(sparql_query, opts={})
|
65
|
+
uris_and_graphs = _select_uris_and_graphs(criteria, opts)
|
66
|
+
_create_and_hydrate_resources(uris_and_graphs)
|
67
|
+
end
|
68
|
+
|
51
69
|
# execute a where clause on this resource.
|
52
70
|
# returns a criteria object
|
53
71
|
def where(sparql_snippet)
|
@@ -91,5 +109,57 @@ module Tripod::Finders
|
|
91
109
|
graph
|
92
110
|
end
|
93
111
|
|
112
|
+
# THESE AREN'T INTENDED TO BE PART OF THE PUBLIC API:
|
113
|
+
|
114
|
+
# create and hydrate the resources identified in uris_and_graphs.
|
115
|
+
# Note: if any of the graphs are not set, those resources can still be constructed, but not persisted back to DB.
|
116
|
+
def _create_and_hydrate_resources(uris_and_graphs)
|
117
|
+
|
118
|
+
graph = describe_uris(uris_and_graphs.keys) #uses the resource_class on the criteria object
|
119
|
+
repo = add_data_to_repository(graph)
|
120
|
+
|
121
|
+
resources = []
|
122
|
+
|
123
|
+
uris_and_graphs.each_pair do |u,g|
|
124
|
+
|
125
|
+
# instantiate a new resource
|
126
|
+
r = self.new(u,g)
|
127
|
+
|
128
|
+
# make a graph of data for this resource's uri
|
129
|
+
data_graph = RDF::Graph.new
|
130
|
+
repo.query( [RDF::URI.new(u), :predicate, :object] ) do |statement|
|
131
|
+
data_graph << statement
|
132
|
+
end
|
133
|
+
|
134
|
+
# use it to hydrate this resource
|
135
|
+
r.hydrate!(:graph => data_graph)
|
136
|
+
r.new_record = false
|
137
|
+
resources << r
|
138
|
+
end
|
139
|
+
|
140
|
+
resources
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# based on the query passed in, build a hash of uris->graphs
|
145
|
+
# @param [ String] sparql. The sparql query
|
146
|
+
# @param [ Hash ] opts. A hash of options.
|
147
|
+
#
|
148
|
+
# @option options [ String ] uri_variable The name of the uri variable in the query, if not 'uri'
|
149
|
+
# @option options [ String ] graph_variable The name of the uri variable in thh query, if not 'graph'
|
150
|
+
def _select_uris_and_graphs(sparql, opts={})
|
151
|
+
select_results = Tripod::SparqlClient::Query.select(sparql)
|
152
|
+
|
153
|
+
uris_and_graphs = {}
|
154
|
+
|
155
|
+
select_results.each do |r|
|
156
|
+
uri_variable = opts[:uri_variable] || 'uri'
|
157
|
+
graph_variable = opts[:graph_variable] || 'graph'
|
158
|
+
uris_and_graphs[ r[uri_variable]["value"] ] = r[graph_variable]["value"]
|
159
|
+
end
|
160
|
+
|
161
|
+
uris_and_graphs
|
162
|
+
end
|
163
|
+
|
94
164
|
end
|
95
165
|
end
|
data/lib/tripod/sparql_query.rb
CHANGED
@@ -15,9 +15,8 @@ module Tripod
|
|
15
15
|
cattr_accessor :KEYWORDS
|
16
16
|
@@KEYWORDS = %w(CONSTRUCT ASK DESCRIBE SELECT)
|
17
17
|
|
18
|
-
def initialize(query_string
|
18
|
+
def initialize(query_string)
|
19
19
|
@query = query_string
|
20
|
-
@parent_query = parent_query
|
21
20
|
|
22
21
|
if self.has_prefixes?
|
23
22
|
@prefixes, @body = self.extract_prefixes
|
@@ -42,9 +41,14 @@ module Tripod
|
|
42
41
|
return p.strip, b.strip
|
43
42
|
end
|
44
43
|
|
45
|
-
def
|
44
|
+
def check_subqueryable!
|
46
45
|
# only allow for selects
|
47
46
|
raise SparqlQueryError.new("Can't turn this into a subquery") unless self.query_type == :select
|
47
|
+
end
|
48
|
+
|
49
|
+
def as_count_query_str
|
50
|
+
|
51
|
+
check_subqueryable!
|
48
52
|
|
49
53
|
count_query = "SELECT COUNT(*) { #{self.body} }"
|
50
54
|
count_query = "#{self.prefixes} #{count_query}" if self.prefixes
|
data/lib/tripod/version.rb
CHANGED
@@ -11,34 +11,42 @@ describe Tripod::Criteria do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let(:john) do
|
14
|
-
p = Person.new('http://john'
|
14
|
+
p = Person.new('http://john')
|
15
15
|
p.name = "John"
|
16
16
|
p
|
17
17
|
end
|
18
18
|
|
19
19
|
let(:barry) do
|
20
|
-
p = Person.new('http://barry'
|
20
|
+
p = Person.new('http://barry')
|
21
21
|
p.name = "Barry"
|
22
22
|
p
|
23
23
|
end
|
24
24
|
|
25
25
|
describe "#build_select_query" do
|
26
26
|
|
27
|
-
context "for a class with an rdf_type" do
|
27
|
+
context "for a class with an rdf_type and graph" do
|
28
28
|
it "should return a SELECT query based with an rdf type restriction" do
|
29
|
-
person_criteria.send(:build_select_query).should == "SELECT ?uri ?graph WHERE { GRAPH
|
29
|
+
person_criteria.send(:build_select_query).should == "SELECT ?uri (<http://graph> as ?graph) WHERE { GRAPH <http://graph> { ?uri a <http://person> } }"
|
30
30
|
end
|
31
31
|
|
32
32
|
context "and extra restrictions" do
|
33
33
|
before { person_criteria.where("[pattern]") }
|
34
34
|
|
35
|
-
it "should return a SELECT query with the extra restriction
|
36
|
-
person_criteria.send(:build_select_query).should == "SELECT ?uri ?graph WHERE { GRAPH
|
35
|
+
it "should return a SELECT query with the extra restriction" do
|
36
|
+
person_criteria.send(:build_select_query).should == "SELECT ?uri (<http://graph> as ?graph) WHERE { GRAPH <http://graph> { ?uri a <http://person> . [pattern] } }"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with an overriden graph" do
|
41
|
+
before { person_criteria.graph("http://anothergraph") }
|
42
|
+
|
43
|
+
it "should override the graph in the query" do
|
44
|
+
person_criteria.send(:build_select_query).should == "SELECT ?uri (<http://anothergraph> as ?graph) WHERE { GRAPH <http://anothergraph> { ?uri a <http://person> } }"
|
37
45
|
end
|
38
46
|
end
|
39
47
|
end
|
40
48
|
|
41
|
-
context "for a class without an rdf_type" do
|
49
|
+
context "for a class without an rdf_type and graph" do
|
42
50
|
it "should return a SELECT query without an rdf_type restriction" do
|
43
51
|
resource_criteria.send(:build_select_query).should == "SELECT ?uri ?graph WHERE { GRAPH ?graph { ?uri ?p ?o } }"
|
44
52
|
end
|
@@ -50,6 +58,14 @@ describe Tripod::Criteria do
|
|
50
58
|
resource_criteria.send(:build_select_query).should == "SELECT ?uri ?graph WHERE { GRAPH ?graph { ?uri ?p ?o . [pattern] } }"
|
51
59
|
end
|
52
60
|
end
|
61
|
+
|
62
|
+
context "with a graph set" do
|
63
|
+
before { resource_criteria.graph("http://graphy") }
|
64
|
+
|
65
|
+
it "should override the graph in the query" do
|
66
|
+
resource_criteria.send(:build_select_query).should == "SELECT ?uri (<http://graphy> as ?graph) WHERE { GRAPH <http://graphy> { ?uri ?p ?o } }"
|
67
|
+
end
|
68
|
+
end
|
53
69
|
end
|
54
70
|
|
55
71
|
context "with extras" do
|
@@ -134,7 +150,7 @@ describe Tripod::Criteria do
|
|
134
150
|
let(:chained_criteria) { Person.where("?uri <http://name> ?name").limit(1).offset(0).order("DESC(?name)") }
|
135
151
|
|
136
152
|
it "should run the right Sparql" do
|
137
|
-
sparql = "SELECT ?uri ?graph WHERE { GRAPH
|
153
|
+
sparql = "SELECT ?uri (<http://graph> as ?graph) WHERE { GRAPH <http://graph> { ?uri a <http://person> . ?uri <http://name> ?name } } ORDER BY DESC(?name) LIMIT 1 OFFSET 0"
|
138
154
|
Tripod::SparqlClient::Query.should_receive(:select).with(sparql).and_call_original
|
139
155
|
chained_criteria.resources
|
140
156
|
end
|
@@ -107,4 +107,11 @@ describe Tripod::Criteria do
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
describe "#graph" do
|
111
|
+
it "sets the graph_uri for this criteria, as a string" do
|
112
|
+
resource_criteria.graph(RDF::URI("http://foobar"))
|
113
|
+
resource_criteria.graph_uri.should == "http://foobar"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
110
117
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tripod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -15,7 +15,7 @@ date: 2013-02-20 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rest-client
|
18
|
-
requirement: &
|
18
|
+
requirement: &70205083592080 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: '0'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70205083592080
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
|
-
requirement: &
|
29
|
+
requirement: &70205083591380 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ~>
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: '3.1'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *70205083591380
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: equivalent-xml
|
40
|
-
requirement: &
|
40
|
+
requirement: &70205083590920 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: '0'
|
46
46
|
type: :runtime
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *70205083590920
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: rdf
|
51
|
-
requirement: &
|
51
|
+
requirement: &70205083589940 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ~>
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: '1.0'
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *70205083589940
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: rdf-rdfxml
|
62
|
-
requirement: &
|
62
|
+
requirement: &70205083589120 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: '0'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *70205083589120
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: rdf-n3
|
73
|
-
requirement: &
|
73
|
+
requirement: &70205083588320 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: '0'
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *70205083588320
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: rdf-json
|
84
|
-
requirement: &
|
84
|
+
requirement: &70205083587160 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,10 +89,10 @@ dependencies:
|
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *70205083587160
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: json-ld
|
95
|
-
requirement: &
|
95
|
+
requirement: &70205083586480 !ruby/object:Gem::Requirement
|
96
96
|
none: false
|
97
97
|
requirements:
|
98
98
|
- - ! '>='
|
@@ -100,10 +100,10 @@ dependencies:
|
|
100
100
|
version: '0'
|
101
101
|
type: :runtime
|
102
102
|
prerelease: false
|
103
|
-
version_requirements: *
|
103
|
+
version_requirements: *70205083586480
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: guid
|
106
|
-
requirement: &
|
106
|
+
requirement: &70205083584700 !ruby/object:Gem::Requirement
|
107
107
|
none: false
|
108
108
|
requirements:
|
109
109
|
- - ! '>='
|
@@ -111,7 +111,7 @@ dependencies:
|
|
111
111
|
version: '0'
|
112
112
|
type: :runtime
|
113
113
|
prerelease: false
|
114
|
-
version_requirements: *
|
114
|
+
version_requirements: *70205083584700
|
115
115
|
description: RDF ruby ORM
|
116
116
|
email:
|
117
117
|
- ric@swirrl.com
|