Class: Qreport::Connection
- Inherits:
-
Object
- Object
- Qreport::Connection
show all
- Defined in:
- lib/qreport/connection.rb,
lib/qreport/connection/query.rb
Defined Under Namespace
Modules: TypeName
Classes: Query, SQL
Constant Summary
collapse
- NULL =
'NULL'.freeze
- QUOTE =
"'".freeze
- T_ =
"'t'::boolean".freeze
- F_ =
"'f'::boolean".freeze
- T =
't'.freeze
- S_TIMESTAMP =
"::timestamp".freeze
- IDENTITY =
lambda { | val, type | val }
- @@require_pg =
true
Class Attribute Summary collapse
Instance Attribute Summary collapse
Instance Method Summary
collapse
-
#_close ⇒ Object
-
#_transaction_abort ⇒ Object
-
#_transaction_begin ⇒ Object
-
#_transaction_commit ⇒ Object
-
#_type_name(args) ⇒ Object
-
#close ⇒ Object
-
#dump_result!(result, stream = nil) ⇒ Object
-
#escape_identifier(name) ⇒ Object
-
#escape_value(val, example_value = nil) ⇒ Object
-
#fd ⇒ Object
-
#in_transaction? ⇒ Boolean
-
#initialize(args = nil) ⇒ Connection
constructor
A new instance of Connection.
-
#initialize_copy(src) ⇒ Object
-
#run(sql, options = nil) ⇒ Object
options: :arguments => { :key => value, … } :limit => size :limit => [ size, offset ].
-
#run_query!(sql, query, options = nil) ⇒ Object
-
#safe_sql(x) ⇒ Object
-
#table_exists?(name, schemaname = nil) ⇒ Boolean
-
#transaction ⇒ Object
-
#transaction_begin ⇒ Object
-
#transaction_end(abort = nil) ⇒ Object
-
#type_name(*args) ⇒ Object
Returns a frozen String representing a column type.
-
#unescape_value(val, type) ⇒ Object
-
#unescape_value_func(type) ⇒ Object
-
#with_limit(sql, limit = nil) ⇒ Object
Constructor Details
#initialize(args = nil) ⇒ Connection
Returns a new instance of Connection.
18
19
20
21
22
23
24
|
# File 'lib/qreport/connection.rb', line 18
def initialize args = nil
@arguments = args
initialize_copy nil
if conn = @arguments && @arguments.delete(:conn)
self.conn = conn
end
end
|
Class Attribute Details
.current ⇒ Object
Returns the value of attribute current.
15
16
17
|
# File 'lib/qreport/connection.rb', line 15
def current
@current
end
|
Instance Attribute Details
#arguments ⇒ Object
Returns the value of attribute arguments.
8
9
10
|
# File 'lib/qreport/connection.rb', line 8
def arguments
@arguments
end
|
#conn ⇒ Object
Returns the PG connection object. Create a new connection from #arguments. New connection will be closed by #close.
50
51
52
|
# File 'lib/qreport/connection.rb', line 50
def conn
@conn
end
|
#conn_owned ⇒ Object
Returns the value of attribute conn_owned.
11
12
13
|
# File 'lib/qreport/connection.rb', line 11
def conn_owned
@conn_owned
end
|
#env ⇒ Object
Returns the value of attribute env.
8
9
10
|
# File 'lib/qreport/connection.rb', line 8
def env
@env
end
|
#schemaname ⇒ Object
Returns the value of attribute schemaname.
10
11
12
|
# File 'lib/qreport/connection.rb', line 10
def schemaname
@schemaname
end
|
#unescape_value_funcs ⇒ Object
Returns the value of attribute unescape_value_funcs.
12
13
14
|
# File 'lib/qreport/connection.rb', line 12
def unescape_value_funcs
@unescape_value_funcs
end
|
#verbose ⇒ Object
Returns the value of attribute verbose.
9
10
11
|
# File 'lib/qreport/connection.rb', line 9
def verbose
@verbose
end
|
#verbose_result ⇒ Object
Returns the value of attribute verbose_result.
9
10
11
|
# File 'lib/qreport/connection.rb', line 9
def verbose_result
@verbose_result
end
|
#verbose_stream ⇒ Object
Returns the value of attribute verbose_stream.
9
10
11
|
# File 'lib/qreport/connection.rb', line 9
def verbose_stream
@verbose_stream
end
|
Instance Method Details
#_close ⇒ Object
83
84
85
86
87
88
89
90
91
92
|
# File 'lib/qreport/connection.rb', line 83
def _close
if @conn
conn = @conn
@conn = nil
conn.close if @conn_owned
end
ensure
@conn_owned = false
@transaction_nesting = 0
end
|
#_transaction_abort ⇒ Object
144
145
146
|
# File 'lib/qreport/connection.rb', line 144
def _transaction_abort
run "ABORT"; self
end
|
#_transaction_begin ⇒ Object
136
137
138
|
# File 'lib/qreport/connection.rb', line 136
def _transaction_begin
run "BEGIN"; self
end
|
#_transaction_commit ⇒ Object
140
141
142
|
# File 'lib/qreport/connection.rb', line 140
def _transaction_commit
run "COMMIT"; self
end
|
#_type_name(args) ⇒ Object
296
297
298
299
300
301
302
303
304
|
# File 'lib/qreport/connection.rb', line 296
def _type_name args
x = conn.exec("SELECT pg_catalog.format_type($1,$2)", args).
getvalue(0, 0).to_s.dup
x.extend(TypeName)
x.pg_ftype, x.pg_fmod = args
x.freeze
x
end
|
#close ⇒ Object
76
77
78
79
80
81
|
# File 'lib/qreport/connection.rb', line 76
def close
raise Error, "close during transaction" if in_transaction?
_close
ensure
@invalid = false
end
|
#dump_result!(result, stream = nil) ⇒ Object
280
281
282
283
|
# File 'lib/qreport/connection.rb', line 280
def dump_result! result, stream = nil
PP.pp(result, stream || verbose_stream) if result
result
end
|
#escape_identifier(name) ⇒ Object
187
188
189
|
# File 'lib/qreport/connection.rb', line 187
def escape_identifier name
conn.escape_identifier name.to_s
end
|
#escape_value(val, example_value = nil) ⇒ Object
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'lib/qreport/connection.rb', line 191
def escape_value val, example_value = nil
example_val ||= val
case val
when SQL
val.to_s
when nil
NULL
when true
T_
when false
F_
when Rational
val.to_f
when Numeric
val
when String, Symbol
"'" << conn.escape_string(val.to_s) << QUOTE
when Time
escape_value(val.iso8601(6)) << S_TIMESTAMP
when Range
"BETWEEN #{escape_value(val.first)} AND #{escape_value(val.last)}"
when Hash
escape_value(val.to_json)
when Array
case
when true
escape_value(val.to_json)
when example_val.all?{|x| Numeric === x || x.nil?} && ! example_val.empty?
"ARRAY[#{val.map{|x| escape_value(x, example_val[0])} * ','}]"
else
escape_value(val.to_json)
end
else
raise TypeError, "cannot escape_value on #{val.class.name}"
end.to_s
end
|
#fd ⇒ Object
72
73
74
|
# File 'lib/qreport/connection.rb', line 72
def fd
@conn && @conn.socket
end
|
#in_transaction? ⇒ Boolean
95
|
# File 'lib/qreport/connection.rb', line 95
def in_transaction?; @transaction_nesting > 0; end
|
#initialize_copy(src) ⇒ Object
26
27
28
29
30
31
|
# File 'lib/qreport/connection.rb', line 26
def initialize_copy src
@conn = @conn_owned = nil
@abort_transaction = @invalid = nil
@unescape_value_funcs_cache = nil
@transaction_nesting = 0
end
|
#run(sql, options = nil) ⇒ Object
options:
:arguments => { :key => value, ... }
:limit => size
:limit => [ size, offset ]
164
165
166
167
168
169
170
171
172
173
174
|
# File 'lib/qreport/connection.rb', line 164
def run sql, options = nil
options ||= { }
conn = options[:connection] || self.conn
result = Query.new
result.sql = sql
result.options = options
result.conn = self
result.run!
dump_result! result if @verbose_result || options[:verbose_result]
result
end
|
#run_query!(sql, query, options = nil) ⇒ Object
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
|
# File 'lib/qreport/connection.rb', line 320
def run_query! sql, query, options = nil
error = nil
options ||= EMPTY_Hash
result = nil
begin
result = conn.async_exec(sql)
rescue ::PG::Error => exc
error = exc
rescue ::StandardError => exc
@invalid = true
error = exc
end
result
ensure
if error
query.error = error.inspect
raise error unless options[:capture_error]
end
end
|
#safe_sql(x) ⇒ Object
183
184
185
|
# File 'lib/qreport/connection.rb', line 183
def safe_sql x
SQL.new(x)
end
|
#table_exists?(name, schemaname = nil) ⇒ Boolean
148
149
150
151
152
153
154
155
156
157
158
|
# File 'lib/qreport/connection.rb', line 148
def table_exists? name, schemaname = nil
schema_name = name.split('.', 2)
schema = schema_name.shift if schema_name.size > 1
name = schema_name.first
schema ||= schemaname || self.schemaname || 'public'
result =
run "SELECT EXISTS(SELECT * FROM pg_catalog.pg_tables WHERE tablename = :tablename AND schemaname = :schemaname) as \"exists\"",
:arguments => { :tablename => name, :schemaname => schema }
result.rows[0]["exists"]
end
|
#transaction ⇒ Object
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/qreport/connection.rb', line 97
def transaction
raise Error, "no block" unless block_given?
abort = false
begin
transaction_begin
yield
rescue ::StandardError => exc
abort = @abort_transaction = exc
raise exc
ensure
transaction_end abort
end
end
|
#transaction_begin ⇒ Object
111
112
113
114
115
116
117
|
# File 'lib/qreport/connection.rb', line 111
def transaction_begin
if @transaction_nesting == 0
_transaction_begin
end
@transaction_nesting += 1
self
end
|
#transaction_end(abort = nil) ⇒ Object
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/qreport/connection.rb', line 119
def transaction_end abort = nil
if (@transaction_nesting -= 1) == 0
begin
if abort
_transaction_abort
else
_transaction_commit
end
ensure
if @invalid
close
end
end
end
self
end
|
#type_name(*args) ⇒ Object
Returns a frozen String representing a column type. The String also responds to #pg_ftype and #pg_fmod.
287
288
289
290
|
# File 'lib/qreport/connection.rb', line 287
def type_name *args
(@type_names ||= { })[args] ||=
_type_name(args)
end
|
#unescape_value(val, type) ⇒ Object
237
238
239
240
241
242
243
244
245
246
|
# File 'lib/qreport/connection.rb', line 237
def unescape_value val, type
case val
when nil
when String
return nil if val == NULL
func = (@unescape_value_funcs_cache ||= { })[type] ||= unescape_value_func(type)
val = func.call(val, type)
end
val
end
|
#unescape_value_func(type) ⇒ Object
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
# File 'lib/qreport/connection.rb', line 248
def unescape_value_func type
if @unescape_value_funcs and func = @unescape_value_funcs[type]
return func
end
case type
when /\[\]\Z/
et = $`
el = unescape_value_func(et)
lambda do | val, type |
val.gsub(/\A\{|\}\Z/, '').
split(',').
map{|x| x == 'NULL' ? nil : el.call(x, et)}
end
when /^bool/
lambda { | val, type | val == T }
when /^(int|smallint|bigint|oid|tid|xid|cid)/
lambda { | val, type | val.to_i }
when /^(float|real|double|numeric)/
lambda { | val, type | val.to_f }
when /^timestamp/
lambda { | val, type | Time.parse(val) }
else
IDENTITY
end
end
|
#with_limit(sql, limit = nil) ⇒ Object
306
307
308
309
310
311
312
313
314
315
316
317
318
|
# File 'lib/qreport/connection.rb', line 306
def with_limit sql, limit = nil
sql = sql.dup
case limit
when Integer
limit = "LIMIT #{limit}"
when Array
limit = "OFFSET #{limit[1].to_i}\nLIMIT #{limit[0].to_i}"
end
unless sql.sub!(/:LIMIT\b|\bLIMIT\s+\S+\s*|\Z/im, "\n#{limit}")
sql << "\n" << limit
end
sql
end
|