class RDF::Sesame::Repository

A repository on a Sesame 2.0-compatible HTTP server.

Instances of this class represent RDF repositories on Sesame-compatible servers.

This class implements the [`:Repository`] interface; refer to the relevant RDF.rb API documentation for further usage instructions.

[RDF::Repository]: rdf.rubyforge.org/RDF/Repository.html

@example Opening a Sesame repository (1)

url = "http://localhost:8080/openrdf-sesame/repositories/SYSTEM"
repository = RDF::Sesame::Repository.new(url)

@example Opening a Sesame repository (2)

server = RDF::Sesame::Server.new("http://localhost:8080/openrdf-sesame")
repository = RDF::Sesame::Repository.new(:server => server, :id => :SYSTEM)

@example Opening a Sesame repository (3)

server = RDF::Sesame::Server.new("http://localhost:8080/openrdf-sesame")
repository = server.repository(:SYSTEM)

@see www.openrdf.org/doc/sesame2/system/ch08.html @see rdf.rubyforge.org/RDF/Repository.html

Constants

MAX_LENGTH_GET_QUERY

Maximum length for GET query

Attributes

context[R]

@return [String,Array]

id[R]

@return [String]

readable[R]

@return [String]

server[R]

@return [Server]

title[R]

@return [String]

writeble[R]

@return [String]

Public Class Methods

new(url_or_options, &block) click to toggle source

Initializes this `Repository` instance.

@overload initialize(url)

@param  [String, URI, RDF::URI] url
@yield  [repository]
@yieldparam [Repository]

@overload initialize(options = {})

@param  [Hash{Symbol => Object}] options
@option options [Server] :server (nil)
@option options [String] :id (nil)
@option options [String] :title (nil)
@yield  [repository]
@yieldparam [Repository]
Calls superclass method
# File lib/rdf/sesame/repository.rb, line 66
def initialize(url_or_options, &block)
  options = {}
  case url_or_options
    when String, RDF::URI, URI
      pathname = Pathname.new(url_or_options.to_s)
      @server = Server.new(pathname.parent.parent.to_s)
      @id = pathname.basename.to_s

    when Hash
      raise ArgumentError, "missing options[:server]" unless url_or_options.has_key?(:server)
      raise ArgumentError, "missing options[:id]"     unless url_or_options.has_key?(:id)
      options    = url_or_options.dup
      @server    = options.delete(:server)
      @id        = options.delete(:id)
      @readable  = options.delete(:readable)
      @writable  = options.delete(:writable)

    else
      raise ArgumentError, "expected String, RDF::URI or Hash, but got #{url_or_options.inspect}"
  end

  super(options)
end

Private Class Methods

parse_json(json) click to toggle source
# File lib/rdf/sesame/repository.rb, line 503
def self.parse_json(json)
  require 'json' unless defined?(::JSON)
  json = JSON.parse(json.to_s) unless json.is_a?(Hash)
end
parse_json_bindings(json, nodes = {}) click to toggle source

@param [String, Hash] json @return [<RDF::Query::Solutions>] @see www.w3.org/TR/rdf-sparql-json-res/#results

# File lib/rdf/sesame/repository.rb, line 519
def self.parse_json_bindings(json, nodes = {})
  json = self.parse_json(json)

  case
    when json['boolean']
      json['boolean']
    when json['results']
      solutions = RDF::Query::Solutions()
      json['results']['bindings'].each do |row|
        row = row.inject({}) do |cols, (name, value)|
          cols.merge(name.to_sym => parse_json_value(value))
        end
        solutions << RDF::Query::Solution.new(row)
      end
      solutions
  end
end
parse_json_value(value, nodes = {}) click to toggle source

@param [Hash{String => String}] value @return [RDF::Value] @see www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results

# File lib/rdf/sesame/repository.rb, line 541
def self.parse_json_value(value, nodes = {})
  case value['type'].to_sym
    when :bnode
      nodes[id = value['value']] ||= RDF::Node.new(id)
    when :uri
      RDF::URI.new(value['value'])
    when :literal
      RDF::Literal.new(value['value'], :language => value['xml:lang'])
    when :'typed-literal'
      RDF::Literal.new(value['value'], :datatype => value['datatype'])
    else nil
  end
end
parse_xml(xml) click to toggle source
# File lib/rdf/sesame/repository.rb, line 508
def self.parse_xml(xml)
  xml.force_encoding(::Encoding::UTF_8) if xml.respond_to?(:force_encoding)
  require 'rexml/document' unless defined?(::REXML::Document)
  xml = REXML::Document.new(xml).root unless xml.is_a?(REXML::Element)
  xml
end
parse_xml_bindings(xml, nodes = {}) click to toggle source

@param [String, REXML::Element] xml @return [<RDF::Query::Solutions>] @see www.w3.org/TR/rdf-sparql-json-res/#results

# File lib/rdf/sesame/repository.rb, line 559
def self.parse_xml_bindings(xml, nodes = {})
  xml = self.parse_xml(xml)

  case
    when boolean = xml.elements['boolean']
      boolean.text == 'true'
    when results = xml.elements['results']
      solutions = RDF::Query::Solutions()
      results.elements.each do |result|
        row = {}
        result.elements.each do |binding|
          name = binding.attributes['name'].to_sym
          value = binding.select { |node| node.kind_of?(::REXML::Element) }.first
          row[name] = parse_xml_value(value, nodes)
        end
        solutions << RDF::Query::Solution.new(row)
      end
      solutions
  end
end
parse_xml_value(value, nodes = {}) click to toggle source

@param [REXML::Element] value @return [RDF::Value] @see www.w3.org/TR/rdf-sparql-json-res/#variable-binding-results

# File lib/rdf/sesame/repository.rb, line 584
def self.parse_xml_value(value, nodes = {})
  case value.name.to_sym
    when :bnode
      nodes[id = value.text] ||= RDF::Node.new(id)
    when :uri
      RDF::URI.new(value.text)
    when :literal
      RDF::Literal.new(value.text, {
        :language => value.attributes['xml:lang'],
        :datatype => value.attributes['datatype'],
      })
    else nil
  end
end

Public Instance Methods

clear(options = {}) click to toggle source

# Clear all statements from the repository. @see RDF::Mutable#clear @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e304

@param [Hash] options @option options [String] :subject Match a specific subject @option options [String] :predicate Match a specific predicate @option options [String] :object Match a specific object @option options [String] :graph_name Match a specific graph name. @return [void]

# File lib/rdf/sesame/repository.rb, line 389
def clear(options = {})
  parameters = {}
  { :subject => :subj, :predicate => :pred, :object => :obj, :graph_name => :context }.each do |option_key, parameter_key|
    parameters.merge! parameter_key => RDF::NTriples.serialize(RDF::URI.new(options[option_key])) if options.has_key?(option_key)
  end
  response = server.delete(path(:statements, statements_options.merge(parameters)))
  response.code == "204"
end
count() click to toggle source

@see RDF::Countable#count @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e569

# File lib/rdf/sesame/repository.rb, line 164
def count
  response = server.get(path(:size, statements_options))
  begin
    size = response.body
    size.to_i
  rescue
    0
  end
end
durable?() click to toggle source

@see RDF::Durable#durable?

# File lib/rdf/sesame/repository.rb, line 151
def durable?
  true # TODO: would need to query the SYSTEM repository for this information
end
each()
Alias for: each_statement
each_statement() { |statement| ... } click to toggle source

@see RDF::Enumerable#each_statement @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e304

# File lib/rdf/sesame/repository.rb, line 241
def each_statement
  return enum_statement unless block_given?

  # Each context will trigger a query that will be parsed with a NTriples::Reader.
  # This is for performance. Otherwise only one query with TriG::Reader will be
  # necessary

  ['null', *graph_names].uniq.each do |context|
    query = {}
    query.merge!(:context => serialize_context(context)) if context
    response = server.get(path(:statements, query), 'Accept' => 'text/plain')
    RDF::NTriples::Reader.new(response.body).each_statement do |statement|
      statement.graph_name = context
      yield statement
    end
  end
end
Also aliased as: each
empty?() click to toggle source

@see RDF::Countable#empty?

# File lib/rdf/sesame/repository.rb, line 157
def empty?
  count.zero?
end
graph_names(unique: true) click to toggle source

Returns all unique RDF graph names, other than the default graph.

@param unique (true) @return [Array<RDF::Resource>] @see each_graph @see enum_graph @since 2.0

# File lib/rdf/sesame/repository.rb, line 269
def graph_names(unique: true)
  fetch_graph_names
end
has_object?(value) click to toggle source

Returns `true` if `self` contains the given RDF object term.

@param [RDF::Term] value @return [Boolean]

# File lib/rdf/sesame/repository.rb, line 234
def has_object?(value)
  !first([nil, nil, value]).nil?
end
has_predicate?(value) click to toggle source

Returns `true` if `self` contains the given RDF predicate term.

@param [RDF::URI] value @return [Boolean]

# File lib/rdf/sesame/repository.rb, line 225
def has_predicate?(value)
  !first([nil, value, nil]).nil?
end
has_quad?(quad) click to toggle source

@see RDF::Enumerable#has_quad?

# File lib/rdf/sesame/repository.rb, line 199
def has_quad?(quad)
  has_statement?(RDF::Statement.new(quad[0], quad[1], quad[2], :graph_name => quad[3]))
end
has_statement?(statement) click to toggle source

@see RDF::Enumerable#has_statement? @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e304

# File lib/rdf/sesame/repository.rb, line 206
def has_statement?(statement)
  response = server.get(path(:statements, statement), 'Accept' => 'text/plain')
  !response.body.empty?
end
has_subject?(value) click to toggle source

Returns `true` if `self` contains the given RDF subject term.

@param [RDF::Resource] value @return [Boolean]

# File lib/rdf/sesame/repository.rb, line 216
def has_subject?(value)
  !first([value, nil, nil]).nil?
end
has_triple?(triple) click to toggle source

@see RDF::Enumerable#has_triple?

# File lib/rdf/sesame/repository.rb, line 193
def has_triple?(triple)
  has_statement?(RDF::Statement.from(triple))
end
namespaces() click to toggle source

Returns all namespaces on this Sesame repository.

@return [Hash{Symbol => RDF::URI}] @see repository @see each_repository @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e204

# File lib/rdf/sesame/repository.rb, line 181
def namespaces
  require 'json' unless defined?(::JSON)

  response = server.get(path(:namespaces), Server::ACCEPT_JSON)
  json = ::JSON.parse(response.body)
  json['results']['bindings'].each_with_object({}) do |binding, namespaces|
    namespaces[binding['prefix']['value'].to_sym] = RDF::Vocabulary.new(binding['namespace']['value'])
  end
end
nodes() click to toggle source

A mapping of blank node results for this client @private

# File lib/rdf/sesame/repository.rb, line 136
def nodes
  @nodes ||= {}
end
path(path = nil, query = {}) click to toggle source

Returns the server-relative path for the given repository-relative `path`.

@param [String, to_s] path @param [Hash, RDF::Statement] query @return [String]

# File lib/rdf/sesame/repository.rb, line 111
def path(path = nil, query = {})
  url =  RDF::URI.new(path ? "repositories/#{@id}/#{path}" : "repositories/#{@id}")
  unless query.nil?
    case query
      when RDF::Statement
        writer = RDF::NTriples::Writer.new
        q  = {
          :subj    => writer.format_term(query.subject),
          :pred    => writer.format_term(query.predicate),
          :obj     => writer.format_term(query.object)
        }
        q.merge!(:context => writer.format_term(query.graph_name)) if query.has_graph?
        url.query_values = q
      when Hash
        url.query_values = query unless query.empty?
    end
  end
  return url.to_s
end
raw_query(query, queryLn = 'sparql', options={}, &block) click to toggle source

Returns all statements of the given query when the query is a READ query. Execute a WRITE query and returns the status of the query.

@private @param [String, to_s] query @param [String, to_s] queryLn @return [RDF::Enumerator, Boolean]

# File lib/rdf/sesame/repository.rb, line 303
def raw_query(query, queryLn = 'sparql', options={}, &block)
  options = { infer: true }.merge(options)

  response = if query =~ /\b(delete|insert)\b/i
    write_query(query, queryLn, options)
  else
    read_query(query, queryLn, options)
  end
end
read_query(query, queryLn, options) { |s| ... } click to toggle source

Returns all statements of the given query.

@private @param [String, to_s] query @param [String, to_s] queryLn @return [RDF::Enumerator]

# File lib/rdf/sesame/repository.rb, line 320
def read_query(query, queryLn, options)
  if queryLn == 'sparql' and options[:format].nil? and query =~ /\bconstruct\b/i
    options[:format] = Server::ACCEPT_NTRIPLES
  end

  options[:format] = Server::ACCEPT_JSON unless options[:format]
  options[:parsing] = :full unless options[:parsing]

  parameters = { :queryLn => queryLn, :infer => options[:infer] }

  response = server.post(
    encode_url_parameters(path, parameters),
    query,
    Server::CONTENT_TYPE_SPARQL_QUERY.merge(options[:format])
  )

  results = if (options[:parsing] == :full)
    parse_response(response)
  else
    raw_parse_response(response)
  end

  if block_given?
    results.each {|s| yield s }
  else
    results
  end
end
set_context(*context) click to toggle source

Set a global context that will be used for any statements request

@param context the context(s) to use

# File lib/rdf/sesame/repository.rb, line 373
def set_context(*context)
  options||={}
  @context = serialize_context(context)
end
sparql_query(query, options={}, &block) click to toggle source

Run a raw SPARQL query.

@overload sparql_query(query) {|solution| … }

@yield solution
@yieldparam [RDF::Query::Solution] solution
@yieldreturn [void]
@return [void]

@overload sparql_query(pattern)

@return [Enumerator<RDF::Query::Solution>]

@param [String] query The query to run. @param [Hash{Symbol => Object}] options

The query options (see build_query).

@return [void]

@see build_query

# File lib/rdf/sesame/repository.rb, line 290
def sparql_query(query, options={}, &block)
  raw_query(query, 'sparql', options, &block)
end
supports?(feature) click to toggle source

@see RDF::Repository#supports?

Calls superclass method
# File lib/rdf/sesame/repository.rb, line 142
def supports?(feature)
  case feature.to_sym
    when :graph_name then true # statement contexts / named graphs
    else super
  end
end
uri(relative_path = nil)
Alias for: url
url(relative_path = nil) click to toggle source

@example Getting a Sesame server's protocol URL

server.url(:protocol) #=> "http://localhost:8080/openrdf-sesame/protocol"

@param [String, to_s] path @return [String]

# File lib/rdf/sesame/repository.rb, line 101
def url(relative_path = nil)
  self.server.url(path(relative_path))
end
Also aliased as: uri
write_query(query, queryLn, options) click to toggle source

Execute a WRITE query against the repository. Returns true if the query was succesful.

@private @param [String, to_s] query @param [String, to_s] queryLn @param [Hash] options @return [Boolean]

# File lib/rdf/sesame/repository.rb, line 358
def write_query(query, queryLn, options)
  parameters = { infer: options[:infer] }

  response = server.post(
    encode_url_parameters(path(:statements), parameters),
    query,
    Server::CONTENT_TYPE_SPARQL_UPDATE
  )

  response.code == "204"
end

Protected Instance Methods

delete_statement(statement) click to toggle source

@private @see RDF::Mutable#delete @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e304

# File lib/rdf/sesame/repository.rb, line 443
def delete_statement(statement)
  response = server.delete(path(:statements, statement))
  response.code == "204"
end
delete_statements(statements) click to toggle source

@private @see RDF::Mutable#delete

Optimization to remove multiple statements in one query

# File lib/rdf/sesame/repository.rb, line 453
def delete_statements(statements)
  data = "DELETE DATA { #{statements_to_text_plain(statements)} }"
  write_query data, 'sparql', {}
end
insert_statement(statement) click to toggle source

@private @see RDF::Mutable#insert @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e304

# File lib/rdf/sesame/repository.rb, line 425
def insert_statement(statement)
  insert_statements([statement])
end
insert_statements(statements) click to toggle source

@private @see RDF::Mutable#insert @see www.openrdf.org/doc/sesame2/system/ch08.html#d0e304

# File lib/rdf/sesame/repository.rb, line 433
def insert_statements(statements)
  data = statements_to_text_plain(statements)
  response = server.post(path(:statements, statements_options), data, Server::CONTENT_TYPE_TEXT)
  response.code == "204"
end
query_pattern(pattern, options = {}) { |statement| ... } click to toggle source

@private @see RDF::Queryable#query

# File lib/rdf/sesame/repository.rb, line 403
def query_pattern(pattern, options = {}, &block)
  writer = RDF::NTriples::Writer.new
  query = {}
  query.merge!(:context => writer.format_term(pattern.graph_name)) if pattern.has_graph?
  query.merge!(:subj => writer.format_term(pattern.subject)) unless pattern.subject.is_a?(RDF::Query::Variable) || pattern.subject.nil?
  query.merge!(:pred => writer.format_term(pattern.predicate)) unless pattern.predicate.is_a?(RDF::Query::Variable) || pattern.predicate.nil?
  query.merge!(:obj => writer.format_term(pattern.object)) unless pattern.object.is_a?(RDF::Query::Variable) || pattern.object.nil?
  response = server.get(path(:statements, query), Server::ACCEPT_NTRIPLES)
  RDF::NTriples::Reader.new(response.body).each_statement do |statement|
    statement.graph_name = pattern.graph_name
    yield statement if block_given?
  end
end

Private Instance Methods

encode_url_parameters(path, parameters) click to toggle source

@private

Encode in the URL parameters

# File lib/rdf/sesame/repository.rb, line 644
def encode_url_parameters(path, parameters)
  params = Addressable::URI.form_encode(parameters).gsub("+", "%20").to_s
  url = Addressable::URI.parse(path)

  unless url.normalize.query.nil?
    url.query = [url.query, params].compact.join('&')
  else
    url.query = [url.query, params].compact.join('?')
  end

  url
end
fetch_graph_names() click to toggle source

@private

Fetch the graph names from SESAME API

# File lib/rdf/sesame/repository.rb, line 660
def fetch_graph_names
  require 'json' unless defined?(::JSON)

  response = server.get(path(:contexts), Server::ACCEPT_JSON)
  json = ::JSON.parse(response.body)

  json['results']['bindings'].map do |binding|
    binding['contextID']
  end
  .map do |context_id|
    case context_id['type'].to_s.to_sym
    when :bnode
      RDF::Node.new(context_id['value'])
    when :uri
      RDF::URI.new(context_id['value'])
    else
      nil
    end
  end.compact
end
parse_rdf_serialization(response, options = {}) click to toggle source

@param [Net::HTTPSuccess] response @param [Hash{Symbol => Object}] options @return [RDF::Enumerable]

# File lib/rdf/sesame/repository.rb, line 603
def parse_rdf_serialization(response, options = {})
  options = {:content_type => response.content_type} if options.empty?
  if reader_for = RDF::Reader.for(options)
    reader_for.new(response.body) do |reader|
      reader # FIXME
    end
  end
end
parse_response(response, options = {}) click to toggle source

@param [Net::HTTPSuccess] response @param [Hash{Symbol => Object}] options @return [Object]

# File lib/rdf/sesame/repository.rb, line 473
def parse_response(response, options = {})
  case content_type = options[:content_type] || response.content_type
    when Server::RESULT_BOOL
      response.body == 'true'
    when Server::RESULT_JSON
      self.class.parse_json_bindings(response.body, nodes)
    when Server::RESULT_XML
      self.class.parse_xml_bindings(response.body, nodes)
    else
      parse_rdf_serialization(response, options)
  end
end
raw_parse_response(response, options = {}) click to toggle source

@param [Net::HTTPSuccess] response @param [Hash{Symbol => Object}] options @return [Object]

# File lib/rdf/sesame/repository.rb, line 490
def raw_parse_response(response, options = {})
  case content_type = options[:content_type] || response.content_type
    when Server::RESULT_BOOL
      response.body == 'true'
    when Server::RESULT_JSON, Server::RESULT_RDF_JSON
      self.class.parse_json(response.body)
    when Server::RESULT_XML
      self.class.parse_xml(response.body)
    else
      response.body
  end
end
serialize_context(context) click to toggle source

@private

Serialize the context

# File lib/rdf/sesame/repository.rb, line 615
def serialize_context(context)
  context = [context] unless context.is_a?(Enumerable)
  serialization = context.map do |c|
    if c == 'null' or !c
      c
    else
      RDF::NTriples.serialize(RDF::URI(c))
    end
  end

  if serialization.size == 1
    serialization.first
  else
    serialization
  end
end
statements_options() click to toggle source

@private

Construct the statements options list

# File lib/rdf/sesame/repository.rb, line 635
def statements_options
  options = {}
  options[:context] = @context if @context
  options
end
statements_to_text_plain(statements) click to toggle source

Convert a list of statements to a text-plain-compatible text.

# File lib/rdf/sesame/repository.rb, line 461
def statements_to_text_plain(statements)
  graph = RDF::Repository.new
  statements.each do |s|
    graph << s
  end
  RDF::NTriples::Writer.dump(graph, nil, :encoding => Encoding::ASCII)
end