ruby-rdf/rdf

View on GitHub
lib/rdf/model/dataset.rb

Summary

Maintainability
A
55 mins
Test Coverage
module RDF
  ##
  # An RDF Dataset
  #
  # Datasets are immutable by default. {RDF::Repository} provides an interface
  # for mutable Datasets.
  #
  # A Dataset functions as an a set of named RDF graphs with a default graph.
  # It implements {RDF::Enumerable} and {RDF::Queryable} over the whole set;
  # if no specific graph name is queried, enumerating and querying takes place
  # over the intersection of all the graphs in the Dataset.
  #
  # The default graph is named with a constant `DEFAULT_GRAPH`.
  #
  # @example initializing an RDF::Dataset with existing data
  #   statements = [RDF::Statement.new(RDF::URI(:s), RDF::URI(:p), :o)]
  #   dataset    = RDF::Dataset.new(statements: statements)
  #   dataset.count # => 1
  #
  # @see https://www.w3.org/TR/rdf11-concepts/#section-dataset
  # @see https://www.w3.org/TR/rdf11-datasets/
  class Dataset
    include RDF::Enumerable
    include RDF::Durable
    include RDF::Queryable

    DEFAULT_GRAPH = false

    ISOLATION_LEVELS = [ :read_uncommitted,
                         :read_committed,
                         :repeatable_read,
                         :snapshot,
                         :serializable ].freeze

    ##
    # @param [RDF::Enumerable, Array<RDF::Statement>] statements  the initial 
    #   contents of the dataset
    # @yield [dataset] yields itself when a block is given
    # @yieldparam [RDF::Dataset] dataset
    def initialize(statements: [], **options, &block)
      @statements = statements.map do |s| 
        s = s.dup
        s.graph_name ||= DEFAULT_GRAPH
        s.freeze
      end.freeze

      if block_given?
        case block.arity
          when 1 then yield self
          else instance_eval(&block)
        end
      end
    end

    ##
    # @private
    # @see RDF::Durable#durable?
    def durable?
      false
    end

    ##
    # @private
    # @see RDF::Enumerable#each
    def each
      @statements.each do |st| 
        if st.graph_name.equal?(DEFAULT_GRAPH)
          st = st.dup
          st.graph_name = nil
        end

        yield st
      end
      self
    end

    ##
    # Returns a developer-friendly representation of this object.
    #
    # @return [String]
    def inspect
      sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, count.to_s)
    end

    ##
    # Outputs a developer-friendly representation of this object to
    # `stderr`.
    #
    # @return [void]
    def inspect!
      each_statement { |statement| statement.inspect! }
      nil
    end

    ##
    # @return [Symbol] a representation of the isolation level for reads of this
    #   Dataset. One of `:read_uncommitted`, `:read_committed`, `:repeatable_read`,
    #  `:snapshot`, or `:serializable`.
    def isolation_level
      :read_committed
    end

    ##
    # @private
    # @see RDF::Enumerable#supports?
    def supports?(feature)
      return true if %i(graph_name quoted_triples).include?(feature)
      super
    end

    protected
    
    ##
    # Implements basic query pattern matching over the Dataset, with handling 
    # for a default graph.
    def query_pattern(pattern, **options, &block)
      return super unless pattern.graph_name == DEFAULT_GRAPH

      if block_given?
        pattern = pattern.dup
        pattern.graph_name = nil

        each_statement do |statement|
          yield statement if (statement.graph_name == DEFAULT_GRAPH ||
                              statement.graph_name.nil?) && pattern === statement
        end
      else
        enum_for(:query_pattern, pattern, options)
      end
    end
  end
end