require 'rdf' require 'sparql/client' require 'enumerator' module RDF class Marmotta < ::SPARQL::Client::Repository attr_accessor :endpoints attr_reader :update_client DEFAULT_OPTIONS = { :sparql => 'sparql/select', :sparql_update => 'sparql/update', :ldpath => 'ldpath' } ## # Supported Accept headers for Marmotta. As of 3.3.0, Marmotta will reject # a request if the first content type listed is not suppported. # # @see https://issues.apache.org/jira/browse/MARMOTTA-585 CTYPES = RDF::Format.content_types.select do |key, values| !(values.map(&:to_s) & ['RDF::RDFXML::Format', 'RDF::Turtle::Format', 'RDF::TriG::Format', 'RDF::TriX::Format', 'RDF::N3::Format']).empty? end def initialize(base_url, options = {}) @options = options.dup @tx_class ||= @options.delete(:transaction_class) { DEFAULT_TX_CLASS } @endpoints = DEFAULT_OPTIONS @endpoints.merge!(options) @endpoints.each do |k, v| next unless RDF::URI(v.to_s).relative? @endpoints[k] = (RDF::URI(base_url.to_s) / v.to_s) end @client = Client.new(endpoints[:sparql].to_s, options) @update_client = Client.new(endpoints[:sparql_update].to_s, options) end def query_client @client end def delete_statement(statement) delete(statement) end def count begin binding = client.query("SELECT (COUNT(*) AS ?no) WHERE { ?s ?p ?o }").first.to_hash binding[binding.keys.first].value.to_i rescue SPARQL::Client::ServerError count = 0 each_statement { count += 1 } count end end def clear update_client.query("DELETE { ?s ?p ?o } WHERE { ?s ?p ?o }") end class Client < SPARQL::Client MARMOTTA_GRAPH_ALL = (Marmotta::CTYPES.keys + ['*/*;p=0.1']) .join(', ').freeze def initialize(url, options = {}, &block) options[:method] ||= :get options[:protocol] ||= '1.1' super end ## # Limit to accepted content types per comment on RDF::Marmotta::CTYPES def request(query, headers={}, &block) headers['Accept'] ||= MARMOTTA_GRAPH_ALL if (query.respond_to?(:expects_statements?) ? query.expects_statements? : (query =~ /CONSTRUCT|DESCRIBE|DELETE|CLEAR/)) super end ## # @private def parse_rdf_serialization(response, options = {}) options[:content_type] ||= 'text/turtle' if response.content_type.nil? super end # Do HTTP POST if it's an INSERT def request_method(query) method = (self.options[:method] || DEFAULT_METHOD).to_sym method = :post if query.to_s =~ /INSERT/ method end end end end