pg_conn 0.21.0 → 0.23.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/TODO +2 -1
- data/lib/pg_conn/rdbms_methods.rb +3 -3
- data/lib/pg_conn/role_methods.rb +3 -3
- data/lib/pg_conn/schema_methods.rb +7 -7
- data/lib/pg_conn/version.rb +1 -1
- data/lib/pg_conn.rb +47 -18
- 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: d7de75668042e3abdc5b983e0b9a3f6c909ff69aeed2f22c632d1c693f3baac0
|
4
|
+
data.tar.gz: 90cecbdd79e6478d7f6bd1bc3ae042917bc2683771c89de61aab6c05fa2e5279
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76b775138260668bf75e5bc31e220561f665dffc901349a9ec875e7ec594dee2750e0d979bde80e9045e38e44a3894fe55c2be37faefbe7f35173812cea2a22a
|
7
|
+
data.tar.gz: f0e2e9169cd734814cce4e8b73f7ec017cf3fd9a2622290c4acbf06620ddb3b943957ab5dab527ee0e29a9d71ad4efb511f4f219543ca86301d9fd5c4f5838ad
|
data/TODO
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
TODO
|
2
|
-
o
|
2
|
+
o Use :elem_type everywhere
|
3
|
+
o Use 'drop ... cascade' everywhere
|
3
4
|
o db.context(schema: app_portal, transaction: true) { ... }
|
4
5
|
db.context(set: app_portal, transaction: true) { ... }
|
5
6
|
db.context(add: app_portal, transaction: true) { ... }
|
@@ -21,7 +21,7 @@ module PgConn
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Create a new database
|
24
|
-
def create(database, owner: ENV['USER'], template: "template1")
|
24
|
+
def create(database, owner: ENV['USER'], template: "template1")
|
25
25
|
owner_clause = owner ? "owner = \"#{owner}\"" : nil
|
26
26
|
template_clause = template ? "template = \"#{template}\"" : nil
|
27
27
|
stmt = ["create database \"#{database}\"", owner_clause, template_clause].compact.join(" ")
|
@@ -80,7 +80,7 @@ module PgConn
|
|
80
80
|
local = !database.nil?
|
81
81
|
begin
|
82
82
|
conn = local ? PgConn.new(database) : self.conn
|
83
|
-
schemas =
|
83
|
+
schemas =
|
84
84
|
conn
|
85
85
|
.values("select nspname from pg_namespace where nspowner != 10 or nspname = 'public'")
|
86
86
|
.select { |schema| !exclude.include?(schema) }
|
@@ -90,7 +90,7 @@ module PgConn
|
|
90
90
|
# FIXME FIXME FIXME SECURITY Why grant 'create' to public?
|
91
91
|
conn.exec %(
|
92
92
|
create schema public authorization postgres;
|
93
|
-
grant usage, create on schema public to public
|
93
|
+
grant usage, create on schema public to public
|
94
94
|
) if public
|
95
95
|
ensure
|
96
96
|
conn&.terminate if local
|
data/lib/pg_conn/role_methods.rb
CHANGED
@@ -18,7 +18,7 @@ module PgConn
|
|
18
18
|
else
|
19
19
|
nil
|
20
20
|
end
|
21
|
-
can_login_clause =
|
21
|
+
can_login_clause =
|
22
22
|
case can_login
|
23
23
|
when true; "rolcanlogin"
|
24
24
|
when false; "not rolcanlogin"
|
@@ -62,7 +62,7 @@ module PgConn
|
|
62
62
|
# counldn't be deleted
|
63
63
|
#
|
64
64
|
# Note that cascade only works if connected to the database where the
|
65
|
-
# privileges exist.
|
65
|
+
# privileges exist.
|
66
66
|
#
|
67
67
|
# TODO The :silent option is used in tests - fix it somehow!
|
68
68
|
def drop(*rolenames, cascade: false, fail: true, silent: false)
|
@@ -86,7 +86,7 @@ module PgConn
|
|
86
86
|
superuser_clause = superuser.nil? ? nil : "rolsuper = #{superuser}"
|
87
87
|
can_login_clause = can_login.nil? ? nil : "rolcanlogin = #{can_login}"
|
88
88
|
query = [
|
89
|
-
"select rolname from pg_roles where true",
|
89
|
+
"select rolname from pg_roles where true",
|
90
90
|
database_clause, superuser_clause, can_login_clause
|
91
91
|
].compact.join(" and ")
|
92
92
|
conn.values(query)
|
@@ -49,8 +49,8 @@ module PgConn
|
|
49
49
|
# Empty all tables in the given schema
|
50
50
|
def clean!(schema, exclude: [])
|
51
51
|
conn.session.triggers(false) {
|
52
|
-
self.list_tables(schema, exclude: exclude).each { |table|
|
53
|
-
conn.exec "delete from #{schema}.#{table}"
|
52
|
+
self.list_tables(schema, exclude: exclude).each { |table|
|
53
|
+
conn.exec "delete from #{schema}.#{table}"
|
54
54
|
}
|
55
55
|
}
|
56
56
|
end
|
@@ -125,8 +125,8 @@ module PgConn
|
|
125
125
|
end
|
126
126
|
|
127
127
|
# Return name of the table's sequence (if any)
|
128
|
-
def sequence(schema, table)
|
129
|
-
conn.value "select pg_get_serial_sequence('#{schema}.#{table}', 'id')"
|
128
|
+
def sequence(schema, table)
|
129
|
+
conn.value "select pg_get_serial_sequence('#{schema}.#{table}', 'id')"
|
130
130
|
end
|
131
131
|
|
132
132
|
# Get the current serial value for the table. Returns nil if the serial has
|
@@ -168,7 +168,7 @@ module PgConn
|
|
168
168
|
kind_sql_list = "'" + (kind.nil? ? %w(r f v m) : Array(kind).flatten).join("', '") + "'"
|
169
169
|
%(
|
170
170
|
select 1
|
171
|
-
from pg_class
|
171
|
+
from pg_class
|
172
172
|
where relnamespace::regnamespace::text = '#{schema}'
|
173
173
|
and relname = '#{relation}'
|
174
174
|
and relkind in (#{kind_sql_list})
|
@@ -183,7 +183,7 @@ module PgConn
|
|
183
183
|
exclude_expr = exclude.empty? ? "true = true" : "not relname in (#{exclude_list})"
|
184
184
|
%(
|
185
185
|
select relname
|
186
|
-
from pg_class
|
186
|
+
from pg_class
|
187
187
|
where relnamespace::regnamespace::text = '#{schema}'
|
188
188
|
and #{kind_expr}
|
189
189
|
and #{exclude_expr}
|
@@ -211,7 +211,7 @@ module PgConn
|
|
211
211
|
join pg_attribute a on a.attrelid = c.oid
|
212
212
|
where relnamespace::regnamespace::text = '#{schema}'
|
213
213
|
and a.attnum > 0
|
214
|
-
),
|
214
|
+
),
|
215
215
|
relation_clause
|
216
216
|
].compact.join(" and ")
|
217
217
|
end
|
data/lib/pg_conn/version.rb
CHANGED
data/lib/pg_conn.rb
CHANGED
@@ -239,12 +239,16 @@ module PgConn
|
|
239
239
|
end
|
240
240
|
end
|
241
241
|
|
242
|
-
# Quote
|
242
|
+
# Quote argument as an identifier. The argument should be a non-nil string
|
243
|
+
# or a symbol
|
243
244
|
def quote_identifier(s)
|
244
245
|
s = s.to_s if s.is_a?(Symbol)
|
245
246
|
@pg_connection.escape_identifier(s)
|
246
247
|
end
|
247
248
|
|
249
|
+
# Quote identifiers and concatenate them using ',' as separator
|
250
|
+
def quote_identifiers(idents) = idents.map { |ident| quote_identifier(ident) }.join(", ")
|
251
|
+
|
248
252
|
# Quote the value as a string. Emit 'null' if value is nil
|
249
253
|
#
|
250
254
|
# The value can be of any type but is converted to a string using #to_s
|
@@ -255,7 +259,13 @@ module PgConn
|
|
255
259
|
# Note that a tuple value (an array) must be quoted using #quote_tuple
|
256
260
|
# because #quote_value would quote the tuple as an array instead of a list
|
257
261
|
# of values
|
258
|
-
|
262
|
+
#
|
263
|
+
# The :elem_type option can be a postgres type name (String or Symbol) or
|
264
|
+
# an array of type names. They are used as the required explicit element
|
265
|
+
# type when the argument is an empty array. The element types shoud be in
|
266
|
+
# the same order as the array arguments. Nested arrays is not supported
|
267
|
+
#
|
268
|
+
def quote_value(value, elem_type: nil)
|
259
269
|
case value
|
260
270
|
when String; @pg_connection.escape_literal(value)
|
261
271
|
when Integer, Float; value.to_s
|
@@ -263,23 +273,34 @@ module PgConn
|
|
263
273
|
when nil; 'null'
|
264
274
|
when Date, DateTime; "'#{value}'"
|
265
275
|
when Time; "'#{value.strftime("%FT%T%:z")}'"
|
266
|
-
when Array
|
276
|
+
when Array
|
277
|
+
if value.empty?
|
278
|
+
elem_type or raise Error, "Empty array without elem_type"
|
279
|
+
"array[]::#{elem_type}[]"
|
280
|
+
else
|
281
|
+
"array[#{value.map { |elem| quote_value(elem) }.join(', ')}]"
|
282
|
+
end
|
267
283
|
else
|
268
284
|
@pg_connection.escape_literal(value.to_s)
|
269
285
|
end
|
270
286
|
end
|
271
287
|
|
272
|
-
# Quote an array of values as a tuple. Just an alias for #quote_values
|
273
|
-
def quote_tuple(tuple) = quote_values(tuple)
|
274
|
-
|
275
|
-
# Quote identifiers and concatenate them using ',' as separator
|
276
|
-
def quote_identifiers(idents) = idents.map { |ident| quote_identifier(ident) }.join(", ")
|
277
|
-
|
278
288
|
# Quote values and concatenate them using ',' as separator
|
279
|
-
def quote_values(values
|
289
|
+
def quote_values(values, elem_type: nil)
|
290
|
+
elem_types = Array(elem_type)
|
291
|
+
values.map { |value|
|
292
|
+
elem_type = value.is_a?(Array) ? elem_types&.shift : nil
|
293
|
+
quote_value(value, elem_type: elem_type)
|
294
|
+
}.join(", ")
|
295
|
+
end
|
296
|
+
|
297
|
+
# Quote an array of values as a tuple. Just an alias for #quote_values
|
298
|
+
def quote_tuple(tuple, elem_type: nil) = quote_values(tuple, elem_type: elem_type)
|
280
299
|
|
281
300
|
# Quote an array of tuples
|
282
|
-
def quote_tuples(tuples
|
301
|
+
def quote_tuples(tuples, elem_type: nil)
|
302
|
+
tuples.map { |tuple| "(#{quote_values(tuple, elem_type: elem_type)})" }.join(", ")
|
303
|
+
end
|
283
304
|
|
284
305
|
# :call-seq:
|
285
306
|
# exist?(query)
|
@@ -515,8 +536,9 @@ module PgConn
|
|
515
536
|
|
516
537
|
# Returns a hash from the first field to a tuple of the remaining fields.
|
517
538
|
# If there is only one remaining field then that value is used instead of a
|
518
|
-
# tuple
|
519
|
-
|
539
|
+
# tuple. The optional +key+ argument sets the mapping field and the
|
540
|
+
# +symbol+ option convert key to Symbol objects when true
|
541
|
+
def map(query, key = nil, symbol: false) # TODO Swap arguments
|
520
542
|
r = pg_exec(query)
|
521
543
|
begin
|
522
544
|
key = (key || r.fname(0)).to_s
|
@@ -528,13 +550,18 @@ module PgConn
|
|
528
550
|
h = {}
|
529
551
|
r.each_row { |row|
|
530
552
|
key_value = row.delete_at(key_index)
|
553
|
+
key_value = key_value.to_sym if symbol
|
531
554
|
!h.key?(key_value) or raise Error, "Duplicate key: #{key_value}"
|
532
555
|
h[key_value] = (one ? row.first : row)
|
533
556
|
}
|
534
557
|
h
|
535
558
|
end
|
536
559
|
|
537
|
-
|
560
|
+
# Like #map but values of duplicate keys are concatenated. It acts as a
|
561
|
+
# group-by on the key and array_agg on the remaining values. The value is
|
562
|
+
# an array of tuples if the query has more than one value field and an
|
563
|
+
# array of values if there is only one value field
|
564
|
+
def multimap(query, key = nil, symbol: false)
|
538
565
|
r = pg_exec(query)
|
539
566
|
begin
|
540
567
|
key = (key || r.fname(0)).to_s
|
@@ -546,6 +573,7 @@ module PgConn
|
|
546
573
|
h = {}
|
547
574
|
r.each_row { |row|
|
548
575
|
key_value = row.delete_at(key_index)
|
576
|
+
key_value = key_value.to_sym if symbol
|
549
577
|
(h[key_value] ||= []) << (one ? row.first : row)
|
550
578
|
}
|
551
579
|
h
|
@@ -557,10 +585,11 @@ module PgConn
|
|
557
585
|
# values if the result contained only one column (like #value or #values),
|
558
586
|
# a tuple if the record has multiple columns (like #tuple), and an array of
|
559
587
|
# of tuples if the result contained more than one record with multiple
|
560
|
-
# columns (like #tuples)
|
588
|
+
# columns (like #tuples). If the :proc option is true the "function" is
|
589
|
+
# assumed to be a procedure
|
561
590
|
#
|
562
|
-
def call(name, *args, proc: false) # :proc may interfere with hashes
|
563
|
-
args_seq = quote_values(args)
|
591
|
+
def call(name, *args, elem_type: nil, proc: false) # :proc may interfere with hashes
|
592
|
+
args_seq = quote_values(args, elem_type: elem_type)
|
564
593
|
if proc
|
565
594
|
pg_exec "call #{name}(#{args_seq})"
|
566
595
|
return nil
|
@@ -582,7 +611,7 @@ module PgConn
|
|
582
611
|
end
|
583
612
|
end
|
584
613
|
|
585
|
-
# :call-seq
|
614
|
+
# :call-seq:
|
586
615
|
# insert(table, record|records)
|
587
616
|
# insert(table, fields, record|records|tuples)
|
588
617
|
# insert(schema, table, record|records)
|
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.23.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: 2024-08-
|
11
|
+
date: 2024-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|