db2_query 0.2.3 → 0.3.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.
@@ -1,37 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record/database_configurations"
3
+ module Db2Query
4
+ class DbClient
5
+ attr_reader :dsn
4
6
 
5
- module DB2Query
6
- module Core
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- def self.configurations=(config)
11
- @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
12
- end
13
- self.configurations = {}
7
+ delegate :run, :do, to: :client
14
8
 
15
- def self.configurations
16
- @@configurations
17
- end
18
-
19
- mattr_accessor :connection_handlers, instance_accessor: false, default: {}
20
-
21
- class_attribute :default_connection_handler
9
+ def initialize(dsn)
10
+ @dsn = dsn
11
+ @client = retrieve_db_client
12
+ end
22
13
 
23
- def self.connection_handler
24
- Thread.current.thread_variable_get("db2q_connection_handler") || default_connection_handler
25
- end
14
+ def retrieve_db_client
15
+ ODBC.connect(dsn)
16
+ end
26
17
 
27
- def self.connection_handler=(handler)
28
- Thread.current.thread_variable_set("db2q_connection_handler", handler)
18
+ def client
19
+ unless @client.connected?
20
+ @client = retrieve_db_client
29
21
  end
22
+ @client
23
+ end
24
+ end
30
25
 
31
- self.default_connection_handler = DB2Query::ConnectionHandler.new
26
+ module Core
27
+ extend ActiveSupport::Concern
28
+ included do
29
+ @@connection = nil
30
+ @@mutex = Mutex.new
32
31
  end
33
32
 
34
- module ClassMethods
33
+ class_methods do
35
34
  def initiation
36
35
  yield(self) if block_given?
37
36
  end
@@ -40,9 +39,25 @@ module DB2Query
40
39
  formatters.store(attr_name, format)
41
40
  end
42
41
 
42
+ def connection
43
+ @@connection || create_connection
44
+ end
45
+
46
+ def create_connection
47
+ @@mutex.synchronize do
48
+ return @@connection if @@connection
49
+ @@connection = Connection.new(config) { DbClient.new(config[:dsn]) }
50
+ end
51
+ end
52
+
53
+ def establish_connection
54
+ load_database_configurations
55
+ create_connection
56
+ end
57
+
43
58
  def query(name, body)
44
59
  if defined_method_name?(name)
45
- raise DB2Query::Error, "You tried to define a scope named \"#{name}\" " \
60
+ raise Db2Query::Error, "You tried to define a scope named \"#{name}\" " \
46
61
  "on the model \"#{self.name}\", but DB2Query already defined " \
47
62
  "a class method with the same name."
48
63
  end
@@ -52,14 +67,33 @@ module DB2Query
52
67
  body.call(*args)
53
68
  end
54
69
  elsif body.is_a?(String)
55
- sql = body
70
+ sql = body.strip
56
71
  singleton_class.define_method(name) do |*args|
57
72
  connection.exec_query(formatters, sql, args)
58
73
  end
59
74
  else
60
- raise DB2Query::Error, "The query body needs to be callable or is a sql string"
75
+ raise Db2Query::Error, "The query body needs to be callable or is a sql string"
61
76
  end
62
77
  end
78
+ alias define query
79
+
80
+ def fetch(sql, args)
81
+ validate_sql(sql)
82
+ connection.exec_query({}, sql, args)
83
+ end
84
+
85
+ def fetch_list(sql, args)
86
+ validate_sql(sql)
87
+ raise Db2Query::Error, "Missing @list pointer at SQL" if sql.scan(/\@list+/).length == 0
88
+ raise Db2Query::Error, "The arguments should be an array of list" unless args.is_a?(Array)
89
+ connection.exec_query({}, sql.gsub("@list", "'#{args.join("', '")}'"), [])
90
+ end
91
+
92
+ def sql_with_extention(sql, extention)
93
+ validate_sql(sql)
94
+ raise Db2Query::Error, "Missing @extention pointer at SQL" if sql.scan(/\@extention+/).length == 0
95
+ sql.gsub("@extention", extention.strip)
96
+ end
63
97
 
64
98
  private
65
99
  def formatters
@@ -78,11 +112,18 @@ module DB2Query
78
112
  sql_statement = allocate.method(sql_method).call
79
113
 
80
114
  unless sql_statement.is_a? String
81
- raise DB2Query::Error, "Query methods must return a SQL statement string!"
115
+ raise Db2Query::Error, "Query methods must return a SQL statement string!"
82
116
  end
83
117
 
84
118
  query(method_name, sql_statement)
85
119
 
120
+ if args[0].is_a?(Hash)
121
+ keys = sql_statement.scan(/\$\S+/).map { |key| key.gsub!(/[$=]/, "") }
122
+ rearrange_args = {}
123
+ keys.each { |key| rearrange_args[key.to_sym] = args[0][key.to_sym] }
124
+ args[0] = rearrange_args
125
+ end
126
+
86
127
  method(method_name).call(*args)
87
128
  elsif connection.respond_to?(method_name)
88
129
  connection.send(method_name, *args)
@@ -90,6 +131,10 @@ module DB2Query
90
131
  super
91
132
  end
92
133
  end
134
+
135
+ def validate_sql(sql)
136
+ raise Db2Query::Error, "SQL have to be in string format" unless sql.is_a?(String)
137
+ end
93
138
  end
94
139
  end
95
140
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DB2Query
3
+ module Db2Query
4
4
  class Error < StandardError
5
5
  end
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DB2Query
3
+ module Db2Query
4
4
  module Formatter
5
5
  def self.register(name, klass)
6
6
  self.format_registry.store(name.to_sym, klass.new)
@@ -21,7 +21,7 @@ module DB2Query
21
21
 
22
22
  class AbstractFormatter
23
23
  def format(value)
24
- raise DB2Query::Error, "Implement format method in your subclass."
24
+ raise Db2Query::Error, "Implement format method in your subclass."
25
25
  end
26
26
  end
27
27
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Db2Query
4
+ module Logger
5
+ def translate_exception_class(e, sql, binds)
6
+ message = "#{e.class.name}: #{e.message}"
7
+
8
+ exception = translate_exception(
9
+ e, message: message, sql: sql, binds: binds
10
+ )
11
+ exception.set_backtrace e.backtrace
12
+ exception
13
+ end
14
+
15
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil) # :doc:
16
+ @instrumenter.instrument(
17
+ "sql.active_record",
18
+ sql: sql,
19
+ name: name,
20
+ binds: binds,
21
+ type_casted_binds: type_casted_binds,
22
+ statement_name: statement_name,
23
+ connection_id: object_id,
24
+ connection: self) do
25
+ @lock.synchronize do
26
+ yield
27
+ end
28
+ rescue => e
29
+ raise translate_exception_class(e, sql, binds)
30
+ end
31
+ end
32
+
33
+ def translate_exception(exception, message:, sql:, binds:)
34
+ case exception
35
+ when RuntimeError
36
+ exception
37
+ else
38
+ StatementInvalid.new(message, sql: sql, binds: binds)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,18 +3,13 @@
3
3
  require "db2_query"
4
4
  require "rails"
5
5
 
6
- module DB2Query
7
- class Railtie < Rails::Railtie
6
+ module Db2Query
7
+ class Railtie < ::Rails::Railtie
8
8
  railtie_name :db2_query
9
9
 
10
10
  rake_tasks do
11
11
  path = File.expand_path(__dir__)
12
12
  Dir.glob("#{path}/tasks/*.rake").each { |f| load f }
13
13
  end
14
-
15
- initializer "db2_query.database_initialization" do
16
- DB2Query::Base.configurations = DB2Query.config
17
- DB2Query::Base.establish_connection :primary
18
- end
19
14
  end
20
15
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DB2Query
3
+ module Db2Query
4
4
  class Result < ActiveRecord::Result
5
5
  attr_reader :formatters
6
6
 
@@ -9,6 +9,14 @@ module DB2Query
9
9
  super(columns, rows, column_types)
10
10
  end
11
11
 
12
+ def includes_column?(name)
13
+ @columns.include? name
14
+ end
15
+
16
+ def record
17
+ @record ||= Record.new(rows[0], columns, formatters)
18
+ end
19
+
12
20
  def records
13
21
  @records ||= rows.map do |row|
14
22
  Record.new(row, columns, formatters)
@@ -26,7 +34,7 @@ module DB2Query
26
34
 
27
35
  entries[10] = "..." if entries.size == 11
28
36
 
29
- "#<#{self.class.name} @records=[#{entries.join(', ')}]>"
37
+ "#<#{self.class.name} [#{entries.join(', ')}]>"
30
38
  end
31
39
 
32
40
  class Record
@@ -59,7 +67,7 @@ module DB2Query
59
67
  column = col.downcase
60
68
  format_name = formatters[column.to_sym]
61
69
  unless format_name.nil?
62
- formatter = DB2Query::Formatter.lookup(format_name)
70
+ formatter = Db2Query::Formatter.lookup(format_name)
63
71
  val = formatter.format(val)
64
72
  end
65
73
  [column, val]
@@ -1,48 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "db2_query"
4
+
3
5
  DB2_QUERY_DATABASE_TEMPLATE ||= <<-EOF
4
6
  # frozen_string_literal: true
5
- # Database configuration example
7
+
6
8
  development:
7
- primary:
8
- dsn: iseries
9
- uid: <%= ENV["ISERIES_UID"] %>
10
- pwd: <%= ENV["ISERIES_PWD"] %>
11
- secondary:
12
- conn_string:
13
- driver: DB2
14
- database: ARUNIT2
15
- dbalias: ARUNIT2
16
- hostname: LOCALHOST
17
- currentschema: LIBTEST
18
- port: "0"
19
- protocol: IPC
20
- uid: <%= ENV["DB2EC_UID"] %>
21
- pwd: <%= ENV["DB2EC_PWD"] %>
9
+ dsn: TODO
10
+ pool: 5
11
+ timeout: 5
12
+
22
13
  test:
23
- primary:
24
- dsn: iseries
25
- uid: <%= ENV["ISERIES_UID"] %>
26
- pwd: <%= ENV["ISERIES_PWD"] %>
27
- secondary:
28
- conn_string:
29
- driver: DB2
30
- database: ARUNIT2
31
- dbalias: ARUNIT2
32
- hostname: LOCALHOST
33
- currentschema: LIBTEST
34
- port: "0"
35
- protocol: IPC
36
- uid: <%= ENV["DB2EC_UID"] %>
37
- pwd: <%= ENV["DB2EC_PWD"] %>
14
+ dsn: TODO
15
+ pool: 5
16
+ timeout: 5
17
+
18
+ production:
19
+ dsn: TODO
20
+ pool: 5
21
+ timeout: 5
38
22
  EOF
39
23
 
40
24
  namespace :db2query do
41
25
  desc "Create Database configuration file"
42
26
  task :database do
43
- database_path = "#{Rails.root}/config/db2query_database.yml"
27
+ database_path = "#{Rails.root}/config/db2query.yml"
44
28
  if File.exist?(database_path)
45
- raise ArgumentError, "File exists."
29
+ raise Db2Query::Error, "Db2Query database config file exists, please check first"
46
30
  else
47
31
  puts " Creating database config file ..."
48
32
  File.open(database_path, "w") do |file|
@@ -1,25 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "db2_query"
4
+
3
5
  DB2_QUERY_INITIALIZER_TEMPLATE ||= <<-EOF
4
6
  # frozen_string_literal: true
5
-
6
7
  require "db2_query"
7
8
  require "db2_query/formatter"
8
9
 
9
- DB2Query::Base.initiation do |base|
10
- base.configurations = base.parent.config
11
- base.establish_connection ENV['RAILS_ENV'].to_sym
10
+ Db2Query::Base.initiation do |base|
11
+ base.establish_connection
12
12
  end
13
13
 
14
14
  # Example
15
-
16
- class FirstNameFormatter < DB2Query::AbstractFormatter
15
+ class FirstNameFormatter < Db2Query::AbstractFormatter
17
16
  def format(value)
18
17
  "Dr." + value
19
18
  end
20
19
  end
21
20
 
22
- DB2Query::Formatter.registration do |format|
21
+ Db2Query::Formatter.registration do |format|
23
22
  format.register(:first_name_formatter, FirstNameFormatter)
24
23
  end
25
24
  EOF
@@ -30,7 +29,7 @@ namespace :db2query do
30
29
  # Create initializer file
31
30
  initializer_path = "#{Rails.root}/config/initializers/db2query.rb"
32
31
  if File.exist?(initializer_path)
33
- raise ArgumentError, "File exists."
32
+ raise Db2Query::Error, "Db2Query initializer file exists, please check first"
34
33
  else
35
34
  puts " Creating initializer file ..."
36
35
  File.open(initializer_path, "w") do |file|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module DB2Query
4
- VERSION = "0.2.3"
3
+ module Db2Query
4
+ VERSION = "0.3.0"
5
5
  end
metadata CHANGED
@@ -1,59 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db2_query
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yohanes_l
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-13 00:00:00.000000000 Z
11
+ date: 2021-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ruby-odbc
14
+ name: rubocop
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0.99999'
20
- type: :runtime
19
+ version: '0'
20
+ type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0.99999'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: rubocop-performance
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 6.0.3
34
- type: :runtime
33
+ version: '0'
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 6.0.3
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: activerecord
42
+ name: rubocop-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 6.0.3
48
- type: :runtime
47
+ version: '0'
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 6.0.3
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop
56
+ name: faker
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rubocop-performance
70
+ name: byebug
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,50 +81,62 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rubocop-rails
84
+ name: rails
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 6.1.3
87
90
  - - ">="
88
91
  - !ruby/object:Gem::Version
89
- version: '0'
92
+ version: 6.1.3.2
90
93
  type: :development
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: 6.1.3
94
100
  - - ">="
95
101
  - !ruby/object:Gem::Version
96
- version: '0'
102
+ version: 6.1.3.2
97
103
  - !ruby/object:Gem::Dependency
98
- name: faker
104
+ name: connection_pool
99
105
  requirement: !ruby/object:Gem::Requirement
100
106
  requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '2.2'
101
110
  - - ">="
102
111
  - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
112
+ version: 2.2.5
113
+ type: :runtime
105
114
  prerelease: false
106
115
  version_requirements: !ruby/object:Gem::Requirement
107
116
  requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '2.2'
108
120
  - - ">="
109
121
  - !ruby/object:Gem::Version
110
- version: '0'
122
+ version: 2.2.5
111
123
  - !ruby/object:Gem::Dependency
112
- name: byebug
124
+ name: ruby-odbc
113
125
  requirement: !ruby/object:Gem::Requirement
114
126
  requirements:
115
127
  - - ">="
116
128
  - !ruby/object:Gem::Version
117
129
  version: '0'
118
- type: :development
130
+ type: :runtime
119
131
  prerelease: false
120
132
  version_requirements: !ruby/object:Gem::Requirement
121
133
  requirements:
122
134
  - - ">="
123
135
  - !ruby/object:Gem::Version
124
136
  version: '0'
125
- description: A Rails query plugin to fetch data from Db2 database by using ODBC connection.
137
+ description: A Rails Db2 ODBC adapter
126
138
  email:
127
- - yohanes.lumentut@yahoo.com
139
+ - yohanes.lumentut@gmail.com
128
140
  executables: []
129
141
  extensions: []
130
142
  extra_rdoc_files: []
@@ -134,26 +146,25 @@ files:
134
146
  - Rakefile
135
147
  - lib/db2_query.rb
136
148
  - lib/db2_query/base.rb
137
- - lib/db2_query/bind.rb
138
149
  - lib/db2_query/config.rb
139
150
  - lib/db2_query/connection.rb
140
- - lib/db2_query/connection_handling.rb
141
151
  - lib/db2_query/core.rb
142
- - lib/db2_query/database_statements.rb
143
152
  - lib/db2_query/error.rb
144
153
  - lib/db2_query/formatter.rb
145
- - lib/db2_query/odbc_connector.rb
154
+ - lib/db2_query/logger.rb
146
155
  - lib/db2_query/railtie.rb
147
156
  - lib/db2_query/result.rb
148
157
  - lib/db2_query/tasks/database.rake
149
158
  - lib/db2_query/tasks/init.rake
150
159
  - lib/db2_query/tasks/initializer.rake
151
160
  - lib/db2_query/version.rb
152
- homepage: https://github.com/yohaneslumentut/db2_query
161
+ homepage: https://github.com/yohaneslumentut
153
162
  licenses:
154
163
  - MIT
155
164
  metadata:
156
- allowed_push_host: https://rubygems.org
165
+ homepage_uri: https://github.com/yohaneslumentut
166
+ source_code_uri: https://github.com/yohaneslumentut/db2_query
167
+ changelog_uri: https://github.com/yohaneslumentut/db2_query
157
168
  post_install_message:
158
169
  rdoc_options: []
159
170
  require_paths:
@@ -169,8 +180,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
180
  - !ruby/object:Gem::Version
170
181
  version: '0'
171
182
  requirements: []
172
- rubygems_version: 3.1.3
183
+ rubygems_version: 3.0.3
173
184
  signing_key:
174
185
  specification_version: 4
175
- summary: DB2Query
186
+ summary: Db2 ODBC adapter
176
187
  test_files: []