class RDF::HamsterRepo

Sub-class of RDF::Repository with order-preserving properties.

Constants

DEFAULT_GRAPH

Public Class Methods

extend_object(obj) click to toggle source

@private

Calls superclass method
# File lib/rdf/hamster_repo.rb, line 12
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) || 
                            RDF::Transaction::SerializedTransaction)
  super
end
new(uri: nil, title: nil, **options, &block) click to toggle source

Initializes this repository instance.

@param [URI, to_s] uri (nil) @param [String, to_s] title (nil) @param [Hash{Symbol => Object}] options @option options [Boolean] :with_graph_name (true)

Indicates that the repository supports named graphs, otherwise,
only the default graph is supported.

@option options [Boolean] :with_validity (true)

Indicates that the repository supports named validation.

@option options [Boolean] :transaction_class (SerializedTransaction)

Specifies the RDF::Transaction implementation to use in this Repository.

@yield [repository] @yieldparam [Repository] repository

Calls superclass method
# File lib/rdf/hamster_repo.rb, line 36
def initialize(uri: nil, title: nil, **options, &block)
  @data = options.delete(:data) || Hamster::Hash.new
  super do
    if block_given?
      case block.arity
        when 1 then block.call(self)
        else instance_eval(&block)
      end
    end
  end
end

Public Instance Methods

apply_changeset(changeset) click to toggle source

@see Mutable#apply_changeset

# File lib/rdf/hamster_repo.rb, line 163
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/hamster_repo.rb, line 76
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/hamster_repo.rb, line 116
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/hamster_repo.rb, line 145
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/hamster_repo.rb, line 97
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/hamster_repo.rb, line 109
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/hamster_repo.rb, line 179
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 Mutable#snapshot

# File lib/rdf/hamster_repo.rb, line 190
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/hamster_repo.rb, line 133
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

Returns ‘true` if this respository supports the given `feature`.

This repository supports list_terms.

Calls superclass method
# File lib/rdf/hamster_repo.rb, line 52
def supports?(feature)
  case feature.to_sym
  when :atomic_write     then true
  when :rdfstar          then true
  when :snapshots        then true
  else super
  end
end
to_query() click to toggle source

Creates a query from the statements in this repository, turning blank nodes into non-distinguished variables. This can be used to determine if this repository is logically a subset of another repository.

@return [RDF::Query]

# File lib/rdf/hamster_repo.rb, line 65
def to_query
  RDF::Query.new do |query|
    each do |statement|
      query.pattern RDF::Query::Pattern.from(statement, ndvars: true)
    end
  end
end

Protected Instance Methods

clear_statements() click to toggle source

@private @see RDF::Mutable#clear

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

@private @return [Hash]

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

@private @return [Hash]

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

@private @see RDF::Mutable#delete

# File lib/rdf/hamster_repo.rb, line 264
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/hamster_repo.rb, line 257
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.

Matches terms which are native lists.

@private @see RDF::Queryable#query_pattern

# File lib/rdf/hamster_repo.rb, line 206
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 == 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.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, 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 [Hash] a new, updated hash

# File lib/rdf/hamster_repo.rb, line 329
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)
Alias for: statement_in?
insert_to(data, statement) click to toggle source

@private @return [Hash] a new, updated hash

# File lib/rdf/hamster_repo.rb, line 308
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
    
    return data.put(c) do |subs|
      (subs || Hamster::Hash.new).put(s) do |preds|
        (preds || Hamster::Hash.new).put(p) do |objs|
          (objs || Hamster::Hash.new).put(o, statement.options)
        end
      end
    end
  end
  data
end
statement_in?(data, statement) click to toggle source

@private @see statement?

# File lib/rdf/hamster_repo.rb, line 294
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?