oci8_simple 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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