lib/oci8_simple/describe.rb in oci8_simple-0.4.2 vs lib/oci8_simple/describe.rb in oci8_simple-0.5.0
- old
+ new
@@ -1,59 +1,131 @@
-class Oci8Simple::Describe
- def initialize(env=nil)
- @env = env || "development"
- end
+module Oci8Simple
+ # == Description
+ # This class creates a string describing a table's columns, intended to be
+ # displayed in a fixed-width font.
+ # == Usage
+ # Oci8Simple::Describe.new("development").run("users")
+ class Describe
+ SPACE_BETWEEN=2
+ FIELDS=[
+ {:select => "NULLABLE", :header => "Required", :content => :format_nullable, :right => true},
+ {:select => "lower(COLUMN_NAME)", :header=> "Name"},
+ {:select => "lower(DATA_TYPE)", :header => "Type"},
+ {:select => "DATA_LENGTH", :header => "Size", :content => :format_size},
+ {:select => "CHAR_USED", :header => "Char?", :content => :format_char_used},
+ {:select => "CHAR_LENGTH", :header => "Char_size", :content => :format_char_length},
+ {:select => "DATA_PRECISION", :header => "Precision"},
+ {:select => "DATA_SCALE", :header => "Scale"},
+ {:select => "DATA_DEFAULT", :header => "Default", :content => :format_default, :max => 10}
+ ]
- def run(table)
- description = client.conn.describe_table(table)
- c = description.columns.sort{|a,b| a.name <=> b.name }
- max_name = max(c.map(&:name)) + 3
- max_type = max(c.map {|col| type_and_size(col)}) + 1
- c.map do |col|
- "\"#{col.name}\"".ljust(max_name, ' ') + type_and_size(col).ljust(max_type, ' ') + null(col)
- end.map(&:upcase).join("\n")
- end
+ def run(table)
+ sql = <<-SQL
+ select #{select_fields}
+ from user_tab_columns
+ where table_name='#{table.upcase}'
+ order by column_name asc
+ SQL
+ results = client.run(sql)
+ calculate_widths(results)
+ format_results(results)
+ end
- def null(col)
- col.nullable? ? "" : "NOT NULL"
- end
+ def initialize(env=nil)
+ @env = env || "development"
+ end
- def type_and_size(col)
- str = "#{col.data_type}"
- if(col.data_type.to_s =~ /varchar/i)
- str << "(#{col.char_size} CHAR)"
- elsif(col.data_type == :number)
- str << "(#{col.precision})"
+ def self.usage
+ "Usage: #{0} TABLE_NAME [ENVIRONMENT]"
end
- str
- end
- def max(arr)
- arr.map(&:length).max
- end
+ def self.run_from_argv
+ o = OptionParser.new do |opt|
+ opt.banner = usage
+ opt.on("-v", "--version", "Show version") do
+ puts "version #{File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))}"
+ exit
+ end
+ end
+ o.parse!
+ if(ARGV[0].nil?)
+ puts o
+ else
+ puts self.new(ARGV[1]).run(ARGV[0])
+ end
+ end
- def self.usage
- "Usage: #{0} TABLE_NAME [ENVIRONMENT]"
- end
+ private
- def self.run_from_argv
- o = OptionParser.new do |opt|
- opt.banner = usage
- opt.on("-v", "--version", "Show version") do
- puts "version #{File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))}"
- exit
+ def format_nullable(value, row)
+ value == 'N' ? '*' : ' '
+ end
+
+ def format_char_used(value, row)
+ value == 'C' ? "*" : ' '
+ end
+
+ def format_char_length(value, row)
+ row[FIELDS.index{|f| f[:select] == "CHAR_USED"}] == "C" ? value.to_s : ""
+ end
+
+ def format_size(value, row)
+ row[FIELDS.index{|f| f[:select] == "lower(DATA_TYPE)"}] =~ /lob/i ? "" : value.to_s
+ end
+
+ def format_default(value, row)
+ value = value.to_s.strip.gsub(/^'(.+)'$/,'\1')
+
+ if(value.length > 10)
+ value = value[0..9] + "..."
end
+ value
end
- o.parse!
- if(ARGV[0].nil?)
- puts o
- else
- puts self.new(ARGV[1]).run(ARGV[0])
+
+ def select_fields
+ FIELDS.map{|f| f[:select]}.join(",")
end
- end
- private
+ def max(column, header)
+ max = header.length
+ column.each {|s| max = s.length if s.length > max}
+ max + SPACE_BETWEEN
+ end
+
+ def header
+ FIELDS.map{|f| f[:header].ljust(f[:max], ' ')}.join("")
+ end
- def client
- @client ||= Oci8Simple::Client.new(@env)
+ def calculate_widths(results)
+ FIELDS.each_with_index do |hsh,i|
+ if(hsh[:max].nil?)
+ hsh[:max] = max(results.map{|row| row[i].to_s}, hsh[:header])
+ end
+ end
+ end
+
+ def format_results(results)
+ arr = []
+ arr << header
+ arr << "-" * arr[0].length
+ results.each do |result|
+ str = ""
+ result.each_with_index do |col, i|
+ field = FIELDS[i]
+ value = field[:content].nil? ? col.to_s : send(field[:content], col, result)
+ if(field[:right])
+ str << value.rjust(field[:max] - SPACE_BETWEEN, ' ')
+ str << ' ' * SPACE_BETWEEN
+ else
+ str << value.ljust(field[:max], ' ')
+ end
+ end
+ arr << str
+ end
+ arr.join("\n")
+ end
+
+ def client
+ @client ||= Oci8Simple::Client.new(@env)
+ end
end
end
\ No newline at end of file