module RDF::Repository::Implementation

A default Repository implementation supporting atomic writes and serializable transactions.

@see RDF::Repository

Constants

DEFAULT_GRAPH

Public Class Methods

extend_object(obj) click to toggle source

@private

Calls superclass method
# File lib/rdf/repository.rb, line 248
def self.extend_object(obj)
  obj.instance_variable_set(:@data, obj.options.delete(:data) || 
                                    Hamster::Hash.new)
  obj.instance_variable_set(:@tx_class, 
                            obj.options.delete(:transaction_class) || 
                            SerializedTransaction)
  super
end

Public Instance Methods

apply_changeset(changeset) click to toggle source

@see RDF::Mutable#apply_changeset

# File lib/rdf/repository.rb, line 345
def apply_changeset(changeset)
  data = @data
  changeset.deletes.each { |del| data = delete_from(data, del) }
  changeset.inserts.each { |ins| data = insert_to(data, ins) }
  @data = data
end
count() click to toggle source

@private @see RDF::Countable#count

# File lib/rdf/repository.rb, line 274
def count
  count = 0
  @data.each do |_, ss|
    ss.each do |_, ps|
      ps.each { |_, os| count += os.size }
    end
  end
  count
end
durable?() click to toggle source

@private @see RDF::Durable#durable?

# File lib/rdf/repository.rb, line 287
def durable?
  false
end
each(&block)
Alias for: each_statement
each_graph() { |graph(graph_name: (gn == DEFAULT_GRAPH ? nil : gn), data: self)| ... } click to toggle source

@private @see RDF::Enumerable#each_graph

# File lib/rdf/repository.rb, line 308
def each_graph(&block)
  if block_given?
    @data.each_key do |gn|
      yield RDF::Graph.new(graph_name: (gn == DEFAULT_GRAPH ? nil : gn), data: self)
    end
  end
  enum_graph
end
each_statement() { |statement(s, p, o, graph_name: equal?(DEFAULT_GRAPH) ? nil : g)| ... } click to toggle source

@private @see RDF::Enumerable#each_statement

# File lib/rdf/repository.rb, line 327
def each_statement(&block)
  if block_given?
    @data.each do |g, ss|
      ss.each do |s, ps|
        ps.each do |p, os|
          os.each do |o|
            yield RDF::Statement.new(s, p, o, graph_name: g.equal?(DEFAULT_GRAPH) ? nil : g)
          end
        end
      end
    end
  end
  enum_statement
end
Also aliased as: each
graph_names(options = nil, &block) click to toggle source

@private @see RDF::Enumerable#each_graph

# File lib/rdf/repository.rb, line 301
def graph_names(options = nil, &block)        
  @data.keys.reject { |g| g == DEFAULT_GRAPH }.to_a
end
has_graph?(graph) click to toggle source

@private @see RDF::Enumerable#has_graph?

# File lib/rdf/repository.rb, line 294
def has_graph?(graph)
  @data.has_key?(graph)
end
has_statement?(statement) click to toggle source

@private @see RDF::Enumerable#has_statement?

# File lib/rdf/repository.rb, line 320
def has_statement?(statement)
  has_statement_in?(@data, statement)
end
isolation_level() click to toggle source

@see RDF::Dataset#isolation_level

# File lib/rdf/repository.rb, line 354
def isolation_level
  :serializable
end
snapshot() click to toggle source

A readable & queryable snapshot of the repository for isolated reads.

@return [Dataset] an immutable Dataset containing a current snapshot of

the Repository contents.

@see RDF::Mutable#snapshot

# File lib/rdf/repository.rb, line 365
def snapshot
  self.class.new(data: @data).freeze
end
supports?(feature) click to toggle source

@private @see RDF::Enumerable#supports?

# File lib/rdf/repository.rb, line 260
def supports?(feature)
  case feature.to_sym
  when :graph_name   then @options[:with_graph_name]
  when :inference    then false  # forward-chaining inference
  when :validity     then @options.fetch(:with_validity, true)
  when :atomic_write then true
  when :snapshots    then true
  else false
  end
end

Protected Instance Methods

clear_statements() click to toggle source

@private @see RDF::Mutable#clear

# File lib/rdf/repository.rb, line 439
def clear_statements
  @data = @data.clear
end
data() click to toggle source

@private @return [Hamster::Hash]

# File lib/rdf/repository.rb, line 446
def data
  @data
end
data=(hash) click to toggle source

@private @return [Hamster::Hash]

# File lib/rdf/repository.rb, line 453
def data=(hash)
  @data = hash
end
delete_statement(statement) click to toggle source

@private @see RDF::Mutable#delete

# File lib/rdf/repository.rb, line 432
def delete_statement(statement)
  @data = delete_from(@data, statement)
end
insert_statement(statement) click to toggle source

@private @see RDF::Mutable#insert

# File lib/rdf/repository.rb, line 425
def insert_statement(statement)
  @data = insert_to(@data, statement)
end
query_pattern(pattern, options = {}) { |statement(s, p, o, graph_name: equal?(DEFAULT_GRAPH) ? nil : c)| ... } click to toggle source

Match elements with `eql?`, not `==`

`graph_name` of `false` matches default graph. Unbound variable matches non-false graph name

@private @see RDF::Queryable#query_pattern

# File lib/rdf/repository.rb, line 379
def query_pattern(pattern, options = {}, &block)
  snapshot = @data
  if block_given?
    graph_name  = pattern.graph_name
    subject     = pattern.subject
    predicate   = pattern.predicate
    object      = pattern.object

    cs = snapshot.has_key?(graph_name) ? { graph_name => snapshot[graph_name] } : snapshot

    cs.each do |c, ss|
      next unless graph_name.nil? ||
                  graph_name == false && !c ||
                  graph_name.eql?(c)

      ss = if subject.nil? || subject.is_a?(RDF::Query::Variable)
             ss
           elsif ss.has_key?(subject)
             { subject => ss[subject] }
           else
             []
           end
      ss.each do |s, ps|
        ps = if predicate.nil? || predicate.is_a?(RDF::Query::Variable)
               ps
             elsif ps.has_key?(predicate)
               { predicate => ps[predicate] }
             else
               []
             end
        ps.each do |p, os|
          os.each do |o|
            next unless object.nil? || object.eql?(o)
            yield RDF::Statement.new(s, p, o, graph_name: c.equal?(DEFAULT_GRAPH) ? nil : c)
          end
        end
      end
    end
  else
    enum_for(:query_pattern, pattern, options)
  end
end

Private Instance Methods

delete_from(data, statement) click to toggle source

@private @return [Hamster::Hash] a new, updated hamster hash

# File lib/rdf/repository.rb, line 496
def delete_from(data, statement)
  if has_statement_in?(data, statement)
    s, p, o, g = statement.to_quad
    g = DEFAULT_GRAPH unless supports?(:graph_name)
    g ||= DEFAULT_GRAPH

    os   = data[g][s][p].delete(o)
    ps   = os.empty? ? data[g][s].delete(p) : data[g][s].put(p, os)
    ss   = ps.empty? ? data[g].delete(s)    : data[g].put(s, ps)
    return ss.empty? ? data.delete(g) : data.put(g, ss)
  end
  data
end
has_statement_in?(data, statement) click to toggle source

@private @see has_statement

# File lib/rdf/repository.rb, line 462
def has_statement_in?(data, statement)
  s, p, o, g = statement.to_quad
  g ||= DEFAULT_GRAPH

  data.has_key?(g) &&
    data[g].has_key?(s) &&
    data[g][s].has_key?(p) &&
    data[g][s][p].include?(o)
end
insert_to(data, statement) click to toggle source

@private @return [Hamster::Hash] a new, updated hamster hash

# File lib/rdf/repository.rb, line 475
def insert_to(data, statement)
  raise ArgumentError, "Statement #{statement.inspect} is incomplete" if statement.incomplete?

  unless has_statement_in?(data, statement)
    s, p, o, c = statement.to_quad
    c ||= DEFAULT_GRAPH
    
    return data.put(c) do |subs|
      subs = (subs || Hamster::Hash.new).put(s) do |preds|
        preds = (preds || Hamster::Hash.new).put(p) do |objs|
          (objs || Hamster::Set.new).add(o)
        end
      end
    end
  end
  data
end