db2_query 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/README.md +399 -147
- data/lib/db2_query.rb +36 -9
- data/lib/db2_query/base.rb +13 -0
- data/lib/db2_query/config.rb +14 -14
- data/lib/db2_query/core.rb +59 -118
- data/lib/db2_query/db_client.rb +56 -0
- data/lib/db2_query/db_connection.rb +67 -0
- data/lib/db2_query/db_statements.rb +87 -0
- data/lib/db2_query/definitions.rb +79 -0
- data/lib/db2_query/error.rb +71 -6
- data/lib/db2_query/field_type.rb +31 -0
- data/lib/db2_query/helper.rb +49 -0
- data/lib/db2_query/logger.rb +14 -4
- data/lib/db2_query/query.rb +117 -0
- data/lib/db2_query/quoting.rb +102 -0
- data/lib/db2_query/railtie.rb +5 -2
- data/lib/db2_query/result.rb +45 -33
- data/lib/db2_query/sql_statement.rb +34 -0
- data/lib/db2_query/tasks.rb +29 -0
- data/lib/db2_query/tasks/database.rake +2 -33
- data/lib/db2_query/tasks/init.rake +1 -1
- data/lib/db2_query/tasks/initializer.rake +2 -33
- data/lib/db2_query/tasks/templates/database.rb.tt +19 -0
- data/lib/db2_query/tasks/templates/initializer.rb.tt +8 -0
- data/lib/db2_query/type/binary.rb +19 -0
- data/lib/db2_query/type/boolean.rb +41 -0
- data/lib/db2_query/type/date.rb +34 -0
- data/lib/db2_query/type/decimal.rb +15 -0
- data/lib/db2_query/type/integer.rb +15 -0
- data/lib/db2_query/type/string.rb +30 -0
- data/lib/db2_query/type/text.rb +11 -0
- data/lib/db2_query/type/time.rb +30 -0
- data/lib/db2_query/type/timestamp.rb +30 -0
- data/lib/db2_query/type/value.rb +29 -0
- data/lib/db2_query/version.rb +1 -1
- data/lib/rails/generators/query/USAGE +15 -0
- data/lib/rails/generators/query/query_generator.rb +70 -0
- data/lib/rails/generators/query/templates/query.rb.tt +26 -0
- data/lib/rails/generators/query/templates/query_definitions.rb.tt +12 -0
- data/lib/rails/generators/query/templates/unit_test.rb.tt +9 -0
- metadata +49 -10
- data/lib/db2_query/connection.rb +0 -125
- data/lib/db2_query/formatter.rb +0 -27
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module Quoting
|
5
|
+
def self.included(base)
|
6
|
+
base.send(:extend, ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def quoted_true
|
11
|
+
"TRUE"
|
12
|
+
end
|
13
|
+
|
14
|
+
def unquoted_true
|
15
|
+
1
|
16
|
+
end
|
17
|
+
|
18
|
+
def quoted_false
|
19
|
+
"FALSE"
|
20
|
+
end
|
21
|
+
|
22
|
+
def unquoted_false
|
23
|
+
0
|
24
|
+
end
|
25
|
+
|
26
|
+
def quoted_binary(value)
|
27
|
+
"x'#{value.hex}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
def quoted_time(value)
|
31
|
+
value = value.change(year: 2000, month: 1, day: 1)
|
32
|
+
quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
|
33
|
+
end
|
34
|
+
|
35
|
+
def quoted_date(value)
|
36
|
+
if value.acts_like?(:time)
|
37
|
+
if ActiveRecord::Base.default_timezone == :utc
|
38
|
+
value = value.getutc if !value.utc?
|
39
|
+
else
|
40
|
+
value = value.getlocal
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
result = value.to_s(:db)
|
45
|
+
if value.respond_to?(:usec) && value.usec > 0
|
46
|
+
result << "." << sprintf("%06d", value.usec)
|
47
|
+
else
|
48
|
+
result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def _quote(value)
|
54
|
+
case value
|
55
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
56
|
+
"'#{quote_string(value.to_s)}'"
|
57
|
+
when true
|
58
|
+
quoted_true
|
59
|
+
when false
|
60
|
+
quoted_false
|
61
|
+
when nil
|
62
|
+
"NULL"
|
63
|
+
when BigDecimal
|
64
|
+
value.to_s("F")
|
65
|
+
when Numeric, ActiveSupport::Duration
|
66
|
+
value.to_s
|
67
|
+
when Db2Query::Type::Binary::Data
|
68
|
+
quoted_binary(value)
|
69
|
+
when ActiveRecord::Type::Time::Value
|
70
|
+
"'#{quoted_time(value)}'"
|
71
|
+
when Date, Time
|
72
|
+
"'#{quoted_date(value)}'"
|
73
|
+
when Class
|
74
|
+
"'#{value}'"
|
75
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def _type_cast(value)
|
80
|
+
case value
|
81
|
+
when Symbol, ActiveSupport::Multibyte::Chars
|
82
|
+
value.to_s
|
83
|
+
when Db2Query::Type::Binary::Data
|
84
|
+
value.hex
|
85
|
+
when true
|
86
|
+
unquoted_true
|
87
|
+
when false
|
88
|
+
unquoted_false
|
89
|
+
when BigDecimal
|
90
|
+
value.to_s("F")
|
91
|
+
when nil, Numeric, String
|
92
|
+
value
|
93
|
+
when ActiveRecord::Type::Time::Value
|
94
|
+
quoted_time(value)
|
95
|
+
when Date, Time
|
96
|
+
quoted_date(value)
|
97
|
+
else raise TypeError, "can't cast #{value.class.name}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/db2_query/railtie.rb
CHANGED
@@ -8,8 +8,11 @@ module Db2Query
|
|
8
8
|
railtie_name :db2_query
|
9
9
|
|
10
10
|
rake_tasks do
|
11
|
-
|
12
|
-
|
11
|
+
Dir.glob("#{Db2Query.root}/db2_query/tasks/*.rake").each { |f| load f }
|
12
|
+
end
|
13
|
+
|
14
|
+
config.app_generators do
|
15
|
+
require "#{Db2Query.root}/rails/generators/query/query_generator.rb"
|
13
16
|
end
|
14
17
|
end
|
15
18
|
end
|
data/lib/db2_query/result.rb
CHANGED
@@ -2,76 +2,88 @@
|
|
2
2
|
|
3
3
|
module Db2Query
|
4
4
|
class Result < ActiveRecord::Result
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :definition
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
7
|
+
alias query definition
|
8
|
+
|
9
|
+
delegate :data_type, :validate_result_columns, to: :definition
|
11
10
|
|
12
|
-
def
|
13
|
-
@
|
11
|
+
def initialize(columns, rows, definition)
|
12
|
+
@definition = definition
|
13
|
+
validate_result_columns(columns)
|
14
|
+
super(columns, rows, {})
|
14
15
|
end
|
15
16
|
|
16
17
|
def record
|
17
|
-
|
18
|
+
records.first
|
18
19
|
end
|
19
20
|
|
20
21
|
def records
|
21
|
-
@records ||= rows.map
|
22
|
-
Record.new(row, columns, formatters)
|
23
|
-
end
|
22
|
+
@records ||= rows.map { |row| new_record(row) }
|
24
23
|
end
|
25
24
|
|
26
25
|
def to_h
|
27
26
|
rows.map do |row|
|
28
|
-
|
27
|
+
index, hash = [0, {}]
|
28
|
+
while index < columns.length
|
29
|
+
attr_name = columns[index].to_sym
|
30
|
+
hash[attr_name] = data_type(attr_name).deserialize(row[index])
|
31
|
+
index += 1
|
32
|
+
end
|
33
|
+
hash
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def inspect
|
33
38
|
entries = records.take(11).map!(&:inspect)
|
34
|
-
|
35
39
|
entries[10] = "..." if entries.size == 11
|
36
|
-
|
37
40
|
"#<#{self.class.name} [#{entries.join(', ')}]>"
|
38
41
|
end
|
39
42
|
|
40
43
|
class Record
|
41
|
-
attr_reader :
|
44
|
+
attr_reader :definition
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
send("#{column}=", value)
|
49
|
-
end
|
46
|
+
delegate :data_type, to: :definition
|
47
|
+
|
48
|
+
def initialize(row, columns, definition)
|
49
|
+
@definition = definition
|
50
|
+
add_attributes(columns, row)
|
50
51
|
end
|
51
52
|
|
52
53
|
def inspect
|
53
54
|
inspection = if defined?(instance_variables) && instance_variables
|
54
|
-
instance_variables.reject { |var| var == :@
|
55
|
-
|
56
|
-
"#{attr[1..-1]}: #{(value.kind_of? String) ? %Q{"#{value}"} : value}"
|
55
|
+
instance_variables.reject { |var| var == :@definition }.map do |attribute|
|
56
|
+
"#{attribute[1..-1]}: #{instance_variable_get(attribute)}"
|
57
57
|
end.compact.join(", ")
|
58
58
|
else
|
59
59
|
"not initialized"
|
60
60
|
end
|
61
|
-
|
62
61
|
"#<Record #{inspection}>"
|
63
62
|
end
|
64
63
|
|
65
64
|
private
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
def add_attributes(columns, row)
|
66
|
+
index = 0
|
67
|
+
while index < columns.length
|
68
|
+
column, value = [columns[index], row[index]]
|
69
|
+
class_eval { attr_accessor "#{column}" }
|
70
|
+
send("#{column}=", data_type(column).deserialize(value))
|
71
|
+
index += 1
|
72
72
|
end
|
73
|
-
[column, val]
|
74
73
|
end
|
75
74
|
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def new_record(row)
|
78
|
+
Record.new(row, columns, definition)
|
79
|
+
end
|
80
|
+
|
81
|
+
def method_missing(method_name, *args, &block)
|
82
|
+
if record.respond_to?(method_name)
|
83
|
+
record.send(method_name)
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
76
88
|
end
|
77
89
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module SqlStatement
|
5
|
+
def delete_sql?
|
6
|
+
sql.match?(/delete/i)
|
7
|
+
end
|
8
|
+
|
9
|
+
def insert_sql?
|
10
|
+
sql.match?(/insert/i)
|
11
|
+
end
|
12
|
+
|
13
|
+
def iud_sql?
|
14
|
+
sql.match?(/insert into|update|delete/i)
|
15
|
+
end
|
16
|
+
|
17
|
+
def db2_spec_sql
|
18
|
+
iud_sql? ? iud_spec_sql : sql
|
19
|
+
end
|
20
|
+
|
21
|
+
def table_name
|
22
|
+
insert_sql? ? sql.split("INTO ").last.split(" ").first : nil
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def new_keys(raw_sql)
|
27
|
+
raw_sql.scan(/\$\S+/).map { |key| key.gsub!(/[$=,)]/, "").to_sym }
|
28
|
+
end
|
29
|
+
|
30
|
+
def iud_spec_sql
|
31
|
+
"SELECT * FROM #{delete_sql? ? "OLD" : "NEW"} TABLE (#{sql})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
module Db2Query
|
6
|
+
class Tasks < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
class << self
|
10
|
+
alias generate_file start
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class DatabaseTask < Tasks
|
15
|
+
source_root File.expand_path("../tasks/templates", __FILE__)
|
16
|
+
|
17
|
+
def create_database_config_file
|
18
|
+
template "database.rb", File.join("config/db2query.yml")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class InitializerTask < Tasks
|
23
|
+
source_root File.expand_path("../tasks/templates", __FILE__)
|
24
|
+
|
25
|
+
def create_initializer_file
|
26
|
+
template "initializer.rb", File.join("config/initializers/db2query.rb")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,41 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "db2_query"
|
4
|
-
|
5
|
-
DB2_QUERY_DATABASE_TEMPLATE ||= <<-EOF
|
6
|
-
# frozen_string_literal: true
|
7
|
-
|
8
|
-
development:
|
9
|
-
dsn: TODO
|
10
|
-
idle: 5
|
11
|
-
pool: 5
|
12
|
-
timeout: 5
|
13
|
-
|
14
|
-
test:
|
15
|
-
dsn: TODO
|
16
|
-
idle: 5
|
17
|
-
pool: 5
|
18
|
-
timeout: 5
|
19
|
-
|
20
|
-
production:
|
21
|
-
dsn: TODO
|
22
|
-
idle: 5
|
23
|
-
pool: 5
|
24
|
-
timeout: 5
|
25
|
-
EOF
|
3
|
+
require "db2_query/tasks"
|
26
4
|
|
27
5
|
namespace :db2query do
|
28
6
|
desc "Create Database configuration file"
|
29
7
|
task :database do
|
30
|
-
|
31
|
-
if File.exist?(database_path)
|
32
|
-
raise Db2Query::Error, "Db2Query database config file exists, please check first"
|
33
|
-
else
|
34
|
-
puts " Creating database config file ..."
|
35
|
-
File.open(database_path, "w") do |file|
|
36
|
-
file.puts DB2_QUERY_DATABASE_TEMPLATE
|
37
|
-
end
|
38
|
-
puts " File '#{database_path}' created."
|
39
|
-
end
|
8
|
+
Db2Query::DatabaseTask.generate_file
|
40
9
|
end
|
41
10
|
end
|
@@ -1,41 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "db2_query"
|
4
|
-
|
5
|
-
DB2_QUERY_INITIALIZER_TEMPLATE ||= <<-EOF
|
6
|
-
# frozen_string_literal: true
|
7
|
-
require "db2_query"
|
8
|
-
require "db2_query/formatter"
|
9
|
-
|
10
|
-
Db2Query::Base.initiation do |base|
|
11
|
-
base.establish_connection
|
12
|
-
end
|
13
|
-
|
14
|
-
# Example
|
15
|
-
#class FirstNameFormatter < Db2Query::AbstractFormatter
|
16
|
-
# def format(value)
|
17
|
-
# "Dr." + value
|
18
|
-
# end
|
19
|
-
#end
|
20
|
-
|
21
|
-
#Db2Query::Formatter.registration do |format|
|
22
|
-
# format.register(:first_name_formatter, FirstNameFormatter)
|
23
|
-
#end
|
24
|
-
EOF
|
3
|
+
require "db2_query/tasks"
|
25
4
|
|
26
5
|
namespace :db2query do
|
27
6
|
desc "Create Initializer file"
|
28
7
|
task :initializer do
|
29
|
-
|
30
|
-
initializer_path = "#{Rails.root}/config/initializers/db2query.rb"
|
31
|
-
if File.exist?(initializer_path)
|
32
|
-
raise Db2Query::Error, "Db2Query initializer file exists, please check first"
|
33
|
-
else
|
34
|
-
puts " Creating initializer file ..."
|
35
|
-
File.open(initializer_path, "w") do |file|
|
36
|
-
file.puts DB2_QUERY_INITIALIZER_TEMPLATE
|
37
|
-
end
|
38
|
-
puts " File '#{initializer_path}' created."
|
39
|
-
end
|
8
|
+
Db2Query::InitializerTask.generate_file
|
40
9
|
end
|
41
10
|
end
|