db2_query 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +124 -0
- data/Rakefile +29 -0
- data/lib/db2_query.rb +29 -0
- data/lib/db2_query/base.rb +84 -0
- data/lib/db2_query/column.rb +42 -0
- data/lib/db2_query/connection.rb +50 -0
- data/lib/db2_query/connection_handling.rb +56 -0
- data/lib/db2_query/database_configurations.rb +50 -0
- data/lib/db2_query/database_statements.rb +32 -0
- data/lib/db2_query/error.rb +5 -0
- data/lib/db2_query/formatter.rb +45 -0
- data/lib/db2_query/log_subscriber.rb +50 -0
- data/lib/db2_query/odbc_connector.rb +38 -0
- data/lib/db2_query/path.rb +17 -0
- data/lib/db2_query/railtie.rb +22 -0
- data/lib/db2_query/result.rb +95 -0
- data/lib/db2_query/schema.rb +113 -0
- data/lib/db2_query/sql_validator.rb +26 -0
- data/lib/db2_query/version.rb +5 -0
- data/lib/tasks/database.rake +56 -0
- data/lib/tasks/init.rake +9 -0
- data/lib/tasks/initializer.rake +35 -0
- metadata +199 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5d2946448234d56484778d59e3051573c81c2789631776f0ed543a79fdc510fa
|
4
|
+
data.tar.gz: a257fabf1a7de500f7d325c70dd11f494a08163dbf78460f61b3bf51cb626b77
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca8c1b52138ec97d9f4e9cbbca0d8bb148e95f4ac181a929e3e5715b597ed59b70e25b779156ba45a7fe9f119203e4162a2a932c63d11c94acdc2a1eaeb56db8
|
7
|
+
data.tar.gz: 67f0d7228274d4a7a6e38771cc0743b83da27621d3ce310e0d5d7d323e937316f700ec3b278734312ff27cdc88796321cb09f02d7c2bf48b8c5607a7331a7f27
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 yohanes_l
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# Db2Query
|
2
|
+
A Rails query plugin to fetch data from Db2 database by using ODBC connection.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'db2_query'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
```bash
|
13
|
+
$ bundle
|
14
|
+
```
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
```bash
|
18
|
+
$ gem install db2-query
|
19
|
+
```
|
20
|
+
|
21
|
+
## Initialization
|
22
|
+
Execute init task at the app root
|
23
|
+
```bash
|
24
|
+
$ rake db2query:init
|
25
|
+
```
|
26
|
+
Db2Query will generate two required files:
|
27
|
+
- `config/db2query_database.yml`
|
28
|
+
- `config/initializers/db2query`
|
29
|
+
|
30
|
+
Edit these files according to the requirement.
|
31
|
+
|
32
|
+
### Database Configuration
|
33
|
+
At `db2query_database.yml` we can use two type of connection:
|
34
|
+
1. DSN connection config
|
35
|
+
2. Connection String config
|
36
|
+
```yml
|
37
|
+
development:
|
38
|
+
primary: # Connection String Example
|
39
|
+
conn_string:
|
40
|
+
driver: DB2
|
41
|
+
database: SAMPLE
|
42
|
+
dbalias: SAMPLE
|
43
|
+
hostname: LOCALHOST
|
44
|
+
currentschema: LIBTEST
|
45
|
+
port: "0"
|
46
|
+
protocol: IPC
|
47
|
+
uid: <%= ENV["DB2EC_UID"] %>
|
48
|
+
pwd: <%= ENV["DB2EC_PWD"] %>
|
49
|
+
secondary: # DSN Example
|
50
|
+
dsn: SAMPLE
|
51
|
+
uid: <%= ENV["DB2EC_UID"] %>
|
52
|
+
pwd: <%= ENV["DB2EC_PWD"] %>
|
53
|
+
```
|
54
|
+
|
55
|
+
## Usage
|
56
|
+
### Basic Usage
|
57
|
+
Create query class that inherit from `Db2Query::Base` in `app/queries` folder
|
58
|
+
```ruby
|
59
|
+
class Users < Db2Query::Base
|
60
|
+
query :find_by, <<-SQL
|
61
|
+
SELECT * FROM LIBTEST.USERS WHERE user_id = ?
|
62
|
+
SQL
|
63
|
+
end
|
64
|
+
```
|
65
|
+
Or use a normal sql method (don't forget the `_sql` suffix)
|
66
|
+
```ruby
|
67
|
+
class Users < Db2Query::Base
|
68
|
+
def find_by_sql
|
69
|
+
"SELECT * FROM LIBTEST.USERS WHERE user_id = ?"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
Check it at rails console
|
74
|
+
```bash
|
75
|
+
Users.find_by 10000
|
76
|
+
Users Load (330.28ms) SELECT * FROM LIBTEST.USERS WHERE user_id = ? [[10000]]
|
77
|
+
=> #<Db2Query::Result [#<Users::FindBy user_id: 10000, first_name: "Alex", last_name: "Jacobi", email: "lula_durgan@dooley.com">]>
|
78
|
+
```
|
79
|
+
### Formatter
|
80
|
+
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`
|
81
|
+
```ruby
|
82
|
+
require "db2_query/formatter"
|
83
|
+
|
84
|
+
# create a formatter class
|
85
|
+
class FirstNameFormatter < Db2Query::AbstractFormatter
|
86
|
+
def format(value)
|
87
|
+
"Mr/Mrs. " + value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# register the formatter class
|
92
|
+
Db2Query::Formatter.registration do |format|
|
93
|
+
format.register(:first_name_formatter, FirstNameFormatter)
|
94
|
+
end
|
95
|
+
```
|
96
|
+
Use it at query class
|
97
|
+
```ruby
|
98
|
+
class Users < Db2Query::Base
|
99
|
+
attributes :first_name, :first_name_formatter
|
100
|
+
|
101
|
+
query :find_by, <<-SQL
|
102
|
+
SELECT * FROM LIBTEST.USERS WHERE user_id = ?
|
103
|
+
SQL
|
104
|
+
end
|
105
|
+
```
|
106
|
+
Check it at rails console
|
107
|
+
```bash
|
108
|
+
Users.find_by 10000
|
109
|
+
Users Load (330.28ms) SELECT * FROM LIBTEST.USERS WHERE user_id = ? [[10000]]
|
110
|
+
=> #<Db2Query::Result [#<Users::FindBy user_id: 10000, first_name: "Mr/Mrs. Alex", last_name: "Jacobi", email: "lula_durgan@dooley.com">]>
|
111
|
+
```
|
112
|
+
### Available methods
|
113
|
+
Db2Query::Result has public methods as follows:
|
114
|
+
- to_a
|
115
|
+
- to_hash
|
116
|
+
- pluck
|
117
|
+
- first
|
118
|
+
- last
|
119
|
+
- size
|
120
|
+
- each
|
121
|
+
|
122
|
+
|
123
|
+
## License
|
124
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "bundler/setup"
|
5
|
+
rescue LoadError
|
6
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
7
|
+
end
|
8
|
+
|
9
|
+
require "rdoc/task"
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = "rdoc"
|
13
|
+
rdoc.title = "Db2Query"
|
14
|
+
rdoc.options << "--line-numbers"
|
15
|
+
rdoc.rdoc_files.include("README.md")
|
16
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
17
|
+
end
|
18
|
+
|
19
|
+
require "bundler/gem_tasks"
|
20
|
+
|
21
|
+
require "rake/testtask"
|
22
|
+
|
23
|
+
Rake::TestTask.new(:test) do |t|
|
24
|
+
t.libs << "test"
|
25
|
+
t.pattern = "test/**/*_test.rb"
|
26
|
+
t.verbose = false
|
27
|
+
end
|
28
|
+
|
29
|
+
task default: :test
|
data/lib/db2_query.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
require "odbc"
|
4
|
+
require "yaml"
|
5
|
+
require "erb"
|
6
|
+
require "active_record"
|
7
|
+
require "active_support"
|
8
|
+
|
9
|
+
module Db2Query
|
10
|
+
extend ActiveSupport::Autoload
|
11
|
+
|
12
|
+
autoload :Version
|
13
|
+
autoload :Error
|
14
|
+
autoload :Path
|
15
|
+
autoload :Schema
|
16
|
+
autoload :DatabaseConfigurations
|
17
|
+
autoload :ODBCConnector
|
18
|
+
autoload :Connection
|
19
|
+
autoload :ConnectionHandling
|
20
|
+
autoload :DatabaseStatements
|
21
|
+
autoload :SQLValidator
|
22
|
+
autoload :LogSubscriber
|
23
|
+
autoload :Formatter
|
24
|
+
autoload :Column
|
25
|
+
autoload :Result
|
26
|
+
autoload :Base
|
27
|
+
end
|
28
|
+
|
29
|
+
require "db2_query/railtie"
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Base
|
5
|
+
include DatabaseConfigurations
|
6
|
+
include ConnectionHandling
|
7
|
+
|
8
|
+
class << self
|
9
|
+
include SQLValidator
|
10
|
+
|
11
|
+
def attributes(attr_name, format)
|
12
|
+
attr_format.store(attr_name, format)
|
13
|
+
end
|
14
|
+
|
15
|
+
def query(method_name, sql_statement)
|
16
|
+
unless is_query?(sql_statement)
|
17
|
+
raise Error, "Query only for SQL query commands."
|
18
|
+
end
|
19
|
+
|
20
|
+
if self.class.respond_to?(method_name)
|
21
|
+
raise Error, "Query :#{method_name} has been defined before"
|
22
|
+
end
|
23
|
+
|
24
|
+
self.class.define_method(method_name) do |*args|
|
25
|
+
log(sql_statement, args) do
|
26
|
+
columns, rows = connection.exec_query(sql_statement, *args)
|
27
|
+
Result.new(self, method_name, columns, rows, attr_format)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def attr_format
|
34
|
+
@attr_format ||= Hash.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_query_method(method_name, sql_statement)
|
38
|
+
if is_query?(sql_statement)
|
39
|
+
query(method_name, sql_statement)
|
40
|
+
else
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing(method_name, *args, &block)
|
46
|
+
sql_methods = self.instance_methods.grep(/_sql/)
|
47
|
+
sql_method = "#{method_name}_sql".to_sym
|
48
|
+
|
49
|
+
if sql_methods.include?(sql_method)
|
50
|
+
sql_statement = allocate.method(sql_method).call
|
51
|
+
|
52
|
+
raise Error, "Query methods must return a SQL statement string!" unless sql_statement.is_a? String
|
53
|
+
|
54
|
+
expected_args = sql_statement.count "?"
|
55
|
+
given_args = args.size
|
56
|
+
|
57
|
+
if expected_args == given_args
|
58
|
+
define_query_method(method_name, sql_statement)
|
59
|
+
else
|
60
|
+
raise ArgumentError, "wrong number of arguments (given #{given_args}, expected #{expected_args})"
|
61
|
+
end
|
62
|
+
|
63
|
+
method(method_name).call(*args)
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def instrumenter
|
70
|
+
@instrumenter ||= ActiveSupport::Notifications.instrumenter
|
71
|
+
end
|
72
|
+
|
73
|
+
def log(sql_statement, args)
|
74
|
+
instrumenter.instrument(
|
75
|
+
"sql.db2_query",
|
76
|
+
sql: sql_statement,
|
77
|
+
name: self,
|
78
|
+
binds: args) do
|
79
|
+
yield
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Column
|
5
|
+
attr_reader :name, :type, :formatter
|
6
|
+
|
7
|
+
FLOAT_TYPES = [ODBC::SQL_FLOAT, ODBC::SQL_DOUBLE, ODBC::SQL_DECIMAL, ODBC::SQL_REAL]
|
8
|
+
INTEGER_TYPES = [ODBC::SQL_TINYINT, ODBC::SQL_SMALLINT, ODBC::SQL_INTEGER, ODBC::SQL_BIGINT, ODBC::SQL_NUMERIC]
|
9
|
+
|
10
|
+
def initialize(name, type, format = nil)
|
11
|
+
@name = name
|
12
|
+
@type = type.to_i
|
13
|
+
|
14
|
+
@formatter = if custom_format?(format)
|
15
|
+
Formatter.lookup(format)
|
16
|
+
elsif float_type?
|
17
|
+
FloatFormatter.new
|
18
|
+
elsif integer_type?
|
19
|
+
IntegerFormatter.new
|
20
|
+
else
|
21
|
+
BareFormatter.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def format(value)
|
26
|
+
formatter.format(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def custom_format?(format)
|
31
|
+
Formatter.registry.key?(format)
|
32
|
+
end
|
33
|
+
|
34
|
+
def float_type?
|
35
|
+
FLOAT_TYPES.include?(type)
|
36
|
+
end
|
37
|
+
|
38
|
+
def integer_type?
|
39
|
+
INTEGER_TYPES.include?(type)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Connection
|
5
|
+
include DatabaseStatements
|
6
|
+
|
7
|
+
attr_reader :connector, :db_name, :odbc_conn
|
8
|
+
|
9
|
+
def initialize(connector, db_name)
|
10
|
+
@connector = connector
|
11
|
+
@db_name = db_name.to_sym
|
12
|
+
connect
|
13
|
+
end
|
14
|
+
|
15
|
+
def connect
|
16
|
+
@odbc_conn = connector.connect
|
17
|
+
@odbc_conn.use_time = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def active?
|
21
|
+
@odbc_conn.connected?
|
22
|
+
end
|
23
|
+
|
24
|
+
def disconnect!
|
25
|
+
@odbc_conn.drop_all
|
26
|
+
@odbc_conn.disconnect if active?
|
27
|
+
end
|
28
|
+
|
29
|
+
def reconnect!
|
30
|
+
disconnect!
|
31
|
+
connect
|
32
|
+
end
|
33
|
+
alias reset! reconnect!
|
34
|
+
|
35
|
+
def execute(sql, *args)
|
36
|
+
reset! unless active?
|
37
|
+
@odbc_conn.do(sql, *args)
|
38
|
+
end
|
39
|
+
|
40
|
+
def exec_query(sql, *args)
|
41
|
+
reset! unless active?
|
42
|
+
statement = @odbc_conn.run(sql, *args)
|
43
|
+
columns = statement.columns.values
|
44
|
+
rows = statement.to_a
|
45
|
+
[columns, rows]
|
46
|
+
ensure
|
47
|
+
statement.drop if statement
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module ConnectionHandling
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
DEFAULT_DB = "primary"
|
8
|
+
|
9
|
+
included do |base|
|
10
|
+
def base.inherited(child)
|
11
|
+
child.connection = @connection
|
12
|
+
end
|
13
|
+
|
14
|
+
base.extend ClassMethods
|
15
|
+
base.connection = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
attr_reader :connection
|
20
|
+
|
21
|
+
def connection=(connection)
|
22
|
+
@connection = connection
|
23
|
+
update_descendants_connection unless self.descendants.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_descendants_connection
|
27
|
+
self.descendants.each { |child| child.connection = @connection }
|
28
|
+
end
|
29
|
+
|
30
|
+
def establish_connection(db_name = nil)
|
31
|
+
clear_connection unless self.connection.nil?
|
32
|
+
db_name = db_name.nil? ? DEFAULT_DB : db_name.to_s
|
33
|
+
|
34
|
+
self.load_database_configurations if self.configurations.nil?
|
35
|
+
|
36
|
+
if self.configurations[db_name].nil?
|
37
|
+
raise Error, "Database (:#{db_name}) not found at database configurations."
|
38
|
+
end
|
39
|
+
|
40
|
+
conn_type, conn_config = extract_configuration(db_name)
|
41
|
+
|
42
|
+
connector = ODBCConnector.new(conn_type, conn_config)
|
43
|
+
self.connection = Connection.new(connector, db_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def current_database
|
47
|
+
@connection.db_name
|
48
|
+
end
|
49
|
+
|
50
|
+
def clear_connection
|
51
|
+
@connection.disconnect!
|
52
|
+
@connection = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module DatabaseConfigurations
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
DEFAULT_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
8
|
+
|
9
|
+
included do |base|
|
10
|
+
@@configurations = Hash.new
|
11
|
+
|
12
|
+
base.extend ClassMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def configurations
|
17
|
+
@@configurations
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_database_configurations(path = nil)
|
21
|
+
file_path = path.nil? ? Path.database_config_file : path
|
22
|
+
|
23
|
+
if File.exist?(file_path)
|
24
|
+
file = File.read(file_path)
|
25
|
+
@@configurations = YAML.load(ERB.new(file).result)[DEFAULT_ENV.call]
|
26
|
+
else
|
27
|
+
raise Error, "Could not load db2query database configuration. No such file - #{file_path}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def configurations_databases
|
32
|
+
self.load_database_configurations if self.configurations.nil?
|
33
|
+
@@configurations.keys
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def extract_configuration(db_name)
|
38
|
+
configs = @@configurations[db_name.to_s]
|
39
|
+
conn_config = configs.nil? ? configs : configs.transform_keys(&:to_sym)
|
40
|
+
conn_type = (conn_config.keys & ODBCConnector::CONNECTION_TYPES).first
|
41
|
+
|
42
|
+
if conn_type.nil?
|
43
|
+
raise Error, "No data source name (:dsn) or connection string (:conn_str) provided."
|
44
|
+
end
|
45
|
+
|
46
|
+
[conn_type, conn_config]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module DatabaseStatements
|
5
|
+
def query_value(sql) # :nodoc:
|
6
|
+
single_value_from_rows(query(sql))
|
7
|
+
end
|
8
|
+
|
9
|
+
def query(sql)
|
10
|
+
exec_query(sql).last
|
11
|
+
end
|
12
|
+
|
13
|
+
def query_values(sql)
|
14
|
+
query(sql).map(&:first)
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_database
|
18
|
+
db_name.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_schema
|
22
|
+
query_value("select current_schema from sysibm.sysdummy1").strip
|
23
|
+
end
|
24
|
+
alias library current_schema
|
25
|
+
|
26
|
+
private
|
27
|
+
def single_value_from_rows(rows)
|
28
|
+
row = rows.first
|
29
|
+
row && row.first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module Formatter
|
5
|
+
def self.register(name, klass)
|
6
|
+
self.registry.store(name, klass.new)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.registry
|
10
|
+
@@registry ||= Hash.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.lookup(name)
|
14
|
+
@@registry.fetch(name.to_sym)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.registration(&block)
|
18
|
+
yield self if block_given?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class AbstractFormatter
|
23
|
+
def format(value)
|
24
|
+
raise NotImplementedError, "Implement format method in your subclass."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class BareFormatter < AbstractFormatter
|
29
|
+
def format(value)
|
30
|
+
value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class FloatFormatter < AbstractFormatter
|
35
|
+
def format(value)
|
36
|
+
value.to_f
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class IntegerFormatter < AbstractFormatter
|
41
|
+
def format(value)
|
42
|
+
value.to_i
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
|
+
# Embed in a String to clear all previous ANSI sequences.
|
6
|
+
CLEAR = "\e[0m"
|
7
|
+
BOLD = "\e[1m"
|
8
|
+
|
9
|
+
# Colors
|
10
|
+
BLACK = "\e[30m"
|
11
|
+
RED = "\e[31m"
|
12
|
+
GREEN = "\e[32m"
|
13
|
+
YELLOW = "\e[33m"
|
14
|
+
BLUE = "\e[34m"
|
15
|
+
MAGENTA = "\e[35m"
|
16
|
+
CYAN = "\e[36m"
|
17
|
+
WHITE = "\e[37m"
|
18
|
+
|
19
|
+
def sql(event)
|
20
|
+
class_load_duration = color("#{event.payload[:name]} Load (#{event.duration.round(2)}ms)", :cyan, true)
|
21
|
+
sql_statement = color("#{event.payload[:sql]}", :blue, true)
|
22
|
+
message = " #{class_load_duration} #{sql_statement}"
|
23
|
+
|
24
|
+
if event.payload[:binds].size > 0
|
25
|
+
binds = color("#{event.payload[:binds]}", :white)
|
26
|
+
message = "#{message} [#{binds}]"
|
27
|
+
end
|
28
|
+
|
29
|
+
puts message
|
30
|
+
end
|
31
|
+
|
32
|
+
def schema_task(event)
|
33
|
+
puts color(" Done (#{(event.duration).round(2)}ms)", :green, true)
|
34
|
+
end
|
35
|
+
|
36
|
+
def schema_task_perform(event)
|
37
|
+
task_name = color(":#{event.payload[:task_name]}", :white, true)
|
38
|
+
schema = color("#{event.payload[:schema]}", :white, true)
|
39
|
+
puts "- Performing #{task_name} in #{schema} ..."
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def color(text, color, bold = false) # :doc:
|
44
|
+
return text unless colorize_logging
|
45
|
+
color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
|
46
|
+
bold = bold ? BOLD : ""
|
47
|
+
"#{bold}#{color}#{text}#{CLEAR}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class ODBCConnector
|
5
|
+
attr_reader :connector, :conn_type, :conn_config
|
6
|
+
|
7
|
+
CONNECTION_TYPES = %i[dsn conn_string].freeze
|
8
|
+
|
9
|
+
def initialize(type, config)
|
10
|
+
@conn_type, @conn_config = type, config.transform_keys(&:to_sym)
|
11
|
+
@connector = Db2Query.const_get("#{conn_type.to_s.camelize}Connector").new
|
12
|
+
end
|
13
|
+
|
14
|
+
def connect
|
15
|
+
connector.connect(conn_config)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class DsnConnector
|
20
|
+
def connect(config)
|
21
|
+
::ODBC.connect(config[:dsn], config[:uid], config[:pwd])
|
22
|
+
rescue ::ODBC::Error => e
|
23
|
+
raise Error, "Unable to activate ODBC DSN connection #{e}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ConnStringConnector
|
28
|
+
def connect(config)
|
29
|
+
driver = ::ODBC::Driver.new.tap do |d|
|
30
|
+
d.attrs = config[:conn_string].transform_keys(&:to_s)
|
31
|
+
d.name = "odbc"
|
32
|
+
end
|
33
|
+
::ODBC::Database.new.drvconnect(driver)
|
34
|
+
rescue ::ODBC::Error => e
|
35
|
+
raise Error, "Unable to activate ODBC Conn String connection #{e}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module Path
|
5
|
+
def self.database_config_file
|
6
|
+
@@database_config_file ||= nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.database_config_file=(file_path)
|
10
|
+
@@database_config_file ||= file_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.database_config_file_exists?
|
14
|
+
File.exist?(self.database_config_file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
railtie_name :db2_query
|
6
|
+
|
7
|
+
rake_tasks do
|
8
|
+
tasks_path = "#{File.expand_path("..", __dir__)}/tasks"
|
9
|
+
Dir.glob("#{tasks_path}/*.rake").each { |file| load file }
|
10
|
+
end
|
11
|
+
|
12
|
+
initializer "db2_query.database_initialization" do
|
13
|
+
Path.database_config_file = "#{Rails.root}/config/db2query_database.yml"
|
14
|
+
Base.load_database_configurations
|
15
|
+
Base.establish_connection
|
16
|
+
end
|
17
|
+
|
18
|
+
initializer "db2_query.attach_log_subscription" do
|
19
|
+
LogSubscriber.attach_to :db2_query
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Result
|
5
|
+
attr_reader :core, :klass, :rows, :columns, :column_metadatas, :attr_format
|
6
|
+
|
7
|
+
def initialize(core, klass, columns, rows, attr_format = {})
|
8
|
+
@core = core
|
9
|
+
@klass = klass.to_s.camelize
|
10
|
+
@rows = rows
|
11
|
+
@attr_format = attr_format
|
12
|
+
@columns = []
|
13
|
+
@column_metadatas = extract_metadatas(columns)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_a
|
17
|
+
core.const_set(klass, row_class) unless core.const_defined?(klass)
|
18
|
+
|
19
|
+
rows.map do |row|
|
20
|
+
(core.const_get klass).new(row, column_metadatas)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_hash
|
25
|
+
rows.map do |row|
|
26
|
+
Hash[columns.zip(row)]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def pluck(*column_names)
|
31
|
+
records.map do |record|
|
32
|
+
column_names.map { |column_name| record.send(column_name) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def first
|
37
|
+
records.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def last
|
41
|
+
records.last
|
42
|
+
end
|
43
|
+
|
44
|
+
def size
|
45
|
+
records.size
|
46
|
+
end
|
47
|
+
alias length size
|
48
|
+
|
49
|
+
def each(&block)
|
50
|
+
records.each(&block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
entries = records.take(11).map!(&:inspect)
|
55
|
+
entries[10] = "..." if entries.size == 11
|
56
|
+
"#<#{self.class} [#{entries.join(', ')}]>"
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def records
|
61
|
+
@records ||= to_a
|
62
|
+
end
|
63
|
+
|
64
|
+
def extract_metadatas(columns)
|
65
|
+
columns.map do |col|
|
66
|
+
@columns << column_name = col.name.downcase
|
67
|
+
Column.new(column_name, col.type, attr_format[column_name.to_sym])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def row_class
|
72
|
+
Class.new do
|
73
|
+
def initialize(row, columns_metadata)
|
74
|
+
columns_metadata.zip(row) do |column, val|
|
75
|
+
self.class.send(:attr_accessor, column.name.to_sym)
|
76
|
+
instance_variable_set("@#{column.name}", column.format(val))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def inspect
|
81
|
+
inspection = if defined?(instance_variables) && instance_variables
|
82
|
+
instance_variables.collect do |attr|
|
83
|
+
value = instance_variable_get(attr)
|
84
|
+
"#{attr[1..-1]}: #{(value.kind_of? String) ? %Q{"#{value}"} : value}"
|
85
|
+
end.compact.join(", ")
|
86
|
+
else
|
87
|
+
"not initialized"
|
88
|
+
end
|
89
|
+
|
90
|
+
"#<#{self.class} #{inspection}>"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
class Schema
|
5
|
+
include SQLValidator
|
6
|
+
|
7
|
+
attr_accessor :config, :current_schema
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@config = Config.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def connection
|
14
|
+
Base.connection
|
15
|
+
end
|
16
|
+
|
17
|
+
def schema
|
18
|
+
config.schema
|
19
|
+
end
|
20
|
+
|
21
|
+
def sql_files_dir(path)
|
22
|
+
config.sql_files_dir = path
|
23
|
+
end
|
24
|
+
|
25
|
+
def is_valid_schema?
|
26
|
+
connection.current_schema == config.schema
|
27
|
+
end
|
28
|
+
|
29
|
+
def perform_tasks(&block)
|
30
|
+
raise Error, "#{config.main_library} is not connection's current schema" unless is_valid_schema?
|
31
|
+
|
32
|
+
if Base.connection.nil? && config.init_connection
|
33
|
+
Base.establish_connection
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "\n# Perform Schema Tasks: \n\n"
|
37
|
+
|
38
|
+
instance_eval(&block)
|
39
|
+
|
40
|
+
puts "\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
def sql(sql_statement)
|
44
|
+
raise Error, "Task only for SQL execute commands." if query_command?(sql_statement)
|
45
|
+
sql_statement
|
46
|
+
end
|
47
|
+
|
48
|
+
def file(file_name)
|
49
|
+
sql(File.read("#{config.sql_files_dir}/#{file_name}"))
|
50
|
+
end
|
51
|
+
|
52
|
+
def task(task_name, sql = nil, *args)
|
53
|
+
Task.new(schema, task_name).perform do
|
54
|
+
if block_given?
|
55
|
+
yield(sql)
|
56
|
+
else
|
57
|
+
execute(sql, *args)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def execute(sql, *args)
|
63
|
+
connection.execute(sql, *args)
|
64
|
+
rescue ::ODBC::Error => e
|
65
|
+
raise Error, "Unable to execute SQL - #{e}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def tables_in_schema
|
69
|
+
connection.query_values <<-SQL
|
70
|
+
SELECT table_name FROM SYSIBM.SQLTABLES
|
71
|
+
WHERE table_schem='#{schema}' AND table_type='TABLE'
|
72
|
+
SQL
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.initiation(&block)
|
76
|
+
new.initiation(&block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def initiation(&block)
|
80
|
+
instance_eval(&block)
|
81
|
+
end
|
82
|
+
|
83
|
+
class Task
|
84
|
+
attr_reader :instrumenter, :schema, :task_name, :start_time, :finish_time
|
85
|
+
|
86
|
+
def initialize(schema, task_name)
|
87
|
+
@schema = schema
|
88
|
+
@task_name = task_name
|
89
|
+
@instrumenter = ActiveSupport::Notifications.instrumenter
|
90
|
+
end
|
91
|
+
|
92
|
+
def perform
|
93
|
+
instrumenter.instrument("schema_task_perform.db2_query", payload)
|
94
|
+
instrumenter.start("schema_task.db2_query", payload)
|
95
|
+
yield
|
96
|
+
instrumenter.finish("schema_task.db2_query", payload)
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def payload
|
101
|
+
{ task_name: task_name, schema: schema }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Config
|
106
|
+
attr_accessor :initial_tasks, :init_connection, :schema, :sql_files_dir
|
107
|
+
|
108
|
+
def initialize
|
109
|
+
@init_connection = false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Db2Query
|
4
|
+
module SQLValidator
|
5
|
+
DEFAULT_TASK_COMMANDS = [:create, :drop, :delete, :insert, :set, :update]
|
6
|
+
COMMENT_REGEX = %r{/\*(?:[^\*]|\*[^/])*\*/}m
|
7
|
+
|
8
|
+
def task_command?(sql_statement)
|
9
|
+
sql_statement.match?(task_commands_regexp)
|
10
|
+
end
|
11
|
+
|
12
|
+
def query_command?(sql_statement)
|
13
|
+
sql_statement.match?(/select/i)
|
14
|
+
end
|
15
|
+
|
16
|
+
def is_query?(sql_statement)
|
17
|
+
query_command?(sql_statement) && !task_command?(sql_statement)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def task_commands_regexp
|
22
|
+
parts = DEFAULT_TASK_COMMANDS.map { |part| /#{part}/i }
|
23
|
+
/\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
DB2_QUERY_DATABASE_TEMPLATE ||= <<-EOF
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
# Database configuration example
|
7
|
+
development:
|
8
|
+
primary:
|
9
|
+
conn_string:
|
10
|
+
driver: DB2
|
11
|
+
database: SAMPLE
|
12
|
+
dbalias: SAMPLE
|
13
|
+
hostname: LOCALHOST
|
14
|
+
currentschema: LIBTEST
|
15
|
+
port: "0"
|
16
|
+
protocol: IPC
|
17
|
+
uid: <%= ENV["DB2EC_UID"] %>
|
18
|
+
pwd: <%= ENV["DB2EC_PWD"] %>
|
19
|
+
secondary:
|
20
|
+
dsn: SAMPLE
|
21
|
+
uid: <%= ENV["DB2EC_UID"] %>
|
22
|
+
pwd: <%= ENV["DB2EC_PWD"] %>
|
23
|
+
|
24
|
+
test:
|
25
|
+
primary:
|
26
|
+
conn_string:
|
27
|
+
driver: DB2
|
28
|
+
database: SAMPLE
|
29
|
+
dbalias: SAMPLE
|
30
|
+
hostname: LOCALHOST
|
31
|
+
currentschema: LIBTEST
|
32
|
+
port: "0"
|
33
|
+
protocol: IPC
|
34
|
+
uid: <%= ENV["DB2EC_UID"] %>
|
35
|
+
pwd: <%= ENV["DB2EC_PWD"] %>
|
36
|
+
secondary:
|
37
|
+
dsn: SAMPLE
|
38
|
+
uid: <%= ENV["DB2EC_UID"] %>
|
39
|
+
pwd: <%= ENV["DB2EC_PWD"] %>
|
40
|
+
EOF
|
41
|
+
|
42
|
+
namespace :db2query do
|
43
|
+
desc "Create Database configuration file"
|
44
|
+
task :database do
|
45
|
+
database_path = "#{Rails.root}/config/db2query_database.yml"
|
46
|
+
if File.exist?(database_path)
|
47
|
+
raise ArgumentError, "File exists."
|
48
|
+
else
|
49
|
+
puts " Creating database config file ..."
|
50
|
+
File.open(database_path, "w") do |file|
|
51
|
+
file.puts DB2_QUERY_DATABASE_TEMPLATE
|
52
|
+
end
|
53
|
+
puts " File '#{database_path}' created."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/tasks/init.rake
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
DB2_QUERY_INITIALIZER_TEMPLATE ||= <<-EOF
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
# Example
|
7
|
+
require "db2_query/formatter"
|
8
|
+
|
9
|
+
class FirstNameFormatter < Db2Query::AbstractFormatter
|
10
|
+
def format(value)
|
11
|
+
"First Name: " + value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Db2Query::Formatter.registration do |format|
|
16
|
+
format.register(:first_name_formatter, FirstNameFormatter)
|
17
|
+
end
|
18
|
+
EOF
|
19
|
+
|
20
|
+
namespace :db2query do
|
21
|
+
desc "Create Initializer file"
|
22
|
+
task :initializer do
|
23
|
+
# Create initializer file
|
24
|
+
initializer_path = "#{Rails.root}/config/initializers/db2query.rb"
|
25
|
+
if File.exist?(initializer_path)
|
26
|
+
raise ArgumentError, "File exists."
|
27
|
+
else
|
28
|
+
puts " Creating initializer file ..."
|
29
|
+
File.open(initializer_path, "w") do |file|
|
30
|
+
file.puts DB2_QUERY_INITIALIZER_TEMPLATE
|
31
|
+
end
|
32
|
+
puts " File '#{initializer_path}' created."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db2_query
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- yohanes_l
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-06-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 6.0.3
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 6.0.3.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 6.0.3
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 6.0.3.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: ruby-odbc
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.99999'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0.99999'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rubocop
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rubocop-performance
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rubocop-rails
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: faker
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: dotenv
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: byebug
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: sqlite3
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
description: A Rails query plugin to fetch data from Db2 database by using ODBC connection.
|
146
|
+
email:
|
147
|
+
- yohanes.lumentut@yahoo.com
|
148
|
+
executables: []
|
149
|
+
extensions: []
|
150
|
+
extra_rdoc_files: []
|
151
|
+
files:
|
152
|
+
- MIT-LICENSE
|
153
|
+
- README.md
|
154
|
+
- Rakefile
|
155
|
+
- lib/db2_query.rb
|
156
|
+
- lib/db2_query/base.rb
|
157
|
+
- lib/db2_query/column.rb
|
158
|
+
- lib/db2_query/connection.rb
|
159
|
+
- lib/db2_query/connection_handling.rb
|
160
|
+
- lib/db2_query/database_configurations.rb
|
161
|
+
- lib/db2_query/database_statements.rb
|
162
|
+
- lib/db2_query/error.rb
|
163
|
+
- lib/db2_query/formatter.rb
|
164
|
+
- lib/db2_query/log_subscriber.rb
|
165
|
+
- lib/db2_query/odbc_connector.rb
|
166
|
+
- lib/db2_query/path.rb
|
167
|
+
- lib/db2_query/railtie.rb
|
168
|
+
- lib/db2_query/result.rb
|
169
|
+
- lib/db2_query/schema.rb
|
170
|
+
- lib/db2_query/sql_validator.rb
|
171
|
+
- lib/db2_query/version.rb
|
172
|
+
- lib/tasks/database.rake
|
173
|
+
- lib/tasks/init.rake
|
174
|
+
- lib/tasks/initializer.rake
|
175
|
+
homepage: https://github.com/yohaneslumentut/db2_query
|
176
|
+
licenses:
|
177
|
+
- MIT
|
178
|
+
metadata:
|
179
|
+
allowed_push_host: https://rubygems.org
|
180
|
+
post_install_message:
|
181
|
+
rdoc_options: []
|
182
|
+
require_paths:
|
183
|
+
- lib
|
184
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - ">="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
requirements: []
|
195
|
+
rubygems_version: 3.1.3
|
196
|
+
signing_key:
|
197
|
+
specification_version: 4
|
198
|
+
summary: Db2Query
|
199
|
+
test_files: []
|