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] 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