pg_conn 0.30.0 → 0.32.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.
- checksums.yaml +4 -4
- data/lib/pg_conn/version.rb +1 -1
- data/lib/pg_conn.rb +134 -73
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4afbef1cc74d235f8434c2c92a6537ec24b37cd36e85bb9f07eb6153e6c7938
|
4
|
+
data.tar.gz: cd5af7434cb01ae1f873a7cb18a4cc350e425976c695b93252f2e36cefca2273
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c94d25247ae2167f022a704bdf5b03691f87691dfe88c5187a5cbf2fb117c5ac252c3f649b5b0a20578cfe325b08cfff7f09e41da1d8f6c0bbf81c11cab501bf
|
7
|
+
data.tar.gz: 689be40d28cb3a7ea0c84ab0109b7dc7749b16c47a8240b694ae746ff8602ebed6e5fa4394dc628d1df699a6c7c091db7f345c1ffb81cfc93e81e98d48c60ea0
|
data/lib/pg_conn/version.rb
CHANGED
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
|
-
#
|
257
|
-
|
258
|
-
def
|
259
|
-
|
260
|
-
|
261
|
-
|
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.
|
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
|
+
date: 2025-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|