pg_conn 0.30.0 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pg_conn/version.rb +1 -1
  3. data/lib/pg_conn.rb +134 -73
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28c2a6429f9c8e987f27686e323643baf77f4429599bfb457ecdd6d5b659a289
4
- data.tar.gz: e8e2c96d92401a3eceff86b77152acdfe9019c03306577d260c6039d39881630
3
+ metadata.gz: e4afbef1cc74d235f8434c2c92a6537ec24b37cd36e85bb9f07eb6153e6c7938
4
+ data.tar.gz: cd5af7434cb01ae1f873a7cb18a4cc350e425976c695b93252f2e36cefca2273
5
5
  SHA512:
6
- metadata.gz: b6f08ca6bd0b47206623435dbf6691f0d8276fa5a8ac1c71fcd95a0a763356333528afa0013622665cc0ac5f94960e0f7231abe7c688bfa081bc82034e6fd8ed
7
- data.tar.gz: 1406fdffcb6d44b7d7d0d0eab5fb2d970e501ff90336b88ed80962680021a845753463e14348203123ca612531248f1aab88ebbe0a3ec7cb30d8eb887e4b1ceb
6
+ metadata.gz: c94d25247ae2167f022a704bdf5b03691f87691dfe88c5187a5cbf2fb117c5ac252c3f649b5b0a20578cfe325b08cfff7f09e41da1d8f6c0bbf81c11cab501bf
7
+ data.tar.gz: 689be40d28cb3a7ea0c84ab0109b7dc7749b16c47a8240b694ae746ff8602ebed6e5fa4394dc628d1df699a6c7c091db7f345c1ffb81cfc93e81e98d48c60ea0
@@ -1,3 +1,3 @@
1
1
  module PgConn
2
- VERSION = "0.30.0"
2
+ VERSION = "0.32.0"
3
3
  end
data/lib/pg_conn.rb CHANGED
@@ -32,6 +32,84 @@ module PgConn
32
32
  end
33
33
  end
34
34
 
35
+ # Quote argument as an identifier. The argument should be a non-nil string
36
+ # or a symbol
37
+ #
38
+ # Quote metods are both defined as PgConn class methods and as Connection
39
+ # member methods
40
+ #
41
+ def self.quote_identifier(s)
42
+ s = s.to_s if s.is_a?(Symbol)
43
+ escape_identifier(s).gsub(/\./, '"."').sub(/"\*"/, "*")
44
+ end
45
+
46
+ # Quote identifiers and concatenate them using ',' as separator
47
+ def self.quote_identifiers(idents) = idents.map { |ident| quote_identifier(ident) }.join(", ")
48
+
49
+ # Quote the value as a string. Emit 'null' if value is nil
50
+ #
51
+ # The value can be of any type but is converted to a string using #to_s
52
+ # before quoting. This works by default for the regular types Integer,
53
+ # true/false, Time/Date/DateTime, and arrays. Other types may require
54
+ # special handling
55
+ #
56
+ # Hashes are quoted as a literal JSON expression. The result is a string
57
+ # and it is the application's responsibility to cast them to either 'json'
58
+ # or 'jsonb'
59
+ #
60
+ # Note that a tuple value (an array) must be quoted using #quote_tuple
61
+ # because #quote_value would quote the tuple as an array instead of a list
62
+ # of values
63
+ #
64
+ # The :elem_type option can be a postgres type name (String or Symbol) or
65
+ # an array of type names. It is used as the required explicit element
66
+ # type when the argument is an empty array. It is not needed if the array
67
+ # is guaranteed to be non-empty. Nested arrays are not supported
68
+ #
69
+ def self.quote_value(value, elem_type: nil)
70
+ case value
71
+ when Literal; value
72
+ when String; escape_literal(value)
73
+ when Integer, Float; value.to_s
74
+ when true, false; value.to_s
75
+ when nil; 'null'
76
+ when Date, DateTime; "'#{value}'"
77
+ when Time; "'#{value.strftime("%FT%T%:z")}'"
78
+ when Array
79
+ if value.empty?
80
+ elem_type or raise Error, "Empty array without elem_type"
81
+ "array[]::#{elem_type}[]"
82
+ else
83
+ "array[#{value.map { |elem| quote_value(elem) }.join(', ')}]"
84
+ end
85
+ when Hash; "'#{value.to_json}'"
86
+ else
87
+ escape_literal(value.to_s)
88
+ end
89
+ end
90
+
91
+ # Quote values and concatenate them using ',' as separator
92
+ def self.quote_values(values, elem_type: nil)
93
+ values.map { |value| quote_value(value, elem_type: elem_type) }.join(", ")
94
+ end
95
+
96
+ # Quote an array of values as a tuple. The element types should be in the
97
+ # same order as the array arguments. #quote_tuples is same as #quote_values
98
+ # except the values may have different types (this makes no difference
99
+ # except in the case when the tuple may contain empty array(s))
100
+ def self.quote_tuple(tuple, elem_types: nil)
101
+ elem_types = Array(elem_types)
102
+ tuple.map { |value|
103
+ elem_type = value.is_a?(Array) ? elem_types&.shift : nil
104
+ quote_value(value, elem_type: elem_type)
105
+ }.join(", ")
106
+ end
107
+
108
+ # Quote an array of tuples
109
+ def self.quote_tuples(tuples, elem_types: nil)
110
+ tuples.map { |tuple| "(#{quote_tuple(tuple, elem_types: elem_types)})" }.join(", ")
111
+ end
112
+
35
113
  # Used to mark strings as literals that should not be quoted. This is the
36
114
  # case for row and record values
37
115
  class Literal < String; end
@@ -253,79 +331,13 @@ module PgConn
253
331
 
254
332
  def literal(arg) Literal.new(arg) end
255
333
 
256
- # Quote argument as an identifier. The argument should be a non-nil string
257
- # or a symbol
258
- def quote_identifier(s)
259
- s = s.to_s if s.is_a?(Symbol)
260
- @pg_connection.escape_identifier(s).gsub(/\./, '"."').sub(/"\*"/, "*")
261
- end
262
-
263
- # Quote identifiers and concatenate them using ',' as separator
264
- def quote_identifiers(idents) = idents.map { |ident| quote_identifier(ident) }.join(", ")
265
-
266
- # Quote the value as a string. Emit 'null' if value is nil
267
- #
268
- # The value can be of any type but is converted to a string using #to_s
269
- # before quoting. This works by default for the regular types Integer,
270
- # true/false, Time/Date/DateTime, and arrays. Other types may require
271
- # special handling
272
- #
273
- # Hashes are quoted as a literal JSON expression. The result is a string
274
- # and it is the application's responsibility to cast them to either 'json'
275
- # or 'jsonb'
276
- #
277
- # Note that a tuple value (an array) must be quoted using #quote_tuple
278
- # because #quote_value would quote the tuple as an array instead of a list
279
- # of values
280
- #
281
- # The :elem_type option can be a postgres type name (String or Symbol) or
282
- # an array of type names. It is used as the required explicit element
283
- # type when the argument is an empty array. It is not needed if the array
284
- # is guaranteed to be non-empty. Nested arrays are not supported
285
- #
286
- def quote_value(value, elem_type: nil)
287
- case value
288
- when Literal; value
289
- when String; @pg_connection.escape_literal(value)
290
- when Integer, Float; value.to_s
291
- when true, false; value.to_s
292
- when nil; 'null'
293
- when Date, DateTime; "'#{value}'"
294
- when Time; "'#{value.strftime("%FT%T%:z")}'"
295
- when Array
296
- if value.empty?
297
- elem_type or raise Error, "Empty array without elem_type"
298
- "array[]::#{elem_type}[]"
299
- else
300
- "array[#{value.map { |elem| quote_value(elem) }.join(', ')}]"
301
- end
302
- when Hash; "'#{value.to_json}'"
303
- else
304
- @pg_connection.escape_literal(value.to_s)
305
- end
306
- end
307
-
308
- # Quote values and concatenate them using ',' as separator
309
- def quote_values(values, elem_type: nil)
310
- values.map { |value| quote_value(value, elem_type: elem_type) }.join(", ")
311
- end
312
-
313
- # Quote an array of values as a tuple. The element types should be in the
314
- # same order as the array arguments. #quote_tuples is same as #quote_values
315
- # except the values may have different types (this makes no difference
316
- # except in the case when the tuple may contain empty array(s))
317
- def quote_tuple(tuple, elem_types: nil)
318
- elem_types = Array(elem_types)
319
- tuple.map { |value|
320
- elem_type = value.is_a?(Array) ? elem_types&.shift : nil
321
- quote_value(value, elem_type: elem_type)
322
- }.join(", ")
323
- end
324
-
325
- # Quote an array of tuples
326
- def quote_tuples(tuples, elem_types: nil)
327
- tuples.map { |tuple| "(#{quote_tuple(tuple, elem_types: elem_types)})" }.join(", ")
328
- end
334
+ # Connection member method variations of the PgConn quote class methods
335
+ def quote_identifier(s) = PgConn.quote_identifier(s)
336
+ def quote_identifiers(idents) = PgConn.quote_identifiers(idents)
337
+ def quote_value(value, **opts) = PgConn.quote_value(value, **opts)
338
+ def quote_values(values, **opts) = PgConn.quote_values(values, **opts)
339
+ def quote_tuple(tuple, **opts) = PgConn.quote_tuple(tuple, **opts)
340
+ def quote_tuples(tuples, **opts) = PgConn.quote_tuples(tuples, **opts)
329
341
 
330
342
  # Quote a record and cast it into the given type, the type can also be a
331
343
  # table or view. 'data' is an array, hash, or struct representation of the
@@ -335,6 +347,9 @@ module PgConn
335
347
  # as fast as the other quote-methods. It is however very convenient when
336
348
  # you're testing and need a composite type because record-quoting can
337
349
  # easily become unwieldly
350
+ #
351
+ # Also note that there is not class-method variant of this method because
352
+ # it requires a connection
338
353
  def quote_record(data, schema_name = nil, type, elem_types: nil)
339
354
  quote_record_impl(data, schema_name, type, elem_types: elem_types, array: false)
340
355
  end
@@ -943,6 +958,40 @@ module PgConn
943
958
  end
944
959
  end
945
960
 
961
+ def dump(*query)
962
+ records = self.records(*query)
963
+
964
+ if records.empty?
965
+ puts "No records found"
966
+ else
967
+ headers = records.first.keys
968
+ column_widths = headers.map(&:size)
969
+ column_signs = [nil] * headers.size
970
+
971
+ records.each { |r|
972
+ r.values.each.with_index { |v, i|
973
+ value_width = v.to_s.size
974
+ column_widths[i] = [column_widths[i], value_width].max
975
+
976
+ column_signs[i] ||=
977
+ case v
978
+ when nil; nil
979
+ when Integer; ""
980
+ else
981
+ "-"
982
+ end
983
+ }
984
+ }
985
+
986
+ header_format = column_widths.map { |w,t| "%-#{w}s" }.join(" ")
987
+ body_format = column_widths.zip(column_signs).map { |w,s| "%#{s}#{w}s" }.join(" ")
988
+
989
+ printf "#{header_format}\n", *headers
990
+ printf "#{header_format}\n", *column_widths.map { |w| "-" * w }
991
+ records.each { |r| printf "#{body_format}\n", *r.values }
992
+ end
993
+ end
994
+
946
995
  private
947
996
  # Wrapper around PG::Connection.new that switches to the postgres user
948
997
  # before connecting if the current user is the root user
@@ -1123,5 +1172,17 @@ module PgConn
1123
1172
 
1124
1173
  def self.sql_values(values) "'" + values.join("', '") + "'" end
1125
1174
  def self.sql_idents(values) '"' + values.join('", "') + '"' end
1175
+
1176
+ # Same as postgres PG#escape_literal but do not need a connection
1177
+ def self.escape_literal(s) = s.nil? ? 'NULL' : "'#{s.gsub("'", "''")}'"
1178
+
1179
+ # Same as postgres PG#escape_identifier but do not need a connection
1180
+ def self.escape_identifier(s)
1181
+ !s.nil? or raise TypeError, "Identifier can't be nil"
1182
+ s.is_a?(String) or raise TypeError, "Identifier can't be a #{s.class}"
1183
+ s !~ /\A\s*\z/ or raise TypeError, "Identifier be blank"
1184
+ %("#{s.gsub('"', '""')}")
1185
+ end
1186
+
1126
1187
  end
1127
1188
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_conn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-11 00:00:00.000000000 Z
11
+ date: 2025-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg