db2_query 0.2.2 → 0.2.3
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 +30 -4
- data/lib/db2_query.rb +2 -0
- data/lib/db2_query/bind.rb +6 -0
- data/lib/db2_query/connection.rb +7 -6
- data/lib/db2_query/connection_handling.rb +4 -4
- data/lib/db2_query/core.rb +16 -9
- data/lib/db2_query/database_statements.rb +14 -18
- data/lib/db2_query/error.rb +16 -0
- data/lib/db2_query/formatter.rb +1 -1
- data/lib/db2_query/odbc_connector.rb +6 -2
- data/lib/db2_query/tasks/database.rake +0 -4
- data/lib/db2_query/version.rb +1 -1
- metadata +5 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42c29fbb4c23d3cc0198ea49b0cbb9e980150a610dde50b19e422c8dd9519c99
|
4
|
+
data.tar.gz: 7ff6974cb986bc5df133229f275d4be9bac9a647e7936c35e1f3103967848b95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79661005fa24b32c0b03e119549377f5fea9dde025aa91dc5809ad52ad4f212f9b20a278736ea6a077aefb411d4bbc0513bb0e3acb629675d9735202206ebfd4
|
7
|
+
data.tar.gz: 6f58ef2ceb59765e54310d2ea7c1cf1132da62f6102e7187121691b8018670b6a9abe194d41d86cfd9042f35cb5e5746444dcf10c9adced05b85e2335c37f5e6
|
data/README.md
CHANGED
@@ -45,7 +45,6 @@ At `db2query_database.yml` we can use two type of connection:
|
|
45
45
|
```yml
|
46
46
|
development:
|
47
47
|
primary: # Connection String Example
|
48
|
-
adapter: db2_query
|
49
48
|
conn_string:
|
50
49
|
driver: DB2
|
51
50
|
database: SAMPLE
|
@@ -56,8 +55,7 @@ development:
|
|
56
55
|
protocol: IPC
|
57
56
|
uid: <%= ENV["DB2EC_UID"] %>
|
58
57
|
pwd: <%= ENV["DB2EC_PWD"] %>
|
59
|
-
secondary:
|
60
|
-
adapter: db2_query # DSN Example
|
58
|
+
secondary: # DSN Example
|
61
59
|
dsn: iseries
|
62
60
|
uid: <%= ENV["ISERIES_UID"] %>
|
63
61
|
pwd: <%= ENV["ISERIES_PWD"] %>
|
@@ -92,7 +90,26 @@ class User < DB2Query::Base
|
|
92
90
|
SELECT * FROM LIBTEST.USERS WHERE id = ?
|
93
91
|
SQL
|
94
92
|
end
|
93
|
+
|
94
|
+
class User < DB2query::Base
|
95
|
+
query :id_greater_than, -> id {
|
96
|
+
exec_query({}, "SELECT * FROM LIBTEST.USERS WHERE id > ?", [id])
|
97
|
+
}
|
98
|
+
|
99
|
+
query :insert_record, -> *args {
|
100
|
+
execute(
|
101
|
+
"INSERT INTO users (id, first_name, last_name, email) VALUES (?, ?, ?, ?)", args
|
102
|
+
)
|
103
|
+
}
|
104
|
+
end
|
95
105
|
```
|
106
|
+
|
107
|
+
The query method must have 2 inputs:
|
108
|
+
1. Method name
|
109
|
+
2. Body (can be an SQL statement or lamda).
|
110
|
+
|
111
|
+
The lambda is used to facilitate us in using `built-in methods` as shown at two query methods above.
|
112
|
+
|
96
113
|
Or use a normal sql method (don't forget the `_sql` suffix)
|
97
114
|
```ruby
|
98
115
|
class User < DB2Query::Base
|
@@ -144,11 +161,20 @@ SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE id = ? [["id", 10000]]
|
|
144
161
|
=> #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Dr.Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
|
145
162
|
```
|
146
163
|
|
147
|
-
### Available methods
|
164
|
+
### Available Result Ogject methods
|
148
165
|
`DB2Query::Result` inherit all `ActiveRecord::Result` methods with additional custom methods:
|
149
166
|
1. `records` to convert query result into array of Record objects.
|
150
167
|
2. `to_h` to convert query result into hash with symbolized keys.
|
151
168
|
|
169
|
+
### Built-in methods
|
170
|
+
These built-in methods are delegated to `DB2Query::Connection` methods
|
171
|
+
1. `query_rows(sql)`
|
172
|
+
2. `query_value(sql)`
|
173
|
+
3. `query_values(sql)`
|
174
|
+
4. `execute(sql)`
|
175
|
+
5. `exec_query(formatters, sql, args = [])`
|
176
|
+
They behave just likely `ActiveRecords` connection's public methods.
|
177
|
+
|
152
178
|
### ActiveRecord Combination
|
153
179
|
|
154
180
|
Create an abstract class that inherit from `ActiveRecord::Base`
|
data/lib/db2_query.rb
CHANGED
@@ -5,6 +5,7 @@ require "erb"
|
|
5
5
|
require "active_record"
|
6
6
|
require "active_support"
|
7
7
|
require "db2_query/config"
|
8
|
+
require "db2_query/error"
|
8
9
|
require "db2_query/connection_handling"
|
9
10
|
|
10
11
|
module DB2Query
|
@@ -12,6 +13,7 @@ module DB2Query
|
|
12
13
|
|
13
14
|
autoload :Version
|
14
15
|
autoload :Base
|
16
|
+
autoload :Bind
|
15
17
|
autoload :Core
|
16
18
|
autoload :DatabaseStatements
|
17
19
|
autoload :Connection
|
data/lib/db2_query/connection.rb
CHANGED
@@ -6,6 +6,7 @@ module DB2Query
|
|
6
6
|
|
7
7
|
include DB2Query::DatabaseStatements
|
8
8
|
include ActiveSupport::Callbacks
|
9
|
+
|
9
10
|
define_callbacks :checkout, :checkin
|
10
11
|
|
11
12
|
set_callback :checkin, :after, :enable_lazy_transactions!
|
@@ -81,7 +82,7 @@ module DB2Query
|
|
81
82
|
msg << "it is already in use by a different thread: #{@owner}. " \
|
82
83
|
"Current thread: #{Thread.current}."
|
83
84
|
end
|
84
|
-
raise
|
85
|
+
raise DB2Query::Error, msg
|
85
86
|
end
|
86
87
|
|
87
88
|
@owner = Thread.current
|
@@ -124,14 +125,14 @@ module DB2Query
|
|
124
125
|
when RuntimeError
|
125
126
|
exception
|
126
127
|
else
|
127
|
-
|
128
|
+
DB2Query::StatementInvalid.new(message, sql: sql, binds: binds)
|
128
129
|
end
|
129
130
|
end
|
130
131
|
|
131
132
|
def expire
|
132
133
|
if in_use?
|
133
134
|
if @owner != Thread.current
|
134
|
-
raise
|
135
|
+
raise DB2Query::Error, "Cannot expire connection, " \
|
135
136
|
"it is owned by a different thread: #{@owner}. " \
|
136
137
|
"Current thread: #{Thread.current}."
|
137
138
|
end
|
@@ -139,7 +140,7 @@ module DB2Query
|
|
139
140
|
@idle_since = Concurrent.monotonic_time
|
140
141
|
@owner = nil
|
141
142
|
else
|
142
|
-
raise
|
143
|
+
raise DB2Query::Error, "Cannot expire connection, it is not currently leased."
|
143
144
|
end
|
144
145
|
end
|
145
146
|
|
@@ -151,11 +152,11 @@ module DB2Query
|
|
151
152
|
@owner = Thread.current
|
152
153
|
end
|
153
154
|
else
|
154
|
-
raise
|
155
|
+
raise DB2Query::Error, "Cannot steal connection, it is not currently leased."
|
155
156
|
end
|
156
157
|
end
|
157
158
|
|
158
|
-
def seconds_idle
|
159
|
+
def seconds_idle
|
159
160
|
return 0 if in_use?
|
160
161
|
Concurrent.monotonic_time - @idle_since
|
161
162
|
end
|
@@ -17,7 +17,7 @@ module DB2Query
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
class ConnectionSpecification
|
20
|
+
class ConnectionSpecification
|
21
21
|
attr_reader :name, :config
|
22
22
|
|
23
23
|
def initialize(name, config)
|
@@ -70,12 +70,12 @@ module DB2Query
|
|
70
70
|
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
71
71
|
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
|
72
72
|
|
73
|
-
def lookup_connection_handler(handler_key)
|
73
|
+
def lookup_connection_handler(handler_key)
|
74
74
|
handler_key = DB2Query::Base.reading_role
|
75
75
|
connection_handlers[handler_key] ||= DB2Query::ConnectionHandler.new
|
76
76
|
end
|
77
77
|
|
78
|
-
def resolve_config_for_connection(config_or_env)
|
78
|
+
def resolve_config_for_connection(config_or_env)
|
79
79
|
raise "Anonymous class is not allowed." unless name
|
80
80
|
|
81
81
|
config_or_env ||= DEFAULT_ENV.call.to_sym
|
@@ -101,7 +101,7 @@ module DB2Query
|
|
101
101
|
end
|
102
102
|
|
103
103
|
private
|
104
|
-
def swap_connection_handler(handler, &blk)
|
104
|
+
def swap_connection_handler(handler, &blk)
|
105
105
|
old_handler, DB2Query::Base.connection_handler = DB2Query::Base.connection_handler, handler
|
106
106
|
return_value = yield
|
107
107
|
return_value
|
data/lib/db2_query/core.rb
CHANGED
@@ -40,19 +40,24 @@ module DB2Query
|
|
40
40
|
formatters.store(attr_name, format)
|
41
41
|
end
|
42
42
|
|
43
|
-
def query(name,
|
43
|
+
def query(name, body)
|
44
44
|
if defined_method_name?(name)
|
45
|
-
raise
|
45
|
+
raise DB2Query::Error, "You tried to define a scope named \"#{name}\" " \
|
46
46
|
"on the model \"#{self.name}\", but DB2Query already defined " \
|
47
47
|
"a class method with the same name."
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
if body.respond_to?(:call)
|
51
|
+
singleton_class.define_method(name) do |*args|
|
52
|
+
body.call(*args)
|
53
|
+
end
|
54
|
+
elsif body.is_a?(String)
|
55
|
+
sql = body
|
56
|
+
singleton_class.define_method(name) do |*args|
|
57
|
+
connection.exec_query(formatters, sql, args)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise DB2Query::Error, "The query body needs to be callable or is a sql string"
|
56
61
|
end
|
57
62
|
end
|
58
63
|
|
@@ -73,12 +78,14 @@ module DB2Query
|
|
73
78
|
sql_statement = allocate.method(sql_method).call
|
74
79
|
|
75
80
|
unless sql_statement.is_a? String
|
76
|
-
raise
|
81
|
+
raise DB2Query::Error, "Query methods must return a SQL statement string!"
|
77
82
|
end
|
78
83
|
|
79
84
|
query(method_name, sql_statement)
|
80
85
|
|
81
86
|
method(method_name).call(*args)
|
87
|
+
elsif connection.respond_to?(method_name)
|
88
|
+
connection.send(method_name, *args)
|
82
89
|
else
|
83
90
|
super
|
84
91
|
end
|
@@ -13,25 +13,21 @@ module DB2Query
|
|
13
13
|
query(sql)
|
14
14
|
end
|
15
15
|
|
16
|
-
def query_value(sql
|
16
|
+
def query_value(sql)
|
17
17
|
single_value_from_rows(query(sql))
|
18
18
|
end
|
19
19
|
|
20
|
-
def query_values(sql
|
20
|
+
def query_values(sql)
|
21
21
|
query(sql).map(&:first)
|
22
22
|
end
|
23
23
|
|
24
24
|
def execute(sql, args = [])
|
25
|
-
|
26
|
-
@connection.do(sql)
|
27
|
-
else
|
28
|
-
@connection.do(sql, *args)
|
29
|
-
end
|
25
|
+
@connection.do(sql, *args)
|
30
26
|
end
|
31
27
|
|
32
|
-
def exec_query(
|
28
|
+
def exec_query(formatters, sql, args = [])
|
33
29
|
binds, args = extract_binds_from_sql(sql, args)
|
34
|
-
log(sql,
|
30
|
+
log(sql, "SQL", binds, args) do
|
35
31
|
begin
|
36
32
|
if args.empty?
|
37
33
|
stmt = @connection.run(sql)
|
@@ -43,7 +39,7 @@ module DB2Query
|
|
43
39
|
ensure
|
44
40
|
stmt.drop unless stmt.nil?
|
45
41
|
end
|
46
|
-
DB2Query::Result.new(columns, rows,
|
42
|
+
DB2Query::Result.new(columns, rows, formatters)
|
47
43
|
end
|
48
44
|
end
|
49
45
|
|
@@ -54,36 +50,36 @@ module DB2Query
|
|
54
50
|
end
|
55
51
|
|
56
52
|
def key_finder_regex(k)
|
57
|
-
/#{k}
|
53
|
+
/#{k} .\\? | #{k}.\\? | #{k}. \\? /i
|
58
54
|
end
|
59
55
|
|
60
56
|
def extract_binds_from_sql(sql, args)
|
61
57
|
question_mark_positions = sql.enum_for(:scan, /\?/i).map { Regexp.last_match.begin(0) }
|
62
|
-
args = args.first.is_a?(Hash) ? args.first : args
|
58
|
+
args = args.first.is_a?(Hash) ? args.first : args
|
63
59
|
given, expected = args.length, question_mark_positions.length
|
64
60
|
|
65
61
|
if given != expected
|
66
|
-
raise
|
62
|
+
raise DB2Query::Error, "wrong number of arguments (given #{given}, expected #{expected})"
|
67
63
|
end
|
68
64
|
|
69
65
|
if args.is_a?(Hash)
|
70
66
|
binds = args.map do |key, value|
|
71
67
|
position = sql.enum_for(:scan, key_finder_regex(key)).map { Regexp.last_match.begin(0) }
|
72
68
|
if position.empty?
|
73
|
-
raise
|
69
|
+
raise DB2Query::Error, "Column name: `#{key}` not found inside sql statement."
|
74
70
|
elsif position.length > 1
|
75
|
-
raise
|
71
|
+
raise DB2Query::Error, "Can't handle such this kind of sql. Please refactor your sql."
|
76
72
|
else
|
77
73
|
index = position[0]
|
78
74
|
end
|
79
75
|
|
80
|
-
|
76
|
+
DB2Query::Bind.new(key.to_s, value, index)
|
81
77
|
end
|
82
78
|
binds = binds.sort_by { |bind| bind.index }
|
83
79
|
[binds.map { |bind| [bind, bind.value] }, binds.map { |bind| bind.value }]
|
84
80
|
elsif question_mark_positions.length == 1 && args.length == 1
|
85
|
-
column = sql[/(.*?)
|
86
|
-
bind =
|
81
|
+
column = sql[/(.*?) . \?|(.*?) .\?|(.*?). \?|(.*?).\?/m, 1].split.last.downcase
|
82
|
+
bind = DB2Query::Bind.new(column.gsub(/[)(]/, ""), args, 0)
|
87
83
|
[[[bind, bind.value]], bind.value]
|
88
84
|
else
|
89
85
|
[args.map { |arg| [nil, arg] }, args]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DB2Query
|
4
|
+
class Error < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
class StatementInvalid < ActiveRecord::ActiveRecordError
|
8
|
+
def initialize(message = nil, sql: nil, binds: nil)
|
9
|
+
super(message || $!.try(:message))
|
10
|
+
@sql = sql
|
11
|
+
@binds = binds
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :sql, :binds
|
15
|
+
end
|
16
|
+
end
|
data/lib/db2_query/formatter.rb
CHANGED
@@ -16,13 +16,17 @@ module DB2Query
|
|
16
16
|
def initialize(config)
|
17
17
|
@config = config
|
18
18
|
end
|
19
|
+
|
20
|
+
def connect
|
21
|
+
raise "abstract method #connect must be defined"
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
class DsnConnector < AbstractConnector
|
22
26
|
def connect
|
23
27
|
::ODBC.connect(config[:dsn], config[:uid], config[:pwd])
|
24
28
|
rescue ::ODBC::Error => e
|
25
|
-
raise
|
29
|
+
raise DB2Query::Error, "Unable to activate ODBC DSN connection #{e}"
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
@@ -34,7 +38,7 @@ module DB2Query
|
|
34
38
|
end
|
35
39
|
::ODBC::Database.new.drvconnect(driver)
|
36
40
|
rescue ::ODBC::Error => e
|
37
|
-
raise
|
41
|
+
raise DB2Query::Error, "Unable to activate ODBC Conn String connection #{e}"
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -5,12 +5,10 @@ DB2_QUERY_DATABASE_TEMPLATE ||= <<-EOF
|
|
5
5
|
# Database configuration example
|
6
6
|
development:
|
7
7
|
primary:
|
8
|
-
adapter: db2_query
|
9
8
|
dsn: iseries
|
10
9
|
uid: <%= ENV["ISERIES_UID"] %>
|
11
10
|
pwd: <%= ENV["ISERIES_PWD"] %>
|
12
11
|
secondary:
|
13
|
-
adapter: db2_query
|
14
12
|
conn_string:
|
15
13
|
driver: DB2
|
16
14
|
database: ARUNIT2
|
@@ -23,12 +21,10 @@ development:
|
|
23
21
|
pwd: <%= ENV["DB2EC_PWD"] %>
|
24
22
|
test:
|
25
23
|
primary:
|
26
|
-
adapter: db2_query
|
27
24
|
dsn: iseries
|
28
25
|
uid: <%= ENV["ISERIES_UID"] %>
|
29
26
|
pwd: <%= ENV["ISERIES_PWD"] %>
|
30
27
|
secondary:
|
31
|
-
adapter: db2_query
|
32
28
|
conn_string:
|
33
29
|
driver: DB2
|
34
30
|
database: ARUNIT2
|
data/lib/db2_query/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db2_query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yohanes_l
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-08-
|
11
|
+
date: 2020-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-odbc
|
@@ -108,20 +108,6 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: dotenv
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
112
|
name: byebug
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,20 +122,6 @@ dependencies:
|
|
136
122
|
- - ">="
|
137
123
|
- !ruby/object:Gem::Version
|
138
124
|
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: sqlite3
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - ">="
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - ">="
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
153
125
|
description: A Rails query plugin to fetch data from Db2 database by using ODBC connection.
|
154
126
|
email:
|
155
127
|
- yohanes.lumentut@yahoo.com
|
@@ -162,11 +134,13 @@ files:
|
|
162
134
|
- Rakefile
|
163
135
|
- lib/db2_query.rb
|
164
136
|
- lib/db2_query/base.rb
|
137
|
+
- lib/db2_query/bind.rb
|
165
138
|
- lib/db2_query/config.rb
|
166
139
|
- lib/db2_query/connection.rb
|
167
140
|
- lib/db2_query/connection_handling.rb
|
168
141
|
- lib/db2_query/core.rb
|
169
142
|
- lib/db2_query/database_statements.rb
|
143
|
+
- lib/db2_query/error.rb
|
170
144
|
- lib/db2_query/formatter.rb
|
171
145
|
- lib/db2_query/odbc_connector.rb
|
172
146
|
- lib/db2_query/railtie.rb
|
@@ -195,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
169
|
- !ruby/object:Gem::Version
|
196
170
|
version: '0'
|
197
171
|
requirements: []
|
198
|
-
rubygems_version: 3.
|
172
|
+
rubygems_version: 3.1.3
|
199
173
|
signing_key:
|
200
174
|
specification_version: 4
|
201
175
|
summary: DB2Query
|