db2_query 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []