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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17a782e74c71e670d14ed38e258f7b9c99ee1e832866dd9fa972774b1a21d08c
4
- data.tar.gz: 226ad145da3b41360080a255bb90b65c4a4bbd2ac1fef8bdc2f2e43bed9feab6
3
+ metadata.gz: 634f61e3bd96889ad4207509c73c8b3e6a78c836db9aecbfc974ec5e206c84da
4
+ data.tar.gz: ded665cb58df11f269d951ee0d4cf176c0b99d24c6439edba96f9cf3b03508f0
5
5
  SHA512:
6
- metadata.gz: c15ad10570d71104ac356f2f0da9a1e034cf400356357621300db3af872a73282a233c0a4258dc2bcc98ac2353143a768c1632f59439812965e4b00b41fc62be
7
- data.tar.gz: eec1060c95e94fbb8f59fe56fb233d95dd4d111a6980947dbc8e609788f6b3652f01d9befe9d5af053b224fa1ff661b93fc53d77001ee14593fdfdea985104a4
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
+
@@ -1,3 +1,3 @@
1
1
  module PgConn
2
- VERSION = "0.9.0"
2
+ VERSION = "0.11.0"
3
3
  end
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 it :commit is true
272
- # (the default). This can be used in 'insert ... returning ...' statements
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.9.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-06 00:00:00.000000000 Z
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/