oci8_simple 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -15,9 +15,9 @@ Jeweler::Tasks.new do |gem|
15
15
  gem.name = "oci8_simple"
16
16
  gem.homepage = "http://github.com/unclebilly/oci8_simple"
17
17
  gem.license = "MIT"
18
- gem.summary = %Q{Run single statements against an arbitrary Oracle schema.}
19
- gem.description = %Q{Run single statements against an arbitrary Oracle schema. This client is intended to be used by simple
20
- command-line scripts to aid automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
18
+ gem.summary = %Q{Command-line tools for interacting with an Oracle database.}
19
+ gem.description = %Q{Command-line tools for interacting with an Oracle database. This client is intended to be used
20
+ to aid development and automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
21
21
  The only prerequisite to running this code is that you have installed the ruby-oci8 gem on your machine.}
22
22
  gem.email = "billy.reisinger@gmail.com"
23
23
  gem.authors = ["Billy Reisinger"]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.2
1
+ 0.5.0
@@ -1,4 +1,3 @@
1
- require 'optparse'
2
1
  module Oci8Simple
3
2
  # == Description
4
3
  # A very thin wrapper around Oci8Simple::Client that handles ARGV / options and
@@ -1,44 +1,39 @@
1
- #!/usr/bin/env ruby
2
-
3
-
4
- # Run single statements against an arbitrary Oracle schema. This client is intended to be used by simple
5
- # command-line scripts to aid automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
6
- # The only prerequisite to running this code is that you have installed the ruby-oci8 gem on your machine.
7
- #
8
- # == Logging
9
- # All logging is done to ~/.oci8_simple/oci8_simple.log
10
- #
11
- # == Examples
12
- # * Initialize a client against the development schema
13
- # client = Oci8Simple::Client.new
14
- # * Run a simple select query against development schema
15
- # client.run('select id, name from foos') => [[2, "lol"], [3, "hey"], ...]
16
- # * Run a simple select query against stage schema
17
- # Oci8Simple:Client.new("stage").run('select id, name from foos') => [[2, "lol"], [3, "hey"], ...]
18
- # * Update something
19
- # client.run <<-SQL
20
- # UPDATE foos SET bar='baz' WHERE id=1233
21
- # SQL
22
- # * Run some DDL
23
- # client.run <<-SQL
24
- # CREATE TABLE foos (
25
- # ID NUMBER(38) NOT NULL
26
- # )
27
- # SQL
28
- # * Run some PL/SQL
29
- # client.run <<-SQL
30
- # DECLARE
31
- # a NUMBER;
32
- # b NUMBER;
33
- # BEGIN
34
- # SELECT e,f INTO a,b FROM T1 WHERE e>1;
35
- # INSERT INTO T1 VALUES(b,a);
36
- # END;
37
- # SQL
38
1
  module Oci8Simple
39
2
  class ConfigError < Exception; end
40
3
  class LogError < Exception; end
41
4
 
5
+ # Run SQL and PL/SQL statements against an Oracle schema.
6
+ #
7
+ # == Logging
8
+ # All logging is done to ~/.oci8_simple/oci8_simple.log
9
+ #
10
+ # == Examples
11
+ # * Initialize a client against the development schema
12
+ # client = Oci8Simple::Client.new
13
+ # * Run a simple select query against development schema
14
+ # client.run('select id, name from foos') => [[2, "lol"], [3, "hey"], ...]
15
+ # * Run a simple select query against stage schema
16
+ # Oci8Simple:Client.new("stage").run('select id, name from foos') => [[2, "lol"], [3, "hey"], ...]
17
+ # * Update something
18
+ # client.run <<-SQL
19
+ # UPDATE foos SET bar='baz' WHERE id=1233
20
+ # SQL
21
+ # * Run some DDL
22
+ # client.run <<-SQL
23
+ # CREATE TABLE foos (
24
+ # ID NUMBER(38) NOT NULL
25
+ # )
26
+ # SQL
27
+ # * Run some PL/SQL
28
+ # client.run <<-SQL
29
+ # DECLARE
30
+ # a NUMBER;
31
+ # b NUMBER;
32
+ # BEGIN
33
+ # SELECT e,f INTO a,b FROM T1 WHERE e>1;
34
+ # INSERT INTO T1 VALUES(b,a);
35
+ # END;
36
+ # SQL
42
37
  class Client
43
38
  USER_DIR = File.join(ENV["HOME"], ".oci8_simple")
44
39
  CONFIG_FILE = File.join(USER_DIR, "database.yml")
@@ -1,59 +1,131 @@
1
- class Oci8Simple::Describe
2
- def initialize(env=nil)
3
- @env = env || "development"
4
- end
1
+ module Oci8Simple
2
+ # == Description
3
+ # This class creates a string describing a table's columns, intended to be
4
+ # displayed in a fixed-width font.
5
+ # == Usage
6
+ # Oci8Simple::Describe.new("development").run("users")
7
+ class Describe
8
+ SPACE_BETWEEN=2
9
+ FIELDS=[
10
+ {:select => "NULLABLE", :header => "Required", :content => :format_nullable, :right => true},
11
+ {:select => "lower(COLUMN_NAME)", :header=> "Name"},
12
+ {:select => "lower(DATA_TYPE)", :header => "Type"},
13
+ {:select => "DATA_LENGTH", :header => "Size", :content => :format_size},
14
+ {:select => "CHAR_USED", :header => "Char?", :content => :format_char_used},
15
+ {:select => "CHAR_LENGTH", :header => "Char_size", :content => :format_char_length},
16
+ {:select => "DATA_PRECISION", :header => "Precision"},
17
+ {:select => "DATA_SCALE", :header => "Scale"},
18
+ {:select => "DATA_DEFAULT", :header => "Default", :content => :format_default, :max => 10}
19
+ ]
5
20
 
6
- def run(table)
7
- description = client.conn.describe_table(table)
8
- c = description.columns.sort{|a,b| a.name <=> b.name }
9
- max_name = max(c.map(&:name)) + 3
10
- max_type = max(c.map {|col| type_and_size(col)}) + 1
11
- c.map do |col|
12
- "\"#{col.name}\"".ljust(max_name, ' ') + type_and_size(col).ljust(max_type, ' ') + null(col)
13
- end.map(&:upcase).join("\n")
14
- end
21
+ def run(table)
22
+ sql = <<-SQL
23
+ select #{select_fields}
24
+ from user_tab_columns
25
+ where table_name='#{table.upcase}'
26
+ order by column_name asc
27
+ SQL
28
+ results = client.run(sql)
29
+ calculate_widths(results)
30
+ format_results(results)
31
+ end
15
32
 
16
- def null(col)
17
- col.nullable? ? "" : "NOT NULL"
18
- end
33
+ def initialize(env=nil)
34
+ @env = env || "development"
35
+ end
19
36
 
20
- def type_and_size(col)
21
- str = "#{col.data_type}"
22
- if(col.data_type.to_s =~ /varchar/i)
23
- str << "(#{col.char_size} CHAR)"
24
- elsif(col.data_type == :number)
25
- str << "(#{col.precision})"
37
+ def self.usage
38
+ "Usage: #{0} TABLE_NAME [ENVIRONMENT]"
26
39
  end
27
- str
28
- end
29
40
 
30
- def max(arr)
31
- arr.map(&:length).max
32
- end
41
+ def self.run_from_argv
42
+ o = OptionParser.new do |opt|
43
+ opt.banner = usage
44
+ opt.on("-v", "--version", "Show version") do
45
+ puts "version #{File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))}"
46
+ exit
47
+ end
48
+ end
49
+ o.parse!
50
+ if(ARGV[0].nil?)
51
+ puts o
52
+ else
53
+ puts self.new(ARGV[1]).run(ARGV[0])
54
+ end
55
+ end
33
56
 
34
- def self.usage
35
- "Usage: #{0} TABLE_NAME [ENVIRONMENT]"
36
- end
57
+ private
37
58
 
38
- def self.run_from_argv
39
- o = OptionParser.new do |opt|
40
- opt.banner = usage
41
- opt.on("-v", "--version", "Show version") do
42
- puts "version #{File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))}"
43
- exit
59
+ def format_nullable(value, row)
60
+ value == 'N' ? '*' : ' '
61
+ end
62
+
63
+ def format_char_used(value, row)
64
+ value == 'C' ? "*" : ' '
65
+ end
66
+
67
+ def format_char_length(value, row)
68
+ row[FIELDS.index{|f| f[:select] == "CHAR_USED"}] == "C" ? value.to_s : ""
69
+ end
70
+
71
+ def format_size(value, row)
72
+ row[FIELDS.index{|f| f[:select] == "lower(DATA_TYPE)"}] =~ /lob/i ? "" : value.to_s
73
+ end
74
+
75
+ def format_default(value, row)
76
+ value = value.to_s.strip.gsub(/^'(.+)'$/,'\1')
77
+
78
+ if(value.length > 10)
79
+ value = value[0..9] + "..."
44
80
  end
81
+ value
45
82
  end
46
- o.parse!
47
- if(ARGV[0].nil?)
48
- puts o
49
- else
50
- puts self.new(ARGV[1]).run(ARGV[0])
83
+
84
+ def select_fields
85
+ FIELDS.map{|f| f[:select]}.join(",")
86
+ end
87
+
88
+ def max(column, header)
89
+ max = header.length
90
+ column.each {|s| max = s.length if s.length > max}
91
+ max + SPACE_BETWEEN
92
+ end
93
+
94
+ def header
95
+ FIELDS.map{|f| f[:header].ljust(f[:max], ' ')}.join("")
51
96
  end
52
- end
53
97
 
54
- private
98
+ def calculate_widths(results)
99
+ FIELDS.each_with_index do |hsh,i|
100
+ if(hsh[:max].nil?)
101
+ hsh[:max] = max(results.map{|row| row[i].to_s}, hsh[:header])
102
+ end
103
+ end
104
+ end
55
105
 
56
- def client
57
- @client ||= Oci8Simple::Client.new(@env)
106
+ def format_results(results)
107
+ arr = []
108
+ arr << header
109
+ arr << "-" * arr[0].length
110
+ results.each do |result|
111
+ str = ""
112
+ result.each_with_index do |col, i|
113
+ field = FIELDS[i]
114
+ value = field[:content].nil? ? col.to_s : send(field[:content], col, result)
115
+ if(field[:right])
116
+ str << value.rjust(field[:max] - SPACE_BETWEEN, ' ')
117
+ str << ' ' * SPACE_BETWEEN
118
+ else
119
+ str << value.ljust(field[:max], ' ')
120
+ end
121
+ end
122
+ arr << str
123
+ end
124
+ arr.join("\n")
125
+ end
126
+
127
+ def client
128
+ @client ||= Oci8Simple::Client.new(@env)
129
+ end
58
130
  end
59
131
  end
data/lib/oci8_simple.rb CHANGED
@@ -2,6 +2,7 @@ require 'rubygems'
2
2
  require 'pp'
3
3
  require 'bigdecimal'
4
4
  require 'yaml'
5
+ require 'optparse'
5
6
 
6
7
  gem 'ruby-oci8'
7
8
  require 'oci8'
data/oci8_simple.gemspec CHANGED
@@ -5,13 +5,13 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{oci8_simple}
8
- s.version = "0.4.2"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Billy Reisinger"]
12
- s.date = %q{2011-06-11}
13
- s.description = %q{Run single statements against an arbitrary Oracle schema. This client is intended to be used by simple
14
- command-line scripts to aid automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
12
+ s.date = %q{2011-06-30}
13
+ s.description = %q{Command-line tools for interacting with an Oracle database. This client is intended to be used
14
+ to aid development and automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
15
15
  The only prerequisite to running this code is that you have installed the ruby-oci8 gem on your machine.}
16
16
  s.email = %q{billy.reisinger@gmail.com}
17
17
  s.executables = ["oci8_simple", "describe"]
@@ -42,7 +42,7 @@ Gem::Specification.new do |s|
42
42
  s.licenses = ["MIT"]
43
43
  s.require_paths = ["lib"]
44
44
  s.rubygems_version = %q{1.5.2}
45
- s.summary = %q{Run single statements against an arbitrary Oracle schema.}
45
+ s.summary = %q{Command-line tools for interacting with an Oracle database.}
46
46
  s.test_files = [
47
47
  "test/cli_test.rb",
48
48
  "test/client_test.rb",
@@ -7,8 +7,9 @@ class DescribeTest < Test::Unit::TestCase
7
7
  @client.run <<-SQL
8
8
  CREATE TABLE "OCI8_SIMPLE_TEST"
9
9
  (
10
- "NAME" VARCHAR2(400 CHAR) NOT NULL ENABLE,
11
- "ID" NUMBER(38,0) NOT NULL ENABLE,
10
+ "NAME" VARCHAR2(400 CHAR) DEFAULT 'FOO' NOT NULL ENABLE,
11
+ "ID" NUMBER(38,0) DEFAULT 7 NOT NULL ENABLE,
12
+ "LONG_THING" VARCHAR(2000 CHAR) DEFAULT '#{"a " * 50}' NOT NULL ENABLE,
12
13
  "TEXTS" CLOB
13
14
  )
14
15
  SQL
@@ -19,10 +20,16 @@ class DescribeTest < Test::Unit::TestCase
19
20
  end
20
21
  should "format results for the command line" do
21
22
  expected=<<-STR
22
- "ID" NUMBER(38) NOT NULL
23
- "NAME" VARCHAR2(400 CHAR) NOT NULL
24
- "TEXTS" CLOB
23
+ Required Name Type Size Char? Char_size Precision Scale Default
24
+ ------------------------------------------------------------------------------------
25
+ * id number 22 38 0 7
26
+ * long_thing varchar2 4000 * 2000 a a a a a ...
27
+ * name varchar2 1600 * 400 FOO
28
+ texts clob
25
29
  STR
30
+ # puts
31
+ # puts expected.chop
32
+ # puts @describe.run("oci8_simple_test")
26
33
  assert_equal(expected.chop, @describe.run("oci8_simple_test"))
27
34
  end
28
35
  end
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 4
9
- - 2
10
- version: 0.4.2
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Billy Reisinger
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-11 00:00:00 -05:00
18
+ date: 2011-06-30 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -111,8 +111,8 @@ dependencies:
111
111
  type: :runtime
112
112
  requirement: *id006
113
113
  description: |-
114
- Run single statements against an arbitrary Oracle schema. This client is intended to be used by simple
115
- command-line scripts to aid automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
114
+ Command-line tools for interacting with an Oracle database. This client is intended to be used
115
+ to aid development and automation. This is *not* meant to replace an ORM such as ActiveRecord + OracleEnhancedAdapter.
116
116
  The only prerequisite to running this code is that you have installed the ruby-oci8 gem on your machine.
117
117
  email: billy.reisinger@gmail.com
118
118
  executables:
@@ -174,7 +174,7 @@ rubyforge_project:
174
174
  rubygems_version: 1.5.2
175
175
  signing_key:
176
176
  specification_version: 3
177
- summary: Run single statements against an arbitrary Oracle schema.
177
+ summary: Command-line tools for interacting with an Oracle database.
178
178
  test_files:
179
179
  - test/cli_test.rb
180
180
  - test/client_test.rb