grel 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/grel/base.rb +128 -8
- data/lib/grel/ql.rb +10 -0
- data/lib/grel.rb +25 -0
- metadata +2 -2
data/lib/grel/base.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module GRel
|
2
2
|
|
3
|
+
# Base class for the graph of ruby objects stored in Stardog
|
3
4
|
class Base
|
4
5
|
|
5
6
|
include Stardog
|
@@ -7,6 +8,15 @@ module GRel
|
|
7
8
|
attr_accessor :connection, :last_query_context
|
8
9
|
attr_reader :db_name, :schema_graph
|
9
10
|
|
11
|
+
# Builds the graph with the provided connection string and options.
|
12
|
+
# - endpoint : connection string. localhost:5822 by default.
|
13
|
+
# - options: hash of options:
|
14
|
+
# Valid options are:
|
15
|
+
# - user : user name for authentication
|
16
|
+
# - password : password for authentication
|
17
|
+
# - validate : should validate integrity constraints
|
18
|
+
# - db : name of the db to use
|
19
|
+
# Returns the newly built graph object.
|
10
20
|
def initialize(endpoint, options)
|
11
21
|
@options = options
|
12
22
|
@endpoint = endpoint
|
@@ -17,6 +27,12 @@ module GRel
|
|
17
27
|
self
|
18
28
|
end
|
19
29
|
|
30
|
+
# Turns on reasoning in queries.
|
31
|
+
# The type of reasoning must be provided as an argument.
|
32
|
+
# By default 'QL' is provided.
|
33
|
+
# Reasoning will remain turned on for all operations in the graph until it is
|
34
|
+
# explicitely turned off with the +without_reasoning+ message.
|
35
|
+
# It returns the current graph object.
|
20
36
|
def with_reasoning(reasoning="QL")
|
21
37
|
@reasoning = true
|
22
38
|
@connection = stardog(@endpoint,@options.merge(:reasoning => reasoning))
|
@@ -26,12 +42,21 @@ module GRel
|
|
26
42
|
self
|
27
43
|
end
|
28
44
|
|
45
|
+
# Turns off reasoning in queries.
|
46
|
+
# Reasoning will remain turned off until enabled again with the +with_reasoning+ message.
|
47
|
+
# It returns the current graph object.
|
29
48
|
def without_reasoning
|
30
49
|
@reasoning = false
|
31
50
|
@connection = stardog(@endpoint,@options)
|
32
51
|
self
|
33
52
|
end
|
34
53
|
|
54
|
+
# Sets the current Stardog database this graph is connected to.
|
55
|
+
# It accepts the name of the database as an argument.
|
56
|
+
# If an optional block is provided, operations in the block
|
57
|
+
# will be executed in the provided database and the old database
|
58
|
+
# will be restored afterwards.
|
59
|
+
# It returns the current graph object.
|
35
60
|
def with_db(db_name)
|
36
61
|
ensure_db(db_name) do
|
37
62
|
old_db_name = @db_name
|
@@ -46,6 +71,12 @@ module GRel
|
|
46
71
|
end
|
47
72
|
|
48
73
|
|
74
|
+
# Stores a graph of ruby objects encoded as a nested collection of hashes in a database.
|
75
|
+
# Arguments:
|
76
|
+
# - data : objects to be stored.
|
77
|
+
# - db_name : optional database where this objects will be stored.
|
78
|
+
# It returns the current graph object.
|
79
|
+
# if a validation fails, a ValidationError will be raised.
|
49
80
|
def store(data, db_name=nil)
|
50
81
|
if(db_name)
|
51
82
|
with_db(db_name) do
|
@@ -64,6 +95,11 @@ module GRel
|
|
64
95
|
end
|
65
96
|
|
66
97
|
|
98
|
+
# Builds a query for the graph of objects.
|
99
|
+
# The query is expressed as a pattern of nested hashes that will be matched agains the data
|
100
|
+
# stored in the graph.
|
101
|
+
# Wildcard values and filters can also be added to the query.
|
102
|
+
# It returns the current graph object.
|
67
103
|
def where(query)
|
68
104
|
@last_query_context = QL::QueryContext.new(self)
|
69
105
|
@last_query_context.register_query(query)
|
@@ -71,6 +107,10 @@ module GRel
|
|
71
107
|
self
|
72
108
|
end
|
73
109
|
|
110
|
+
# Adds another pattern to the current query being defined.
|
111
|
+
# It accepts a query pattern hash identical to the one accepted by the
|
112
|
+
# +where+ method.
|
113
|
+
# It returns the current graph object.
|
74
114
|
def union(query)
|
75
115
|
union_context = QL::QueryContext.new(self)
|
76
116
|
union_context.register_query(query)
|
@@ -80,25 +120,44 @@ module GRel
|
|
80
120
|
self
|
81
121
|
end
|
82
122
|
|
123
|
+
# Limits how many triples will be returned from the server.
|
124
|
+
# The limit refers to triples, not nodes in the graph.
|
125
|
+
# It returns the current graph object.
|
83
126
|
def limit(limit)
|
84
127
|
@last_query_context.limit = limit
|
85
128
|
self
|
86
129
|
end
|
87
130
|
|
131
|
+
# Skip the first offset number of triples in the response returned from
|
132
|
+
# the server.
|
133
|
+
# The offset refers to triples, not nodes in the graph.
|
134
|
+
# It returns the current graph object.
|
88
135
|
def offset(offset)
|
89
136
|
@last_query_context.offset = offset
|
90
137
|
self
|
91
138
|
end
|
92
|
-
|
93
|
-
def order(order)
|
94
|
-
@last_query_context.order = order
|
95
|
-
self
|
96
|
-
end
|
97
|
-
|
139
|
+
|
140
|
+
# def order(order)
|
141
|
+
# @last_query_context.order = order
|
142
|
+
# self
|
143
|
+
# end
|
144
|
+
|
145
|
+
# Exceutes the current query returning the raw response from the server
|
146
|
+
# It returns the a list of JSON-LD linked objects.
|
98
147
|
def run
|
99
148
|
@last_query_context.run
|
100
149
|
end
|
101
150
|
|
151
|
+
# Defines schema meta data that will be used in the processing of queries
|
152
|
+
# if reasoning is activated.
|
153
|
+
# It accepts a list of definitions as an argument.
|
154
|
+
# Valid definitions are:
|
155
|
+
# - @subclass definitions
|
156
|
+
# - @subproperty definitions
|
157
|
+
# - @domain definitions
|
158
|
+
# - @range defintions
|
159
|
+
# - @cardinality definitions
|
160
|
+
# It returns the current graph object.
|
102
161
|
def define(*args)
|
103
162
|
unless(args.length == 3 && !args.first.is_a?(Array))
|
104
163
|
args = args.inject([]) {|a,i| a += i; a }
|
@@ -115,13 +174,17 @@ module GRel
|
|
115
174
|
self
|
116
175
|
end
|
117
176
|
|
177
|
+
# Drop definition statements from the schema meta data.
|
178
|
+
# It accepts statements equivalent to the ones provided to the +define+ method.
|
179
|
+
# It returns the current graph object.
|
118
180
|
def retract_definition(*args)
|
119
181
|
unless(args.length == 3 && !args.first.is_a?(Array))
|
120
182
|
args = args.inject([]) {|a,i| a += i }
|
121
183
|
end
|
122
|
-
additional_triples = []
|
123
184
|
|
124
|
-
|
185
|
+
args = parse_schema_axioms(args)
|
186
|
+
|
187
|
+
triples = QL.to_turtle(args, true)
|
125
188
|
GRel::Debugger.debug "REMOVING FROM SCHEMA #{@schema_graph}"
|
126
189
|
GRel::Debugger.debug triples
|
127
190
|
GRel::Debugger.debug "IN"
|
@@ -130,6 +193,17 @@ module GRel
|
|
130
193
|
self
|
131
194
|
end
|
132
195
|
|
196
|
+
# Adds a validation statement to the graph.
|
197
|
+
# Validations will be checked in every +store+ operation if validations are activated.
|
198
|
+
# A ValidationError exception will be raised if a validation fails.
|
199
|
+
# It accepts a list of definitions as an argument.
|
200
|
+
# Valid definitions are:
|
201
|
+
# - @subclass definitions
|
202
|
+
# - @subproperty definitions
|
203
|
+
# - @domain definitions
|
204
|
+
# - @range defintions
|
205
|
+
# - @cardinality definitions
|
206
|
+
# It returns the current graph object.
|
133
207
|
def validate(*args)
|
134
208
|
unless(args.detect{|e| !e.is_a?(Array)})
|
135
209
|
args = args.inject([]) {|a,i| a += i; a }
|
@@ -152,6 +226,9 @@ module GRel
|
|
152
226
|
self
|
153
227
|
end
|
154
228
|
|
229
|
+
# Removes a validation from the graph.
|
230
|
+
# It accepts a list of validation statements equivalent to the ones accepted by the +validate+ method.
|
231
|
+
# It returns the current graph object.
|
155
232
|
def retract_validation(*args)
|
156
233
|
unless(args.length == 3 && !args.first.is_a?(Array))
|
157
234
|
args = args.inject([]) {|a,i| a += i }
|
@@ -165,6 +242,11 @@ module GRel
|
|
165
242
|
self
|
166
243
|
end
|
167
244
|
|
245
|
+
# Removes data from the graph of objects.
|
246
|
+
# If no arguments are provided, the nodes returned from the last executed query will
|
247
|
+
# be removed from the graph.
|
248
|
+
# If a graph of objects are provided, the equivalent statements will be removed instead.
|
249
|
+
# It returns the current graph object.
|
168
250
|
def remove(data = nil, options = {})
|
169
251
|
if data
|
170
252
|
GRel::Debugger.debug "REMMOVING"
|
@@ -184,6 +266,10 @@ module GRel
|
|
184
266
|
self
|
185
267
|
end
|
186
268
|
|
269
|
+
# Executes the current defined query and returns a list of matching noes from the graph.
|
270
|
+
# Nodes will be correctly linked in the returned list.
|
271
|
+
# if the option +:unlinked+ is provided with true value, only the top level nodes that has not incoming links
|
272
|
+
# will be returned.
|
187
273
|
def all(options = {})
|
188
274
|
unlinked = options[:unlinked] || false
|
189
275
|
|
@@ -219,6 +305,8 @@ module GRel
|
|
219
305
|
#end
|
220
306
|
end
|
221
307
|
|
308
|
+
# Executes the current defined query returning a list of hashes where pairs key,value
|
309
|
+
# are bound to the tuple variables in the query hash and retrived values for those variables.
|
222
310
|
def tuples
|
223
311
|
results = run_tuples(@last_query_context.to_sparql_select)
|
224
312
|
results["results"]["bindings"].map do |h|
|
@@ -230,10 +318,13 @@ module GRel
|
|
230
318
|
end
|
231
319
|
end
|
232
320
|
|
321
|
+
# Returns only the first node from the list of retrieved nodes in an all query.
|
233
322
|
def first(options = {})
|
234
323
|
all(options).first
|
235
324
|
end
|
236
325
|
|
326
|
+
# Executes a raw SPARQL DESCRIBE query for the current defined query.
|
327
|
+
# It returns the results of the query without any other processing.
|
237
328
|
def query(query, options = {})
|
238
329
|
GRel::Debugger.debug "QUERYING DESCRIBE..."
|
239
330
|
GRel::Debugger.debug query
|
@@ -247,6 +338,8 @@ module GRel
|
|
247
338
|
@connection.query(@db_name,query, args).body
|
248
339
|
end
|
249
340
|
|
341
|
+
# Executes a raw SPARQL SELECT query for the current defined query.
|
342
|
+
# It returns the results of the query without any other processing.
|
250
343
|
def run_tuples(query, options = {})
|
251
344
|
GRel::Debugger.debug "QUERYING SELECT..."
|
252
345
|
GRel::Debugger.debug query
|
@@ -260,6 +353,9 @@ module GRel
|
|
260
353
|
@connection.query(@db_name,query, args).body
|
261
354
|
end
|
262
355
|
|
356
|
+
# It turns on validations for any insertion in the graph.
|
357
|
+
# Validations will remain turned on until they are disabled using the +without_validations+ message.
|
358
|
+
# It returns the current graph.
|
263
359
|
def with_validations(state = true)
|
264
360
|
@validations = state
|
265
361
|
@connection.offline_db(@db_name)
|
@@ -269,10 +365,34 @@ module GRel
|
|
269
365
|
self
|
270
366
|
end
|
271
367
|
|
368
|
+
# It disables validations for any insertion in the graph.
|
369
|
+
# Validations will remain turned off until they are enabled again using the +with_validations+ message.
|
370
|
+
# It returns the current graph.
|
272
371
|
def without_validations
|
273
372
|
with_validations(false)
|
274
373
|
end
|
275
374
|
|
375
|
+
# Removes connection to a node in the graph.
|
376
|
+
# It accepts a list of node IDs that will be unlinked.
|
377
|
+
def unlink(ids)
|
378
|
+
ids = [ids] if(ids.is_a?(String))
|
379
|
+
query = QL.unlink_sparql_query(ids)
|
380
|
+
results = @connection.query(@db_name, query,{}).body
|
381
|
+
triples = results["results"]["bindings"].map do |h|
|
382
|
+
"<#{h['S']['value']}> <#{h['P']['value']}> <#{h['O']['value']}>"
|
383
|
+
end
|
384
|
+
|
385
|
+
if(triples.length > 0)
|
386
|
+
triples = "#{triples.join('.')} ."
|
387
|
+
GRel::Debugger.debug "REMMOVING"
|
388
|
+
GRel::Debugger.debug triples
|
389
|
+
GRel::Debugger.debug "IN"
|
390
|
+
GRel::Debugger.debug @db_name
|
391
|
+
@connection.remove(@db_name, triples, nil, "text/turtle")
|
392
|
+
end
|
393
|
+
self
|
394
|
+
end
|
395
|
+
|
276
396
|
private
|
277
397
|
|
278
398
|
def ensure_db(db_name)
|
data/lib/grel/ql.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
module GRel
|
2
2
|
module QL
|
3
|
+
|
4
|
+
def self.unlink_sparql_query(ids)
|
5
|
+
conditions = ids.map do |id|
|
6
|
+
id = "@id(#{id})" if id && id.is_a?(String) && id.index("@id(").nil?
|
7
|
+
id = QL.to_query(id)
|
8
|
+
"(?S = #{id} && isIRI(?O) && ?P != <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>) || ?O = #{id}"
|
9
|
+
end
|
10
|
+
"SELECT ?S ?P ?O WHERE { ?S ?P ?O . FILTER (#{conditions.join(' || ')}) } "
|
11
|
+
end
|
12
|
+
|
3
13
|
def self.to_id(obj)
|
4
14
|
if(obj =~ ID_REGEX)
|
5
15
|
"<http://grel.org/ids/id/#{URI.encode(ID_REGEX.match(obj)[1])}>"
|
data/lib/grel.rb
CHANGED
@@ -4,6 +4,8 @@ require 'uri'
|
|
4
4
|
require 'securerandom'
|
5
5
|
|
6
6
|
class Array
|
7
|
+
# When using an array of arrays to hold list of triples,
|
8
|
+
# returns the first triple subject.
|
7
9
|
def triples_id
|
8
10
|
self.first.first
|
9
11
|
end
|
@@ -11,6 +13,8 @@ end
|
|
11
13
|
|
12
14
|
module GRel
|
13
15
|
|
16
|
+
# Exception raised to signal a validation error due to a
|
17
|
+
# Stardog ICV.
|
14
18
|
class ValidationError < Stardog::ICVException
|
15
19
|
attr_accessor :icv_exception
|
16
20
|
def initialize(msg, exception)
|
@@ -21,19 +25,25 @@ module GRel
|
|
21
25
|
|
22
26
|
DEBUG = ENV["GREL_DEBUG"] || false
|
23
27
|
|
28
|
+
# Wrapper for the debugging logger method.
|
24
29
|
class Debugger
|
25
30
|
def self.debug(msg)
|
26
31
|
puts msg if DEBUG
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
35
|
+
# Common namespace for all URIs generated by GRel.
|
30
36
|
NAMESPACE = "http://grel.org/vocabulary#"
|
37
|
+
# Used to match valid ID strings
|
31
38
|
ID_REGEX = /^\@id\((\w+)\)$/
|
39
|
+
# A URI denoting a ruby nil value
|
32
40
|
NIL = "\"http://www.w3.org/1999/02/22-rdf-syntax-ns#nil\""
|
33
41
|
BNODE = "BNODE"
|
34
42
|
|
43
|
+
# XML Scheam NonNegativeInteger type
|
35
44
|
class NonNegativeInteger
|
36
45
|
|
46
|
+
# Just wraps a numeric type
|
37
47
|
def initialize(number)
|
38
48
|
@number = number
|
39
49
|
end
|
@@ -49,25 +59,40 @@ module GRel
|
|
49
59
|
|
50
60
|
end
|
51
61
|
|
62
|
+
# RDF Blank nodes
|
52
63
|
class BlankId
|
53
64
|
|
65
|
+
# The ID of the blank node.
|
54
66
|
attr_reader :blank_id
|
55
67
|
|
68
|
+
# Creates a new BlankId object with an unique ID for
|
69
|
+
# this execution.
|
56
70
|
def initialize
|
57
71
|
@blank_id = BlankId.next_id
|
58
72
|
end
|
59
73
|
|
74
|
+
# Unique IDs generator.
|
60
75
|
def self.next_id
|
61
76
|
next_id = (@counter ||= 0)
|
62
77
|
@counter += 1
|
63
78
|
next_id
|
64
79
|
end
|
65
80
|
|
81
|
+
# Turtle represenation of the blank node.
|
66
82
|
def to_s
|
67
83
|
"_:#{@blank_id}"
|
68
84
|
end
|
69
85
|
end
|
70
86
|
|
87
|
+
# Creates a new graph object connected to the provided Stardog server.
|
88
|
+
# Arguments:
|
89
|
+
# - name : connection string. localhost:5822 by default.
|
90
|
+
# - options: hash of options:
|
91
|
+
# + user : user name for authentication
|
92
|
+
# + password : password for authentication
|
93
|
+
# + validate : should validate integrity constraints
|
94
|
+
# + db : name of the db to use
|
95
|
+
# Returns the newly built graph object.
|
71
96
|
def graph(name='http://localhost:5822/',options = {})
|
72
97
|
options[:user] ||= "admin"
|
73
98
|
options[:password] ||= "admin"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: stardog-rb
|