Class: GRel::Base

Inherits:
Object
  • Object
show all
Includes:
Stardog
Defined in:
lib/grel/base.rb

Overview

Base class for the graph of ruby objects stored in Stardog

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(endpoint, options) ⇒ Base

Builds the graph with the provided connection string and options.

  • endpoint : connection string. localhost:5822 by default.

  • options: hash of options:

Valid options are:

  • user : user name for authentication

  • password : password for authentication

  • validate : should validate integrity constraints

  • db : name of the db to use

Returns the newly built graph object.



20
21
22
23
24
25
26
27
28
# File 'lib/grel/base.rb', line 20

def initialize(endpoint, options) 
  @options = options
  @endpoint = endpoint
  @connection = stardog(endpoint,options)
  @validations = options[:validate] || false
  @dbs = @connection.list_dbs.body["databases"]
  @reasoning = false
  self
end

Instance Attribute Details

#connectionObject

Returns the value of attribute connection.



8
9
10
# File 'lib/grel/base.rb', line 8

def connection
  @connection
end

#db_nameObject (readonly)

Returns the value of attribute db_name.



9
10
11
# File 'lib/grel/base.rb', line 9

def db_name
  @db_name
end

#last_query_contextObject

Returns the value of attribute last_query_context.



8
9
10
# File 'lib/grel/base.rb', line 8

def last_query_context
  @last_query_context
end

#schema_graphObject (readonly)

Returns the value of attribute schema_graph.



9
10
11
# File 'lib/grel/base.rb', line 9

def schema_graph
  @schema_graph
end

Instance Method Details

#all(options = {}) ⇒ Object

Executes the current defined query and returns a list of matching noes from the graph. Nodes will be correctly linked in the returned list. if the option :unlinked is provided with true value, only the top level nodes that has not incoming links will be returned.



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# File 'lib/grel/base.rb', line 323

def all(options = {})
  unlinked = options[:unlinked] || false

  results = run
  nodes = QL.from_bindings_to_nodes(results, @last_query_context, :unlinked => unlinked)
  nodes
  #sets = @last_query_context.query_keys
  #nodes.select do |node|
  #  valid = false
  #  c = 0
  #  while(!valid && c<sets.length)
  #    sets_keys, sets_query = sets[c]
  #    valid = (sets_keys.empty?) || sets_keys.inject(true) do |ac,k|
  #      value = nil
  #      if (sets_query[k].is_a?(Hash) || (sets_query[k].is_a?(Symbol)))
  #        value = ac && node[k]
  #      end
  #      if(value.nil? && @reasoning == true)
  #        value = ac && node.values.include?(sets_query[k])
  #      end
  #      if (value.nil? && sets_query[k].is_a?(String) && sets_query[k].index("@id("))
  #        value = ac && node[k]
  #      end
  #      if(value.nil?)
  #         ac && node[k] == sets_query[k]
  #      else
  #        value
  #      end
  #    end
  #    c += 1
  #  end
  #  valid
  #end
end

#define(*args) ⇒ Object

Defines schema meta data that will be used in the processing of queries if reasoning is activated. It accepts a list of definitions as an argument. Valid definitions are:

  • @subclass definitions

  • @subproperty definitions

  • @domain definitions

  • @range defintions

  • @cardinality definitions

It returns the current graph object.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/grel/base.rb', line 194

def define(*args)
  unless(args.length == 3 && !args.first.is_a?(Array))
    args = args.inject([]) {|a,i| a += i; a }
  end

  args = parse_schema_axioms(args)

  triples = QL.to_turtle(args, true)
  GRel::Debugger.debug "STORING IN SCHEMA #{@schema_graph}"
  GRel::Debugger.debug triples
  GRel::Debugger.debug "IN"
  GRel::Debugger.debug @db_name
  @connection.add(@db_name, triples, @schema_graph, "text/turtle")
  self
end

#first(options = {}) ⇒ Object

Returns only the first node from the list of retrieved nodes in an all query.



372
373
374
# File 'lib/grel/base.rb', line 372

def first(options = {})
  all(options).first
end

#limit(limit) ⇒ Object

Limits how many triples will be returned from the server. The limit refers to triples, not nodes in the graph. It returns the current graph object.



130
131
132
133
# File 'lib/grel/base.rb', line 130

def limit(limit)
  @last_query_context.limit = limit
  self
end

#offset(offset) ⇒ Object

Skip the first offset number of triples in the response returned from the server. The offset refers to triples, not nodes in the graph. It returns the current graph object.



139
140
141
142
# File 'lib/grel/base.rb', line 139

def offset(offset)
  @last_query_context.offset = offset
  self
end

#query(query, options = {}) ⇒ Object

Executes a raw SPARQL DESCRIBE query for the current defined query. It returns the results of the query without any other processing.



378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/grel/base.rb', line 378

def query(query, options = {})
  GRel::Debugger.debug "QUERYING DESCRIBE..."
  GRel::Debugger.debug query
  GRel::Debugger.debug "** LIMIT #{@last_query_context.limit}" if @last_query_context.limit
  GRel::Debugger.debug "** OFFSET #{@last_query_context.offset}" if @last_query_context.offset
  GRel::Debugger.debug "----------------------"
  args = {:describe => true}
  #args = {}
  args[:accept] = options[:accept] if options[:accept]
  args[:offset] = @last_query_context.offset if @last_query_context.offset
  args[:limit] = @last_query_context.limit if @last_query_context.limit
  @connection.query(@db_name,query, args).body
end

#remove(data = nil, options = {}) ⇒ Object

Removes data from the graph of objects. If no arguments are provided, the nodes returned from the last executed query will be removed from the graph. If a graph of objects are provided, the equivalent statements will be removed instead. It returns the current graph object.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/grel/base.rb', line 283

def remove(data = nil, options = {})
  if data
    GRel::Debugger.debug "REMMOVING"
    GRel::Debugger.debug QL.to_turtle(data)
    GRel::Debugger.debug "IN"
    GRel::Debugger.debug @db_name
    @connection.remove(@db_name, QL.to_turtle(data), nil, "text/turtle")
  else
    args = {:describe => true}
    args = {:accept => "application/rdf+xml"}

    sparql = @last_query_context.to_sparql_describe
    triples = @connection.query(@db_name,sparql, args).body

    @connection.remove(@db_name, triples, nil, "application/rdf+xml")
  end
  self
end

#retract_definition(*args) ⇒ Object

Drop definition statements from the schema meta data. It accepts statements equivalent to the ones provided to the define method. It returns the current graph object.



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/grel/base.rb', line 213

def retract_definition(*args)
  unless(args.length == 3 && !args.first.is_a?(Array))
    args = args.inject([]) {|a,i| a += i }
  end

  args = parse_schema_axioms(args)

  triples = QL.to_turtle(args, true)
  GRel::Debugger.debug "REMOVING FROM SCHEMA #{@schema_graph}"
  GRel::Debugger.debug triples
  GRel::Debugger.debug "IN"
  GRel::Debugger.debug @db_name
  @connection.remove(@db_name, triples, @schema_graph, "text/turtle")
  self
end

#retract_rules(rules) ⇒ Object

Removes rules from the graph. It accepts a hash of rules definitions that will be removed. It returns the current graph object.



174
175
176
177
178
179
180
181
182
# File 'lib/grel/base.rb', line 174

def retract_rules(rules)
  rules = QL.to_rules(rules)
  GRel::Debugger.debug "REMOVING FROM SCHEMA #{@schema_graph}"
  GRel::Debugger.debug rules
  GRel::Debugger.debug "IN"
  GRel::Debugger.debug @db_name
  @connection.remove(@db_name, rules, @schema_graph, "text/turtle")
  self
end

#retract_validation(*args) ⇒ Object

Removes a validation from the graph. It accepts a list of validation statements equivalent to the ones accepted by the validate method. It returns the current graph object.



265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/grel/base.rb', line 265

def retract_validation(*args)
  unless(args.length == 3 && !args.first.is_a?(Array))
    args = args.inject([]) {|a,i| a += i }
  end
  triples = QL.to_turtle(args, true)
  GRel::Debugger.debug "REMOVING FROM SCHEMA #{@schema_graph}"
  GRel::Debugger.debug triples
  GRel::Debugger.debug "IN"
  GRel::Debugger.debug @db_name
  @connection.remove_icv(@db_name, triples, "text/turtle")
  self
end

#rules(rules) ⇒ Object

Add some rules to the database. The rules are expressed as a hash map where the body of the rule is the key and the head of the rule is the value. Variables in the rule are expressed as strings starting with the ‘?’ character. Classes and properties are expressed as symbols as usual. If the rules cannot be parsed, an exception will be raised.



161
162
163
164
165
166
167
168
169
# File 'lib/grel/base.rb', line 161

def rules(rules)
  rules = QL.to_rules(rules)
  GRel::Debugger.debug "STORING IN SCHEMA #{@schema_graph}"
  GRel::Debugger.debug rules
  GRel::Debugger.debug "IN"
  GRel::Debugger.debug @db_name
  @connection.add(@db_name, rules, @schema_graph, "application/rdf+xml")
  self
end

#runObject

Exceutes the current query returning the raw response from the server It returns the a list of JSON-LD linked objects.



151
152
153
# File 'lib/grel/base.rb', line 151

def run
  @last_query_context.run
end

#run_tuples(query, options = {}) ⇒ Object

Executes a raw SPARQL SELECT query for the current defined query. It returns the results of the query without any other processing.



394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/grel/base.rb', line 394

def run_tuples(query, options = {})
  GRel::Debugger.debug "QUERYING SELECT..."
  GRel::Debugger.debug query
  GRel::Debugger.debug "** LIMIT #{@last_query_context.limit}" if @last_query_context.limit
  GRel::Debugger.debug "** OFFSET #{@last_query_context.offset}" if @last_query_context.offset
  GRel::Debugger.debug "----------------------"
  args = {}
  args[:accept] = options[:accept] if options[:accept]
  args[:offset] = @last_query_context.offset if @last_query_context.offset
  args[:limit] = @last_query_context.limit if @last_query_context.limit
  @connection.query(@db_name,query, args).body
end

#store(data, db_name = nil) ⇒ Object

Stores a graph of ruby objects encoded as a nested collection of hashes in a database. Arguments:

  • data : objects to be stored.

  • db_name : optional database where this objects will be stored.

It returns the current graph object. if a validation fails, a ValidationError will be raised.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/grel/base.rb', line 80

def store(data, db_name=nil)
  if(db_name)
    with_db(db_name) do
      store(data)
    end
  else
    GRel::Debugger.debug "STORING"
    GRel::Debugger.debug QL.to_turtle(data)
    GRel::Debugger.debug "IN"
    GRel::Debugger.debug @db_name
    res = @connection.add(@db_name, QL.to_turtle(data), nil, "text/turtle")
    if(res == false)
      raise Exception.new("Error storing data, an ICV validation might have been violated")
    end
    res
  end
  self
rescue Stardog::ICVException => ex
  raise ValidationError.new("Error storing objects in the graph. A Validation has failed.", ex)
end

#tuplesObject

Executes the current defined query returning a list of hashes where pairs key,value are bound to the tuple variables in the query hash and retrived values for those variables.



360
361
362
363
364
365
366
367
368
369
# File 'lib/grel/base.rb', line 360

def tuples
  results = run_tuples(@last_query_context.to_sparql_select)
  results["results"]["bindings"].map do |h|
    h.keys.each do |k|
      h[k.to_sym] = QL.from_tuple_binding(h[k])
      h.delete(k)
    end
    h
  end
end

#union(query) ⇒ Object

Adds another pattern to the current query being defined. It accepts a query pattern hash identical to the one accepted by the where method. It returns the current graph object.



118
119
120
121
122
123
124
125
# File 'lib/grel/base.rb', line 118

def union(query)
  union_context = QL::QueryContext.new(self)
  union_context.register_query(query)
  union_context =  QL.to_query(query, union_context)

  @last_query_context.union(union_context)
  self
end

Removes connection to a node in the graph. It accepts a list of node IDs that will be unlinked.



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/grel/base.rb', line 428

def unlink(ids)
  ids = [ids] if(ids.is_a?(String))
  query = QL.unlink_sparql_query(ids)
  results = @connection.query(@db_name, query,{}).body
  triples = results["results"]["bindings"].map do |h|
    "<#{h['S']['value']}> <#{h['P']['value']}> <#{h['O']['value']}>"
  end

  if(triples.length > 0)
    triples = "#{triples.join('.')} ."
    GRel::Debugger.debug "REMMOVING"
    GRel::Debugger.debug triples
    GRel::Debugger.debug "IN"
    GRel::Debugger.debug @db_name
    @connection.remove(@db_name, triples, nil, "text/turtle")
  end
  self
end

#update(new_data, options = {}) ⇒ Object

Replaces the selected triples with a new set of triples provided as an argument in a single atomic operation

Raises:

  • (Exception)


304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/grel/base.rb', line 304

def update(new_data, options = {})
  args = {:describe => true}
  args = {:accept => "application/rdf+xml"}

  sparql = @last_query_context.to_sparql_describe
  triples = @connection.query(@db_name,sparql, args).body

  success = @connection.with_transaction(@db_name) do |txId|
    @connection.remove_in_transaction(@db_name, txId, triples, nil, "application/rdf+xml")
    @connection.add_in_transaction(@db_name, txId, QL.to_turtle(new_data), nil, "text/turtle")
  end
  raise Exception.new("Error updating data") unless success
  self
end

#validate(*args) ⇒ Object

Adds a validation statement to the graph. Validations will be checked in every store operation if validations are activated. A ValidationError exception will be raised if a validation fails. It accepts a list of definitions as an argument. Valid definitions are:

  • @subclass definitions

  • @subproperty definitions

  • @domain definitions

  • @range defintions

  • @cardinality definitions

It returns the current graph object.



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/grel/base.rb', line 240

def validate(*args)
  unless(args.detect{|e| !e.is_a?(Array)})
    args = args.inject([]) {|a,i| a += i; a }
  end

  args = parse_schema_axioms(args)
  additional_triples = []      
  found = args.each_slice(3).detect{|(s,p,o)|  p == :@range && o.is_a?(Class)}
  if(found)
    additional_triples += [found.first, :@type, :"<http://www.w3.org/2002/07/owl#DatatypeProperty>"]
  end


  triples = QL.to_turtle(args + additional_triples, true)
  GRel::Debugger.debug "STORING IN VALIDATIONS #{@schema_graph}"
  GRel::Debugger.debug triples
  GRel::Debugger.debug "IN"
  GRel::Debugger.debug @db_name
  @connection.add_icv(@db_name, triples, "text/turtle")
  self
end

#where(query) ⇒ Object

Builds a query for the graph of objects. The query is expressed as a pattern of nested hashes that will be matched agains the data stored in the graph. Wildcard values and filters can also be added to the query. It returns the current graph object.



107
108
109
110
111
112
# File 'lib/grel/base.rb', line 107

def where(query)
  @last_query_context = QL::QueryContext.new(self)
  @last_query_context.register_query(query)
  @last_query_context = QL.to_query(query, @last_query_context)
  self
end

#with_db(db_name) ⇒ Object

Sets the current Stardog database this graph is connected to. It accepts the name of the database as an argument. If an optional block is provided, operations in the block will be executed in the provided database and the old database will be restored afterwards. It returns the current graph object.



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/grel/base.rb', line 60

def with_db(db_name)
  ensure_db(db_name) do
    old_db_name = @db_name
    @db_name = db_name
    @schema_graph = "#{db_name}:schema"
    if block_given?
      yield
      @db_name = old_db_name
    end
  end
  self
end

#with_reasoning(reasoning = "QL") ⇒ Object

Turns on reasoning in queries. The type of reasoning must be provided as an argument. By default ‘QL’ is provided. Reasoning will remain turned on for all operations in the graph until it is explicitely turned off with the without_reasoning message. It returns the current graph object.



36
37
38
39
40
41
42
43
# File 'lib/grel/base.rb', line 36

def with_reasoning(reasoning="QL")
  @reasoning = true
  @connection = stardog(@endpoint,@options.merge(:reasoning => reasoning))
  @connection.offline_db(@db_name)
  @connection.set_db_options(@db_name, "icv.reasoning.type" => reasoning)
  @connection.online_db(@db_name, 'WAIT')
  self
end

#with_validations(state = true) ⇒ Object

It turns on validations for any insertion in the graph. Validations will remain turned on until they are disabled using the without_validations message. It returns the current graph.



410
411
412
413
414
415
416
417
# File 'lib/grel/base.rb', line 410

def with_validations(state = true)
  @validations = state
  @connection.offline_db(@db_name)
  @connection.set_db_options(@db_name, "icv.enabled" => @validations)
  @connection.online_db(@db_name, 'WAIT')

  self
end

#without_reasoningObject

Turns off reasoning in queries. Reasoning will remain turned off until enabled again with the with_reasoning message. It returns the current graph object.



48
49
50
51
52
# File 'lib/grel/base.rb', line 48

def without_reasoning
  @reasoning = false
  @connection = stardog(@endpoint,@options)
  self
end

#without_validationsObject

It disables validations for any insertion in the graph. Validations will remain turned off until they are enabled again using the with_validations message. It returns the current graph.



422
423
424
# File 'lib/grel/base.rb', line 422

def without_validations
  with_validations(false)
end