db2_query 0.3.2 → 0.3.6
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 +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
|
[![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 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
|