Skip to content

Instantly share code, notes, and snippets.

@abrisse
Created December 2, 2021 11:35
Show Gist options
  • Save abrisse/8f9893549f00e94c25cbe0bea93e532d to your computer and use it in GitHub Desktop.
Save abrisse/8f9893549f00e94c25cbe0bea93e532d to your computer and use it in GitHub Desktop.
Ruby RDF SPARQL Generator
require 'sparql'
module RDF
class Literal
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(_options = {})
to_base
end
end
end
module RDF
class URI
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(_options = {})
to_base
end
end
end
module RDF
class Query
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(options = {})
q = sparql_internal_fragment(options)
if options.delete(:dump_where)
"WHERE {\n #{q} \n}"
else
q
end
end
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
str = @patterns.map { |e| e.sparql_fragment(options) }.join("\n")
if graph_name
"GRAPH #{graph_name.sparql_fragment(options)} {\n#{str}\n}\n"
else
str
end
end
class Pattern
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(_options = {})
to_s
end
end
class Variable
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(_options = {})
to_s
end
end
end
end
module SPARQL
module Algebra
module Query
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(options = {})
if options.delete(:dump_where)
"WHERE {\n #{super} \n}"
else
super
end
end
end
end
end
module SPARQL
module Algebra
class Operator
def sparql_fragment(options = {})
sparql_internal_fragment(options)
end
class Construct
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"CONSTRUCT {\n" + selection_sparql(operands[0], options) + "\n}\n#{operands[1].sparql_fragment(options.merge(dump_where: true))}"
end
private
def selection_sparql(array, options = {})
array.map { |e| e.sparql_fragment(options) }.join("\n")
end
end
class Project
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
distinct = options.delete(:distinct)
"SELECT#{distinct ? ' DISTINCT' : ''} #{operands[0].map { |e| e.sparql_fragment(options) }.join(' ')}\n#{operands[1].sparql_fragment(options.merge(dump_where: true))}"
end
end
class Dataset
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(options = {})
operands[0].each_with_object('') do |graph, str|
str << if graph.is_a?(Array)
"FROM #{graph[0].upcase} #{graph[1].sparql_fragment(options)}\n"
else
"FROM #{graph.sparql_fragment(options)}\n"
end
end.tap do |str|
str << operands[1].sparql_fragment(options)
end
end
end
class Distinct
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
operands[0].sparql_fragment(options.merge(distinct: true))
end
end
class Prefix
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
str = ''
str << prefixes_sparql(operands[0]) + "\n" unless options[:no_prefixes]
str << operands[1].sparql_fragment(options)
end
private
def prefixes_sparql(array)
array.map { |e| "PREFIX #{e[0]} #{e[1].to_base}" }.join("\n")
end
end
class LeftJoin
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
str = ''
str << operands[0].sparql_fragment(options) + "\nOPTIONAL { \n" + operands[1].sparql_fragment(options) + "\n"
str << 'FILTER (' + operands[2].sparql_fragment(options) + ") \n" if operands[2]
str << '}'
end
end
class Join
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
operands.map { |operand| wrap_operand(operand, options) }.join("\n")
end
# Wrap operand
#
# Necessary for sub-queries
# @param [Operand] the Algebra operator
# @param [Hash{Symbol => Object}] options ({})
# @return [String]
def wrap_operand(operand, options)
case operand
when SPARQL::Algebra::Operator::Slice, SPARQL::Algebra::Operator::Project, SPARQL::Algebra::Operator::Distinct
"{\n#{operand.sparql_fragment(options)}\n}"
# when RDF::Query, SPARQL::Algebra::Operator::Join, SPARQL::Algebra::Operator::Path
# operand.sparql_fragment(options)
else
operand.sparql_fragment(options)
end
end
end
class Union
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"{\n" + operands[0].sparql_fragment(options) + "\n} UNION {\n" + operands[1].sparql_fragment(options) + "\n}"
end
end
class Filter
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[1].sparql_fragment(options)} \nFILTER (#{operands[0].sparql_fragment(options)}) ."
end
end
# --------------------------
# Evaluatable
# --------------------------
class Exprlist
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
'(' + operands.map { |o| o.sparql_fragment(options) }.join(') && (') + ')'
end
end
class Regex
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"regex(#{operands[0].sparql_fragment(options)}, #{operands[1].sparql_fragment(options)})"
end
end
class StrStarts
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"strstarts(#{operands[0].sparql_fragment(options)}, #{operands[1].sparql_fragment(options)})"
end
end
class Str
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"str(#{operands[0].sparql_fragment(options)})"
end
end
class Not
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"!#{operands[0].sparql_fragment(options)}"
end
end
class Contains
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"contains(#{operands[0].sparql_fragment(options)}, #{operands[1].sparql_fragment(options)})"
end
end
class Bound
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"bound(#{operands[0].sparql_fragment(options)})"
end
end
class IsBlank
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"isBlank(#{operands[0].sparql_fragment(options)})"
end
end
class NotExists
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"NOT EXISTS {\n#{operands[0].sparql_fragment(options)}\n}"
end
end
class Compare
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} #{self.class.const_get(:NAME)} #{operands[1].sparql_fragment(options)}"
end
end
class IsLiteral
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"isLiteral(#{operands[0].sparql_fragment(options)})"
end
end
class Multiply
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} * #{operands[1].sparql_fragment(options)}"
end
end
class Divide
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} / #{operands[1].sparql_fragment(options)}"
end
end
class Plus
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} + #{operands[1].sparql_fragment(options)}"
end
end
class Subtract
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} - #{operands[1].sparql_fragment(options)}"
end
end
class Or
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} || #{operands[1].sparql_fragment(options)}"
end
end
class And
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} && #{operands[1].sparql_fragment(options)}"
end
end
class In
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} IN (#{operands[1..-1].map{|e| e.sparql_fragment(options)}.join(', ')})"
end
end
class NotIn
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} NOT IN (#{operands[1..-1].map{|e| e.sparql_fragment(options)}.join(', ')})"
end
end
class Extend
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
operands[1].sparql_fragment(options).tap do |full_str|
operands[0].each_with_object(full_str) do |operation, str|
as, expression = operation
str << "\nBIND (#{expression.sparql_fragment(options)} AS #{as.sparql_fragment(options)}) ."
end
end
end
end
class Path
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)} #{operands[1].sparql_fragment(options)} #{operands[2].sparql_fragment(options)} ."
end
end
class Seq
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)}/#{operands[1].sparql_fragment(options)}"
end
end
class Reverse
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"^#{operands[0].sparql_fragment(options)}"
end
end
class Alt
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)}|#{operands[1].sparql_fragment(options)}"
end
end
class PathPlus
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)}+"
end
end
class PathStar
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)}*"
end
end
class PathOpt
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"#{operands[0].sparql_fragment(options)}?"
end
end
class Lang
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"lang(#{operands[0].sparql_fragment(options)})"
end
end
class LangMatches
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
"langMatches(#{operands[0].sparql_fragment(options)}, #{operands[1].sparql_fragment(options)})"
end
end
class Slice
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_fragment(options = {})
super.tap do |str|
str << "\nLIMIT #{operands[1]}"
str << " OFFSET #{operands[0]}" unless operands[0] == :_
end
end
def sparql_internal_fragment(options = {})
operands[2].sparql_fragment(options)
end
end
class Table
##
# Returns the object SPARQL representation
#
# @param [Hash{Symbol => Object}] options ({})
# options passed for the generation
# @return [String]
def sparql_internal_fragment(options = {})
str = "VALUES (#{operands[0][1..-1].map { |e| e.sparql_fragment(options) }.join(' ')}) {\n"
operands[1..-1].each do |row|
line = '('
row[1..-1].each do |col|
line << "#{col[1].sparql_fragment(options)} "
end
line = line.chop
line << ")\n"
str << line
end
str << "}\n"
str
end
end
end
end
end
query = %q{
PREFIX uuid: <http://www.perfect-memory.com/profile/showroom/resource/>
SELECT ?uri ?uri2
WHERE {
VALUES (?uri ?uri2) {
(uuid:e5a0607b-8158-430d-b05c-2d064aee01a6 "pop")
(uuid:f5cebb49-3a34-4f4b-91de-866623aae777 "rock")
}
}
}
puts ::SPARQL::Grammar.parse(query).sparql_fragment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment