pg_conn 0.9.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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/