tripod 0.2.3 → 0.3.0
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/.autotest +1 -0
- data/.rspec +1 -0
- data/Gemfile +2 -1
- data/README.md +27 -16
- data/lib/tripod/criteria/execution.rb +100 -0
- data/lib/tripod/criteria.rb +56 -0
- data/lib/tripod/errors/bad_data_request.rb +15 -0
- data/lib/tripod/errors/bad_sparql_request.rb +15 -0
- data/lib/tripod/errors/rdf_parse_failed.rb +7 -0
- data/lib/tripod/errors/rdf_type_not_set.rb +9 -0
- data/lib/tripod/errors.rb +6 -1
- data/lib/tripod/finders.rb +21 -76
- data/lib/tripod/persistence.rb +4 -4
- data/lib/tripod/resource.rb +3 -1
- data/lib/tripod/sparql_client.rb +45 -13
- data/lib/tripod/sparql_query.rb +86 -0
- data/lib/tripod/version.rb +1 -1
- data/lib/tripod.rb +5 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/tripod/criteria_execution_spec.rb +118 -0
- data/spec/tripod/criteria_spec.rb +65 -0
- data/spec/tripod/finders_spec.rb +66 -46
- data/spec/tripod/resource_spec.rb +4 -2
- data/spec/tripod/sparql_client_spec.rb +46 -0
- data/spec/tripod/sparql_query_spec.rb +133 -0
- metadata +37 -20
data/.autotest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "autotest/bundler"
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -55,21 +55,10 @@ Note: Tripod doesn't supply a database. You need to install one. I recommend [Fu
|
|
55
55
|
p.important_dates = [Date.new(2011,1,1)]
|
56
56
|
p.save!
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
SELECT ?person ?graph
|
62
|
-
WHERE {
|
63
|
-
GRAPH ?graph {
|
64
|
-
?person ?p ?o .
|
65
|
-
?person a <http://person> .
|
66
|
-
}
|
67
|
-
}",
|
68
|
-
:uri_variable => 'person' ) # optionally, set a different name for the uri parameter (default: uri)
|
69
|
-
# => returns an array of Person objects, containing all data we know about them.
|
58
|
+
people = Person.all.resources #=> returns all people as an array
|
59
|
+
|
60
|
+
ric = Person.find('http://ric') #=> returns a single Person object.
|
70
61
|
|
71
|
-
ric = Person.find('http://ric')
|
72
|
-
# => returns a single Person object.
|
73
62
|
|
74
63
|
## Some Other interesting features
|
75
64
|
|
@@ -89,20 +78,42 @@ Note: Tripod doesn't supply a database. You need to install one. I recommend [Fu
|
|
89
78
|
## Defining a graph at instantiation-time
|
90
79
|
|
91
80
|
class Resource
|
92
|
-
|
81
|
+
include Tripod::Resource
|
82
|
+
field :label, RDF::RDFS.label
|
93
83
|
|
94
84
|
# notice also that you don't need to supply an rdf type or graph here!
|
95
85
|
end
|
96
86
|
|
97
87
|
r = Resource.new('http://foo', 'http://mygraph')
|
88
|
+
r.label = "example"
|
89
|
+
r.save
|
98
90
|
|
99
|
-
# if you don't supply a graph at any point, you will get an error when you try to persist the resource.
|
91
|
+
# Note: if you don't supply a graph at any point (i.e. class or instance level), you will get an error when you try to persist the resource.
|
100
92
|
|
101
93
|
## Reading and writing arbitrary predicates
|
102
94
|
|
103
95
|
r.write_predicate(RDF.type, 'http://myresource/type')
|
104
96
|
r.read_predicate(RDF.type) # => RDF::URI.new("http://myresource/type")
|
105
97
|
|
98
|
+
## Finders and criteria
|
99
|
+
|
100
|
+
Person.all #=> returns a Tripod::Criteria which selets all resources of rdf_type http://person
|
101
|
+
|
102
|
+
Resource.all #=> returns all resources in the database (as no rdf_type specified at class level)
|
103
|
+
|
104
|
+
Person.all.resources #=> returns all the actual resources for the criteria, as an array
|
105
|
+
|
106
|
+
Person.first #=> returns the first person
|
107
|
+
|
108
|
+
Person.count #=> returns the count of all people
|
109
|
+
|
110
|
+
# note that you need to use ?uri as the variable for the subject.
|
111
|
+
Person.where("?uri <http://name> 'Joe'") #=> returns a Tripod::Criteria
|
112
|
+
|
113
|
+
## Chainable criteria
|
114
|
+
|
115
|
+
Person.all.where("?uri <http://name> 'Ric'").where("?uri <http://knows> <http://asa>).first
|
116
|
+
|
106
117
|
|
107
118
|
|
108
119
|
[Full Documentation](http://rubydoc.info/gems/tripod/frames)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# This module defines behaviour for criteria
|
2
|
+
module Tripod
|
3
|
+
|
4
|
+
# this module provides execution methods to a criteria object
|
5
|
+
module CriteriaExecution
|
6
|
+
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
# Execute the query and return an array of all hydrated resources
|
10
|
+
def resources
|
11
|
+
resources_from_sparql(build_select_query)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Execute the query and return the first result as a hydrated resource
|
15
|
+
def first
|
16
|
+
sq = Tripod::SparqlQuery.new(build_select_query)
|
17
|
+
first_sparql = sq.as_first_query_str
|
18
|
+
resources_from_sparql(first_sparql).first
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return how many records the current criteria would return
|
22
|
+
def count
|
23
|
+
sq = Tripod::SparqlQuery.new(build_select_query)
|
24
|
+
count_sparql = sq.as_count_query_str
|
25
|
+
result = Tripod::SparqlClient::Query.select(count_sparql)
|
26
|
+
result[0][".1"]["value"].to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
# PRIVATE:
|
30
|
+
|
31
|
+
included do
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def resources_from_sparql(sparql)
|
36
|
+
uris_and_graphs = select_uris_and_graphs(sparql)
|
37
|
+
create_and_hydrate_resources(uris_and_graphs)
|
38
|
+
end
|
39
|
+
|
40
|
+
def build_select_query
|
41
|
+
select_query = "SELECT ?uri ?graph WHERE { GRAPH ?graph { "
|
42
|
+
select_query += self.where_clauses.join(" . ")
|
43
|
+
# TODO: Deal with extras.
|
44
|
+
select_query += " } }"
|
45
|
+
end
|
46
|
+
|
47
|
+
# create and hydrate the resources identified in uris_and_graphs.
|
48
|
+
# Note: if any of the graphs are not set, those resources can still be constructed, but not persisted back to DB.
|
49
|
+
def create_and_hydrate_resources(uris_and_graphs)
|
50
|
+
|
51
|
+
graph = self.resource_class.describe_uris(uris_and_graphs.keys) #uses the resource_class on the criteria object
|
52
|
+
repo = self.resource_class.add_data_to_repository(graph)
|
53
|
+
|
54
|
+
resources = []
|
55
|
+
|
56
|
+
uris_and_graphs.each_pair do |u,g|
|
57
|
+
|
58
|
+
# instantiate a new resource
|
59
|
+
r = self.resource_class.new(u,g)
|
60
|
+
|
61
|
+
# make a graph of data for this resource's uri
|
62
|
+
data_graph = RDF::Graph.new
|
63
|
+
repo.query( [RDF::URI.new(u), :predicate, :object] ) do |statement|
|
64
|
+
data_graph << statement
|
65
|
+
end
|
66
|
+
|
67
|
+
# use it to hydrate this resource
|
68
|
+
r.hydrate!(:graph => data_graph)
|
69
|
+
r.new_record = false
|
70
|
+
resources << r
|
71
|
+
end
|
72
|
+
|
73
|
+
resources
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# based on the query passed in, build a hash of uris->graphs
|
78
|
+
# @param [ String] sparql. The sparql query
|
79
|
+
# @param [ Hash ] opts. A hash of options.
|
80
|
+
#
|
81
|
+
# @option options [ String ] uri_variable The name of the uri variable in the query, if not 'uri'
|
82
|
+
# @option options [ String ] graph_variable The name of the uri variable in thh query, if not 'graph'
|
83
|
+
def select_uris_and_graphs(sparql, opts={})
|
84
|
+
select_results = Tripod::SparqlClient::Query.select(sparql)
|
85
|
+
|
86
|
+
uris_and_graphs = {}
|
87
|
+
|
88
|
+
select_results.each do |r|
|
89
|
+
uri_variable = opts[:uri_variable] || 'uri'
|
90
|
+
graph_variable = opts[:graph_variable] || 'graph'
|
91
|
+
uris_and_graphs[ r[uri_variable]["value"] ] = r[graph_variable]["value"]
|
92
|
+
end
|
93
|
+
|
94
|
+
uris_and_graphs
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "tripod/criteria/execution"
|
3
|
+
|
4
|
+
module Tripod
|
5
|
+
|
6
|
+
# This module defines behaviour for criteria
|
7
|
+
class Criteria
|
8
|
+
|
9
|
+
include Tripod::CriteriaExecution
|
10
|
+
|
11
|
+
# the resource class that this criteria is for.
|
12
|
+
attr_accessor :resource_class
|
13
|
+
|
14
|
+
# array of all the where clauses in this criteria
|
15
|
+
attr_accessor :where_clauses
|
16
|
+
|
17
|
+
# array of all the extra clauses in this criteria
|
18
|
+
attr_accessor :extra_clauses
|
19
|
+
|
20
|
+
def initialize(resource_class)
|
21
|
+
self.resource_class = resource_class
|
22
|
+
self.where_clauses = []
|
23
|
+
self.extra_clauses = []
|
24
|
+
|
25
|
+
if resource_class._RDF_TYPE
|
26
|
+
self.where("?uri a <#{resource_class._RDF_TYPE.to_s}>")
|
27
|
+
else
|
28
|
+
self.where("?uri ?p ?o")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# they're equal if they return the same query
|
33
|
+
def ==(other)
|
34
|
+
build_select_query == other.send(:build_select_query)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Takes a string and adds a where clause to this criteria.
|
38
|
+
# Returns a criteria object.
|
39
|
+
# Note: the subject being returned by the query must be identified by ?uri
|
40
|
+
# e.g. my_criteria.where("?uri a <http://my-type>")
|
41
|
+
#
|
42
|
+
# TODO: make it also take a hash?
|
43
|
+
def where(sparql_snippet)
|
44
|
+
where_clauses << sparql_snippet
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# takes a string and adds an extra clause to this criteria.
|
49
|
+
# TODO: make it also take a hash?
|
50
|
+
def extras(sparql_snippet)
|
51
|
+
extra_clauses << sparql_snippet
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Tripod::Errors
|
3
|
+
|
4
|
+
# field not present error.
|
5
|
+
class BadDataRequest < StandardError
|
6
|
+
|
7
|
+
attr_accessor :parent_bad_request
|
8
|
+
|
9
|
+
def initialize(message=nil, parent_bad_request_error=nil)
|
10
|
+
super(message)
|
11
|
+
parent_bad_request = parent_bad_request_error
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Tripod::Errors
|
3
|
+
|
4
|
+
# field not present error.
|
5
|
+
class BadSparqlRequest < StandardError
|
6
|
+
|
7
|
+
attr_accessor :parent_bad_request
|
8
|
+
|
9
|
+
def initialize(message=nil, parent_bad_request_error=nil)
|
10
|
+
super(message)
|
11
|
+
parent_bad_request = parent_bad_request_error
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/tripod/errors.rb
CHANGED
@@ -3,4 +3,9 @@ require 'tripod/errors/field_not_present'
|
|
3
3
|
require 'tripod/errors/resource_not_found'
|
4
4
|
require 'tripod/errors/uri_not_set'
|
5
5
|
require 'tripod/errors/graph_uri_not_set'
|
6
|
-
require 'tripod/errors/
|
6
|
+
require 'tripod/errors/rdf_type_not_set'
|
7
|
+
require 'tripod/errors/validations'
|
8
|
+
require 'tripod/errors/rdf_parse_failed'
|
9
|
+
|
10
|
+
require 'tripod/errors/bad_sparql_request'
|
11
|
+
require 'tripod/errors/bad_data_request'
|
data/lib/tripod/finders.rb
CHANGED
@@ -48,23 +48,26 @@ module Tripod::Finders
|
|
48
48
|
resource
|
49
49
|
end
|
50
50
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
#
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
def
|
66
|
-
|
67
|
-
|
51
|
+
# execute a where clause on this resource.
|
52
|
+
# returns a criteria object
|
53
|
+
def where(sparql_snippet)
|
54
|
+
criteria = Tripod::Criteria.new(self)
|
55
|
+
criteria.where(sparql_snippet)
|
56
|
+
end
|
57
|
+
|
58
|
+
# execute a query to return all objects (restricted by this class's rdf_type if specified)
|
59
|
+
# returns a criteria object
|
60
|
+
def all
|
61
|
+
criteria = Tripod::Criteria.new(self)
|
62
|
+
criteria
|
63
|
+
end
|
64
|
+
|
65
|
+
def count
|
66
|
+
self.all.count
|
67
|
+
end
|
68
|
+
|
69
|
+
def first
|
70
|
+
self.all.first
|
68
71
|
end
|
69
72
|
|
70
73
|
# returns a graph of triples which describe the uris passed in.
|
@@ -75,7 +78,7 @@ module Tripod::Finders
|
|
75
78
|
uris_sparql_str = uris.map{ |u| "<#{u.to_s}>" }.join(" ")
|
76
79
|
|
77
80
|
# Do a big describe statement, and read the results into an in-memory repo
|
78
|
-
triples_string = Tripod::SparqlClient::Query
|
81
|
+
triples_string = Tripod::SparqlClient::Query.describe("DESCRIBE #{uris_sparql_str}")
|
79
82
|
|
80
83
|
RDF::Reader.for(:ntriples).new(triples_string) do |reader|
|
81
84
|
reader.each_statement do |statement|
|
@@ -88,63 +91,5 @@ module Tripod::Finders
|
|
88
91
|
graph
|
89
92
|
end
|
90
93
|
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
# FOLLOWING METHODS NOT PART OF THE PUBLIC API:
|
95
|
-
def self.included(base)
|
96
|
-
|
97
|
-
class << base
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
# create and hydrate the resources identified in uris_and_graphs.
|
102
|
-
# Note: if any of the graphs are not set, those resources can still be constructed, but not persisted back to DB.
|
103
|
-
def create_and_hydrate_resources(uris_and_graphs)
|
104
|
-
|
105
|
-
graph = describe_uris(uris_and_graphs.keys)
|
106
|
-
repo = add_data_to_repository(graph)
|
107
|
-
|
108
|
-
resources = []
|
109
|
-
|
110
|
-
uris_and_graphs.each_pair do |u,g|
|
111
|
-
|
112
|
-
# instantiate a new resource
|
113
|
-
r = self.new(u,g)
|
114
|
-
|
115
|
-
# make a graph of data for this resource's uri
|
116
|
-
data_graph = RDF::Graph.new
|
117
|
-
repo.query( [RDF::URI.new(u), :predicate, :object] ) do |statement|
|
118
|
-
data_graph << statement
|
119
|
-
end
|
120
|
-
|
121
|
-
# use it to hydrate this resource
|
122
|
-
r.hydrate!(:graph => data_graph)
|
123
|
-
r.new_record = false
|
124
|
-
resources << r
|
125
|
-
end
|
126
|
-
|
127
|
-
resources
|
128
|
-
end
|
129
|
-
|
130
|
-
|
131
|
-
# based on the query passed in, build a hash of uris->graphs
|
132
|
-
def select_uris_and_graphs(criteria, opts)
|
133
|
-
select_results = Tripod::SparqlClient::Query.select(criteria)
|
134
|
-
|
135
|
-
uris_and_graphs = {}
|
136
|
-
|
137
|
-
select_results.each do |r|
|
138
|
-
uri_variable = opts[:uri_variable] || 'uri'
|
139
|
-
graph_variable = opts[:graph_variable] || 'graph'
|
140
|
-
uris_and_graphs[ r[uri_variable]["value"] ] = r[graph_variable]["value"]
|
141
|
-
end
|
142
|
-
|
143
|
-
uris_and_graphs
|
144
|
-
end
|
145
|
-
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
94
|
end
|
150
95
|
end
|
data/lib/tripod/persistence.rb
CHANGED
@@ -32,7 +32,7 @@ module Tripod::Persistence
|
|
32
32
|
transaction && transaction.class == Tripod::Persistence::Transaction
|
33
33
|
end
|
34
34
|
|
35
|
-
def self.
|
35
|
+
def self.get_transaction(trans)
|
36
36
|
transaction = nil
|
37
37
|
|
38
38
|
if Tripod::Persistence::Transaction.valid_transaction(trans)
|
@@ -70,7 +70,7 @@ module Tripod::Persistence
|
|
70
70
|
|
71
71
|
raise Tripod::Errors::GraphUriNotSet.new() unless @graph_uri
|
72
72
|
|
73
|
-
transaction = Tripod::Persistence::Transaction.
|
73
|
+
transaction = Tripod::Persistence::Transaction.get_transaction(opts[:transaction])
|
74
74
|
|
75
75
|
if self.valid?
|
76
76
|
|
@@ -114,7 +114,7 @@ module Tripod::Persistence
|
|
114
114
|
# if we get in here, save failed.
|
115
115
|
|
116
116
|
# abort the transaction
|
117
|
-
transaction = Tripod::Persistence::Transaction.
|
117
|
+
transaction = Tripod::Persistence::Transaction.get_transaction(opts[:transaction])
|
118
118
|
transaction.abort() if transaction
|
119
119
|
|
120
120
|
self.class.fail_validate!(self) # throw an exception
|
@@ -126,7 +126,7 @@ module Tripod::Persistence
|
|
126
126
|
|
127
127
|
def destroy(opts={})
|
128
128
|
|
129
|
-
transaction = Tripod::Persistence::Transaction.
|
129
|
+
transaction = Tripod::Persistence::Transaction.get_transaction(opts[:transaction])
|
130
130
|
|
131
131
|
query = "
|
132
132
|
# delete from default graph:
|
data/lib/tripod/resource.rb
CHANGED
@@ -92,9 +92,11 @@ module Tripod::Resource
|
|
92
92
|
other.class == Class ? self <= other : other.is_a?(self)
|
93
93
|
end
|
94
94
|
|
95
|
+
# makes a "field" on this model called rdf_type
|
96
|
+
# and sets a class level _RDF_TYPE variable with the rdf_type passed in.
|
95
97
|
def rdf_type(new_rdf_type)
|
96
98
|
field :rdf_type, RDF.type
|
97
|
-
self._RDF_TYPE = new_rdf_type
|
99
|
+
self._RDF_TYPE = RDF::URI.new(new_rdf_type.to_s)
|
98
100
|
end
|
99
101
|
|
100
102
|
def graph_uri(new_graph_uri)
|
data/lib/tripod/sparql_client.rb
CHANGED
@@ -23,13 +23,8 @@ module Tripod::SparqlClient
|
|
23
23
|
:timeout => Tripod.timeout_seconds,
|
24
24
|
)
|
25
25
|
rescue RestClient::BadRequest => e
|
26
|
-
|
27
|
-
|
28
|
-
# TODO: this is a SPARQL parsing exception. Do something different.
|
29
|
-
raise e
|
30
|
-
else
|
31
|
-
raise e
|
32
|
-
end
|
26
|
+
# just re-raise as a BadSparqlRequest Exception
|
27
|
+
raise Tripod::Errors::BadSparqlRequest.new(e.http_body, e)
|
33
28
|
end
|
34
29
|
end
|
35
30
|
|
@@ -67,6 +62,21 @@ module Tripod::SparqlClient
|
|
67
62
|
return response.body
|
68
63
|
end
|
69
64
|
|
65
|
+
# Executes an ASK +query+ against the SPARQL endpoint.
|
66
|
+
# Executes the +query+ and returns text by default
|
67
|
+
#
|
68
|
+
# @example Run a ASK query
|
69
|
+
# Tripod::SparqlClient::Query.select('ASK <http://foo>')
|
70
|
+
#
|
71
|
+
# @param [ String ] query The query to run
|
72
|
+
# @param [ String ] accept_header The format parameter to send to the database. Valud valid formats are text, xml, json
|
73
|
+
#
|
74
|
+
# @return [ String ] the raw response from the endpoint
|
75
|
+
def self.ask(query, format='text')
|
76
|
+
response = self.query(query, format)
|
77
|
+
return response.body
|
78
|
+
end
|
79
|
+
|
70
80
|
# Executes a CONSTRUCT +query+ against the SPARQL endpoint.
|
71
81
|
# Executes the +query+ and returns ntriples by default
|
72
82
|
#
|
@@ -102,15 +112,37 @@ module Tripod::SparqlClient
|
|
102
112
|
)
|
103
113
|
true
|
104
114
|
rescue RestClient::BadRequest => e
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
115
|
+
# just re-raise as a BadSparqlRequest Exception
|
116
|
+
raise Tripod::Errors::BadSparqlRequest.new(e.http_body, e)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
module Data
|
123
|
+
class DataClient
|
124
|
+
def self.submit(graph_uri, data, method)
|
125
|
+
url = "#{Tripod.data_endpoint}?graph=#{graph_uri}"
|
126
|
+
begin
|
127
|
+
RestClient::Request.execute(
|
128
|
+
:method => method,
|
129
|
+
:url => url,
|
130
|
+
:timeout => Tripod.timeout_seconds,
|
131
|
+
:payload => data
|
132
|
+
)
|
133
|
+
true
|
134
|
+
rescue RestClient::BadRequest => e
|
135
|
+
raise Tripod::Errors::BadDataRequest.new(e.http_body, e)
|
111
136
|
end
|
112
137
|
end
|
113
138
|
end
|
114
139
|
|
140
|
+
def self.append(graph_uri, data)
|
141
|
+
DataClient.submit(graph_uri, data, :post)
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.replace(graph_uri, data)
|
145
|
+
DataClient.submit(graph_uri, data, :put)
|
146
|
+
end
|
115
147
|
end
|
116
148
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Tripod
|
3
|
+
|
4
|
+
class SparqlQueryError < StandardError; end
|
5
|
+
|
6
|
+
class SparqlQuery
|
7
|
+
|
8
|
+
attr_reader :query # the original query string
|
9
|
+
attr_reader :query_type # symbol representing the type (:select, :ask etc)
|
10
|
+
attr_reader :body # the body of the query
|
11
|
+
attr_reader :prefixes # any prefixes the query may have
|
12
|
+
|
13
|
+
cattr_accessor :PREFIX_KEYWORDS
|
14
|
+
@@PREFIX_KEYWORDS = %w(BASE PREFIX)
|
15
|
+
cattr_accessor :KEYWORDS
|
16
|
+
@@KEYWORDS = %w(CONSTRUCT ASK DESCRIBE SELECT)
|
17
|
+
|
18
|
+
def initialize(query_string, parent_query=nil)
|
19
|
+
@query = query_string
|
20
|
+
@parent_query = parent_query
|
21
|
+
|
22
|
+
if self.has_prefixes?
|
23
|
+
@prefixes, @body = self.extract_prefixes
|
24
|
+
else
|
25
|
+
@body = self.query
|
26
|
+
end
|
27
|
+
|
28
|
+
@query_type = get_query_type
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_prefixes?
|
32
|
+
self.class.PREFIX_KEYWORDS.each do |k|
|
33
|
+
return true if /^#{k}/i.match(query)
|
34
|
+
end
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
|
38
|
+
def extract_prefixes
|
39
|
+
i = self.class.KEYWORDS.map {|k| self.query.index(/#{k}/i) || self.query.size+1 }.min
|
40
|
+
p = query[0..i-1]
|
41
|
+
b = query[i..-1]
|
42
|
+
return p.strip, b.strip
|
43
|
+
end
|
44
|
+
|
45
|
+
def as_count_query_str
|
46
|
+
# only allow for selects
|
47
|
+
raise SparqlQueryError.new("Can't turn this into a subquery") unless self.query_type == :select
|
48
|
+
|
49
|
+
count_query = "SELECT COUNT(*) { #{self.body} }"
|
50
|
+
count_query = "#{self.prefixes} #{count_query}" if self.prefixes
|
51
|
+
|
52
|
+
# just returns the string representing the count query for this query.
|
53
|
+
count_query
|
54
|
+
end
|
55
|
+
|
56
|
+
def as_first_query_str
|
57
|
+
# only allow for selects
|
58
|
+
raise SparqlQueryError.new("Can't turn this into a subquery") unless self.query_type == :select
|
59
|
+
|
60
|
+
first_query = "SELECT * { #{self.body} } LIMIT 1"
|
61
|
+
first_query = "#{self.prefixes} #{first_query}" if self.prefixes
|
62
|
+
|
63
|
+
# just returns the string representing the 'first' query for this query.
|
64
|
+
first_query
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def get_query_type
|
70
|
+
if /^CONSTRUCT/i.match(self.body)
|
71
|
+
:construct
|
72
|
+
elsif /^ASK/i.match(self.body)
|
73
|
+
:ask
|
74
|
+
elsif /^DESCRIBE/i.match(self.body)
|
75
|
+
:describe
|
76
|
+
elsif /^SELECT/i.match(self.body)
|
77
|
+
:select
|
78
|
+
else
|
79
|
+
:unknown
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/lib/tripod/version.rb
CHANGED
data/lib/tripod.rb
CHANGED
@@ -45,6 +45,9 @@ module Tripod
|
|
45
45
|
mattr_accessor :query_endpoint
|
46
46
|
@@query_endpoint = 'http://127.0.0.1:3030/tripod/sparql'
|
47
47
|
|
48
|
+
mattr_accessor :data_endpoint
|
49
|
+
@@data_endpoint = 'http://127.0.0.1:3030/tripod/data'
|
50
|
+
|
48
51
|
mattr_accessor :timeout_seconds
|
49
52
|
@@timeout_seconds = 30
|
50
53
|
|
@@ -64,12 +67,14 @@ end
|
|
64
67
|
|
65
68
|
require "tripod/extensions"
|
66
69
|
require "tripod/sparql_client"
|
70
|
+
require "tripod/sparql_query"
|
67
71
|
|
68
72
|
require "tripod/predicates"
|
69
73
|
require "tripod/attributes"
|
70
74
|
require "tripod/errors"
|
71
75
|
require "tripod/repository"
|
72
76
|
require "tripod/fields"
|
77
|
+
require "tripod/criteria"
|
73
78
|
require "tripod/finders"
|
74
79
|
require "tripod/persistence"
|
75
80
|
require "tripod/eager_loading"
|