db2_query 0.3.1 → 0.3.2

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