pgx 1.0.4 → 1.0.7

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pgx.rb +51 -96
  3. metadata +21 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '02338571ec666c08713d25e4aa87b8ae7ff0ad9a153615db8c242d0d59450f1c'
4
- data.tar.gz: 17c398d0f872f428203497dcc83111fe996f8b58372ed927c3336ea9f875df90
3
+ metadata.gz: 6d32046f29c429a8e7c9e45ec0d603fd96a2588a18bbe14d773a355e2e37e061
4
+ data.tar.gz: 28e35690b03970729e9ea98080473f90ada24435089237775d3e3c8275515aa6
5
5
  SHA512:
6
- metadata.gz: b3090b8d4b06143e946437d0074dcf06f105d338bb9c70b7aeddc5cab3fc5da82545b39de8eb4f189d53ef8d8fae464a66f32a17a2c37abc6ff11ce89446fd21
7
- data.tar.gz: 13650f36b6a5a1b3b323d2c9dbea6b7df00a8d8bd8c0fd22241e5b12a3a39853b318e4bda88ada8e73e715a8746db42c74439164c70796d1ca6e8cdf7d7cd4e3
6
+ metadata.gz: 9b5bc92e8d2b851dd43b668ab278d7129dac7e7dd6fa9d18800d4f644d376b345a2dae37392629cc10f0bda979adb0deaff40cfee43d920ebf17dc650725b3cc
7
+ data.tar.gz: e43a561b2ec0dc3e5202d7774a52ad145a80ae543b0d7e52fb83273eb250c1ca08040c49b42be1f94e7249fb209b97530ad25deefc9a56594a97ef7814979544
data/lib/pgx.rb CHANGED
@@ -37,15 +37,13 @@ module PGx
37
37
  )
38
38
 
39
39
  # @author Kiriakos Georgiou, http://www.mockbites.com/about
40
- # Extends the base class PG::Connection methods by adding logging and
40
+ # Extends the PG::Connection methods by adding logging and
41
41
  # retrying capabilities (synchronous methods only.)
42
42
  # The arguments and method behaviors are
43
43
  # identical, except for the 'new' method.
44
44
  # @see http://www.mockbites.com/articles/tech/pgx pgx documentation
45
45
  # @see http://deveiate.org/code/pg/PG/Connection.html Base class methods
46
- class PGx::Connection < PG::Connection
47
- alias PG_close close # for use when closing bad connections
48
-
46
+ class PGx::Connection
49
47
  # @param [Logger] logger: a logger object, or a lambda returning the
50
48
  # logger object. Note that a lambda returning the logger is
51
49
  # preferable because it makes logging of the log object itself
@@ -87,7 +85,7 @@ module PGx
87
85
  # )
88
86
  def initialize(*args)
89
87
  connect_args = PGx.const_get('CONNECT_ARGS')
90
- (our_args, parent_args) = extract_our_args(connect_args, args)
88
+ (our_args, pg_args) = extract_our_args(connect_args, args)
91
89
 
92
90
  log = arg_with_default(connect_args, our_args, :logger)
93
91
  @logger = [ log.is_a?(Proc) ? log.call : log ].flatten
@@ -112,47 +110,29 @@ module PGx
112
110
  @connect_proc = lambda {
113
111
  @prepared_live = {} # reset on connect
114
112
  connect_log_and_try(
115
- lambda { super(*parent_args) },
113
+ lambda { PG::Connection.new(*pg_args) },
116
114
  our_args,
117
- parent_args
115
+ pg_args
118
116
  )
119
117
  }
120
118
  connect_loop()
121
119
  end
122
120
 
121
+ def method_missing(m, *args, &block)
122
+ sql_log_and_try(lambda { @connection.send(m, *args, &block) }, m, args)
123
+ end
124
+
123
125
  # @example
124
126
  # con.transaction do
125
127
  # con.exec "create temp table mytable(x text)"
126
128
  # con.exec "insert into mytable(x) values('a')"
127
129
  # con.exec "insert into mytable(x) values('b')"
128
130
  # end
129
- def transaction(*args)
131
+ def transaction(*args, &block)
130
132
  @in_transaction_block = true
131
- sql_log_and_try(lambda { super }, __method__, args)
133
+ r = sql_log_and_try(lambda { @connection.transaction(*args, &block) }, __method__, args)
132
134
  @in_transaction_block = false
133
- end
134
-
135
- # @example
136
- # con.exec "insert into mytable(x) values('test value')"
137
- # con.exec 'insert into mytable(x) values($1)', ['test value']
138
- def exec(*args)
139
- sql_log_and_try(lambda { super }, __method__, args)
140
- end
141
-
142
- # Alias for exec
143
- def query(*args)
144
- sql_log_and_try(lambda { super }, __method__, args)
145
- end
146
-
147
- # @example
148
- # con.exec_params 'select * from mytable where x = $1 limit $2', [1, 100] do |rs|
149
- # puts rs.fields.collect { |fname| "%-15s" % [fname] }.join('')
150
- # rs.values.collect { |row|
151
- # puts row.collect { |col| "%-15s" % [col] }.join('')
152
- # }
153
- # end
154
- def exec_params(*args)
155
- sql_log_and_try(lambda { super }, __method__, args)
135
+ r
156
136
  end
157
137
 
158
138
  # @example
@@ -163,52 +143,27 @@ module PGx
163
143
  # puts row.collect { |col| "%-15s" % [col] }.join('')
164
144
  # }
165
145
  # end
166
- def prepare(*args)
146
+ def prepare(*args, &block)
167
147
  # it's possible to call prepare() on an statement that is already prepared
168
148
  # if you have a prepare() inside a transaction, and the transaction is retried
169
149
  # thus we check if it's already live
170
150
  s = args[0]
151
+ r = nil
171
152
  if @prepared_live.has_key?(s)
172
153
  log_debug %Q{prepared statement #{s} is already live, skipping re-preparing it}
173
154
  else
174
- sql_log_and_try(lambda { super }, __method__, args)
155
+ r = sql_log_and_try(lambda { @connection.prepare(*args, &block) }, __method__, args)
175
156
  @prepared_statements[s] = args[1]
176
157
  @prepared_live[s] = true
177
158
  end
159
+ r
178
160
  end
179
161
 
180
- # @example
181
- # con.prepare 'sql1', 'select * from mytable limit $1'
182
- # con.exec_prepared 'sql1', [100] do |rs|
183
- # puts rs.fields.collect { |fname| "%-15s" % [fname] }.join('')
184
- # rs.values.collect { |row|
185
- # puts row.collect { |col| "%-15s" % [col] }.join('')
186
- # }
187
- # end
188
- def exec_prepared(*args)
189
- sql_log_and_try(lambda { super }, __method__, args)
190
- end
191
-
192
- def cancel(*args)
193
- sql_log_and_try(lambda { super }, __method__, args)
194
- end
195
-
196
- def close(*args)
197
- sql_log_and_try(lambda { super }, __method__, args)
198
- end
199
-
200
- def finish(*args)
201
- sql_log_and_try(lambda { super }, __method__, args)
202
- end
203
-
204
- def reset(*args)
205
- sql_log_and_try(lambda { super }, __method__, args)
162
+ def reset(*args, &block)
163
+ r = sql_log_and_try(lambda { @connection.reset(*args, &block) }, __method__, args)
206
164
  @prepared_live = {} # reset on connect
207
165
  @connect_init.call(@connection)
208
- end
209
-
210
- def wait_for_notify(*args)
211
- sql_log_and_try(lambda { super }, __method__, args)
166
+ r
212
167
  end
213
168
 
214
169
  private
@@ -221,7 +176,7 @@ module PGx
221
176
 
222
177
  # extract our arguments defined in all_our_possible_args from args
223
178
  # returns an array containing our arguments (hash) and the aguments
224
- # for the parent method
179
+ # for the pg method
225
180
  def extract_our_args(all_our_possible_args, args)
226
181
  our_args = {}
227
182
  if args[0].is_a?(Hash)
@@ -280,45 +235,45 @@ module PGx
280
235
  end
281
236
  end
282
237
 
283
- # sanitize parent arguments, eg: blank the password so it's not in the logs
284
- def sanitize_parent_connect_args(parent_args)
285
- if parent_args.empty?
286
- return parent_args
287
- elsif parent_args.length == 1
288
- if parent_args[0].is_a?(Hash) # hash method
289
- return [ parent_args[0].merge(parent_args[0]) { |k, ov| k == :password ? '...' : ov } ]
238
+ # sanitize pg arguments, eg: blank the password so it's not in the logs
239
+ def sanitize_pg_connect_args(pg_args)
240
+ if pg_args.empty?
241
+ return pg_args
242
+ elsif pg_args.length == 1
243
+ if pg_args[0].is_a?(Hash) # hash method
244
+ return [ pg_args[0].merge(pg_args[0]) { |k, ov| k == :password ? '...' : ov } ]
290
245
  end
291
- if parent_args[0].is_a?(String) # string method
292
- return [ parent_args[0].gsub(/(password\s*=\s*)\S+/, '\1...') ]
246
+ if pg_args[0].is_a?(String) # string method
247
+ return [ pg_args[0].gsub(/(password\s*=\s*)\S+/, '\1...') ]
293
248
  end
294
249
  else # positional arguments method
295
- return [ parent_args.map.with_index { |x, i| i == 6 ? '...' : x } ]
250
+ return [ pg_args.map.with_index { |x, i| i == 6 ? '...' : x } ]
296
251
  end
297
252
  end
298
253
 
299
254
  # merge as follows:
300
255
  # hash and hash -> hash
301
256
  # hash and array -> array
302
- def merge_connect_args(our_args, parent_args)
257
+ def merge_connect_args(our_args, pg_args)
303
258
  if our_args.empty?
304
- return parent_args
305
- elsif parent_args.empty?
259
+ return pg_args
260
+ elsif pg_args.empty?
306
261
  return our_args
307
- elsif parent_args.length == 1 and parent_args[0].is_a?(Hash)
308
- return our_args.merge(parent_args[0]) # connection hash style
262
+ elsif pg_args.length == 1 and pg_args[0].is_a?(Hash)
263
+ return our_args.merge(pg_args[0]) # connection hash style
309
264
  else
310
- return [our_args].concat(parent_args)
265
+ return [our_args].concat(pg_args)
311
266
  end
312
267
  end
313
268
 
314
269
  # log and retry the connect/new method
315
- def connect_log_and_try(caller_super, our_args, parent_args)
270
+ def connect_log_and_try(pg_lambda, our_args, pg_args)
316
271
  try_count = 0
317
272
  all_args = merge_connect_args( sanitize_our_connect_args(our_args),
318
- sanitize_parent_connect_args(parent_args) )
273
+ sanitize_pg_connect_args(pg_args) )
319
274
  begin
320
275
  log_debug function_call_string('connect', all_args)
321
- @connection = caller_super.call # run the parent 'pg' function, new()
276
+ @connection = pg_lambda.call # run pg new() mathod
322
277
  log_debug 'calling connection initialization proc'
323
278
  @connect_init.call(@connection)
324
279
  rescue PG::Error => e
@@ -336,25 +291,25 @@ module PGx
336
291
  end
337
292
 
338
293
  # log and retry statement related methods
339
- def sql_log_and_try(caller_super, caller_method, args)
294
+ def sql_log_and_try(pg_lambda, method, args)
340
295
  try_count = 0
341
296
  begin # re-prepare prepared statements after a failed transaction
342
- transaction_reprepare(caller_method) # just prior to retrying the transaction
343
- log_debug function_call_string(caller_method, args)
344
- caller_super.call # run the parent 'pg' function
297
+ transaction_reprepare(method) # just prior to retrying the transaction
298
+ log_debug function_call_string(method, args)
299
+ pg_lambda.call # run the pg method
345
300
  rescue PG::Error => e
346
301
  if connected? # if we are connected, it's an SQL related error
347
- if not method_in_transaction_block(caller_method) # do not log errors and retry
302
+ if not method_in_transaction_block(method) # do not log errors and retry
348
303
  try_count = try_count + 1 # methods within a transaction
349
304
  log_error(get_error_fields(e) + "\n" + get_error_message(e)) # block because the transaction
350
- error_handlers(e, caller_method, args) # itself will log the error and
305
+ error_handlers(e, method, args) # itself will log the error and
351
306
  retry if sql_retriable?(e, try_count) # retry the transaction block
352
- elsif caller_method.to_s == 'exec_prepared' # exec_prepared failed within a transaction
307
+ elsif method.to_s == 'exec_prepared' # exec_prepared failed within a transaction
353
308
  @transaction_reprepare = args[0] # make a note to re-prepare before retrying
354
309
  end # the transaction
355
310
  else # not connected
356
311
  log_warn 'bad database connection'
357
- #PG_close()
312
+ @connection.close # just in case so we don't leak connections
358
313
  connect_loop()
359
314
  retry
360
315
  end
@@ -363,7 +318,7 @@ module PGx
363
318
  end
364
319
 
365
320
  # special handling of certain error states (not in a transaction)
366
- def error_handlers(pgerr, caller_method, args)
321
+ def error_handlers(pgerr, method, args)
367
322
  begin
368
323
  state = pgerr.result.error_field(PG::Result::PG_DIAG_SQLSTATE)
369
324
  rescue PG::Error => e
@@ -372,12 +327,12 @@ module PGx
372
327
 
373
328
  case state
374
329
  when '26000'
375
- reprepare_statement(args[0]) if caller_method.to_s == 'exec_prepared'
330
+ reprepare_statement(args[0]) if method.to_s == 'exec_prepared'
376
331
  end # case
377
332
  end
378
333
 
379
- def transaction_reprepare(caller_method)
380
- if caller_method.to_s == 'transaction' and not @transaction_reprepare.nil?
334
+ def transaction_reprepare(method)
335
+ if method.to_s == 'transaction' and not @transaction_reprepare.nil?
381
336
  reprepare_statement(@transaction_reprepare)
382
337
  @transaction_reprepare = nil
383
338
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kiriakos Georgiou
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-18 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-04-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
13
27
  description: |2
14
28
  A pure ruby "thin" extension of pg that provides logging,
15
29
  transaction retrying, and database reconnecting functionality.
@@ -23,7 +37,7 @@ homepage: http://www.mockbites.com/articles/tech/pgx
23
37
  licenses:
24
38
  - MIT
25
39
  metadata: {}
26
- post_install_message:
40
+ post_install_message:
27
41
  rdoc_options: []
28
42
  require_paths:
29
43
  - lib
@@ -38,8 +52,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
52
  - !ruby/object:Gem::Version
39
53
  version: '0'
40
54
  requirements: []
41
- rubygems_version: 3.1.2
42
- signing_key:
55
+ rubygems_version: 3.3.26
56
+ signing_key:
43
57
  specification_version: 4
44
58
  summary: A thin extension of pg
45
59
  test_files: []