module RDF::Repository::Implementation

A default Repository implementation supporting atomic writes and serializable transactions.

@see RDF::Repository

Constants

DEFAULT_GRAPH
SerializedTransaction

@deprecated moved to {RDF::Transaction::SerializedTransaction}

Public Class Methods

extend_object(obj) click to toggle source

@private

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

Public Instance Methods

apply_changeset(changeset) click to toggle source

@see Mutable#apply_changeset

# File lib/rdf/repository.rb, line 374
def apply_changeset(changeset)
  data = @data
  changeset.deletes.each do |del|
    if del.constant?
      data = delete_from(data, del)
    else
      # we need this condition to handle wildcard statements
      query_pattern(del) { |stmt| data = delete_from(data, stmt) }
    end
  end
  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 286
def count
  count = 0
  @data.each do |_, ss|
    ss.each do |_, ps|
      ps.each { |_, os| count += os.size }
    end
  end
  count
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 326
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, merge(graph_name: equal?(DEFAULT_GRAPH) ? nil : g))| ... } click to toggle source

@private @see RDF::Enumerable#each_statement

# File lib/rdf/repository.rb, line 356
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, object_options|
            yield RDF::Statement.new(s, p, o, object_options.merge(graph_name: g.equal?(DEFAULT_GRAPH) ? nil : g))
          end
        end
      end
    end
  end
  enum_statement
end
Also aliased as: each
graph?(*args) click to toggle source

@overload graph?

Returns `false` to indicate that this is not a graph.

@return [Boolean]

@overload graph?(name)

Returns `true` if `self` contains the given RDF graph_name.

@param  [RDF::Resource, false] graph_name
  Use value `false` to query for the default graph_name
@return [Boolean]
# File lib/rdf/repository.rb, line 307
def graph?(*args)
  case args.length
  when 0 then false
  when 1 then @data.key?(args.first)
  else raise ArgumentError("wrong number of arguments (given #{args.length}, expected 0 or 1)")
  end
end
Also aliased as: has_graph?
graph_names(options = nil, &block) click to toggle source

@private @see RDF::Enumerable#each_graph

# File lib/rdf/repository.rb, line 319
def graph_names(options = nil, &block)        
  @data.keys.reject { |g| g == DEFAULT_GRAPH }.to_a
end
has_graph?(*args)
Alias for: graph?
has_statement?(*args)
Alias for: statement?
isolation_level() click to toggle source

@see RDF::Dataset#isolation_level

# File lib/rdf/repository.rb, line 390
def isolation_level
  :snapshot
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 Mutable#snapshot

# File lib/rdf/repository.rb, line 401
def snapshot
  self.class.new(data: @data).freeze
end
statement?(*args) click to toggle source

@overload statement?

Returns `false` indicating this is not an RDF::Statemenet.
@return [Boolean]
@see RDF::Value#statement?

@overload statement?(statement)

@private
@see    RDF::Enumerable#statement?
# File lib/rdf/repository.rb, line 344
def statement?(*args)
  case args.length
  when 0 then false
  when 1 then args.first && statement_in?(@data, args.first)
  else raise ArgumentError("wrong number of arguments (given #{args.length}, expected 0 or 1)")
  end
end
Also aliased as: has_statement?
supports?(feature) click to toggle source

@private @see RDF::Enumerable#supports?

# File lib/rdf/repository.rb, line 269
def supports?(feature)
  case feature.to_sym
  when :graph_name       then @options[:with_graph_name]
  when :validity         then @options.fetch(:with_validity, true)
  when :literal_equality then true
  when :atomic_write     then true
  when :rdf_full         then true
  when :quoted_triples   then true
  when :base_direction   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 480
def clear_statements
  @data = @data.class.new
end
data() click to toggle source

@private @return [Hamster::Hash]

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

@private @return [Hamster::Hash]

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

@private @see RDF::Mutable#delete

# File lib/rdf/repository.rb, line 473
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 466
def insert_statement(statement)
  @data = insert_to(@data, statement)
end
query_pattern(pattern, **options) { |statement(s, p, o, merge(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 415
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.key?(graph_name) ? { graph_name => snapshot[graph_name] } : snapshot

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

      ss = if subject.nil? || subject.is_a?(RDF::Query::Variable)
        ss
      elsif subject.is_a?(RDF::Query::Pattern)
        # Match subjects which are statements matching this pattern
        ss.keys.select {|s| s.statement? && subject.eql?(s)}.inject({}) do |memo, st|
          memo.merge(st => ss[st])
        end
      elsif ss.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.key?(predicate)
          { predicate => ps[predicate] }
        else
          []
        end
        ps.each do |p, os|
          os.each do |o, object_options|
            next unless object.nil? || object.eql?(o)
            yield RDF::Statement.new(s, p, o, object_options.merge(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 535
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].dup.delete_if {|k,v| k == o}
    ps   = os.empty? ? data[g][s].dup.delete_if {|k,v| k == p} : data[g][s].merge(p => os)
    ss   = ps.empty? ? data[g].dup.delete_if    {|k,v| k == s} : data[g].merge(s => ps)
    return ss.empty? ? data.dup.delete_if       {|k,v| k == g} : data.merge(g => ss)
  end
  data
end
has_statement_in?(data, statement)
Alias for: statement_in?
insert_to(data, statement) click to toggle source

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

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

  unless statement_in?(data, statement)
    s, p, o, c = statement.to_quad
    c ||= DEFAULT_GRAPH

    data          = data.has_key?(c)       ? data.dup       : data.merge(c => {})
    data[c]       = data[c].has_key?(s)    ? data[c].dup    : data[c].merge(s => {})
    data[c][s]    = data[c][s].has_key?(p) ? data[c][s].dup : data[c][s].merge(p => {})
    data[c][s][p] = data[c][s][p].merge(o => statement.options)
  end
  data
end
statement_in?(data, statement) click to toggle source

@private @see statement?

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

  data.key?(g) &&
    data[g].key?(s) &&
    data[g][s].key?(p) &&
    data[g][s][p].key?(o)
end
Also aliased as: has_statement_in?