class Sequel::ToDot

Constants

TO_DOT_OPTIONS

The option keys that should be included in the dot output.

Public Class Methods

new(ds) click to toggle source

Given a Dataset, parse the internal structure to generate a dataset visualization.

# File lib/sequel/extensions/to_dot.rb, line 37
def initialize(ds)
  @i = 0
  @stack = [@i]
  @dot = ["digraph G {", "0 [label=\"self\"];"]
  v(ds, "")
  @dot << "}"
end
output(ds) click to toggle source

Given a Dataset, return a string in dot format that will generate a visualization of the dataset.

# File lib/sequel/extensions/to_dot.rb, line 31
def self.output(ds)
  new(ds).output
end

Public Instance Methods

output() click to toggle source

Output the dataset visualization as a string in dot format.

# File lib/sequel/extensions/to_dot.rb, line 46
def output
  @dot.join("\n")
end

Private Instance Methods

dot(label, j=nil) click to toggle source

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.

# File lib/sequel/extensions/to_dot.rb, line 55
def dot(label, j=nil)
  @dot << "#{j||@i} [label=#{label.to_s.inspect}];"
end
v(e, l) click to toggle source

Recursive method that parses all of Sequel's internal datastructures, adding the appropriate nodes and transitions to the internal dot structure.

# File lib/sequel/extensions/to_dot.rb, line 62
def v(e, l)
  @i += 1
  dot(l, "#{@stack.last} -> #{@i}") if l
  @stack.push(@i)
  case e
  when LiteralString
    dot "Sequel.lit(#{e.to_s.inspect})"
  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.alias, :alias)
    v(e.columns, :columns) if e.columns
  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.name}"
    e.args.each_with_index do |val, j|
      v(val, j)
    end
    v(e.args, :args)
    v(e.opts, :opts)
  when SQL::Subscript 
    dot "Subscript"
    v(e.f, :f)
    v(e.sub, :sub)
  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".dup
    if e.is_a?(SQL::JoinOnClause)
      str << " ON"
    elsif e.is_a?(SQL::JoinUsingClause)
      str << " USING"
    end
    dot str
    v(e.table_expr, :table)
    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