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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fde277f004b8ff05460621968ce473c7f15f047a5903e77c6bf7da997640d8dc
4
- data.tar.gz: 72fc3599f00909fabc2125964ce5a3f79de9e2343577937206c04c88d7b97cc1
3
+ metadata.gz: a62d60225cd34e421f6d6fd8becf1d45bb6e0ffb35db266bac881734a4b15340
4
+ data.tar.gz: 8b02f4869439de1dcdb14cfca0f731ee99ce143f504b6a56c7e04db74684da65
5
5
  SHA512:
6
- metadata.gz: 477d63287ce0a745ba5dfd91c82f8984632976dec003c305f5a888ba54bccec8b5b8a065c12462bb2294dc14f74537d135ed012df9a0a541cb773109c22a6ff9
7
- data.tar.gz: ab481810cc3cb1ed79bb97594d3af8480e518e7527d770d73606523b5ae35504a4bb6b0ef128ee32f579216604a6b1e43e6230e6e0b0e4fc222a005e086cc513
6
+ metadata.gz: a684c13ff35469b6f53c13b0bcd2c21c997b9b51abce517bc66ca920a4cc764ae885a1746b1e256d50945cc038d240739c8de72045b899af6e63421b8a520c24
7
+ data.tar.gz: a2698708b312200a55f93334c5f27b5345f9b0515a6ca8aee82926562388178588766bb708959178f26488774a3994a5e88f2181691e8604f9d7ac6f62a2dcfb
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2020 yohanes_l
1
+ Copyright 2021 yohanes oktavianus lumentut
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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 query plugin to fetch data from Db2 database by using ODBC connection.
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
- DB2Query will generate two required files:
30
- - `config/db2query_database.yml`
31
- - `config/initializers/db2query`
31
+ Db2Query will generate two required files:
32
+ - `config/db2query.yml`
33
+ - `config/initializers/db2query.rb`
32
34
 
33
- Edit these files according to the requirement.
35
+ Edit those files according to the requirement.
34
36
 
35
37
  ### Database Configuration
36
- At `db2query_database.yml` we can use two type of connection:
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
- primary: # Connection String Example
42
- adapter: db2_query
43
- conn_string:
44
- driver: DB2
45
- database: SAMPLE
46
- dbalias: SAMPLE
47
- hostname: LOCALHOST
48
- currentschema: LIBTEST
49
- port: "0"
50
- protocol: IPC
51
- uid: <%= ENV["DB2EC_UID"] %>
52
- pwd: <%= ENV["DB2EC_PWD"] %>
53
- secondary:
54
- adapter: db2_query # DSN Example
55
- dsn: iseries
56
- uid: <%= ENV["ISERIES_UID"] %>
57
- pwd: <%= ENV["ISERIES_PWD"] %>
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 < DB2Query::Base
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
- Or use a normal sql method (don't forget the `_sql` suffix)
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 < DB2Query::Base
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
- Check it at rails console
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 user_id = ? [[nil, 10000]]
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 using keywords argument
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.by_name first_name: "Strange", last_name: "Stephen"
87
- SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["last_name", Stephen]]
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 add a formatter class that inherit `DB2Query::AbstractFormatter` then register at `config\initializers\db2query.rb`
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 < DB2Query::AbstractFormatter
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
- DB2Query::Formatter.registration do |format|
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 (30.28ms) SELECT * FROM LIBTEST.USERS WHERE user_id = ? [["id", 10000]]
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
- ### Available methods
122
- `DB2Query::Result` inherit all `ActiveRecord::Result` methods with additional custom `records` method.
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.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
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 "active_record/database_configurations"
8
- require "db2_query/config"
5
+ require "active_support/concurrency/load_interlock_aware_monitor"
6
+ require "connection_pool"
7
+ require "odbc_utf8"
9
8
 
10
- module DB2Query
9
+ module Db2Query
11
10
  extend ActiveSupport::Autoload
12
11
 
13
12
  autoload :Version
14
- autoload :Base
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
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DB2Query
3
+ module Db2Query
4
4
  class Base
5
- include DB2Query::Core
6
- include ActiveRecord::Inheritance
7
- extend ActiveSupport::Concern
8
- extend ActiveRecord::ConnectionHandling
9
- extend DB2Query::ConnectionHandling
5
+ include Config
6
+ include Core
10
7
  end
11
8
  end
@@ -1,30 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DB2Query
4
- class << self
5
- def config
6
- @config ||= read_config
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
- def config_file
18
- Pathname.new(config_path)
8
+ included do
9
+ @@configurations = nil
19
10
  end
20
11
 
21
- def read_config
22
- erb = ERB.new(config_file.read)
23
- YAML.parse(erb.result(binding)).transform
24
- end
12
+ class_methods do
13
+ def configurations
14
+ @@configurations
15
+ end
16
+ alias config configurations
25
17
 
26
- def connection_env
27
- ENV["RAILS_ENV"].to_sym
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