pg_conn 0.9.0 → 0.11.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 +17 -0
- data/lib/pg_conn/session_methods.rb +82 -0
- data/lib/pg_conn/version.rb +1 -1
- data/lib/pg_conn.rb +45 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 634f61e3bd96889ad4207509c73c8b3e6a78c836db9aecbfc974ec5e206c84da
|
4
|
+
data.tar.gz: ded665cb58df11f269d951ee0d4cf176c0b99d24c6439edba96f9cf3b03508f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ad32ff6b5f33b2ec0cd2e309e243177ba1b9b3b5d24281b8e1e2aa8c956f193df64babe15691c80f50807ff7a5dd7c58c966de872b39695354f3aefaaf89343
|
7
|
+
data.tar.gz: 6bba6d97558b0c7750971dbc23a3d1eacf1c83072c4fcad3d327324e5547d0607b4f427810bfda3fb0e4d27b3e5f679c437fd5a57572309b9156bfc6d313daef
|
data/TODO
CHANGED
@@ -1,4 +1,20 @@
|
|
1
1
|
TODO
|
2
|
+
o Create aliases
|
3
|
+
|
4
|
+
tuple -> array
|
5
|
+
tuples arrays
|
6
|
+
field
|
7
|
+
fields # aka. 'column'
|
8
|
+
record hash
|
9
|
+
records hashes
|
10
|
+
struct # exists
|
11
|
+
structs
|
12
|
+
|
13
|
+
|
14
|
+
o Make rdbms, role, schema, and session methods part of a PgModel file that
|
15
|
+
monkey patch PgConn objects to include a #model method that returns the
|
16
|
+
top-level rdbms object
|
17
|
+
|
2
18
|
o #group method
|
3
19
|
|
4
20
|
group(query, column: nil)
|
@@ -59,6 +75,7 @@ TODO
|
|
59
75
|
o Allow a :type argument to all query methods that can be used to specify the
|
60
76
|
composition of anonymous record types
|
61
77
|
|
78
|
+
+ Quote methods (value, identier, ... -> Postgres string)
|
62
79
|
|
63
80
|
REFACTOR
|
64
81
|
#!/usr/bin/env ruby
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module PgConn
|
2
|
+
# Schema methods
|
3
|
+
class SessionMethods
|
4
|
+
attr_reader :conn
|
5
|
+
|
6
|
+
def initialize(conn)
|
7
|
+
@conn = conn
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a list of users connected to the given database. If database is
|
11
|
+
# nil, it returns a list of database/username tuples for all connected users
|
12
|
+
def list(database)
|
13
|
+
if database
|
14
|
+
conn.values "select usename from pg_stat_activity where datname = '#{database}'"
|
15
|
+
else
|
16
|
+
conn.tuples %(
|
17
|
+
select datname, usename
|
18
|
+
from pg_stat_activity
|
19
|
+
where datname is not null and usename is not null
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Terminate sessions in the database of the given users or of all users if
|
25
|
+
# the users is nil. Note that 'terminate(database)' is a nop because the
|
26
|
+
# absent users argument defaults to an empty list
|
27
|
+
#
|
28
|
+
# TODO: Make is possible to terminate a single session of a user with
|
29
|
+
# multiple sessions (is this ever relevant?)
|
30
|
+
def terminate(database, *users)
|
31
|
+
!database.nil? or raise ArgumentError
|
32
|
+
users = Array(users).flatten
|
33
|
+
case users
|
34
|
+
when []; return
|
35
|
+
when [nil]; users = list(database)
|
36
|
+
else users = Array(users).flatten
|
37
|
+
end
|
38
|
+
pids = self.pids(database, users)
|
39
|
+
return if pids.empty?
|
40
|
+
pids_sql = pids.map { |pid| "(#{pid})" }.join(", ")
|
41
|
+
conn.execute "select pg_terminate_backend(pid) from ( values #{pids_sql} ) as x(pid)"
|
42
|
+
end
|
43
|
+
|
44
|
+
def disable(database)
|
45
|
+
!database.nil? or raise ArgumentError
|
46
|
+
conn.execute "alter database #{database} allow_connections = false"
|
47
|
+
end
|
48
|
+
|
49
|
+
def enable(database)
|
50
|
+
!database.nil? or raise ArgumentError
|
51
|
+
conn.execute "alter database #{database} allow_connections = true"
|
52
|
+
end
|
53
|
+
|
54
|
+
# Run block without any connected users. Existing sessions are terminated
|
55
|
+
def exclusive(database, &block)
|
56
|
+
!database.nil? or raise ArgumentError
|
57
|
+
begin
|
58
|
+
disable(database)
|
59
|
+
users = list(database)
|
60
|
+
terminate(database, users)
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
enable(database)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
# Like #list but returns the PIDs of the users
|
69
|
+
def pids(database, users)
|
70
|
+
users ||= list(database)
|
71
|
+
if !users.empty?
|
72
|
+
users_sql = "(" + users.map { |user| "'#{user}'" }.join(", ") + ")"
|
73
|
+
conn.values "select pid from pg_stat_activity where datname = '#{database}' and usename in #{users_sql}"
|
74
|
+
else
|
75
|
+
conn.values "select pid from pg_stat_activity where datname = '#{database}'"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
|
data/lib/pg_conn/version.rb
CHANGED
data/lib/pg_conn.rb
CHANGED
@@ -5,6 +5,7 @@ require "pg_conn/version"
|
|
5
5
|
require "pg_conn/role_methods"
|
6
6
|
require "pg_conn/schema_methods"
|
7
7
|
require "pg_conn/rdbms_methods"
|
8
|
+
require "pg_conn/session_methods"
|
8
9
|
|
9
10
|
module PgConn
|
10
11
|
class Error < StandardError; end
|
@@ -59,6 +60,9 @@ module PgConn
|
|
59
60
|
# #exist?/#list for relations/tables/views/columns
|
60
61
|
attr_reader :schema
|
61
62
|
|
63
|
+
# Session manipulation methods: #list, #terminate, #disable, #enable
|
64
|
+
attr_reader :session
|
65
|
+
|
62
66
|
# The transaction timestamp of the most recent SQL statement executed by
|
63
67
|
# #exec or #transaction block
|
64
68
|
attr_reader :timestamp
|
@@ -198,11 +202,12 @@ module PgConn
|
|
198
202
|
@schema = SchemaMethods.new(self)
|
199
203
|
@role = RoleMethods.new(self)
|
200
204
|
@rdbms = RdbmsMethods.new(self)
|
205
|
+
@session = SessionMethods.new(self)
|
201
206
|
@timestamp = nil
|
202
207
|
@savepoints = nil # Stack of savepoint names. Nil if no transaction in progress
|
203
208
|
end
|
204
209
|
|
205
|
-
# Close the database connection
|
210
|
+
# Close the database connection. TODO: Rename 'close'
|
206
211
|
def terminate()
|
207
212
|
@pg_connection.close if @pg_connection && !@pg_connection.finished?
|
208
213
|
end
|
@@ -221,12 +226,40 @@ module PgConn
|
|
221
226
|
end
|
222
227
|
end
|
223
228
|
|
229
|
+
# Quote value as an identifier. Value should be a non-nil string
|
230
|
+
def quote_identifier(s) = @pg_connection.escape_identifier(s)
|
231
|
+
|
232
|
+
# Quote the value as a string. Emit 'null' if value is nil
|
233
|
+
#
|
234
|
+
# The value can be of any type but is converted to a string using #to_s
|
235
|
+
# before quoting. This works by default for the regular types Integer,
|
236
|
+
# true/false, Time/Date/DateTime, and arrays. Other types may require
|
237
|
+
# special handling
|
238
|
+
def quote_literal(value)
|
239
|
+
case value
|
240
|
+
when String; @pg_connection.escape_literal(value)
|
241
|
+
when Integer, Float; value.to_s
|
242
|
+
when true, false; value.to_s
|
243
|
+
when nil; 'null'
|
244
|
+
when Date, DateTime; "'#{value}'"
|
245
|
+
when Time; "'#{value.strftime("%FT%T%:z")}'"
|
246
|
+
when Array; "array[#{value.map { |elem| quote_literal(elem) }.join(', ')}]"
|
247
|
+
else
|
248
|
+
@pg_connection.escape_literal(value.to_s)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def quote_array(value)
|
253
|
+
|
254
|
+
end
|
255
|
+
|
224
256
|
# :call-seq:
|
225
257
|
# exist?(query)
|
226
258
|
# exist?(table, id)
|
227
259
|
# eists?(table, where_clause)
|
228
260
|
#
|
229
|
-
# Return true iff the query returns exactly one value
|
261
|
+
# Return true iff the query returns exactly one value. Use '!empty?' to
|
262
|
+
# check if the query returns one or more records
|
230
263
|
def exist?(*args)
|
231
264
|
arg1, arg2 = *args
|
232
265
|
query =
|
@@ -268,8 +301,9 @@ module PgConn
|
|
268
301
|
|
269
302
|
# Return a single value. It is an error if the query doesn't return a
|
270
303
|
# single record with a single column. If :transaction is true, the query
|
271
|
-
# will be executed in a transaction and be committed
|
272
|
-
# (the default).
|
304
|
+
# will be executed in a transaction and also be committed if :commit is
|
305
|
+
# true (this is the default). It can be used to execute 'insert' statements
|
306
|
+
# with a 'returning' clause
|
273
307
|
def value(query) #, transaction: false, commit: true)
|
274
308
|
r = pg_exec(query)
|
275
309
|
check_1c(r)
|
@@ -416,6 +450,12 @@ module PgConn
|
|
416
450
|
h
|
417
451
|
end
|
418
452
|
|
453
|
+
# TODO: #group - same as table but partitions a table on the given keys
|
454
|
+
# returning a map from key to array of records
|
455
|
+
|
456
|
+
# TODO: An #array method that returns a map from id to tuple. Hmm... almost
|
457
|
+
# the same as #map
|
458
|
+
|
419
459
|
# Return a hash from the record id column to an OpenStruct representation
|
420
460
|
# of the record. If the :key_column option is defined it will be used
|
421
461
|
# instead of id as the key. It is an error if the id field value is not
|
@@ -567,6 +607,7 @@ module PgConn
|
|
567
607
|
# back to the original user
|
568
608
|
#
|
569
609
|
# FIXME: The out-commented transaction block makes postspec fail for some reason
|
610
|
+
# TODO: Rename 'sudo' because it acts just like it.
|
570
611
|
def su(username, &block)
|
571
612
|
raise Error, "Missing block in call to PgConn::Connection#su" if !block_given?
|
572
613
|
realuser = self.value "select current_user"
|
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.11.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-02-
|
11
|
+
date: 2024-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- lib/pg_conn/rdbms_methods.rb
|
86
86
|
- lib/pg_conn/role_methods.rb
|
87
87
|
- lib/pg_conn/schema_methods.rb
|
88
|
+
- lib/pg_conn/session_methods.rb
|
88
89
|
- lib/pg_conn/version.rb
|
89
90
|
- pg_conn.gemspec
|
90
91
|
homepage: http://www.nowhere.com/
|