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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +399 -147
  3. data/lib/db2_query.rb +36 -9
  4. data/lib/db2_query/base.rb +13 -0
  5. data/lib/db2_query/config.rb +14 -14
  6. data/lib/db2_query/core.rb +59 -118
  7. data/lib/db2_query/db_client.rb +56 -0
  8. data/lib/db2_query/db_connection.rb +67 -0
  9. data/lib/db2_query/db_statements.rb +87 -0
  10. data/lib/db2_query/definitions.rb +79 -0
  11. data/lib/db2_query/error.rb +71 -6
  12. data/lib/db2_query/field_type.rb +31 -0
  13. data/lib/db2_query/helper.rb +49 -0
  14. data/lib/db2_query/logger.rb +14 -4
  15. data/lib/db2_query/query.rb +117 -0
  16. data/lib/db2_query/quoting.rb +102 -0
  17. data/lib/db2_query/railtie.rb +5 -2
  18. data/lib/db2_query/result.rb +45 -33
  19. data/lib/db2_query/sql_statement.rb +34 -0
  20. data/lib/db2_query/tasks.rb +29 -0
  21. data/lib/db2_query/tasks/database.rake +2 -33
  22. data/lib/db2_query/tasks/init.rake +1 -1
  23. data/lib/db2_query/tasks/initializer.rake +2 -33
  24. data/lib/db2_query/tasks/templates/database.rb.tt +19 -0
  25. data/lib/db2_query/tasks/templates/initializer.rb.tt +8 -0
  26. data/lib/db2_query/type/binary.rb +19 -0
  27. data/lib/db2_query/type/boolean.rb +41 -0
  28. data/lib/db2_query/type/date.rb +34 -0
  29. data/lib/db2_query/type/decimal.rb +15 -0
  30. data/lib/db2_query/type/integer.rb +15 -0
  31. data/lib/db2_query/type/string.rb +30 -0
  32. data/lib/db2_query/type/text.rb +11 -0
  33. data/lib/db2_query/type/time.rb +30 -0
  34. data/lib/db2_query/type/timestamp.rb +30 -0
  35. data/lib/db2_query/type/value.rb +29 -0
  36. data/lib/db2_query/version.rb +1 -1
  37. data/lib/rails/generators/query/USAGE +15 -0
  38. data/lib/rails/generators/query/query_generator.rb +70 -0
  39. data/lib/rails/generators/query/templates/query.rb.tt +26 -0
  40. data/lib/rails/generators/query/templates/query_definitions.rb.tt +12 -0
  41. data/lib/rails/generators/query/templates/unit_test.rb.tt +9 -0
  42. metadata +49 -10
  43. data/lib/db2_query/connection.rb +0 -125
  44. 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
@@ -8,8 +8,11 @@ module Db2Query
8
8
  railtie_name :db2_query
9
9
 
10
10
  rake_tasks do
11
- path = File.expand_path(__dir__)
12
- Dir.glob("#{path}/tasks/*.rake").each { |f| load f }
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
@@ -2,76 +2,88 @@
2
2
 
3
3
  module Db2Query
4
4
  class Result < ActiveRecord::Result
5
- attr_reader :formatters
5
+ attr_reader :definition
6
6
 
7
- def initialize(columns, rows, formatters = {}, column_types = {})
8
- @formatters = formatters
9
- super(columns, rows, column_types)
10
- end
7
+ alias query definition
8
+
9
+ delegate :data_type, :validate_result_columns, to: :definition
11
10
 
12
- def includes_column?(name)
13
- @columns.include? name
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
- @record ||= Record.new(rows[0], columns, formatters)
18
+ records.first
18
19
  end
19
20
 
20
21
  def records
21
- @records ||= rows.map do |row|
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
- columns.zip(row).each_with_object({}) { |cr, h| h[cr[0].to_sym] = cr[1] }
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 :formatters
44
+ attr_reader :definition
42
45
 
43
- def initialize(row, columns, formatters)
44
- @formatters = formatters
45
- columns.zip(row) do |col, val|
46
- column, value = format(col, val)
47
- singleton_class.class_eval { attr_accessor "#{column}" }
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 == :@formatters }.map do |attr|
55
- value = instance_variable_get(attr)
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 format(col, val)
67
- column = col.downcase
68
- format_name = formatters[column.to_sym]
69
- unless format_name.nil?
70
- formatter = Db2Query::Formatter.lookup(format_name)
71
- val = formatter.format(val)
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
- database_path = "#{Rails.root}/config/db2query.yml"
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
@@ -3,7 +3,7 @@
3
3
  namespace :db2query do
4
4
  desc "Create Initializer and Database configuration file"
5
5
  task :init do
6
- Rake::Task["db2query:initializer"].invoke
7
6
  Rake::Task["db2query:database"].invoke
7
+ Rake::Task["db2query:initializer"].invoke
8
8
  end
9
9
  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
- # Create initializer file
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
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ development:
4
+ dsn: TODO
5
+ idle: 5
6
+ pool: 5
7
+ timeout: 5
8
+
9
+ test:
10
+ dsn: TODO
11
+ idle: 5
12
+ pool: 5
13
+ timeout: 5
14
+
15
+ production:
16
+ dsn: TODO
17
+ idle: 5
18
+ pool: 5
19
+ timeout: 5
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "db2_query"
4
+
5
+ Db2Query::Base.initiation do |base|
6
+ base.set_field_types
7
+ base.establish_connection
8
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Db2Query
4
+ module Type
5
+ class Binary
6
+ def type
7
+ :binary
8
+ end
9
+
10
+ def serialize(value)
11
+ value.unpack1("H*")
12
+ end
13
+
14
+ def deserialize(value)
15
+ [value].pack("H*")
16
+ end
17
+ end
18
+ end
19
+ end