db2_query 0.2.2 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +453 -110
  4. data/Rakefile +3 -2
  5. data/lib/db2_query.rb +41 -15
  6. data/lib/db2_query/base.rb +16 -5
  7. data/lib/db2_query/config.rb +20 -17
  8. data/lib/db2_query/core.rb +68 -55
  9. data/lib/db2_query/db_client.rb +56 -0
  10. data/lib/db2_query/db_connection.rb +67 -0
  11. data/lib/db2_query/db_statements.rb +87 -0
  12. data/lib/db2_query/definitions.rb +79 -0
  13. data/lib/db2_query/error.rb +81 -0
  14. data/lib/db2_query/field_type.rb +31 -0
  15. data/lib/db2_query/helper.rb +49 -0
  16. data/lib/db2_query/logger.rb +52 -0
  17. data/lib/db2_query/query.rb +117 -0
  18. data/lib/db2_query/quoting.rb +102 -0
  19. data/lib/db2_query/railtie.rb +5 -7
  20. data/lib/db2_query/result.rb +51 -31
  21. data/lib/db2_query/sql_statement.rb +34 -0
  22. data/lib/db2_query/tasks.rb +29 -0
  23. data/lib/db2_query/tasks/database.rake +2 -50
  24. data/lib/db2_query/tasks/init.rake +1 -1
  25. data/lib/db2_query/tasks/initializer.rake +2 -34
  26. data/lib/db2_query/tasks/templates/database.rb.tt +19 -0
  27. data/lib/db2_query/tasks/templates/initializer.rb.tt +8 -0
  28. data/lib/db2_query/type/binary.rb +19 -0
  29. data/lib/db2_query/type/boolean.rb +41 -0
  30. data/lib/db2_query/type/date.rb +34 -0
  31. data/lib/db2_query/type/decimal.rb +15 -0
  32. data/lib/db2_query/type/integer.rb +15 -0
  33. data/lib/db2_query/type/string.rb +30 -0
  34. data/lib/db2_query/type/text.rb +11 -0
  35. data/lib/db2_query/type/time.rb +30 -0
  36. data/lib/db2_query/type/timestamp.rb +30 -0
  37. data/lib/db2_query/type/value.rb +29 -0
  38. data/lib/db2_query/version.rb +2 -2
  39. data/lib/rails/generators/query/USAGE +15 -0
  40. data/lib/rails/generators/query/query_generator.rb +70 -0
  41. data/lib/rails/generators/query/templates/query.rb.tt +26 -0
  42. data/lib/rails/generators/query/templates/query_definitions.rb.tt +12 -0
  43. data/lib/rails/generators/query/templates/unit_test.rb.tt +9 -0
  44. metadata +62 -49
  45. data/lib/db2_query/connection.rb +0 -163
  46. data/lib/db2_query/connection_handling.rb +0 -112
  47. data/lib/db2_query/database_statements.rb +0 -93
  48. data/lib/db2_query/formatter.rb +0 -27
  49. data/lib/db2_query/odbc_connector.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a54ab3ca53e8078aee466400a89ec9b18c5c5ed65450d6d35cdf7a8552e0e21c
4
- data.tar.gz: 72ad54eb98b13a471ba8e022e57cb686a31cf7a2e1d833a4d54d833f3d900105
3
+ metadata.gz: a863b9451d52ea28e71b1477cfd7275bb76b34c91a1302208f4052674dc7b901
4
+ data.tar.gz: 555eafaa282e3cab7a0d4231592a6d2a6d3087d0c194f98040dff1724f5da0f2
5
5
  SHA512:
6
- metadata.gz: a037c568900f33c3eefdc2692fd0d8d470dc4167ff87f3b1c0fa11902204fb38523b4bc257cf6cac069590a9706f1c94f506fc13fd35aa7388495fc9e28ea84a
7
- data.tar.gz: 9f1815d05567d1f972ff1f7d0ff5324a2d11781ae0000b13b552c1c21b4da260de7e7e0d8a633fb48a5ce5636ceea7f90e1fe0a509352a7ff99779788ef0b7d7
6
+ metadata.gz: 917d8a2a7a1eefbb85185d021642f42115e7fd51969b302752f1284e274799fca9d7b24c3f6a7fdc764fa9a79cfd6cac7245e4500b0005d5e498f1e718e63a5b
7
+ data.tar.gz: 353f50ef752eaaee361c939c21f6552e4fa5c8b5bc81a0face640aae420d889fcb1fb148bd0d7b74e8fec3b1867ffa31df9996cacb05465302e512ec0a5d2147
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
@@ -1,10 +1,12 @@
1
- # DB2Query
1
+ # Db2Query
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 6+ 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
6
 
7
- ## Installation
7
+ Note: Tested at Rails 5.2.6 and Rails 6.1.4
8
+
9
+ ## 1. Installation
8
10
  Add this line to your application's Gemfile:
9
11
 
10
12
  ```ruby
@@ -20,144 +22,482 @@ Or install it yourself as:
20
22
  ```bash
21
23
  $ gem install db2_query
22
24
  ```
23
-
24
- ## Initialization
25
- Execute init task at the app root
25
+ ## 2. Initialization
26
+ Execute **db2query:init** task at the app root to create database configurations and initializer file.
26
27
  ```bash
27
28
  $ rake db2query:init
29
+ create config/db2query.yml
30
+ create config/initializers/db2query.rb
28
31
  ```
29
- DB2Query will generate two required files:
30
- - `config/db2query_database.yml`
31
- - `config/initializers/db2query.rb`
32
32
 
33
- Edit these files according to the requirement.
33
+ Complete the configurations by editing the files according to your application requirement.
34
34
 
35
- Note:
35
+ ### Database Configuration
36
+ File **config/db2query.yml** consist of DSN/database name and connection pool config:
37
+ ```yml
38
+ development:
39
+ dsn: ARUNIT
40
+ idle: 5
41
+ pool: 5
42
+ timeout: 5
43
+ test:
44
+ dsn: ARUNIT
45
+ idle: 5
46
+ pool: 5
47
+ timeout: 5
48
+ production:
49
+ dsn: ARUNIT
50
+ idle: 5
51
+ pool: 5
52
+ timeout: 5
53
+ ```
36
54
 
37
- To upgrade from the previous version to v.0.2.1, please delete all the files generated by init task and do init task again (don't forget to backup your db2query_database.yml).
55
+ Key **idle** is a **client** idle maximum limit value (in minutes) to avoid the client being 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 your application idle in a certain period of time.
38
56
 
39
- In v.0.2.0, we have to `require 'db2_query'` at initializer manually.
57
+ [**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.
40
58
 
41
- ### Database Configuration
42
- At `db2query_database.yml` we can use two type of connection:
43
- 1. DSN connection config
44
- 2. Connection String config
45
- ```yml
46
- development:
47
- primary: # Connection String Example
48
- adapter: db2_query
49
- conn_string:
50
- driver: DB2
51
- database: SAMPLE
52
- dbalias: SAMPLE
53
- hostname: LOCALHOST
54
- currentschema: LIBTEST
55
- port: "0"
56
- protocol: IPC
57
- uid: <%= ENV["DB2EC_UID"] %>
58
- pwd: <%= ENV["DB2EC_PWD"] %>
59
- secondary:
60
- adapter: db2_query # DSN Example
61
- dsn: iseries
62
- uid: <%= ENV["ISERIES_UID"] %>
63
- pwd: <%= ENV["ISERIES_PWD"] %>
64
- ```
65
-
66
- Ensure that `unixodbc` have been installed and test your connection first by using `isql` commands.
59
+ ### Initializer File
60
+ This file is used by **Db2Query::Base** to load **field types** configurations and establish a **connection** instance.
61
+ ```ruby
62
+ # app_root/config/initializers/db2query.rb
67
63
 
68
- Example:
64
+ require "db2_query"
65
+
66
+ Db2Query::Base.initiation do |base|
67
+ base.set_field_types # or base.set_field_types(CUSTOM_FIELD_TYPES) if you have CUSTOM TYPES
68
+ base.establish_connection
69
+ end
70
+ ```
71
+
72
+ ### Custom Field Type
73
+ **FieldTypes** are classes that used by **Db2Query** to format the data before sending it to the database by using `serialize` method and converting the **query result** before consumed by your **Rails application** by using `deserialize` method. Both `serialize` and `deserialize` operations are only applied when you provide **QueryDefinitions** on your query. By default, there are ten field types that can be used in your [query definitions](#32-querydefinitions) :
74
+
75
+ ```ruby
76
+ DEFAULT_FIELD_TYPES = {
77
+ binary: Db2Query::Type::Binary,
78
+ boolean: Db2Query::Type::Boolean,
79
+ string: Db2Query::Type::String,
80
+ varchar: Db2Query::Type::String,
81
+ longvarchar: Db2Query::Type::String,
82
+ decimal: Db2Query::Type::Decimal,
83
+ integer: Db2Query::Type::Integer,
84
+ date: Db2Query::Type::Date,
85
+ time: Db2Query::Type::Time,
86
+ timestamp: Db2Query::Type::Timestamp
87
+ }
88
+ ```
89
+ You can use your own Field type class by extending **Db2Query::Type::Value** class. For example:
90
+ ```ruby
91
+ class CustomTypeClass < Db2Query::Type::Value
92
+ # Method to convert data from ruby type value into data that is understood by Db2
93
+ def serialize(value)
94
+ # Your logic
95
+ end
96
+
97
+ # Method to convert Db2 database output data type that is recognized by your rails app
98
+ def deserialize(value)
99
+ # Your logic
100
+ end
101
+ end
102
+ ```
103
+ Then map the classes into a variable and load it into the **Db2Query::Base** by using **set_field_types** method in the initializer file.
104
+ ```ruby
105
+ # app_root/config/initializers/db2query.rb
106
+
107
+ require "db2_query"
108
+
109
+ CUSTOM_FIELD_TYPES = {
110
+ binary: CustomBinaryTypeClass
111
+ integer: CustomIntegerTypeClass
112
+ string: CustomStringTypeClass
113
+ ...
114
+ }
115
+
116
+ Db2Query::Base.initiation do |base|
117
+ base.set_field_types(CUSTOM_FIELD_TYPES)
118
+ base.establish_connection
119
+ end
120
+
121
+ ```
122
+
123
+ ## 3. Usage
124
+
125
+ Once you completely do [**Installation**](#1-installation) & [**Initialization**](#2-initialization), basically you has been ready to use **Db2Query::Base** with three additional conventions: **SQL Convention**, **Field Type Convention**, **Argument Key Convention**.
126
+
127
+ **SQL Convention**:
128
+ > **"** Dollar symbol **$** is used as the prefix of all column names **in the WHERE clause** of provided **Parameterized Query** SQL string. It is used as a pointer in the binding process of key and value of query arguments. We have to provide it manually in the SQL string of each **Parameterized Query**. Here, **Parameterized Query** is used to minimize SQL injection risks.**"**
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
+
136
+
137
+ ```ruby
138
+ # SQL Convention Examples
139
+ # Example of Parameterized Query SQL usage
140
+
141
+ Db2Query::Base.query("SELECT * FROM USERS WHERE $email = ?", "my_account@email.com")
142
+
143
+ # Example of Normal SQL usage
144
+
145
+ Db2Query::Base.query("SELECT * FROM USERS WHERE email = 'my_account@email.com'")
146
+
147
+ # Field Type Convention Example
148
+
149
+ module Definitions
150
+ class UsersQueryDefinitions < Db2Query::Definitions
151
+ def describe
152
+ query_definition :all do |c|
153
+ c.id :integer
154
+ c.first_name :varchar
155
+ c.last_name :varchar
156
+ c.email :varchar
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ # Argument Key Convention Example
163
+
164
+ MyQuery.find_user_by_id id: 10000
165
+
166
+ ```
167
+
168
+
169
+ ### 3.1 Basic Usage
170
+
171
+ #### Base Class Query Methods
172
+
173
+ ##### #query(sql, args)
174
+ A raw query to perform a `connection.run(sql, args)` operation and returns an array of hashes representing each row record being executed.
175
+ ```ruby
176
+ Db2Query::Base.query("SELECT * FROM USERS WHERE $id < ?", 10003)
177
+ => [{: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
+ ```
179
+
180
+ ##### #query_rows(sql)
181
+ Execute the `SELECT Statement SQL` and returns collections of arrays consisting of row values.
182
+ ```ruby
183
+ Db2Query::Base.query_rows("SELECT * FROM USERS WHERE id < 10003")
184
+ => [[10000, "Taisha", "Kutch", "willie.lesch@toy.org"], [10001, "Setsuko", "Kutch", "thelma@purdy.co"], [10002, "Trina", "Mayer", "dorsey_upton@flatley-gulgowski.name"]]
185
+ ```
186
+
187
+ ##### #query_value(sql)
188
+ Execute the `SELECT Statement SQL` and returns the first value of the query results first row.
189
+ ```ruby
190
+ Db2Query::Base.query_value("SELECT * FROM USERS WHERE id < 10003")
191
+ => 10000
192
+ ```
193
+
194
+ ##### #query_values(sql)
195
+ Execute the `SELECT Statement SQL` and returns a collection of the first value of each query result rows.
196
+ ```ruby
197
+ Db2Query::Base.query_values("SELECT * FROM USERS WHERE id < 10003")
198
+ => [10000, 10001, 10002]
199
+ ```
200
+
201
+ ##### #execute(sql, args)
202
+ A method to execute `DUI Statement SQL` by using `connection.do(sql, args)`
203
+ ```ruby
204
+ Db2Query::Base.execute("DELETE FROM users WHERE $id = ?", 10000)
205
+ => -1
206
+ ```
207
+
208
+ ### 3.2 QueryDefinitions
209
+
210
+ 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
+ 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
+ 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
+
214
+ A QueryDefinitions reside in `app_root/app/queries/definitions` directory. It is automatically created when you create your query by using run `rails g query query_name` [**generator**](#33-generator) command. The QueryDefinitions class can be defined as follow:
215
+ ```ruby
216
+ # app_root/app/queries/definitions/your_query_definitions.rb
217
+ module Definitions
218
+ class YourQueryDefinitions < Db2Query::Definitions
219
+ def describe # method that is used by Db2Query to describe your query definition
220
+ query_definition :your_first_query_name do |c|
221
+ c.field_name :field_type, options
222
+ ...
223
+ end
224
+
225
+ query_definition :your_next_query_name do |c|
226
+ c.field_name :field_type, options
227
+ ...
228
+ end
229
+ end
230
+ end
231
+ end
232
+ ```
233
+ For Example:
234
+
235
+ ```ruby
236
+ # app_root/app/queries/definitions/users_query_definitions.rb
237
+
238
+ module Definitions
239
+ class UsersQueryDefinitions < Db2Query::Definitions
240
+ def describe
241
+ query_definition :all do |c|
242
+ c.id :integer
243
+ c.first_name :varchar
244
+ c.last_name :varchar
245
+ c.email :varchar
246
+ end
247
+
248
+ query_definition :insert do |c|
249
+ c.id :integer
250
+ c.first_name :varchar
251
+ c.last_name :varchar
252
+ c.email :varchar
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ ```
259
+
260
+
261
+ ### 3.3 Generator
262
+
263
+ Create query class by using `rails g query NAME` commands. For example:
69
264
 
70
- Secondary database connection test
71
265
  ```bash
72
- $ isql -v iseries
73
- +---------------------------------------+
74
- | Connected! |
75
- | |
76
- | sql-statement |
77
- | help [tablename] |
78
- | quit |
79
- | |
80
- +---------------------------------------+
81
- SQL>
82
- ```
83
-
84
- ## Usage
85
- Note: Version 0.1.0 use `Db2Query` namespace. Please use `DB2Query` in versions greater than it.
86
-
87
- ### Basic Usage
88
- Create query class that inherit from `DB2Query::Base` in `app/queries` folder
89
- ```ruby
90
- class User < DB2Query::Base
91
- query :find_by, <<-SQL
92
- SELECT * FROM LIBTEST.USERS WHERE id = ?
266
+ $ rails g query NameSpace::Name --defines=first_query --queries=next_query --lambdas=last_query
267
+ create app/queries/name_space/name_query.rb
268
+ create app/queries/definitions/movies_query_definitions.rb
269
+ create test/queries/name_space/name_query_test.rb
270
+ ```
271
+ This will create `app/queries/name_space/name_query.rb` file in `app/queries` directory.
272
+
273
+ ```ruby
274
+ module NameSpace
275
+ class Name < Db2Query::Base
276
+ def first_query_sql
277
+
278
+ end
279
+
280
+ query :next_query, <<-SQL
281
+
282
+ SQL
283
+
284
+ query :last_query, -> {
285
+
286
+ }
287
+ end
288
+ end
289
+ ```
290
+
291
+ ```ruby
292
+ # app_root/app/queries/definitions/name_space/name_query.rb
293
+
294
+ module Definitions
295
+ module NameSpace
296
+ class NameQueryDefinition < Db2Query::Definitions
297
+ def describe # method that is used by Db2Query to describe your query definition
298
+ query_definition :first_query do |c|
299
+
300
+ end
301
+
302
+ query_definition :next_query do |c|
303
+
304
+ end
305
+
306
+ query_definition :last_query do |c|
307
+
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
313
+ ```
314
+
315
+ Please run `rails g query --help` to get more information on how to use the file generator.
316
+
317
+ ### 3.4 Queries Methods
318
+
319
+ In a **Query** class that extends **Db2Query::Base** class, there are 3 ways of query implementation:
320
+
321
+ ```ruby
322
+ class MyQuery < Db2Query::Base
323
+ # 1. Plain Query (--defines)
324
+ def query_name_sql
325
+ "YOUR AMAZING SQL STATEMENT STRING"
326
+ end
327
+
328
+ # 2. String Query (--queries)
329
+ query :query_name, <<-SQL
330
+ YOUR AMAZING SQL STATEMENT
93
331
  SQL
332
+
333
+ # 3. Lambda Query (--lambdas)
334
+ query :query_name, -> args {
335
+ # implement fetch, fetch_list, and exec_query
336
+ fetch("YOUR AMAZING SQL", args)
337
+ }
94
338
  end
95
339
  ```
96
- Or use a normal sql method (don't forget the `_sql` suffix)
340
+
341
+ #### 3.4.1 Plain Query (--defines)
342
+ Query implementation that uses the plain method. The method name must have a `_sql` suffix and return SQL statement string.
343
+
344
+ Example:
97
345
  ```ruby
98
- class User < DB2Query::Base
99
- def find_by_sql
100
- "SELECT * FROM LIBTEST.USERS WHERE id = ?"
346
+ class MyQuery < Db2Query::Base
347
+ def all_users_sql
348
+ "SELECT * FROM USERS"
349
+ end
350
+
351
+ def find_user_by_id_sql
352
+ "SELECT * FROM USERS WHERE $id = ?"
101
353
  end
102
354
  end
103
355
  ```
104
- Check it at rails console
356
+
357
+ #### 3.4.2 String Query (--queries)
358
+ Query implementation that uses the built-in `query` method. The input arguments consist of `query_name` symbol and SQL statement
359
+
360
+ Example:
361
+ ```ruby
362
+ class MyQuery < Db2Query::Base
363
+ query :all_users, <<-SQL
364
+ SELECT * FROM USERS
365
+ SQL
366
+
367
+ query :find_user_by_id, <<-SQL
368
+ SELECT * FROM USERS WHERE $id = ?
369
+ end
370
+ end
371
+ ```
372
+
373
+ #### 3.4.3 Lambda Query (--lambdas)
374
+ 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
+
376
+ Example:
377
+ ```ruby
378
+ class MyQuery < Db2Query::Base
379
+ query :all_users, -> args {
380
+ fetch("SELECT * FROM USERS", args)
381
+ }
382
+
383
+ query :find_user_by_id, -> args {
384
+ fetch("SELECT * FROM USERS WHERE $id = ?", args)
385
+ }
386
+ end
387
+ ```
388
+
389
+ Then you can call all three example with the same methods:
390
+
105
391
  ```bash
106
- User.find_by 10000
107
- SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE id = ? [[nil, 10000]]
108
- => #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
392
+ irb(main):001:0> MyQuery.all_users
393
+ SQL (2.7ms) SELECT * FROM USERS
394
+ => #<Db2Query::Result [#<Record id: 10000, first_name: Yohanes, ...]>
395
+
396
+ irb(main):001:0> MyQuery.find_user_by_id 10000
397
+ SQL (3.0ms) SELECT * FROM USERS WHERE id = ? [["id", 10000]]
398
+ => #<Db2Query::Result [#<Record id: 10004, first_name: Yohanes, ...]>
109
399
  ```
110
- Or using keywords argument if the sql use `=` operator, e.g `first_name = ?`
400
+ If you pass a key-value argument into query, the key has to follow **Argument Key Convention**
401
+
111
402
  ```bash
112
- User.by_name first_name: "Strange", last_name: "Stephen"
113
- SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["last_name", Stephen]]
114
- => #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
403
+ irb(main):001:0> MyQuery.find_user_by_id(id: 10000)
404
+ SQL (3.0ms) SELECT * FROM USERS WHERE id = ? [["id", 10000]]
405
+ => #<Db2Query::Result [#<Record id: 10004, first_name: Yohanes, ...]>
406
+
115
407
  ```
116
408
 
117
- ### Formatter
118
- 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`
409
+ And use it at your application
119
410
  ```ruby
120
- require "db2_query/formatter"
411
+ users = MyQuery.all
412
+ user_records = users.records
413
+ user_1 = user_records.first
414
+ user_1.id # => 10000
415
+ user_1.first_name # => "Yohanes"
416
+ user_1.last_name # => "Lumentut"
417
+ user_1.email # => "yohanes@github.com"
121
418
 
122
- # create a formatter class
123
- class FirstNameFormatter < DB2Query::AbstractFormatter
124
- def format(value)
125
- "Dr." + value
126
- end
127
- end
419
+ user_1 == users.record # => true
128
420
 
129
- # register the formatter class
130
- DB2Query::Formatter.registration do |format|
131
- format.register(:first_name_formatter, FirstNameFormatter)
421
+ user = MyQuery.find_user_by_id id: 10000
422
+ user.id # => 10000
423
+ user.first_name # => "Yohanes"
424
+ user.last_name # => "Lumentut"
425
+ user.email # => "yohanes@github.com"
426
+ ```
427
+
428
+ ### 3.5 SQL extention (`@extention`)
429
+ 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.
430
+ ```ruby
431
+ class MyQuery < Db2Query::Base
432
+ # reusable SQL
433
+ _SQL = -> extention {
434
+ sql_with_extention("SELECT * FROM USERS WHERE @extention", extention)
435
+ }
436
+
437
+ # implementation
438
+ query :user_by_email, _SQL.("$email = ?")
132
439
  end
133
440
  ```
134
- Use it at query class
441
+ ```bash
442
+ irb(main):001:0> MyQuery.user_by_email
443
+ SQL (2.7ms) SELECT * FROM USERS email = ? [["email", "yohanes@github.com"]]
444
+ => #<Db2Query::Result [#<Record id: 10000, first_name: Yohanes, ...]>
445
+ ```
135
446
  ```ruby
136
- class Doctor < User
137
- attributes :first_name, :first_name_formatter
447
+ user = MyQuery.user_by_email "yohanes@github.com"
448
+ user.id # => 10000
449
+ user.first_name # => "Yohanes"
450
+ user.last_name # => "Lumentut"
451
+ user.email # => "yohanes@github.com"
452
+ ```
453
+ ### 3.6 List input (`@list`)
454
+ For an array consist list of inputs, we can use `fetch_list` method and `@list` pointer at the SQL statement.
455
+
456
+ ```ruby
457
+ class MyQuery < Db2Query::Base
458
+ query :user_by_ids, -> args {
459
+ fetch_list("SELECT * FROM USERS WHERE ID IN (@list)", args)
460
+ }
138
461
  end
139
462
  ```
140
- Check it at rails console
141
463
  ```bash
142
- Doctor.find_by id: 10000
143
- SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE id = ? [["id", 10000]]
144
- => #<DB2Query::Result @records=[#<Record id: 10000, first_name: "Dr.Strange", last_name: "Stephen", email: "strange@marvel.universe.com">]>
464
+ irb(main):007:0> MyQuery.user_by_ids [10000,10001,10002]
465
+ SQL (2.8ms) SELECT * FROM USERS WHERE ID IN ('10000', '10001', '10002')
466
+ => #<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
+
145
468
  ```
469
+ ```ruby
470
+ users = MyQuery.user_by_ids [10000,10001,10002]
471
+ user = users.first
472
+ user == users.record # => true
473
+
474
+ user.id # => 10000
475
+ user.first_name # => "Carol"
476
+ user.last_name # => "Danvers"
477
+ user.email # => "captain.marvel@marvel.universe.com"
478
+ ```
479
+
480
+ ### 3.7 Formatter
481
+ 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).
146
482
 
147
- ### Available methods
148
- `DB2Query::Result` inherit all `ActiveRecord::Result` methods with additional custom methods:
149
- 1. `records` to convert query result into array of Record objects.
150
- 2. `to_h` to convert query result into hash with symbolized keys.
483
+ 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**.
151
484
 
152
- ### ActiveRecord Combination
485
+ ## 4. Available Result Object methods
486
+ `Db2Query::Result` inherit all `ActiveRecord::Result` methods with additional custom methods:
487
+ 1. `records` to convert query result into an array of Result query's Record objects.
488
+ 2. `record` to get the first Record Object of Result query.
489
+ 3. `to_h` to convert query result into an array of hashes with symbolized keys.
490
+
491
+ ## 5. ActiveRecord Combination
492
+
493
+ Create an abstract class that inherits from `ActiveRecord::Base`. We have to implement `splat` operator correctly at the arguments to make it works.
153
494
 
154
- Create an abstract class that inherit from `ActiveRecord::Base`
155
495
  ```ruby
156
496
  class Db2Record < ActiveRecord::Base
157
497
  self.abstract_class = true
158
498
 
159
- def self.query(sql, formatter = {}, args = [])
160
- DB2Query::Base.connection.exec_query(sql, formatter, args).to_a.map(&:deep_symbolize_keys)
499
+ def self.query(sql, args)
500
+ Db2Query::Base.query(sql, *args)
161
501
  end
162
502
  end
163
503
  ```
@@ -166,32 +506,35 @@ Utilize the goodness of rails model `scope`
166
506
  ```ruby
167
507
  class User < Db2Record
168
508
  scope :by_name, -> *args {
169
- query(
170
- "SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ?", {}, args
171
- )
509
+ query("SELECT * FROM USERS WHERE $first_name = ? AND $last_name = ?", args)
172
510
  }
173
511
  end
174
512
  ```
513
+
175
514
  ```bash
176
515
  User.by_name first_name: "Strange", last_name: "Stephen"
177
- SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["last_name", Stephen]]
516
+ SQL Load (3.28ms) SELECT * FROM USERS WHERE first_name = ? AND last_name = ? [["first_name", Strange], ["last_name", Stephen]]
178
517
  => [{:id=> 10000, :first_name=> "Strange", :last_name=> "Stephen", :email=> "strange@marvel.universe.com"}]
179
518
  ```
180
519
 
181
520
  Another example:
182
521
  ```ruby
183
522
  class User < Db2Record
184
- scope :age_gt, -> age {
185
- query("SELECT * FROM LIBTEST.USERS WHERE age > #{age}")
523
+ scope :age_gt, -> *args {
524
+ query("SELECT * FROM USERS WHERE age > ?", args)
186
525
  }
187
526
  end
188
527
  ```
189
528
 
190
529
  ```bash
191
530
  User.age_gt 500
192
- SQL Load (3.28ms) SELECT * FROM LIBTEST.USERS WHERE age > 500
531
+ SQL Load (3.28ms) SELECT * FROM USERS WHERE age > 500
193
532
  => [{:id=> 99999, :first_name=> "Ancient", :last_name=> "One", :email=> "ancientone@marvel.universe.com"}]
194
533
  ```
195
534
 
196
- ## License
197
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
535
+ ## 6. Examples
536
+
537
+ For complete examples please see the basic examples [here](https://github.com/yohaneslumentut/db2_query/blob/master/test/dummy/app/queries/user_query.rb).
538
+
539
+ ## 7. License
540
+ The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).