pg_conn 0.35.1 → 0.37.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 +5 -5
- data/lib/pg_conn/schema_methods.rb +1 -1
- data/lib/pg_conn/session_methods.rb +0 -32
- data/lib/pg_conn/version.rb +1 -1
- data/lib/pg_conn.rb +77 -38
- 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: 1edd50ec4e7e4f072a695cd044ab6d930dd14cdf763dd335ee0fbb65865e83c4
|
4
|
+
data.tar.gz: 3fe0cf2fe952999dceea4b6776155b7252d4e3f4aeeab7089348fc10ec9cfc5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a84b206b8c7b19813a3acbc63350289e6b072fc1ef8edb65901c99fe6f76fffe3c9ad9ab54d44105652902a8486e5904071e8f6712e73b7b9752019646a8bb8b
|
7
|
+
data.tar.gz: 6725ac8c9ef737db41770df819fefa88cb716ff189d714b139079475ee3255a59ec996e9d9c1e138b971b2b4908d6a91f08b9d7bc3731a7e46c32bd684f28000
|
data/TODO
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
TODO
|
2
|
+
o Drop existing SQL output interface and instead implement a SQL logger
|
3
|
+
|
2
4
|
o Add support for hstore (a hash)
|
3
5
|
|
4
6
|
o Add a <fetch>! method. Require v2
|
5
7
|
value? 0 or 1
|
6
8
|
value 1
|
7
9
|
values 0 or n
|
8
|
-
values? 0 or n
|
9
10
|
values! 1 or more
|
10
11
|
|
11
12
|
o Instrumentation of connection object
|
@@ -43,10 +44,6 @@ TODO
|
|
43
44
|
|
44
45
|
server.call :sp_nic_update_comtext, str_id, str_comtext, site.current_user.id
|
45
46
|
|
46
|
-
o Have a 'with' method that combines multiple brachet-methods:
|
47
|
-
|
48
|
-
conn.with(schema: public, transation: true) { ... }
|
49
|
-
|
50
47
|
o Create aliases
|
51
48
|
tuple -> array
|
52
49
|
tuples arrays
|
@@ -120,6 +117,9 @@ TODO
|
|
120
117
|
composition of anonymous record types
|
121
118
|
|
122
119
|
+ Quote methods (value, identier, ... -> Postgres string)
|
120
|
+
+ Have a 'with' method that combines multiple brachet-methods:
|
121
|
+
conn.with(schema: public, transation: true) { ... }
|
122
|
+
|
123
123
|
|
124
124
|
REFACTOR
|
125
125
|
#!/usr/bin/env ruby
|
@@ -48,7 +48,7 @@ module PgConn
|
|
48
48
|
|
49
49
|
# Empty all tables in the given schema
|
50
50
|
def clean!(schema, exclude: [])
|
51
|
-
conn.
|
51
|
+
conn.without_triggers {
|
52
52
|
self.list_tables(schema, exclude: exclude).each { |table|
|
53
53
|
conn.exec "delete from #{schema}.#{table}"
|
54
54
|
}
|
@@ -84,38 +84,6 @@ module PgConn
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
# Return true if session triggers are enabled. Triggers are enabled by
|
88
|
-
# default by Postgres
|
89
|
-
def triggers?() conn.value "select current_setting('session_replication_role') <> 'replica'" end
|
90
|
-
|
91
|
-
# Enable session triggers
|
92
|
-
def enable_triggers()
|
93
|
-
conn.execute "set session session_replication_role = DEFAULT"
|
94
|
-
end
|
95
|
-
|
96
|
-
# Disable session triggers
|
97
|
-
def disable_triggers()
|
98
|
-
conn.execute "set session session_replication_role = replica"
|
99
|
-
end
|
100
|
-
|
101
|
-
# Execute block with session triggers on or off
|
102
|
-
def triggers(on_off, &block)
|
103
|
-
begin
|
104
|
-
active = triggers?
|
105
|
-
if on_off && !active
|
106
|
-
enable_triggers
|
107
|
-
elsif !on_off && active
|
108
|
-
disable_triggers
|
109
|
-
end
|
110
|
-
yield
|
111
|
-
ensure
|
112
|
-
case active
|
113
|
-
when true; enable_triggers if !triggers?
|
114
|
-
when false; disable_triggers if triggers?
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
87
|
private
|
120
88
|
# Like #list but returns the PIDs of the users
|
121
89
|
def pids(database, users)
|
data/lib/pg_conn/version.rb
CHANGED
data/lib/pg_conn.rb
CHANGED
@@ -40,13 +40,13 @@ module PgConn
|
|
40
40
|
#
|
41
41
|
def self.quote_identifier(s)
|
42
42
|
s = s.to_s if s.is_a?(Symbol)
|
43
|
-
escape_identifier(s).gsub(/\./, '"."').sub(/"\*"/, "*")
|
43
|
+
Literal.new escape_identifier(s).gsub(/\./, '"."').sub(/"\*"/, "*")
|
44
44
|
end
|
45
45
|
|
46
46
|
# Quote identifiers and concatenate them using ',' as separator
|
47
|
-
def self.quote_identifiers(idents) = idents.map { |ident| quote_identifier(ident) }.join(", ")
|
47
|
+
def self.quote_identifiers(idents) = Literal.new idents.map { |ident| quote_identifier(ident) }.join(", ")
|
48
48
|
|
49
|
-
# Quote the value as a string.
|
49
|
+
# Quote the value as a string. Returns a Literal object
|
50
50
|
#
|
51
51
|
# The value can be of any type but is converted to a string using #to_s
|
52
52
|
# before quoting. This works by default for the regular types Integer,
|
@@ -55,7 +55,7 @@ module PgConn
|
|
55
55
|
#
|
56
56
|
# Hashes are quoted as a literal JSON expression converted into the given
|
57
57
|
# :json_type. If :json_type is nil, it is the application's responsibility to
|
58
|
-
# cast
|
58
|
+
# cast the value to either 'json' or 'jsonb'
|
59
59
|
#
|
60
60
|
# Note that a tuple value (an array) must be quoted using #quote_tuple
|
61
61
|
# because #quote_value would quote the tuple as an array value instead of a
|
@@ -67,30 +67,31 @@ module PgConn
|
|
67
67
|
# is guaranteed to be non-empty. Nested arrays are not supported
|
68
68
|
#
|
69
69
|
def self.quote_value(value, elem_type: nil, json_type: nil)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
70
|
+
Literal.new \
|
71
|
+
case value
|
72
|
+
when Literal; value
|
73
|
+
when String; escape_literal(value)
|
74
|
+
when Integer, Float; value.to_s
|
75
|
+
when true, false; value.to_s
|
76
|
+
when nil; 'null'
|
77
|
+
when Date, DateTime; "'#{value}'"
|
78
|
+
when Time; "'#{value.strftime("%FT%T%:z")}'"
|
79
|
+
when Array
|
80
|
+
if value.empty?
|
81
|
+
elem_type or raise Error, "Empty array without elem_type"
|
82
|
+
"array[]::#{elem_type}[]"
|
83
|
+
else
|
84
|
+
"array[#{value.map { |elem| quote_value(elem) }.join(', ')}]"
|
85
|
+
end
|
86
|
+
when Hash; ["'#{value.to_json}'", json_type].compact.join('::')
|
82
87
|
else
|
83
|
-
|
88
|
+
escape_literal(value.to_s)
|
84
89
|
end
|
85
|
-
when Hash; ["'#{value.to_json}'", json_type].compact.join('::')
|
86
|
-
else
|
87
|
-
escape_literal(value.to_s)
|
88
|
-
end
|
89
90
|
end
|
90
91
|
|
91
92
|
# Quote values and concatenate them using ',' as separator
|
92
93
|
def self.quote_values(values, **opts)
|
93
|
-
values.map { |value| quote_value(value, **opts) }.join(", ")
|
94
|
+
Literal.new values.map { |value| quote_value(value, **opts) }.join(", ")
|
94
95
|
end
|
95
96
|
|
96
97
|
# Quote an array of values as a tuple. The element types should be in the
|
@@ -101,7 +102,7 @@ module PgConn
|
|
101
102
|
# Note that it is :elem_types (plural) and not :elem_type
|
102
103
|
def self.quote_tuple(tuple, elem_types: nil, **opts)
|
103
104
|
elem_types = Array(elem_types)
|
104
|
-
tuple.map { |value|
|
105
|
+
Literal.new tuple.map { |value|
|
105
106
|
elem_type = value.is_a?(Array) ? elem_types&.shift : nil
|
106
107
|
quote_value(value, **opts, elem_type: elem_type)
|
107
108
|
}.join(", ")
|
@@ -109,7 +110,7 @@ module PgConn
|
|
109
110
|
|
110
111
|
# Quote an array of tuples
|
111
112
|
def self.quote_tuples(tuples, **opts)
|
112
|
-
tuples.map { |tuple| "(#{quote_tuple(tuple, **opts)})" }.join(", ")
|
113
|
+
Literal.new tuples.map { |tuple| "(#{quote_tuple(tuple, **opts)})" }.join(", ")
|
113
114
|
end
|
114
115
|
|
115
116
|
# Used to mark strings as literals that should not be quoted. This is the
|
@@ -132,7 +133,7 @@ module PgConn
|
|
132
133
|
|
133
134
|
# Name of user
|
134
135
|
def user() @pg_connection.user end
|
135
|
-
alias_method :username, :user # Obsolete FIXME Is it?
|
136
|
+
alias_method :username, :user # Obsolete FIXME Is it? No it is not!
|
136
137
|
|
137
138
|
# Name of database
|
138
139
|
def name() @pg_connection.db end
|
@@ -262,12 +263,13 @@ module PgConn
|
|
262
263
|
# The possible keys of the connection hash are :host, :port, :dbname, :user,
|
263
264
|
# and :password. The connection string can either be a space-separated list
|
264
265
|
# of <key>=<value> pairs with the same keys as the hash, or a URI with the
|
265
|
-
# format 'postgres[ql]://[user[:password]@][host][:port][/name]
|
266
|
+
# format 'postgres[ql]://[user[:password]@][host][:port][/name]. TODO Also
|
267
|
+
# allow :database and :username
|
266
268
|
#
|
267
269
|
# If given an array argument, PgConn will not connect to the database and
|
268
270
|
# instead write its commands to the array. In this case, methods extracting
|
269
271
|
# values from the database (eg. #value) will return nil or raise an
|
270
|
-
# exception
|
272
|
+
# exception. TODO: Remove
|
271
273
|
#
|
272
274
|
# The last variant is used to establish a PgConn from an existing
|
273
275
|
# connection. It doesn't change the connection settings and is not
|
@@ -429,8 +431,8 @@ module PgConn
|
|
429
431
|
end
|
430
432
|
end
|
431
433
|
|
432
|
-
# Mark argument as already being quoted.
|
433
|
-
#
|
434
|
+
# Mark string argument as already being quoted. This is done automatically
|
435
|
+
# by all quote_* methods
|
434
436
|
def literal(arg) Literal.new(arg) end
|
435
437
|
|
436
438
|
# Connection member method variations of the PgConn quote class methods
|
@@ -784,6 +786,8 @@ module PgConn
|
|
784
786
|
# There is no variant that takes a single tuple because it would then be
|
785
787
|
# impossible to have array or hash field values
|
786
788
|
def insert(*args, upsert: nil, **opts)
|
789
|
+
# Normalize arguments
|
790
|
+
|
787
791
|
# Add options to args except the special :upsert option
|
788
792
|
args << opts if !opts.empty?
|
789
793
|
|
@@ -1091,6 +1095,43 @@ module PgConn
|
|
1091
1095
|
end
|
1092
1096
|
end
|
1093
1097
|
|
1098
|
+
# Return true if session triggers are enabled. Triggers are enabled by
|
1099
|
+
# default by Postgres
|
1100
|
+
def triggers?() self.value "select current_setting('session_replication_role') <> 'replica'" end
|
1101
|
+
|
1102
|
+
# Enable session triggers
|
1103
|
+
def enable_triggers()
|
1104
|
+
self.execute "set session session_replication_role = DEFAULT"
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# Disable session triggers
|
1108
|
+
def disable_triggers()
|
1109
|
+
self.execute "set session session_replication_role = replica"
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
# Executes block without triggers
|
1113
|
+
def without_triggers(&block)
|
1114
|
+
triggers(false) { yield }
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
# Execute block with session triggers on or off
|
1118
|
+
def triggers(on_off, &block)
|
1119
|
+
begin
|
1120
|
+
active = triggers?
|
1121
|
+
if on_off && !active
|
1122
|
+
enable_triggers
|
1123
|
+
elsif !on_off && active
|
1124
|
+
disable_triggers
|
1125
|
+
end
|
1126
|
+
yield
|
1127
|
+
ensure
|
1128
|
+
case active
|
1129
|
+
when true; enable_triggers if !triggers?
|
1130
|
+
when false; disable_triggers if triggers?
|
1131
|
+
end
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
|
1094
1135
|
def dump(*query)
|
1095
1136
|
records = self.records(*query)
|
1096
1137
|
|
@@ -1155,17 +1196,16 @@ module PgConn
|
|
1155
1196
|
end
|
1156
1197
|
|
1157
1198
|
# Common implementation for #quote_record and #quote_records that avoids
|
1158
|
-
# querying the database multiple times or duplication the code
|
1159
|
-
# flag is true when called via #quote_records
|
1199
|
+
# querying the database multiple times or duplication the code
|
1160
1200
|
#
|
1161
1201
|
# @data can be a Hash, Array, or OpenStruct. Hash keys must be symbols or
|
1162
1202
|
# strings, they belong to the same namespace so :k and "k" refer to the
|
1163
|
-
# same value
|
1203
|
+
# same value. The :array flag is true when called via #quote_records
|
1164
1204
|
#
|
1165
1205
|
# Note that #quote_record_impl queries the database for information about
|
1166
1206
|
# the type. TODO Cache this information?
|
1167
|
-
|
1168
|
-
|
1207
|
+
#
|
1208
|
+
def quote_record_impl(datas, schema_name = nil, type, elem_types: nil, array: nil, **opts)
|
1169
1209
|
datas = [datas] if !array
|
1170
1210
|
|
1171
1211
|
pg_type = [schema_name, type].compact.join('.')
|
@@ -1192,10 +1232,9 @@ module PgConn
|
|
1192
1232
|
}
|
1193
1233
|
|
1194
1234
|
if array
|
1195
|
-
|
1196
|
-
"array[#{literals.join(', ')}]::#{pg_type}[]"
|
1235
|
+
Literal.new "array[#{literals.join(', ')}]::#{pg_type}[]"
|
1197
1236
|
else
|
1198
|
-
literals.first
|
1237
|
+
Literal.new literals.first
|
1199
1238
|
end
|
1200
1239
|
end
|
1201
1240
|
|
@@ -1235,7 +1274,7 @@ module PgConn
|
|
1235
1274
|
end
|
1236
1275
|
|
1237
1276
|
STDOUT_PRODUCER = lambda { |msg| $stdout.puts msg }
|
1238
|
-
STDERR_PRODUCER = lambda { |msg| $stderr.puts msg }
|
1277
|
+
STDERR_PRODUCER = lambda { |msg| $stderr.puts msg; $stderr.flush }
|
1239
1278
|
ERROR_PRODUCER = lambda { |msg, stmt| $stderr.puts stmt, nil, msg; $stderr.flush }
|
1240
1279
|
|
1241
1280
|
# Map from message level to default producer. Note that we rely on the key
|
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.37.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-
|
11
|
+
date: 2025-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|