/usr/lib/ruby/vendor_ruby/sequel/extensions/to_dot.rb is in ruby-sequel 3.33.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | # This adds a <tt>Sequel::Dataset#to_dot</tt> method. The +to_dot+ method
# returns a string that can be processed by graphviz's +dot+ program in
# order to get a visualization of the dataset. Basically, it shows a version
# of the dataset's abstract syntax tree.
module Sequel
class ToDot
# The option keys that should be included in the dot output.
TO_DOT_OPTIONS = [:with, :distinct, :select, :from, :join, :where, :group, :having, :compounds, :order, :limit, :offset, :lock].freeze
# Given a +Dataset+, return a string in +dot+ format that will
# generate a visualization of the dataset.
def self.output(ds)
new(ds).output
end
# Given a +Dataset+, parse the internal structure to generate
# a dataset visualization.
def initialize(ds)
@i = 0
@stack = [@i]
@dot = ["digraph G {", "0 [label=\"self\"];"]
v(ds, "")
@dot << "}"
end
# Output the dataset visualization as a string in +dot+ format.
def output
@dot.join("\n")
end
private
# Add an entry to the +dot+ output with the given label. If +j+
# is given, it is used directly as the node or transition. Otherwise
# a node is created for the current object.
def dot(label, j=nil)
@dot << "#{j||@i} [label=#{label.to_s.inspect}];"
end
# Recursive method that parses all of Sequel's internal datastructures,
# adding the appropriate nodes and transitions to the internal +dot+
# structure.
def v(e, l)
@i += 1
dot(l, "#{@stack.last} -> #{@i}") if l
@stack.push(@i)
case e
when LiteralString
dot "#{e.inspect}.lit"
when Symbol, Numeric, String, Class, TrueClass, FalseClass, NilClass
dot e.inspect
when Array
dot "Array"
e.each_with_index do |val, j|
v(val, j)
end
when Hash
dot "Hash"
e.each do |k, val|
v(val, k)
end
when SQL::ComplexExpression
dot "ComplexExpression: #{e.op}"
e.args.each_with_index do |val, j|
v(val, j)
end
when SQL::Identifier
dot "Identifier"
v(e.value, :value)
when SQL::QualifiedIdentifier
dot "QualifiedIdentifier"
v(e.table, :table)
v(e.column, :column)
when SQL::OrderedExpression
dot "OrderedExpression: #{e.descending ? :DESC : :ASC}#{" NULLS #{e.nulls.to_s.upcase}" if e.nulls}"
v(e.expression, :expression)
when SQL::AliasedExpression
dot "AliasedExpression"
v(e.expression, :expression)
v(e.aliaz, :alias)
when SQL::CaseExpression
dot "CaseExpression"
v(e.expression, :expression) if e.expression
v(e.conditions, :conditions)
v(e.default, :default)
when SQL::Cast
dot "Cast"
v(e.expr, :expr)
v(e.type, :type)
when SQL::Function
dot "Function: #{e.f}"
e.args.each_with_index do |val, j|
v(val, j)
end
when SQL::Subscript
dot "Subscript"
v(e.f, :f)
v(e.sub, :sub)
when SQL::WindowFunction
dot "WindowFunction"
v(e.function, :function)
v(e.window, :window)
when SQL::Window
dot "Window"
v(e.opts, :opts)
when SQL::PlaceholderLiteralString
str = e.str
str = "(#{str})" if e.parens
dot "PlaceholderLiteralString: #{str.inspect}"
v(e.args, :args)
when SQL::JoinClause
str = "#{e.join_type.to_s.upcase} JOIN"
if e.is_a?(SQL::JoinOnClause)
str << " ON"
elsif e.is_a?(SQL::JoinUsingClause)
str << " USING"
end
dot str
v(e.table, :table)
v(e.table_alias, :alias) if e.table_alias
if e.is_a?(SQL::JoinOnClause)
v(e.on, :on)
elsif e.is_a?(SQL::JoinUsingClause)
v(e.using, :using)
end
when Dataset
dot "Dataset"
TO_DOT_OPTIONS.each do |k|
if val = e.opts[k]
v(val, k.to_s)
end
end
else
dot "Unhandled: #{e.inspect}"
end
@stack.pop
end
end
class Dataset
# Return a string that can be processed by the +dot+ program (included
# with graphviz) in order to see a visualization of the dataset's
# abstract syntax tree.
def to_dot
ToDot.output(self)
end
end
end
|