db2_query 0.2.3 → 0.3.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.
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DB2Query
4
- class Bind < Struct.new(:name, :value, :index)
5
- end
6
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DB2Query
4
- CONNECTION_TYPES = %i[dsn conn_string].freeze
5
-
6
- class ConnectionPool < ActiveRecord::ConnectionAdapters::ConnectionPool
7
- attr_reader :conn_type
8
-
9
- def initialize(spec)
10
- @conn_type = (spec.config.keys & DB2Query::CONNECTION_TYPES).first
11
- super(spec)
12
- end
13
-
14
- private
15
- def new_connection
16
- DB2Query::Connection.new(conn_type, spec.config)
17
- end
18
- end
19
-
20
- class ConnectionSpecification
21
- attr_reader :name, :config
22
-
23
- def initialize(name, config)
24
- @name, @config = name, config
25
- end
26
-
27
- def initialize_dup(original)
28
- @config = original.config.dup
29
- end
30
-
31
- def to_hash
32
- @config.merge(name: @name)
33
- end
34
-
35
- class Resolver < ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver
36
- def spec(config)
37
- pool_name = config if config.is_a?(Symbol)
38
- spec = resolve(config, pool_name).symbolize_keys
39
- ConnectionSpecification.new(spec.delete(:name) || "primary", spec)
40
- end
41
- end
42
- end
43
-
44
- class ConnectionHandler < ActiveRecord::ConnectionAdapters::ConnectionHandler
45
- def establish_connection(config)
46
- resolver = ConnectionSpecification::Resolver.new(DB2Query::Base.configurations)
47
-
48
- spec = resolver.spec(config)
49
-
50
- remove_connection(spec.name)
51
-
52
- message_bus = ActiveSupport::Notifications.instrumenter
53
- payload = {
54
- connection_id: object_id
55
- }
56
- if spec
57
- payload[:spec_name] = spec.name
58
- payload[:config] = spec.config
59
- end
60
-
61
- message_bus.instrument("!connection.active_record", payload) do
62
- owner_to_pool[spec.name] = DB2Query::ConnectionPool.new(spec)
63
- end
64
-
65
- owner_to_pool[spec.name]
66
- end
67
- end
68
-
69
- module ConnectionHandling
70
- RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
71
- DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
72
-
73
- def lookup_connection_handler(handler_key)
74
- handler_key = DB2Query::Base.reading_role
75
- connection_handlers[handler_key] ||= DB2Query::ConnectionHandler.new
76
- end
77
-
78
- def resolve_config_for_connection(config_or_env)
79
- raise "Anonymous class is not allowed." unless name
80
-
81
- config_or_env ||= DEFAULT_ENV.call.to_sym
82
- pool_name = primary_class? ? "primary" : name
83
- self.connection_specification_name = pool_name
84
- resolver = DB2Query::ConnectionSpecification::Resolver.new(DB2Query::Base.configurations)
85
-
86
- config_hash = resolver.resolve(config_or_env, pool_name).symbolize_keys
87
- config_hash[:name] = pool_name
88
-
89
- config_hash
90
- end
91
-
92
- def connection_specification_name
93
- if !defined?(@connection_specification_name) || @connection_specification_name.nil?
94
- return self == DB2Query::Base ? "primary" : superclass.connection_specification_name
95
- end
96
- @connection_specification_name
97
- end
98
-
99
- def primary_class?
100
- self == DB2Query::Base || defined?(Db2Record) && self == Db2Record
101
- end
102
-
103
- private
104
- def swap_connection_handler(handler, &blk)
105
- old_handler, DB2Query::Base.connection_handler = DB2Query::Base.connection_handler, handler
106
- return_value = yield
107
- return_value
108
- ensure
109
- DB2Query::Base.connection_handler = old_handler
110
- end
111
- end
112
- end
@@ -1,89 +0,0 @@
1
- # frozen_String_literal: true
2
-
3
- module DB2Query
4
- module DatabaseStatements
5
- def query(sql)
6
- stmt = @connection.run(sql)
7
- stmt.to_a
8
- ensure
9
- stmt.drop unless stmt.nil?
10
- end
11
-
12
- def query_rows(sql)
13
- query(sql)
14
- end
15
-
16
- def query_value(sql)
17
- single_value_from_rows(query(sql))
18
- end
19
-
20
- def query_values(sql)
21
- query(sql).map(&:first)
22
- end
23
-
24
- def execute(sql, args = [])
25
- @connection.do(sql, *args)
26
- end
27
-
28
- def exec_query(formatters, sql, args = [])
29
- binds, args = extract_binds_from_sql(sql, args)
30
- log(sql, "SQL", binds, args) do
31
- begin
32
- if args.empty?
33
- stmt = @connection.run(sql)
34
- else
35
- stmt = @connection.run(sql, *args)
36
- end
37
- columns = stmt.columns.values.map { |col| col.name.downcase }
38
- rows = stmt.to_a
39
- ensure
40
- stmt.drop unless stmt.nil?
41
- end
42
- DB2Query::Result.new(columns, rows, formatters)
43
- end
44
- end
45
-
46
- private
47
- def single_value_from_rows(rows)
48
- row = rows.first
49
- row && row.first
50
- end
51
-
52
- def key_finder_regex(k)
53
- /#{k} .\\? | #{k}.\\? | #{k}. \\? /i
54
- end
55
-
56
- def extract_binds_from_sql(sql, args)
57
- question_mark_positions = sql.enum_for(:scan, /\?/i).map { Regexp.last_match.begin(0) }
58
- args = args.first.is_a?(Hash) ? args.first : args
59
- given, expected = args.length, question_mark_positions.length
60
-
61
- if given != expected
62
- raise DB2Query::Error, "wrong number of arguments (given #{given}, expected #{expected})"
63
- end
64
-
65
- if args.is_a?(Hash)
66
- binds = args.map do |key, value|
67
- position = sql.enum_for(:scan, key_finder_regex(key)).map { Regexp.last_match.begin(0) }
68
- if position.empty?
69
- raise DB2Query::Error, "Column name: `#{key}` not found inside sql statement."
70
- elsif position.length > 1
71
- raise DB2Query::Error, "Can't handle such this kind of sql. Please refactor your sql."
72
- else
73
- index = position[0]
74
- end
75
-
76
- DB2Query::Bind.new(key.to_s, value, index)
77
- end
78
- binds = binds.sort_by { |bind| bind.index }
79
- [binds.map { |bind| [bind, bind.value] }, binds.map { |bind| bind.value }]
80
- elsif question_mark_positions.length == 1 && args.length == 1
81
- column = sql[/(.*?) . \?|(.*?) .\?|(.*?). \?|(.*?).\?/m, 1].split.last.downcase
82
- bind = DB2Query::Bind.new(column.gsub(/[)(]/, ""), args, 0)
83
- [[[bind, bind.value]], bind.value]
84
- else
85
- [args.map { |arg| [nil, arg] }, args]
86
- end
87
- end
88
- end
89
- end
@@ -1,44 +0,0 @@
1
- # frozen_String_literal: true
2
-
3
- require "odbc_utf8"
4
-
5
- module DB2Query
6
- class ODBCConnector
7
- def self.new(type, config)
8
- conn_type, conn_config = type, config.transform_keys(&:to_sym)
9
- DB2Query.const_get("#{conn_type.to_s.camelize}Connector").new(conn_config)
10
- end
11
- end
12
-
13
- class AbstractConnector
14
- attr_reader :config
15
-
16
- def initialize(config)
17
- @config = config
18
- end
19
-
20
- def connect
21
- raise "abstract method #connect must be defined"
22
- end
23
- end
24
-
25
- class DsnConnector < AbstractConnector
26
- def connect
27
- ::ODBC.connect(config[:dsn], config[:uid], config[:pwd])
28
- rescue ::ODBC::Error => e
29
- raise DB2Query::Error, "Unable to activate ODBC DSN connection #{e}"
30
- end
31
- end
32
-
33
- class ConnStringConnector < AbstractConnector
34
- def connect
35
- driver = ::ODBC::Driver.new.tap do |d|
36
- d.attrs = config[:conn_string].transform_keys(&:to_s)
37
- d.name = "odbc"
38
- end
39
- ::ODBC::Database.new.drvconnect(driver)
40
- rescue ::ODBC::Error => e
41
- raise DB2Query::Error, "Unable to activate ODBC Conn String connection #{e}"
42
- end
43
- end
44
- end