jdbc_helpers 0.0.4-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/jdbc_helpers.rb +278 -0
  3. metadata +72 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: da31e2a345c9a088a11b6f3ebb6d7cb1615e68de
4
+ data.tar.gz: 9132e05e016094c28a6390d3120f060057cabd79
5
+ SHA512:
6
+ metadata.gz: 1cbdbe86780d684d11152ab64e0ce1023e4ed53b9d247d69e12798a644088bf3e9a28a3e9d6dd913e86b1895e37790efccd744f9062e57723e4260dd093bf8dd
7
+ data.tar.gz: ace30512f1a002d7f2846031651b5e433c970c03f63900e8bb253977d19e6116717ec8f3a3f192acff3a344e26571117717bb8b29461eed26787b0241562edb1
@@ -0,0 +1,278 @@
1
+ require 'json'
2
+ require 'logger'
3
+
4
+ # JDBC helper classes to simplify interactions with JDBC databases.
5
+ # note that this assumes that you have already instantiated
6
+ # a JDBC driver into the current namespace.
7
+ module JDBCHelpers
8
+ # Base class to provide helper methods that may be generally useful to the concrete classes
9
+ class Base
10
+ # Cleanses SQL statements so they can be presented in a log without security risk
11
+ # currently removes AWS credentials for Redshift copy/unload
12
+ # @param [String] stmt SQL statement to cleanse
13
+ # @return [String] cleansed statement
14
+ def cleanse_statement(stmt)
15
+ # filter out aws creds from redshift
16
+ tmp = stmt.to_s
17
+ return tmp.gsub(
18
+ /aws_access_key_id\s*=\s*.{20}\s*\;\s*|aws_secret_access_key\s*=\s*(\w|\/|^'){40,41}/i,
19
+ '<removed>'
20
+ ).gsub(/\s+/,' ')
21
+ end
22
+
23
+ # Array of classes that should be casted to Strings
24
+ # @return [Array<Class>]
25
+ def convert_to_string_classes
26
+ [Java::JavaSql::Timestamp, Java::JavaSql::Date]
27
+ end
28
+ end
29
+
30
+ # Creates a discreet JDBC connection and makes it available via connection attribute
31
+ class ConnectionFactory < JDBCHelpers::Base
32
+ attr_accessor :connection
33
+
34
+ # @param [String] jdbc_url
35
+ # @param [String] db_user
36
+ # @param [String] db_pass
37
+ # @param [Logger] logger object otherwise will default to new Logger
38
+ def initialize(jdbc_url, db_user, db_pass, logger = nil)
39
+ @logger = logger ? logger : Logger.new(STDOUT)
40
+ @logger.info("connecting to #{jdbc_url} as user #{db_user}...")
41
+ @connection = java.sql.DriverManager.get_connection(
42
+ jdbc_url,
43
+ db_user,
44
+ db_pass
45
+ )
46
+ @logger.info("connection successful!") if @connection
47
+ end
48
+ end
49
+
50
+ # executes a sql statement
51
+ class Execute < JDBCHelpers::Base
52
+ # Rows affected by the SQL statement execution. Note that
53
+ # not all JDBC drivers/databases handle this appropriately
54
+ attr_accessor :rows_affected
55
+
56
+ # @param [Object] db_connect active connection against which to execute statement
57
+ # @param [String] statement SQL statement text
58
+ # @param [Logger] logger object otherwise will default to new Logger
59
+ def initialize(db_connect, statement, logger = nil)
60
+ @logger = logger ? logger : Logger.new(STDOUT)
61
+ stmt = db_connect.create_statement
62
+ @logger.info(
63
+ "executing statement: #{cleanse_statement(statement)}"
64
+ )
65
+ start = Time.new.utc
66
+ @rows_affected = stmt.execute_update(statement)
67
+ @logger.info "query executed #{Time.new.utc - start} seconds"
68
+ end
69
+ end
70
+
71
+ # Executes a select query, then returns the first field from the first row
72
+ class SingleValueFromQuery < JDBCHelpers::Base
73
+ # Value of the first field from the first row. class will vary.
74
+ attr_accessor :result
75
+
76
+ # @param [Object] db_connect active connection against which to execute statement
77
+ # @param [String] statement SQL statement text
78
+ # @param [Logger] logger object otherwise will default to new Logger
79
+ def initialize(db_connect, statement, logger = nil)
80
+ @logger = logger ? logger : Logger.new(STDOUT)
81
+ stmt = db_connect.create_statement
82
+ @logger.info(
83
+ "executing query: #{cleanse_statement(statement)}"
84
+ )
85
+ start = Time.new.utc
86
+ rs = stmt.execute_query(statement)
87
+ @logger.info "query executed #{Time.new.utc-start} seconds"
88
+ rs.next
89
+ value = rs.getObject(1)
90
+ rs.close
91
+
92
+ #the below simplifies things... especially comparisons
93
+ #if you don't like it you can write your own damn helper!
94
+ value = value.to_s if convert_to_string_classes.include?(value.class)
95
+ @result = value
96
+ end
97
+ end
98
+
99
+ # Execute a SQL query, store the results as an array of hashes.
100
+ class QueryResultsToArray < JDBCHelpers::Base
101
+ # Contains the array of hashes returned from the select query
102
+ attr_accessor :results
103
+
104
+ # @param [Object] db_connect active connection against which to execute statement
105
+ # @param [String] statement SQL statement text
106
+ # @param [Logger] logger object otherwise will default to new Logger
107
+ def initialize(db_connect, statement, logger = nil)
108
+ @logger = logger ? logger : Logger.new(STDOUT)
109
+ stmt = db_connect.create_statement
110
+ @logger.info "executing query: #{cleanse_statement(statement)}"
111
+ start = Time.new.utc
112
+ rs = stmt.execute_query(statement)
113
+ @logger.info("query executed #{Time.new.utc - start} seconds")
114
+ @results = rs_to_array(rs)
115
+ end
116
+
117
+ # converts a JDBC recordset to an array of hashes, with one hash per record
118
+ # @param [Object] rs JDBC result set object
119
+ # @return [Array<Hash>] Array of Hash with a Hash for each record
120
+ def rs_to_array(rs)
121
+ # creates an array of hashes from a jdbc record set
122
+ arr = []
123
+
124
+ # get basic metadata for the recordset
125
+ meta = rs.getMetaData
126
+ cols = meta.getColumnCount.to_i
127
+
128
+ # loop through the records to add them into hash
129
+ while rs.next do
130
+ # r is a temporary hash for the row being processed
131
+ r = {}
132
+
133
+ # add each row to r
134
+ (1..cols).each do |c|
135
+ r[meta.get_column_name(c)] = rs.getObject(c)
136
+ if convert_to_string_classes.include?(r[meta.get_column_name(c)].class)
137
+ r[meta.get_column_name(c)] = r[meta.get_column_name(c)].to_s
138
+ end
139
+ end # each cols
140
+
141
+ # append hash to array
142
+ arr << r
143
+ end # while
144
+
145
+ # completed hash is returned
146
+ return arr
147
+ end
148
+ end
149
+
150
+ # Creates a hash of arrays of hashes from a SQL query
151
+ class QueryResultsToHashOfArrays < JDBCHelpers::Base
152
+ attr_accessor :results
153
+
154
+ # @param [Object] db_connect active connection against which to execute statement
155
+ # @param [String] statement SQL statement text
156
+ # @param [String] key_field SQL result set field containing the key to be used in the top level of hash
157
+ # @param [Logger] logger object otherwise will default to new Logger
158
+ def initialize(db_connect, statement, key_field, logger = nil)
159
+ @logger = logger ? logger : Logger.new(STDOUT)
160
+ stmt = db_connect.create_statement
161
+ @logger.info "executing query in thread #{Thread.current.object_id}:\n#{cleanse_statement(statement)}"
162
+ start = Time.new.utc
163
+ rs = stmt.execute_query(statement)
164
+ @logger.info "query executed #{Time.new.utc - start} seconds"
165
+ @results=rs_to_hash(rs, key_field, true)
166
+ end
167
+
168
+ # converts a JDBC recordset to an array of hashes, with one hash per record
169
+ # creates a hash from a jdbc record set
170
+ # index_key_field is the field you want to use as the top level
171
+ # hash key... and should exist in the record set
172
+ # multi_val=true will create an array below each index_key_filed,
173
+ # false will create a hash as the child
174
+ # @param [Object] rs JDBC result set object
175
+ # @param [String] index_key_field field to use as top level hash keys
176
+ # @return [Hash] Hash of Arrays of Hashes for each record
177
+ def rs_to_hash(rs, index_key_field, multi_val)
178
+ # setting default hash value is necessary for appending to arrays
179
+ hash=Hash.new{ |h, k| h[k] = [] }
180
+
181
+ # get basic metadata for the recordset
182
+ meta = rs.getMetaData
183
+ cols = meta.getColumnCount.to_i
184
+
185
+ # loop through the records to add them into hash
186
+ while rs.next do
187
+ # if multi_val is not true... create new hash value as an empty hash if it doesn't already exist
188
+ hash[rs.getString(index_key_field)]={} if (!hash[rs.getString(index_key_field)] and !multi_val)
189
+
190
+ # if multi_val is true... create new hash value as an empty array if it doesn't already exist
191
+ hash[rs.getString(index_key_field)]=[] if (!hash[rs.getString(index_key_field)] and multi_val)
192
+
193
+ # r is a temporary hash for the row being processed
194
+ r=Hash.new
195
+
196
+ # add each row to r
197
+ (1..cols).each do |c|
198
+ r[meta.get_column_name(c)] = rs.getObject(c)
199
+ if convert_to_string_classes.include?(r[meta.get_column_name(c)].class)
200
+ r[meta.get_column_name(c)] = r[meta.get_column_name(c)].to_s
201
+ end
202
+ end # each cols
203
+
204
+ # set hash value to r if not multi_val
205
+ hash[rs.getString(index_key_field)] = r if !multi_val
206
+
207
+ # append hash to r if multi_val
208
+ hash[rs.getString(index_key_field)] << r if multi_val
209
+ end # while
210
+
211
+ # completed hash is returned
212
+ return hash
213
+ end
214
+ end # class
215
+
216
+ class QueryResultsToJSONFile < JDBCHelpers::Base
217
+ # runs a SQL query, then writes the results as JSON objects to a provided file object.
218
+ # by use of the formatter parameter, you can change the output to any format you desire (CSV, XML, etc)
219
+ # see json_formatter method for an example of a proc to perform formatting
220
+ # @param [Object] db_connect active connection against which to execute statement
221
+ # @param [String] statement SQL statement text
222
+ # @param [IO] file_object IO object to receive the formatted results
223
+ # @param [proc] formatter proc to handle the actual formatting, defaults to JSON if nil
224
+ # @param [Logger] logger object otherwise will default to new Logger
225
+ def initialize(db_connect, statement, file_object, formatter = nil, logger = nil)
226
+ @logger = logger ? logger : Logger.new(STDOUT)
227
+ stmt = db_connect.create_statement
228
+ @logger.info "executing query: #{cleanse_statement(statement)}"
229
+ start = Time.new.utc
230
+ rs = stmt.execute_query(statement)
231
+ @logger.info "query executed initial results #{Time.new.utc - start} seconds"
232
+ record_count = rs_to_json_file(rs, file_object, formatter)
233
+ @logger.info "query export time #{Time.new.utc - start} seconds"
234
+ @logger.info "#{record_count} rows exported"
235
+ end
236
+
237
+ # outputs a JDBC result set to a formatted file
238
+ # formatter defaults to JSON output unless you provide your own proc
239
+ # @param [Object] rs JDBC result set
240
+ # @param [IO] file_object IO object to receive the formatted results
241
+ # @param [proc] formatter proc to handle the actual formatting, defaults to JSON if nil
242
+ def rs_to_json_file(rs, file_object, formatter)
243
+ # default formatter outputs json objects for each row
244
+ formatter = json_formatter unless formatter
245
+
246
+ # get basic metadata for the recordset
247
+ meta = rs.getMetaData
248
+ cols = meta.getColumnCount.to_i
249
+
250
+ record_count = 0
251
+ # loop through the records to add them into hash
252
+ while rs.next do
253
+
254
+ # r is a temporary hash for the row being processed
255
+ r = Hash.new
256
+
257
+ # add each row to r
258
+ (1..cols).each do |c|
259
+ r[meta.get_column_name(c)] = rs.getObject(c)
260
+ if convert_to_string_classes.include?(r[meta.get_column_name(c)].class)
261
+ r[meta.get_column_name(c)] = r[meta.get_column_name(c)].to_s
262
+ end
263
+ end # each cols
264
+
265
+ # formatter handles output of r to file
266
+ formatter.call(file_object, r)
267
+ record_count += 1
268
+ end # while
269
+ return record_count
270
+ end
271
+
272
+ # proc must handle two inputs, |file_object, record hash|
273
+ # @return [proc] returns proc to output json
274
+ def json_formatter
275
+ Proc.new { |f,h| f.puts h.to_json }
276
+ end
277
+ end # class
278
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jdbc_helpers
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: java
6
+ authors:
7
+ - jeremy winters
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 1.2.8
19
+ name: logger
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.8
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.9.0
33
+ name: minitest
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 5.9.0
41
+ description: allows for easy conversion of query results to hashes, arrays of hashes, json files, etc.
42
+ email: jeremy.winters@full360.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/jdbc_helpers.rb
48
+ homepage: https://www.full360.com
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.6.4
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: helpers for jdbc interaction
72
+ test_files: []