db2_query 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +208 -45
- data/Rakefile +3 -2
- data/lib/db2_query.rb +10 -11
- data/lib/db2_query/base.rb +3 -6
- data/lib/db2_query/config.rb +20 -21
- data/lib/db2_query/connection.rb +125 -0
- data/lib/db2_query/core.rb +105 -33
- data/lib/db2_query/error.rb +16 -0
- data/lib/db2_query/formatter.rb +2 -2
- data/lib/db2_query/logger.rb +42 -0
- data/lib/db2_query/railtie.rb +4 -9
- data/lib/db2_query/result.rb +18 -4
- data/lib/db2_query/tasks/database.rake +20 -37
- data/lib/db2_query/tasks/init.rake +1 -1
- data/lib/db2_query/tasks/initializer.rake +18 -11
- data/lib/db2_query/version.rb +2 -2
- metadata +27 -65
- data/lib/active_record/connection_adapters/db2_query_adapter.rb +0 -203
- data/lib/db2_query/connection_handling.rb +0 -33
- data/lib/db2_query/database_statements.rb +0 -88
- data/lib/db2_query/odbc_connector.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a62d60225cd34e421f6d6fd8becf1d45bb6e0ffb35db266bac881734a4b15340
|
4
|
+
data.tar.gz: 8b02f4869439de1dcdb14cfca0f731ee99ce143f504b6a56c7e04db74684da65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a684c13ff35469b6f53c13b0bcd2c21c997b9b51abce517bc66ca920a4cc764ae885a1746b1e256d50945cc038d240739c8de72045b899af6e63421b8a520c24
|
7
|
+
data.tar.gz: a2698708b312200a55f93334c5f27b5345f9b0515a6ca8aee82926562388178588766bb708959178f26488774a3994a5e88f2181691e8604f9d7ac6f62a2dcfb
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/db2_query.svg)](https://badge.fury.io/rb/db2_query)
|
4
4
|
|
5
|
-
A Rails
|
5
|
+
A Rails 5 & Rails 6 plugin for handling Db2 SQL database `SIUD` statement (`SELECT`, `INSERT`, `UPDATE`, `DELETE`) by using ODBC connection.
|
6
|
+
|
7
|
+
Note: Tested at Rails 5.2.6 and Rails 6.1.4
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
Add this line to your application's Gemfile:
|
@@ -26,82 +28,186 @@ Execute init task at the app root
|
|
26
28
|
```bash
|
27
29
|
$ rake db2query:init
|
28
30
|
```
|
29
|
-
|
30
|
-
- `config/
|
31
|
-
- `config/initializers/db2query`
|
31
|
+
Db2Query will generate two required files:
|
32
|
+
- `config/db2query.yml`
|
33
|
+
- `config/initializers/db2query.rb`
|
32
34
|
|
33
|
-
Edit
|
35
|
+
Edit those files according to the requirement.
|
34
36
|
|
35
37
|
### Database Configuration
|
36
|
-
At `
|
37
|
-
1. DSN connection config
|
38
|
-
2. Connection String config
|
38
|
+
At version 0.3.0, `db2query.yml` only use DSN connection config:
|
39
39
|
```yml
|
40
|
-
development:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
40
|
+
development:
|
41
|
+
dsn: ARUNIT
|
42
|
+
idle: 5
|
43
|
+
pool: 5
|
44
|
+
timeout: 5
|
45
|
+
test:
|
46
|
+
dsn: ARUNIT
|
47
|
+
idle: 5
|
48
|
+
pool: 5
|
49
|
+
timeout: 5
|
50
|
+
production:
|
51
|
+
dsn: ARUNIT
|
52
|
+
idle: 5
|
53
|
+
pool: 5
|
54
|
+
timeout: 5
|
55
|
+
```
|
56
|
+
|
57
|
+
Note: `idle` is a `db_client` idle maximum limit value (in minutes) to avoid the client disconnected by the host server. Setting this value to zero will lead to an "ODBC driver Communication Link Failure. Comm rc 10054 . [CWBCO1047](https://www.ibm.com/support/pages/cwbco1047-any-function-uses-database-host-server)" error after a certain period of time.
|
58
|
+
|
59
|
+
Ensure that `unixodbc` have been installed and test your connection first by using `isql` commands.
|
60
|
+
|
61
|
+
Example:
|
62
|
+
|
63
|
+
ARUNIT DSN connection test
|
64
|
+
```bash
|
65
|
+
$ isql -v ARUNIT
|
66
|
+
+---------------------------------------+
|
67
|
+
| Connected! |
|
68
|
+
| |
|
69
|
+
| sql-statement |
|
70
|
+
| help [tablename] |
|
71
|
+
| quit |
|
72
|
+
| |
|
73
|
+
+---------------------------------------+
|
74
|
+
SQL>
|
58
75
|
```
|
59
76
|
|
60
77
|
## Usage
|
78
|
+
Note: Version 0.1.0 use `Db2Query` namespace. Version 0.2 use `DB2Query`. At version 0.3.0 we use `Db2Query` , revert back to the previous namespace.
|
79
|
+
|
61
80
|
### Basic Usage
|
62
|
-
Create query class that inherit from `DB2Query::Base` in `app/queries` folder
|
81
|
+
Create query class that inherit from `DB2Query::Base` in `app/queries` folder.
|
82
|
+
|
83
|
+
Note: `$`symbol is used as column name prefix.
|
84
|
+
|
85
|
+
### 1. `query` method
|
86
|
+
The `query` method must have 2 inputs:
|
87
|
+
1. Method name
|
88
|
+
2. Body (can be an SQL statement or lamda).
|
89
|
+
|
90
|
+
The lambda is used to facilitate us in using `built-in methods` as shown at examples below:
|
91
|
+
|
92
|
+
Example 1.
|
63
93
|
```ruby
|
64
|
-
class User <
|
94
|
+
class User < Db2Query::Base
|
65
95
|
query :find_by, <<-SQL
|
66
|
-
SELECT * FROM LIBTEST.USERS WHERE id = ?
|
96
|
+
SELECT * FROM LIBTEST.USERS WHERE $id = ?
|
67
97
|
SQL
|
68
98
|
end
|
69
99
|
```
|
70
|
-
|
100
|
+
```bash
|
101
|
+
irb(main):004:0> User.find_by 10000
|
102
|
+
SQL (3.2ms) SELECT * FROM LIBTEST.USERS WHERE id = ? [["id", 10000]]
|
103
|
+
=> #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
|
104
|
+
```
|
105
|
+
Example 2.
|
71
106
|
```ruby
|
72
|
-
class User <
|
107
|
+
class User < Db2query::Base
|
108
|
+
query :id_greater_than, -> id {
|
109
|
+
exec_query({}, "SELECT * FROM LIBTEST.USERS WHERE $id > ?", [id])
|
110
|
+
}
|
111
|
+
end
|
112
|
+
```
|
113
|
+
```bash
|
114
|
+
irb(main):003:0> User.id_greater_than 10000
|
115
|
+
SQL (3.2ms) SELECT * FROM LIBTEST.USERS WHERE id > ? [["id", 1000]]
|
116
|
+
=> #<Db2Query::Result [#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">...">]>
|
117
|
+
```
|
118
|
+
Example 3.
|
119
|
+
```ruby
|
120
|
+
class User < Db2query::Base
|
121
|
+
query :insert_record, -> args {
|
122
|
+
exec_query({},
|
123
|
+
"INSERT INTO users ($id, $first_name, $last_name, $email) VALUES (?, ?, ?, ?)", args
|
124
|
+
)
|
125
|
+
}
|
126
|
+
end
|
127
|
+
```
|
128
|
+
```bash
|
129
|
+
irb(main):002:0> User.insert_record [77777, "Ancient", "One", "ancientone@marvel.universe.com"]
|
130
|
+
SQL (3651.2ms) SELECT * FROM NEW TABLE (INSERT INTO users (id, first_name, last_name, email) VALUES (?, ?, ?, ?)) [["id,", 77777], ["first_name,", "Ancient"], ["last_name,", "One"], ["email)", "ancientone@marvel.universe.com"]]
|
131
|
+
=> #<Db2Query::Result [#<Record id: 77777, first_name: "Ancient", last_name: "One", email: "ancientone@marvel.universe.com">]>
|
132
|
+
```
|
133
|
+
|
134
|
+
### 2. Plain/normal method
|
135
|
+
At a plain/normal sql method we add `_sql` suffix. For example `find_by_sql`
|
136
|
+
```ruby
|
137
|
+
class User < Db2Query::Base
|
73
138
|
def find_by_sql
|
74
|
-
"SELECT * FROM LIBTEST.USERS WHERE id = ?"
|
139
|
+
"SELECT * FROM LIBTEST.USERS WHERE $id = ?"
|
75
140
|
end
|
76
141
|
end
|
77
142
|
```
|
78
|
-
|
143
|
+
Then we can call it by using `find_by` class method.
|
79
144
|
```bash
|
80
|
-
User.find_by 10000
|
81
|
-
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE
|
145
|
+
irb(main):001:0> User.find_by 10000
|
146
|
+
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE id = ? [["id", 10000]]
|
82
147
|
=> #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
|
83
148
|
```
|
84
|
-
Or
|
149
|
+
Or with hash arguments input
|
150
|
+
```ruby
|
151
|
+
class User < Db2Query::Base
|
152
|
+
def by_name_and_email_sql
|
153
|
+
"SELECT * FROM LIBTEST.USERS WHERE $first_name = ? AND $email = ?"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
85
157
|
```bash
|
86
|
-
User.
|
87
|
-
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["
|
158
|
+
irb(main):001:0> User.by_name_and_email first_name: "Strange", email: "strange@marvel.universe.com"
|
159
|
+
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["email", strange@marvel.universe.com]]
|
88
160
|
=> #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
|
161
|
+
```
|
162
|
+
### SQL extention (`@extention`)
|
163
|
+
For a reusable sql, we can extend it by using a combination of `extention` and `sql_with_extention` methods, with an `@extention` pointer at SQL statement.
|
164
|
+
```ruby
|
165
|
+
class User < Db2Query::Base
|
166
|
+
# reusable SQL
|
167
|
+
_SQL = -> extention {
|
168
|
+
sql_with_extention("SELECT * FROM LIBTEST.USERS WHERE @extention", extention)
|
169
|
+
}
|
170
|
+
|
171
|
+
# implementation
|
172
|
+
query :by_email, _SQL.("$email = ?")
|
173
|
+
end
|
174
|
+
```
|
175
|
+
```bash
|
176
|
+
irb(main):004:0> User.by_email "strange@marvel.universe.com"
|
177
|
+
SQL (3.2ms) SELECT * FROM LIBTEST.USERS WHERE email = ? [["email", "strange@marvel.universe.com"]]
|
178
|
+
=> #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
|
179
|
+
```
|
180
|
+
### List input (`@list`)
|
181
|
+
For an array consist list of inputs, we can use `fetch_list` method and `@list` pointer at the SQL statement.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class User < Db2Query
|
185
|
+
query :by_ids, -> ids {
|
186
|
+
fetch_list("SELECT * FROM LIBTEST.USERS WHERE ID IN (@list)", ids)
|
187
|
+
}
|
188
|
+
end
|
189
|
+
```
|
190
|
+
```bash
|
191
|
+
irb(main):007:0> User.by_ids [10000,10001,10002]
|
192
|
+
SQL (2.8ms) SELECT * FROM LIBTEST.USERS WHERE ID IN ('10000', '10001', '10002')
|
193
|
+
=> #<Db2Query::Result [#<Record id: 10000, name: "Carol", last_name: "Danvers", email: "captain.marvel@marvel.universe.com">, #<Record id: 10001, first_name: "Natasha", last_name: "Romanova", email: "black.widow@marvel.universe">, #<Record id: 10002, first_name: "Wanda", last_name: "Maximoff", email: "scarlet.witch@marvel.universe.com">]>
|
194
|
+
|
89
195
|
```
|
90
196
|
|
91
197
|
### Formatter
|
92
|
-
In order to get different result column format, a query result can be reformatted by
|
198
|
+
In order to get different result column format, a query result can be reformatted by adding a formatter class that inherits `DB2Query::AbstractFormatter` then register at `config\initializers\db2query.rb`
|
93
199
|
```ruby
|
94
200
|
require "db2_query/formatter"
|
95
201
|
|
96
202
|
# create a formatter class
|
97
|
-
class FirstNameFormatter <
|
203
|
+
class FirstNameFormatter < Db2Query::AbstractFormatter
|
98
204
|
def format(value)
|
99
205
|
"Dr." + value
|
100
206
|
end
|
101
207
|
end
|
102
208
|
|
103
209
|
# register the formatter class
|
104
|
-
|
210
|
+
Db2Query::Formatter.registration do |format|
|
105
211
|
format.register(:first_name_formatter, FirstNameFormatter)
|
106
212
|
end
|
107
213
|
```
|
@@ -114,12 +220,69 @@ end
|
|
114
220
|
Check it at rails console
|
115
221
|
```bash
|
116
222
|
Doctor.find_by id: 10000
|
117
|
-
SQL Load (
|
223
|
+
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE id = ? [["id", 10000]]
|
118
224
|
=> #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Dr.Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
|
119
225
|
```
|
120
226
|
|
121
|
-
|
122
|
-
|
227
|
+
For complete examples please see the basic examples [here](https://github.com/yohaneslumentut/db2_query/blob/master/test/dummy/app/queries/test_query.rb).
|
228
|
+
|
229
|
+
### Available Result Object methods
|
230
|
+
`Db2Query::Result` inherit all `ActiveRecord::Result` methods with additional custom methods:
|
231
|
+
1. `records` to convert query result into array of Record objects.
|
232
|
+
2. `to_h` to convert query result into hash with symbolized keys.
|
233
|
+
|
234
|
+
### Built-in methods
|
235
|
+
These built-in methods are delegated to `Db2Query::Connection` methods
|
236
|
+
1. `query_rows(sql)`
|
237
|
+
2. `query_value(sql)`
|
238
|
+
3. `query_values(sql)`
|
239
|
+
4. `execute(sql)`
|
240
|
+
5. `exec_query(formatters, sql, args = [])`
|
241
|
+
They behave just likely `ActiveRecords` connection's public methods.
|
242
|
+
|
243
|
+
### ActiveRecord Combination
|
244
|
+
|
245
|
+
Create an abstract class that inherit from `ActiveRecord::Base`
|
246
|
+
```ruby
|
247
|
+
class Db2Record < ActiveRecord::Base
|
248
|
+
self.abstract_class = true
|
249
|
+
|
250
|
+
def self.query(formatter, sql, args = [])
|
251
|
+
Db2Query::Base.connection.exec_query(formatter, sql, args).to_a.map(&:deep_symbolize_keys)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
```
|
255
|
+
|
256
|
+
Utilize the goodness of rails model `scope`
|
257
|
+
```ruby
|
258
|
+
class User < Db2Record
|
259
|
+
scope :by_name, -> *args {
|
260
|
+
query(
|
261
|
+
{}, "SELECT * FROM LIBTEST.USERS WHERE $first_name = ? AND $last_name = ?", args
|
262
|
+
)
|
263
|
+
}
|
264
|
+
end
|
265
|
+
```
|
266
|
+
```bash
|
267
|
+
User.by_name first_name: "Strange", last_name: "Stephen"
|
268
|
+
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["last_name", Stephen]]
|
269
|
+
=> [{:id=> 10000, :first_name=> "Strange", :last_name=> "Stephen", :email=> "strange@marvel.universe.com"}]
|
270
|
+
```
|
271
|
+
|
272
|
+
Another example:
|
273
|
+
```ruby
|
274
|
+
class User < Db2Record
|
275
|
+
scope :age_gt, -> age {
|
276
|
+
query("SELECT * FROM LIBTEST.USERS WHERE age > #{age}")
|
277
|
+
}
|
278
|
+
end
|
279
|
+
```
|
280
|
+
|
281
|
+
```bash
|
282
|
+
User.age_gt 500
|
283
|
+
SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE age > 500
|
284
|
+
=> [{:id=> 99999, :first_name=> "Ancient", :last_name=> "One", :email=> "ancientone@marvel.universe.com"}]
|
285
|
+
```
|
123
286
|
|
124
287
|
## License
|
125
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
288
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bundler/setup"
|
3
4
|
require "bundler/gem_tasks"
|
4
5
|
require "rake/testtask"
|
5
6
|
|
6
7
|
Rake::TestTask.new(:test) do |t|
|
7
8
|
t.libs << "test"
|
8
|
-
t.
|
9
|
-
t.
|
9
|
+
t.pattern = "test/**/*_test.rb"
|
10
|
+
t.verbose = false
|
10
11
|
end
|
11
12
|
|
12
13
|
task default: :test
|
data/lib/db2_query.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
|
-
# frozen_string_literal:true
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "yaml"
|
4
|
-
require "erb"
|
5
3
|
require "active_record"
|
6
4
|
require "active_support"
|
7
|
-
require "
|
8
|
-
require "
|
5
|
+
require "active_support/concurrency/load_interlock_aware_monitor"
|
6
|
+
require "connection_pool"
|
7
|
+
require "odbc_utf8"
|
9
8
|
|
10
|
-
module
|
9
|
+
module Db2Query
|
11
10
|
extend ActiveSupport::Autoload
|
12
11
|
|
13
12
|
autoload :Version
|
14
|
-
autoload :
|
13
|
+
autoload :Config
|
14
|
+
autoload :Connection
|
15
15
|
autoload :Core
|
16
|
-
autoload :ConnectionHandling
|
17
|
-
autoload :DatabaseStatements
|
18
|
-
autoload :ODBCConnector
|
19
|
-
autoload :Formatter
|
20
16
|
autoload :Result
|
17
|
+
autoload :Logger
|
18
|
+
autoload :Error
|
19
|
+
autoload :Base
|
21
20
|
|
22
21
|
require "db2_query/railtie" if defined?(Rails)
|
23
22
|
end
|
data/lib/db2_query/base.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Db2Query
|
4
4
|
class Base
|
5
|
-
include
|
6
|
-
include
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
extend ActiveRecord::ConnectionHandling
|
9
|
-
extend DB2Query::ConnectionHandling
|
5
|
+
include Config
|
6
|
+
include Core
|
10
7
|
end
|
11
8
|
end
|
data/lib/db2_query/config.rb
CHANGED
@@ -1,30 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
def config_path
|
10
|
-
if defined?(Rails)
|
11
|
-
"#{Rails.root}/config/db2query_database.yml"
|
12
|
-
else
|
13
|
-
ENV["DQ_CONFIG_PATH"]
|
14
|
-
end
|
15
|
-
end
|
3
|
+
module Db2Query
|
4
|
+
module Config
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
DEFAULT_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence }
|
16
7
|
|
17
|
-
|
18
|
-
|
8
|
+
included do
|
9
|
+
@@configurations = nil
|
19
10
|
end
|
20
11
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
class_methods do
|
13
|
+
def configurations
|
14
|
+
@@configurations
|
15
|
+
end
|
16
|
+
alias config configurations
|
25
17
|
|
26
|
-
|
27
|
-
|
18
|
+
def load_database_configurations(path = nil)
|
19
|
+
file_path = path || "#{Rails.root}/config/db2query.yml"
|
20
|
+
if File.exist?(file_path)
|
21
|
+
config_file = IO.read(file_path)
|
22
|
+
@@configurations = YAML.load(config_file)[DEFAULT_ENV.call].transform_keys(&:to_sym)
|
23
|
+
else
|
24
|
+
raise Db2Query::Error, "Could not load db2query database configuration. No such file - #{file_path}"
|
25
|
+
end
|
26
|
+
end
|
28
27
|
end
|
29
28
|
end
|
30
29
|
end
|