db2_query 0.3.2 → 0.3.6
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/MIT-LICENSE +1 -1
- data/README.md +127 -34
- data/Rakefile +1 -11
- data/lib/db2_query/base.rb +0 -1
- data/lib/db2_query/core.rb +33 -20
- data/lib/db2_query/db_connection.rb +4 -4
- data/lib/db2_query/definitions.rb +24 -4
- data/lib/db2_query/error.rb +13 -1
- data/lib/db2_query/helper.rb +6 -5
- data/lib/db2_query/logger.rb +1 -1
- data/lib/db2_query/query.rb +30 -16
- data/lib/db2_query/railtie.rb +0 -14
- data/lib/db2_query/version.rb +1 -3
- data/lib/db2_query.rb +3 -8
- data/lib/tasks/db2_query_tasks.rake +4 -0
- metadata +26 -86
- data/lib/db2_query/quoting.rb +0 -102
- data/lib/db2_query/tasks/database.rake +0 -10
- data/lib/db2_query/tasks/init.rake +0 -9
- data/lib/db2_query/tasks/initializer.rake +0 -10
- data/lib/db2_query/tasks/templates/database.rb.tt +0 -19
- data/lib/db2_query/tasks/templates/initializer.rb.tt +0 -8
- data/lib/rails/generators/query/USAGE +0 -15
- data/lib/rails/generators/query/query_generator.rb +0 -70
- data/lib/rails/generators/query/templates/query.rb.tt +0 -26
- data/lib/rails/generators/query/templates/query_definitions.rb.tt +0 -12
- data/lib/rails/generators/query/templates/unit_test.rb.tt +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e06666a1eee58811d081a1d8da67e2d3e814d91ef15a0c12bb5b306ee130aed
|
4
|
+
data.tar.gz: fa7ebb35a4e9019f9619416ed4c97fa410e663d3eb58b9320314002e759c501e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b538e762bf70e00782cc09eb56151c0db034dd13e7b757e8261c27e0e2caafbcd7da70b21a310d8881fe2072e3fd9d56fa072c3499fcd14ab7db97dbac24a2ce
|
7
|
+
data.tar.gz: c507ee06457bd6d84e6232ee5bb900cad7dc26249281fab2bb80e04382ea1f5aafd03a6fe182c056ac997176e33b8236bf587207638c1901ddaef694b53bc7a7
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/db2_query)
|
4
4
|
|
5
|
-
A Rails
|
5
|
+
A Rails 7 (Ruby v3.1.0) plugin for connecting Db2 with Rails appplication by using ODBC connection.
|
6
|
+
Db2Query execute plain SQL instead of using query builder
|
6
7
|
|
7
|
-
Note: Tested at Rails
|
8
|
+
Note: Tested at Rails 7.1.2 on Ruby v3.1.0
|
8
9
|
|
9
10
|
## 1. Installation
|
11
|
+
|
10
12
|
Add this line to your application's Gemfile:
|
11
13
|
|
12
14
|
```ruby
|
@@ -14,16 +16,23 @@ gem 'db2_query'
|
|
14
16
|
```
|
15
17
|
|
16
18
|
And then execute:
|
19
|
+
|
17
20
|
```bash
|
18
21
|
$ bundle
|
22
|
+
...
|
19
23
|
```
|
20
24
|
|
21
25
|
Or install it yourself as:
|
26
|
+
|
22
27
|
```bash
|
23
28
|
$ gem install db2_query
|
29
|
+
...
|
24
30
|
```
|
31
|
+
|
25
32
|
## 2. Initialization
|
33
|
+
|
26
34
|
Execute **db2query:init** task at the app root to create database configurations and initializer file.
|
35
|
+
|
27
36
|
```bash
|
28
37
|
$ rake db2query:init
|
29
38
|
create config/db2query.yml
|
@@ -33,20 +42,22 @@ $ rake db2query:init
|
|
33
42
|
Complete the configurations by editing the files according to your application requirement.
|
34
43
|
|
35
44
|
### Database Configuration
|
45
|
+
|
36
46
|
File **config/db2query.yml** consist of DSN/database name and connection pool config:
|
47
|
+
|
37
48
|
```yml
|
38
49
|
development:
|
39
|
-
dsn:
|
50
|
+
dsn: LIBDEV
|
40
51
|
idle: 5
|
41
52
|
pool: 5
|
42
53
|
timeout: 5
|
43
54
|
test:
|
44
|
-
dsn:
|
55
|
+
dsn: LIBTEST
|
45
56
|
idle: 5
|
46
57
|
pool: 5
|
47
58
|
timeout: 5
|
48
59
|
production:
|
49
|
-
dsn:
|
60
|
+
dsn: LIBPROD
|
50
61
|
idle: 5
|
51
62
|
pool: 5
|
52
63
|
timeout: 5
|
@@ -57,7 +68,9 @@ Key **idle** is a **client** idle maximum limit value (in minutes) to avoid the
|
|
57
68
|
[**Ensure**](https://github.com/yohaneslumentut/db2_query/wiki/DB2-ODBC-Connection#verify-odbc-connection) that **unixodbc** has been installed and test your connection first by using **isql** commands.
|
58
69
|
|
59
70
|
### Initializer File
|
71
|
+
|
60
72
|
This file is used by **Db2Query::Base** to load **field types** configurations and establish a **connection** instance.
|
73
|
+
|
61
74
|
```ruby
|
62
75
|
# app_root/config/initializers/db2query.rb
|
63
76
|
|
@@ -70,7 +83,10 @@ end
|
|
70
83
|
```
|
71
84
|
|
72
85
|
### Custom Field Type
|
73
|
-
|
86
|
+
|
87
|
+
**FieldTypes** are classes that are used by **Db2Query** to format the data before sending it to the database by using `serialize` method and `deserialize` the returned query result data by converting the **query result** before consumed by your **Rails application**. Both `serialize` and `deserialize` operations are only applied when you provide **QueryDefinitions** on your query.
|
88
|
+
|
89
|
+
By default, there are ten field types that can be used in your [query definitions](#32-querydefinitions) :
|
74
90
|
|
75
91
|
```ruby
|
76
92
|
DEFAULT_FIELD_TYPES = {
|
@@ -86,7 +102,9 @@ end
|
|
86
102
|
timestamp: Db2Query::Type::Timestamp
|
87
103
|
}
|
88
104
|
```
|
105
|
+
|
89
106
|
You can use your own Field type class by extending **Db2Query::Type::Value** class. For example:
|
107
|
+
|
90
108
|
```ruby
|
91
109
|
class CustomTypeClass < Db2Query::Type::Value
|
92
110
|
# Method to convert data from ruby type value into data that is understood by Db2
|
@@ -100,7 +118,9 @@ You can use your own Field type class by extending **Db2Query::Type::Value** cla
|
|
100
118
|
end
|
101
119
|
end
|
102
120
|
```
|
103
|
-
|
121
|
+
|
122
|
+
Then put the classes into a field types hash constant and load it into the **Db2Query::Base** by using **set_field_types** method in the initializer file.
|
123
|
+
|
104
124
|
```ruby
|
105
125
|
# app_root/config/initializers/db2query.rb
|
106
126
|
|
@@ -122,28 +142,26 @@ end
|
|
122
142
|
|
123
143
|
## 3. Usage
|
124
144
|
|
125
|
-
Once you completely do [**Installation**](#1-installation) & [**Initialization**](#2-initialization), basically you has been ready to use **Db2Query::Base
|
145
|
+
Once you completely do the [**Installation**](#1-installation) & [**Initialization**](#2-initialization) steps, basically you has been ready to use **Db2Query::Base**. There are three additional rules that help **Db2Query** run properly: **SQL Convention**, **Field Type Convention**, and **Argument Key Convention**.
|
126
146
|
|
127
147
|
**SQL Convention**:
|
128
|
-
>
|
129
|
-
|
130
|
-
**Field Type Convention**:
|
131
|
-
> **"** **field_name** written in **query_definition** block must be in downcased format.**"**
|
132
|
-
|
133
|
-
**Argument Key Convention**:
|
134
|
-
> **"** **Argument Key** passed into query have to follow its parameter written in the SQL. It is case-sensitive. If the parameter in your SQL is written in downcase format, then your argument key has to be in downcase format too.**"**
|
135
|
-
|
148
|
+
> A colon **:** is used as the prefix of all column names of provided **Parameterized Query** SQL string. It is used in determining query arguments key and value binding process. We have to provide it manually in the SQL string of each **Parameterized Query**. Here, **Parameterized Query** is used to minimize SQL injection risks.
|
136
149
|
|
137
150
|
```ruby
|
138
151
|
# SQL Convention Examples
|
139
152
|
# Example of Parameterized Query SQL usage
|
140
153
|
|
141
|
-
Db2Query::Base.query("SELECT * FROM USERS WHERE
|
154
|
+
Db2Query::Base.query("SELECT * FROM USERS WHERE email = :email", "my_account@email.com")
|
142
155
|
|
143
156
|
# Example of Normal SQL usage
|
144
157
|
|
145
158
|
Db2Query::Base.query("SELECT * FROM USERS WHERE email = 'my_account@email.com'")
|
159
|
+
```
|
146
160
|
|
161
|
+
**Field Type Convention**:
|
162
|
+
> Query definition's **field_name** written in **query_definition** block must be in downcased format.
|
163
|
+
|
164
|
+
```ruby
|
147
165
|
# Field Type Convention Example
|
148
166
|
|
149
167
|
module Definitions
|
@@ -158,60 +176,85 @@ module Definitions
|
|
158
176
|
end
|
159
177
|
end
|
160
178
|
end
|
179
|
+
```
|
180
|
+
|
181
|
+
**Argument Key Convention**:
|
182
|
+
> The letter case of a **Named Argument** key that passed into a query, has to follow its parameter letter case format that is written in the SQL. The argument key is case-sensitive. If the parameter in your SQL is written in downcase format, then your argument key has to be in downcase format too, and vice versa.
|
161
183
|
|
184
|
+
```ruby
|
162
185
|
# Argument Key Convention Example
|
163
186
|
|
187
|
+
class MyQuery < Db2Query::Base
|
188
|
+
...
|
189
|
+
query :find_by, <<-SQL
|
190
|
+
SELECT * FROM USERS WHERE id = :id
|
191
|
+
SQL
|
192
|
+
...
|
193
|
+
end
|
194
|
+
|
164
195
|
MyQuery.find_user_by_id id: 10000
|
165
196
|
|
166
197
|
```
|
167
198
|
|
168
|
-
|
169
199
|
### 3.1 Basic Usage
|
170
200
|
|
171
201
|
#### Base Class Query Methods
|
172
202
|
|
173
203
|
##### #query(sql, args)
|
204
|
+
|
174
205
|
A raw query to perform a `connection.run(sql, args)` operation and returns an array of hashes representing each row record being executed.
|
206
|
+
|
175
207
|
```ruby
|
176
|
-
Db2Query::Base.query("SELECT * FROM USERS WHERE
|
208
|
+
Db2Query::Base.query("SELECT * FROM USERS WHERE id < :id", 10003)
|
177
209
|
=> [{:id=>10000, :first_name=>"Taisha", :last_name=>"Kutch", :email=>"willie.lesch@toy.org"}, {:id=>10001, :first_name=>"Setsuko", :last_name=>"Kutch", :email=>"thelma@purdy.co"}, {:id=>10002, :first_name=>"Trina", :last_name=>"Mayer", :email=>"dorsey_upton@flatley-gulgowski.name"}]
|
178
210
|
```
|
179
211
|
|
180
212
|
##### #query_rows(sql)
|
213
|
+
|
181
214
|
Execute the `SELECT Statement SQL` and returns collections of arrays consisting of row values.
|
215
|
+
|
182
216
|
```ruby
|
183
217
|
Db2Query::Base.query_rows("SELECT * FROM USERS WHERE id < 10003")
|
184
218
|
=> [[10000, "Taisha", "Kutch", "willie.lesch@toy.org"], [10001, "Setsuko", "Kutch", "thelma@purdy.co"], [10002, "Trina", "Mayer", "dorsey_upton@flatley-gulgowski.name"]]
|
185
219
|
```
|
186
220
|
|
187
221
|
##### #query_value(sql)
|
222
|
+
|
188
223
|
Execute the `SELECT Statement SQL` and returns the first value of the query results first row.
|
224
|
+
|
189
225
|
```ruby
|
190
226
|
Db2Query::Base.query_value("SELECT * FROM USERS WHERE id < 10003")
|
191
227
|
=> 10000
|
192
228
|
```
|
193
229
|
|
194
230
|
##### #query_values(sql)
|
231
|
+
|
195
232
|
Execute the `SELECT Statement SQL` and returns a collection of the first value of each query result rows.
|
233
|
+
|
196
234
|
```ruby
|
197
235
|
Db2Query::Base.query_values("SELECT * FROM USERS WHERE id < 10003")
|
198
236
|
=> [10000, 10001, 10002]
|
199
237
|
```
|
200
238
|
|
201
239
|
##### #execute(sql, args)
|
240
|
+
|
202
241
|
A method to execute `DUI Statement SQL` by using `connection.do(sql, args)`
|
242
|
+
|
203
243
|
```ruby
|
204
|
-
Db2Query::Base.execute("DELETE FROM users WHERE
|
244
|
+
Db2Query::Base.execute("DELETE FROM users WHERE id = :id", 10000)
|
205
245
|
=> -1
|
206
246
|
```
|
207
247
|
|
208
248
|
### 3.2 QueryDefinitions
|
209
249
|
|
250
|
+
#### 3.2.1 Query Field Definitions
|
251
|
+
|
210
252
|
QueryDefinitions is helpful when you need formatter methods that **serialize** the data before it being sent to the database and **deserialize** database output data before being consumed by **Rails application**. The real examples are **Binary** and **Boolean** field types.
|
211
253
|
At **Db2Query::Type::Binary**, the data `unpacked` by `serialize` method before sending to the database and do `deserialize` operation to `pack` the database returned data.
|
212
254
|
QueryDefinition can be used as **Query Schema** where the **field types** of a query are outlined. The field-type written in QueryDefinition has to follow the **Field Type Convention**.
|
213
255
|
|
214
|
-
A QueryDefinitions reside in `app_root/app/queries/definitions` directory. It is automatically created when you create your query by
|
256
|
+
A QueryDefinitions reside in `app_root/app/queries/definitions` directory. It is automatically created when you create your query by running `rails g query query_name` [**generator**](#33-generator) command. The QueryDefinitions class can be defined as follow:
|
257
|
+
|
215
258
|
```ruby
|
216
259
|
# app_root/app/queries/definitions/your_query_definitions.rb
|
217
260
|
module Definitions
|
@@ -230,6 +273,7 @@ module Definitions
|
|
230
273
|
end
|
231
274
|
end
|
232
275
|
```
|
276
|
+
|
233
277
|
For Example:
|
234
278
|
|
235
279
|
```ruby
|
@@ -257,6 +301,21 @@ end
|
|
257
301
|
|
258
302
|
```
|
259
303
|
|
304
|
+
#### 3.2.2 Query Argument Types
|
305
|
+
|
306
|
+
Sometimes, the `query arguments` do not exist in query definitions fields. In such a case, a `Db2Query::QueryArgumentError` will be raised. So, we have to provide `query argument types` at the Query class.
|
307
|
+
|
308
|
+
```ruby
|
309
|
+
module NameSpace
|
310
|
+
class QueryName < Db2Query::Base
|
311
|
+
query_arguments :user_by_email, { email: :string, trim: true }
|
312
|
+
|
313
|
+
def user_by_email_sql
|
314
|
+
"SELECT id, first_name, last_name FROM USERS WHERE email = :email"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
```
|
260
319
|
|
261
320
|
### 3.3 Generator
|
262
321
|
|
@@ -265,9 +324,10 @@ Create query class by using `rails g query NAME` commands. For example:
|
|
265
324
|
```bash
|
266
325
|
$ rails g query NameSpace::Name --defines=first_query --queries=next_query --lambdas=last_query
|
267
326
|
create app/queries/name_space/name_query.rb
|
268
|
-
create
|
327
|
+
create app/queries/definitions/name_space/name_query_definitions.rb
|
269
328
|
create test/queries/name_space/name_query_test.rb
|
270
329
|
```
|
330
|
+
|
271
331
|
This will create `app/queries/name_space/name_query.rb` file in `app/queries` directory.
|
272
332
|
|
273
333
|
```ruby
|
@@ -339,9 +399,11 @@ end
|
|
339
399
|
```
|
340
400
|
|
341
401
|
#### 3.4.1 Plain Query (--defines)
|
402
|
+
|
342
403
|
Query implementation that uses the plain method. The method name must have a `_sql` suffix and return SQL statement string.
|
343
404
|
|
344
405
|
Example:
|
406
|
+
|
345
407
|
```ruby
|
346
408
|
class MyQuery < Db2Query::Base
|
347
409
|
def all_users_sql
|
@@ -349,15 +411,17 @@ class MyQuery < Db2Query::Base
|
|
349
411
|
end
|
350
412
|
|
351
413
|
def find_user_by_id_sql
|
352
|
-
"SELECT * FROM USERS WHERE
|
414
|
+
"SELECT * FROM USERS WHERE id = :id"
|
353
415
|
end
|
354
416
|
end
|
355
417
|
```
|
356
418
|
|
357
419
|
#### 3.4.2 String Query (--queries)
|
420
|
+
|
358
421
|
Query implementation that uses the built-in `query` method. The input arguments consist of `query_name` symbol and SQL statement
|
359
422
|
|
360
423
|
Example:
|
424
|
+
|
361
425
|
```ruby
|
362
426
|
class MyQuery < Db2Query::Base
|
363
427
|
query :all_users, <<-SQL
|
@@ -365,15 +429,17 @@ class MyQuery < Db2Query::Base
|
|
365
429
|
SQL
|
366
430
|
|
367
431
|
query :find_user_by_id, <<-SQL
|
368
|
-
SELECT * FROM USERS WHERE
|
369
|
-
|
432
|
+
SELECT * FROM USERS WHERE id = :id
|
433
|
+
SQL
|
370
434
|
end
|
371
435
|
```
|
372
436
|
|
373
437
|
#### 3.4.3 Lambda Query (--lambdas)
|
438
|
+
|
374
439
|
Query implementation that uses the built-in `query` method. The input arguments consist of the `query_name` symbol and a lambda function. We have to pass `args` as the arguments of a lambda function. Do not change the `args` with let's say `-> id, email { ... }`. Just leave it written as `args`. The `args` is used by `Db2Query::Base` to store `query_name` and the other `arg` inputs.
|
375
440
|
|
376
441
|
Example:
|
442
|
+
|
377
443
|
```ruby
|
378
444
|
class MyQuery < Db2Query::Base
|
379
445
|
query :all_users, -> args {
|
@@ -381,7 +447,7 @@ class MyQuery < Db2Query::Base
|
|
381
447
|
}
|
382
448
|
|
383
449
|
query :find_user_by_id, -> args {
|
384
|
-
fetch("SELECT * FROM USERS WHERE
|
450
|
+
fetch("SELECT * FROM USERS WHERE id = :id", args)
|
385
451
|
}
|
386
452
|
end
|
387
453
|
```
|
@@ -397,6 +463,7 @@ irb(main):001:0> MyQuery.find_user_by_id 10000
|
|
397
463
|
SQL (3.0ms) SELECT * FROM USERS WHERE id = ? [["id", 10000]]
|
398
464
|
=> #<Db2Query::Result [#<Record id: 10004, first_name: Yohanes, ...]>
|
399
465
|
```
|
466
|
+
|
400
467
|
If you pass a key-value argument into query, the key has to follow **Argument Key Convention**
|
401
468
|
|
402
469
|
```bash
|
@@ -407,6 +474,7 @@ irb(main):001:0> MyQuery.find_user_by_id(id: 10000)
|
|
407
474
|
```
|
408
475
|
|
409
476
|
And use it at your application
|
477
|
+
|
410
478
|
```ruby
|
411
479
|
users = MyQuery.all
|
412
480
|
user_records = users.records
|
@@ -425,24 +493,28 @@ user.last_name # => "Lumentut"
|
|
425
493
|
user.email # => "yohanes@github.com"
|
426
494
|
```
|
427
495
|
|
428
|
-
### 3.5 SQL
|
429
|
-
|
496
|
+
### 3.5 SQL extension (`@extension`)
|
497
|
+
|
498
|
+
For the sake of reusable SQL string, we can reuse the most commonly used SQL part by implementing `sql_with_extension` methods with an SQL string argument contain `@extension` pointer at SQL statement.
|
499
|
+
|
430
500
|
```ruby
|
431
501
|
class MyQuery < Db2Query::Base
|
432
502
|
# reusable SQL
|
433
|
-
_SQL = ->
|
434
|
-
|
503
|
+
_SQL = -> extension {
|
504
|
+
sql_with_extension("SELECT * FROM USERS WHERE @extension", extension)
|
435
505
|
}
|
436
506
|
|
437
507
|
# implementation
|
438
|
-
query :user_by_email, _SQL.("
|
508
|
+
query :user_by_email, _SQL.("email = :email")
|
439
509
|
end
|
440
510
|
```
|
511
|
+
|
441
512
|
```bash
|
442
|
-
irb(main):001:0> MyQuery.user_by_email
|
513
|
+
irb(main):001:0> MyQuery.user_by_email email: "yohanes@github.com"
|
443
514
|
SQL (2.7ms) SELECT * FROM USERS email = ? [["email", "yohanes@github.com"]]
|
444
515
|
=> #<Db2Query::Result [#<Record id: 10000, first_name: Yohanes, ...]>
|
445
516
|
```
|
517
|
+
|
446
518
|
```ruby
|
447
519
|
user = MyQuery.user_by_email "yohanes@github.com"
|
448
520
|
user.id # => 10000
|
@@ -450,7 +522,9 @@ user.first_name # => "Yohanes"
|
|
450
522
|
user.last_name # => "Lumentut"
|
451
523
|
user.email # => "yohanes@github.com"
|
452
524
|
```
|
525
|
+
|
453
526
|
### 3.6 List input (`@list`)
|
527
|
+
|
454
528
|
For an array consist list of inputs, we can use `fetch_list` method and `@list` pointer at the SQL statement.
|
455
529
|
|
456
530
|
```ruby
|
@@ -460,12 +534,14 @@ class MyQuery < Db2Query::Base
|
|
460
534
|
}
|
461
535
|
end
|
462
536
|
```
|
537
|
+
|
463
538
|
```bash
|
464
539
|
irb(main):007:0> MyQuery.user_by_ids [10000,10001,10002]
|
465
540
|
SQL (2.8ms) SELECT * FROM USERS WHERE ID IN ('10000', '10001', '10002')
|
466
541
|
=> #<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">]>
|
467
542
|
|
468
543
|
```
|
544
|
+
|
469
545
|
```ruby
|
470
546
|
users = MyQuery.user_by_ids [10000,10001,10002]
|
471
547
|
user = users.first
|
@@ -478,12 +554,15 @@ user.email # => "captain.marvel@marvel.universe.com"
|
|
478
554
|
```
|
479
555
|
|
480
556
|
### 3.7 Formatter
|
557
|
+
|
481
558
|
For the latest version of **Db2Query**, there is no more **Db2Query::Formatter** class. We can implement our formater into **deserialize** method of our [**QueryDefinitions**](#32-querydefinitions).
|
482
559
|
|
483
560
|
If you upgrade from the previous version, you have to run **`rake db2query:init`** again to override the initializer. Please create a backup of your Formatter classes before you do this operation. Then you can implement your Formatter methods into your **QueryDefinitions**.
|
484
561
|
|
485
562
|
## 4. Available Result Object methods
|
563
|
+
|
486
564
|
`Db2Query::Result` inherit all `ActiveRecord::Result` methods with additional custom methods:
|
565
|
+
|
487
566
|
1. `records` to convert query result into an array of Result query's Record objects.
|
488
567
|
2. `record` to get the first Record Object of Result query.
|
489
568
|
3. `to_h` to convert query result into an array of hashes with symbolized keys.
|
@@ -503,10 +582,11 @@ end
|
|
503
582
|
```
|
504
583
|
|
505
584
|
Utilize the goodness of rails model `scope`
|
585
|
+
|
506
586
|
```ruby
|
507
587
|
class User < Db2Record
|
508
588
|
scope :by_name, -> *args {
|
509
|
-
query("SELECT * FROM USERS WHERE
|
589
|
+
query("SELECT * FROM USERS WHERE first_name = :first_name AND last_name = :last_name", args)
|
510
590
|
}
|
511
591
|
end
|
512
592
|
```
|
@@ -518,6 +598,7 @@ SQL Load (3.28ms) SELECT * FROM USERS WHERE first_name = ? AND last_name = ? [[
|
|
518
598
|
```
|
519
599
|
|
520
600
|
Another example:
|
601
|
+
|
521
602
|
```ruby
|
522
603
|
class User < Db2Record
|
523
604
|
scope :age_gt, -> *args {
|
@@ -535,6 +616,18 @@ SQL Load (3.28ms) SELECT * FROM USERS WHERE age > 500
|
|
535
616
|
## 6. Examples
|
536
617
|
|
537
618
|
For complete examples please see the basic examples [here](https://github.com/yohaneslumentut/db2_query/blob/master/test/dummy/app/queries/user_query.rb).
|
619
|
+
Please see [**Db2Session**](https://github.com/yohaneslumentut/db2_session) for **REST** and **GraphQL** implementation of multi-user on the remote server.
|
620
|
+
|
621
|
+
## 7. Test
|
622
|
+
|
623
|
+
To run a development test:
|
624
|
+
|
625
|
+
```bash
|
626
|
+
$ bin/test test
|
627
|
+
Db2 Version : DB2 v11.5.8.0
|
628
|
+
...
|
629
|
+
```
|
630
|
+
|
631
|
+
## 8. License
|
538
632
|
|
539
|
-
## 7. License
|
540
633
|
The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -1,13 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require "bundler/setup"
|
4
|
-
require "bundler/gem_tasks"
|
5
|
-
require "rake/testtask"
|
6
2
|
|
7
|
-
|
8
|
-
t.libs << "test"
|
9
|
-
t.pattern = "test/**/*_test.rb"
|
10
|
-
t.verbose = false
|
11
|
-
end
|
12
|
-
|
13
|
-
task default: :test
|
3
|
+
require "bundler/gem_tasks"
|
data/lib/db2_query/base.rb
CHANGED
data/lib/db2_query/core.rb
CHANGED
@@ -25,27 +25,44 @@ module Db2Query
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def query(*query_args)
|
28
|
-
if query_args
|
28
|
+
if query_args.first.is_a?(Symbol)
|
29
29
|
query_name, body = query_args
|
30
|
-
|
31
|
-
|
30
|
+
|
31
|
+
body_lambda = if body.is_a?(Proc)
|
32
|
+
-> args { body.call(args << { query_name: query_name }) }
|
33
|
+
elsif body.is_a?(String)
|
34
|
+
definition = definitions.lookup_query(query_name, body.strip)
|
35
|
+
-> args { exec_query_result(definition, args) }
|
36
|
+
else
|
37
|
+
raise Db2Query::QueryMethodError.new
|
32
38
|
end
|
33
|
-
|
34
|
-
sql, query_args = [query_args.first.strip, query_args.drop(1)]
|
35
|
-
query = raw_query(sql, query_args)
|
36
|
-
connection.raw_query(query.db2_spec_sql, query.args)
|
37
|
-
elsif query_args[1].is_a?(String) && query_args[1].strip.length > 0
|
38
|
-
query_name, sql = query_args
|
39
|
-
query = definitions.lookup_query(query_name, sql.strip)
|
39
|
+
|
40
40
|
singleton_class.define_method(query_name) do |*args|
|
41
|
-
|
41
|
+
body_lambda.call(args)
|
42
|
+
end
|
43
|
+
elsif query_args.first.is_a?(String)
|
44
|
+
sql, args = [query_args.first.strip, query_args.drop(1)]
|
45
|
+
|
46
|
+
definition = Query.new.tap do |d|
|
47
|
+
d.define_sql(sql)
|
48
|
+
d.define_args(args)
|
42
49
|
end
|
50
|
+
|
51
|
+
connection.raw_query(definition.db2_spec_sql, definition.args)
|
43
52
|
else
|
44
|
-
raise Db2Query::
|
53
|
+
raise Db2Query::Error, "Wrong query implementation"
|
45
54
|
end
|
46
55
|
end
|
47
56
|
alias define query
|
48
57
|
|
58
|
+
def query_arguments_map
|
59
|
+
@query_arguments_map ||= {}
|
60
|
+
end
|
61
|
+
|
62
|
+
def query_arguments(query_name, argument_types)
|
63
|
+
query_arguments_map[query_name] = argument_types
|
64
|
+
end
|
65
|
+
|
49
66
|
def fetch(sql, args = [])
|
50
67
|
query = definitions.lookup_query(args, sql)
|
51
68
|
query.validate_select_query
|
@@ -60,7 +77,10 @@ module Db2Query
|
|
60
77
|
private
|
61
78
|
def new_definitions
|
62
79
|
definition_class = "Definitions::#{name}Definitions"
|
63
|
-
Object.const_get(definition_class).new(
|
80
|
+
Object.const_get(definition_class).new(
|
81
|
+
query_arguments_map,
|
82
|
+
field_types_map
|
83
|
+
)
|
64
84
|
rescue Exception => e
|
65
85
|
raise Db2Query::Error, e.message
|
66
86
|
end
|
@@ -71,13 +91,6 @@ module Db2Query
|
|
71
91
|
end
|
72
92
|
end
|
73
93
|
|
74
|
-
def raw_query(sql, args)
|
75
|
-
Query.new.tap do |query|
|
76
|
-
query.define_sql(sql)
|
77
|
-
query.define_args(args)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
94
|
def define_sql_query(method_name)
|
82
95
|
sql_query_name = sql_query_symbol(method_name)
|
83
96
|
sql_statement = allocate.method(sql_query_name).call
|
@@ -35,11 +35,10 @@ module Db2Query
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
attr_reader :config, :connection_pool, :instrumenter, :
|
38
|
+
attr_reader :config, :connection_pool, :instrumenter, :mutex
|
39
39
|
|
40
40
|
delegate :with, :current_state, :disconnect!, :reload, to: :connection_pool
|
41
41
|
delegate :instrument, to: :instrumenter
|
42
|
-
delegate :synchronize, to: :lock
|
43
42
|
|
44
43
|
include Logger
|
45
44
|
include DbStatements
|
@@ -47,7 +46,8 @@ module Db2Query
|
|
47
46
|
def initialize(config)
|
48
47
|
@config = config
|
49
48
|
@instrumenter = ActiveSupport::Notifications.instrumenter
|
50
|
-
@
|
49
|
+
@mutex = Mutex.new
|
50
|
+
@connection_pool = nil
|
51
51
|
create_connection_pool
|
52
52
|
end
|
53
53
|
|
@@ -58,7 +58,7 @@ module Db2Query
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def create_connection_pool
|
61
|
-
synchronize do
|
61
|
+
mutex.synchronize do
|
62
62
|
return @connection_pool if @connection_pool
|
63
63
|
@connection_pool = Pool.new(pool_config) { DbClient.new(config) }
|
64
64
|
end
|
@@ -3,9 +3,11 @@
|
|
3
3
|
module Db2Query
|
4
4
|
class Definitions
|
5
5
|
attr_accessor :types, :types_map
|
6
|
+
attr_reader :arguments_map
|
6
7
|
|
7
|
-
def initialize(
|
8
|
-
@
|
8
|
+
def initialize(query_arguments_map, field_types_map)
|
9
|
+
@arguments_map = query_arguments_map
|
10
|
+
@types_map = field_types_map
|
9
11
|
describe
|
10
12
|
initialize_types
|
11
13
|
end
|
@@ -26,14 +28,24 @@ module Db2Query
|
|
26
28
|
|
27
29
|
def lookup(query_name)
|
28
30
|
queries.fetch(query_name)
|
29
|
-
rescue
|
30
|
-
|
31
|
+
rescue Exception => e
|
32
|
+
if defined?(name)
|
33
|
+
raise Db2Query::QueryDefinitionError.new(name, query_name)
|
34
|
+
else
|
35
|
+
raise Db2Query::Error, e.message
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
def lookup_query(*args)
|
34
40
|
query_name, sql = query_definitions(args)
|
35
41
|
lookup(query_name).tap do |query|
|
36
42
|
query.define_sql(sql)
|
43
|
+
query.argument_keys.each do |key|
|
44
|
+
key, key_def = query_arg_key(query, key)
|
45
|
+
query.argument_types.store(key, data_type_instance(key_def))
|
46
|
+
rescue
|
47
|
+
raise Db2Query::QueryArgumentError.new(query_name, key)
|
48
|
+
end
|
37
49
|
end
|
38
50
|
end
|
39
51
|
|
@@ -75,5 +87,13 @@ module Db2Query
|
|
75
87
|
else args
|
76
88
|
end
|
77
89
|
end
|
90
|
+
|
91
|
+
def query_arg_key(query, key)
|
92
|
+
[key, unless arguments_map[query.query_name].nil?
|
93
|
+
arguments_map[query.query_name][key]
|
94
|
+
else
|
95
|
+
query.columns[key]
|
96
|
+
end]
|
97
|
+
end
|
78
98
|
end
|
79
99
|
end
|