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.
- 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
|