github-ds 0.2.7 → 0.2.8
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/CHANGELOG.md +11 -0
- data/lib/github/ds/version.rb +1 -1
- data/lib/github/sql.rb +144 -192
- data/lib/github/sql/errors.rb +22 -0
- data/lib/github/sql/literal.rb +25 -0
- data/lib/github/sql/rows.rb +20 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e72707c0bbfc8fcf2e846d4e16e6735b8b457728
|
4
|
+
data.tar.gz: 11e5d2059aafe9dc81e7cd343c0a1b7218ca23e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9f34c95c26ee3edd98d27acefa2d1ea8ca6c1197c36f1616c0dbc387e2f76c4a16c497024565a85de00138031ec8955ab40bd61c6545e3a6ef0e28f4ef1bfbe
|
7
|
+
data.tar.gz: 38586c9b89eaefa299d45e94ed9beb03cbc21b230c301aada2db21aeab27ff8a851cce41ddfc7f7cec0cfd56193e66a1ff62588f57d930ef3089cecbf3c2634f
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.2.8
|
4
|
+
|
5
|
+
Fixes
|
6
|
+
|
7
|
+
* GitHub::SQL.transaction now takes options and passes them to ActiveRecord::Base.transaction.
|
8
|
+
* Moved default time zone enforcement to sanitize from add. Makes it possible to use interpolate or sanitize and have correct time zone enforcement.
|
9
|
+
|
10
|
+
Additions
|
11
|
+
|
12
|
+
* Added GitHub::SQL#transaction instance method to match the class level one.
|
13
|
+
|
3
14
|
## 0.2.7
|
4
15
|
|
5
16
|
Fixes
|
data/lib/github/ds/version.rb
CHANGED
data/lib/github/sql.rb
CHANGED
@@ -31,47 +31,12 @@ module GitHub
|
|
31
31
|
# GitHub::SQL::ROWS(array_of_arrays).
|
32
32
|
#
|
33
33
|
class SQL
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def initialize(value)
|
41
|
-
@value = value.to_s.dup.freeze
|
42
|
-
end
|
43
|
-
|
44
|
-
def inspect
|
45
|
-
"<#{self.class.name} #{value}>"
|
46
|
-
end
|
47
|
-
|
48
|
-
def bytesize
|
49
|
-
value.bytesize
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Internal: a list of arrays of values for insertion into SQL.
|
54
|
-
class Rows
|
55
|
-
# Public: the Array of row values
|
56
|
-
attr_reader :values
|
57
|
-
|
58
|
-
def initialize(values)
|
59
|
-
unless values.all? { |v| v.is_a? Array }
|
60
|
-
raise ArgumentError, "cannot instantiate SQL rows with anything but arrays"
|
61
|
-
end
|
62
|
-
@values = values.dup.freeze
|
63
|
-
end
|
64
|
-
|
65
|
-
def inspect
|
66
|
-
"<#{self.class.name} #{values.inspect}>"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Public: Run inside a transaction
|
71
|
-
def self.transaction
|
72
|
-
ActiveRecord::Base.connection.transaction do
|
73
|
-
yield
|
74
|
-
end
|
34
|
+
# Public: Run inside a transaction. Class version of this method only works
|
35
|
+
# if only one connection is in use. If passing connections to
|
36
|
+
# GitHub::SQL#initialize or overriding connection then you'll need to use
|
37
|
+
# the instance version.
|
38
|
+
def self.transaction(options = {}, &block)
|
39
|
+
ActiveRecord::Base.connection.transaction(options, &block)
|
75
40
|
end
|
76
41
|
|
77
42
|
# Public: Instantiate a literal SQL value.
|
@@ -103,27 +68,55 @@ module GitHub
|
|
103
68
|
Rows.new(rows)
|
104
69
|
end
|
105
70
|
|
106
|
-
# Public:
|
107
|
-
|
108
|
-
|
71
|
+
# Public: Create and execute a new SQL query, ignoring results.
|
72
|
+
#
|
73
|
+
# sql - A SQL string. See GitHub::SQL#add for details.
|
74
|
+
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
75
|
+
#
|
76
|
+
# Returns self.
|
77
|
+
def self.run(sql, bindings = {})
|
78
|
+
new(sql, bindings).run
|
79
|
+
end
|
109
80
|
|
110
|
-
# Public:
|
111
|
-
|
81
|
+
# Public: Create and execute a new SQL query, returning its hash_result rows.
|
82
|
+
#
|
83
|
+
# sql - A SQL string. See GitHub::SQL#add for details.
|
84
|
+
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
85
|
+
#
|
86
|
+
# Returns an Array of result hashes.
|
87
|
+
def self.hash_results(sql, bindings = {})
|
88
|
+
new(sql, bindings).hash_results
|
112
89
|
end
|
113
90
|
|
114
|
-
# Public:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
91
|
+
# Public: Create and execute a new SQL query, returning its result rows.
|
92
|
+
#
|
93
|
+
# sql - A SQL string. See GitHub::SQL#add for details.
|
94
|
+
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
95
|
+
#
|
96
|
+
# Returns an Array of result arrays.
|
97
|
+
def self.results(sql, bindings = {})
|
98
|
+
new(sql, bindings).results
|
119
99
|
end
|
120
100
|
|
121
|
-
# Public:
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
101
|
+
# Public: Create and execute a new SQL query, returning the value of the
|
102
|
+
# first column of the first result row.
|
103
|
+
#
|
104
|
+
# sql - A SQL string. See GitHub::SQL#add for details.
|
105
|
+
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
106
|
+
#
|
107
|
+
# Returns a value or nil.
|
108
|
+
def self.value(sql, bindings = {})
|
109
|
+
new(sql, bindings).value
|
110
|
+
end
|
111
|
+
|
112
|
+
# Public: Create and execute a new SQL query, returning its values.
|
113
|
+
#
|
114
|
+
# sql - A SQL string. See GitHub::SQL#add for details.
|
115
|
+
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
116
|
+
#
|
117
|
+
# Returns an Array of values.
|
118
|
+
def self.values(sql, bindings = {})
|
119
|
+
new(sql, bindings).values
|
127
120
|
end
|
128
121
|
|
129
122
|
# Internal: A Symbol-Keyed Hash of bind values.
|
@@ -151,10 +144,10 @@ module GitHub
|
|
151
144
|
|
152
145
|
@last_insert_id = nil
|
153
146
|
@affected_rows = nil
|
154
|
-
@binds
|
155
|
-
@query
|
156
|
-
@connection
|
157
|
-
@
|
147
|
+
@binds = binds ? binds.dup : {}
|
148
|
+
@query = ""
|
149
|
+
@connection = @binds.delete :connection
|
150
|
+
@force_timezone = @binds.delete :force_timezone
|
158
151
|
|
159
152
|
add query
|
160
153
|
end
|
@@ -173,19 +166,9 @@ module GitHub
|
|
173
166
|
return self if sql.nil? || sql.empty?
|
174
167
|
|
175
168
|
query << " " unless query.empty?
|
169
|
+
query << interpolate(sql.strip, extras)
|
176
170
|
|
177
|
-
|
178
|
-
if @force_tz
|
179
|
-
zone = ActiveRecord::Base.default_timezone
|
180
|
-
ActiveRecord::Base.default_timezone = @force_tz
|
181
|
-
end
|
182
|
-
|
183
|
-
query << interpolate(sql.strip, extras)
|
184
|
-
|
185
|
-
self
|
186
|
-
ensure
|
187
|
-
ActiveRecord::Base.default_timezone = zone if @force_tz
|
188
|
-
end
|
171
|
+
self
|
189
172
|
end
|
190
173
|
|
191
174
|
# Public: Add a chunk of SQL to the query, unless query generated so far is empty.
|
@@ -204,11 +187,6 @@ module GitHub
|
|
204
187
|
add sql, extras
|
205
188
|
end
|
206
189
|
|
207
|
-
# Public: The number of affected rows for this connection.
|
208
|
-
def affected_rows
|
209
|
-
@affected_rows || connection.raw_connection.affected_rows
|
210
|
-
end
|
211
|
-
|
212
190
|
# Public: Add additional bind values to be interpolated each time SQL
|
213
191
|
# is added to the query.
|
214
192
|
#
|
@@ -220,44 +198,6 @@ module GitHub
|
|
220
198
|
self
|
221
199
|
end
|
222
200
|
|
223
|
-
# Internal: The object we use to execute SQL and retrieve results. Defaults
|
224
|
-
# to AR::B.connection, but can be overridden with a ":connection" key when
|
225
|
-
# initializing a new instance.
|
226
|
-
def connection
|
227
|
-
@connection || ActiveRecord::Base.connection
|
228
|
-
end
|
229
|
-
|
230
|
-
# Public: the number of rows found by the query.
|
231
|
-
#
|
232
|
-
# Returns FOUND_ROWS() if a SELECT query included SQL_CALC_FOUND_ROWS.
|
233
|
-
# Raises if SQL_CALC_FOUND_ROWS was not present in the query.
|
234
|
-
def found_rows
|
235
|
-
raise "no SQL_CALC_FOUND_ROWS clause present" unless defined? @found_rows
|
236
|
-
@found_rows
|
237
|
-
end
|
238
|
-
|
239
|
-
# Internal: Replace ":keywords" with sanitized values from binds or extras.
|
240
|
-
def interpolate(sql, extras = nil)
|
241
|
-
sql.gsub(/:[a-z][a-z0-9_]*/) do |raw|
|
242
|
-
sym = raw[1..-1].intern # O.o gensym
|
243
|
-
|
244
|
-
if extras && extras.include?(sym)
|
245
|
-
val = extras[sym]
|
246
|
-
elsif binds.include?(sym)
|
247
|
-
val = binds[sym]
|
248
|
-
end
|
249
|
-
|
250
|
-
raise BadBind.new raw if val.nil?
|
251
|
-
|
252
|
-
sanitize val
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
# Public: The last inserted ID for this connection.
|
257
|
-
def last_insert_id
|
258
|
-
@last_insert_id || connection.raw_connection.last_insert_id
|
259
|
-
end
|
260
|
-
|
261
201
|
# Public: Map each row to an instance of an ActiveRecord::Base subclass.
|
262
202
|
def models(klass)
|
263
203
|
return @models if defined? @models
|
@@ -279,12 +219,7 @@ module GitHub
|
|
279
219
|
return @results if defined? @results
|
280
220
|
return [] if frozen?
|
281
221
|
|
282
|
-
|
283
|
-
if @force_tz
|
284
|
-
zone = ActiveRecord::Base.default_timezone
|
285
|
-
ActiveRecord::Base.default_timezone = @force_tz
|
286
|
-
end
|
287
|
-
|
222
|
+
enforce_timezone do
|
288
223
|
case query
|
289
224
|
when /\ADELETE/i
|
290
225
|
@affected_rows = connection.delete(query, "#{self.class.name} Delete")
|
@@ -310,11 +245,23 @@ module GitHub
|
|
310
245
|
freeze
|
311
246
|
|
312
247
|
@results
|
313
|
-
ensure
|
314
|
-
ActiveRecord::Base.default_timezone = zone if @force_tz
|
315
248
|
end
|
316
249
|
end
|
317
250
|
|
251
|
+
# Public: Execute, ignoring results. This is useful when the results of a
|
252
|
+
# query aren't important, often INSERTs, UPDATEs, or DELETEs.
|
253
|
+
#
|
254
|
+
# sql - An optional SQL string. See GitHub::SQL#add for details.
|
255
|
+
# extras - Optional bind values. See GitHub::SQL#add for details.
|
256
|
+
#
|
257
|
+
# Returns self.
|
258
|
+
def run(sql = nil, extras = nil)
|
259
|
+
add sql, extras if !sql.nil?
|
260
|
+
results
|
261
|
+
|
262
|
+
self
|
263
|
+
end
|
264
|
+
|
318
265
|
# Public: If the query is a SELECT, return an array of hashes instead of an array of arrays.
|
319
266
|
def hash_results
|
320
267
|
results
|
@@ -326,18 +273,47 @@ module GitHub
|
|
326
273
|
results.first
|
327
274
|
end
|
328
275
|
|
329
|
-
# Public:
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
276
|
+
# Public: Get the first column of the first row of results.
|
277
|
+
def value
|
278
|
+
row && row.first
|
279
|
+
end
|
280
|
+
|
281
|
+
# Public: Is there a value?
|
282
|
+
def value?
|
283
|
+
!value.nil?
|
284
|
+
end
|
285
|
+
|
286
|
+
# Public: Get first column of every row of results.
|
334
287
|
#
|
335
|
-
# Returns
|
336
|
-
def
|
337
|
-
|
338
|
-
|
288
|
+
# Returns an Array or nil.
|
289
|
+
def values
|
290
|
+
results.map(&:first)
|
291
|
+
end
|
339
292
|
|
340
|
-
|
293
|
+
# Public: Run inside a transaction for the connection.
|
294
|
+
def transaction(options = {}, &block)
|
295
|
+
connection.transaction(options, &block)
|
296
|
+
end
|
297
|
+
|
298
|
+
# Internal: The object we use to execute SQL and retrieve results. Defaults
|
299
|
+
# to AR::B.connection, but can be overridden with a ":connection" key when
|
300
|
+
# initializing a new instance.
|
301
|
+
def connection
|
302
|
+
@connection || ActiveRecord::Base.connection
|
303
|
+
end
|
304
|
+
|
305
|
+
# Public: The number of affected rows for this connection.
|
306
|
+
def affected_rows
|
307
|
+
@affected_rows || connection.raw_connection.affected_rows
|
308
|
+
end
|
309
|
+
|
310
|
+
# Public: the number of rows found by the query.
|
311
|
+
#
|
312
|
+
# Returns FOUND_ROWS() if a SELECT query included SQL_CALC_FOUND_ROWS.
|
313
|
+
# Raises if SQL_CALC_FOUND_ROWS was not present in the query.
|
314
|
+
def found_rows
|
315
|
+
raise "no SQL_CALC_FOUND_ROWS clause present" unless defined? @found_rows
|
316
|
+
@found_rows
|
341
317
|
end
|
342
318
|
|
343
319
|
# Internal: when a SQL_CALC_FOUND_ROWS clause is present in a SELECT query,
|
@@ -349,55 +325,26 @@ module GitHub
|
|
349
325
|
end
|
350
326
|
end
|
351
327
|
|
352
|
-
# Public:
|
353
|
-
|
354
|
-
|
355
|
-
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
356
|
-
#
|
357
|
-
# Returns self.
|
358
|
-
def self.run(sql, bindings = {})
|
359
|
-
new(sql, bindings).run
|
328
|
+
# Public: The last inserted ID for this connection.
|
329
|
+
def last_insert_id
|
330
|
+
@last_insert_id || connection.raw_connection.last_insert_id
|
360
331
|
end
|
361
332
|
|
362
|
-
#
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
#
|
367
|
-
# Returns an Array of result hashes.
|
368
|
-
def self.hash_results(sql, bindings = {})
|
369
|
-
new(sql, bindings).hash_results
|
370
|
-
end
|
333
|
+
# Internal: Replace ":keywords" with sanitized values from binds or extras.
|
334
|
+
def interpolate(sql, extras = nil)
|
335
|
+
sql.gsub(/:[a-z][a-z0-9_]*/) do |raw|
|
336
|
+
sym = raw[1..-1].intern # O.o gensym
|
371
337
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
# Returns an Array of result arrays.
|
378
|
-
def self.results(sql, bindings = {})
|
379
|
-
new(sql, bindings).results
|
380
|
-
end
|
338
|
+
if extras && extras.include?(sym)
|
339
|
+
val = extras[sym]
|
340
|
+
elsif binds.include?(sym)
|
341
|
+
val = binds[sym]
|
342
|
+
end
|
381
343
|
|
382
|
-
|
383
|
-
# first column of the first result row.
|
384
|
-
#
|
385
|
-
# sql - A SQL string. See GitHub::SQL#add for details.
|
386
|
-
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
387
|
-
#
|
388
|
-
# Returns a value or nil.
|
389
|
-
def self.value(sql, bindings = {})
|
390
|
-
new(sql, bindings).value
|
391
|
-
end
|
344
|
+
raise BadBind.new raw if val.nil?
|
392
345
|
|
393
|
-
|
394
|
-
|
395
|
-
# sql - A SQL string. See GitHub::SQL#add for details.
|
396
|
-
# bindings - Optional bind values. See GitHub::SQL#add for details.
|
397
|
-
#
|
398
|
-
# Returns an Array of values.
|
399
|
-
def self.values(sql, bindings = {})
|
400
|
-
new(sql, bindings).values
|
346
|
+
sanitize val
|
347
|
+
end
|
401
348
|
end
|
402
349
|
|
403
350
|
# Internal: Make `value` database-safe. Ish.
|
@@ -426,7 +373,9 @@ module GitHub
|
|
426
373
|
connection.quote value.name
|
427
374
|
|
428
375
|
when DateTime, Time, Date
|
429
|
-
|
376
|
+
enforce_timezone do
|
377
|
+
connection.quote value.to_s(:db)
|
378
|
+
end
|
430
379
|
|
431
380
|
when true
|
432
381
|
connection.quoted_true
|
@@ -442,21 +391,24 @@ module GitHub
|
|
442
391
|
end
|
443
392
|
end
|
444
393
|
|
445
|
-
|
446
|
-
def value
|
447
|
-
row && row.first
|
448
|
-
end
|
394
|
+
private
|
449
395
|
|
450
|
-
#
|
451
|
-
def
|
452
|
-
|
453
|
-
|
396
|
+
# Private: Forces ActiveRecord's default timezone for duration of block.
|
397
|
+
def enforce_timezone(&block)
|
398
|
+
begin
|
399
|
+
if @force_timezone
|
400
|
+
zone = ActiveRecord::Base.default_timezone
|
401
|
+
ActiveRecord::Base.default_timezone = @force_timezone
|
402
|
+
end
|
454
403
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
results.map(&:first)
|
404
|
+
yield if block_given?
|
405
|
+
ensure
|
406
|
+
ActiveRecord::Base.default_timezone = zone if @force_timezone
|
407
|
+
end
|
460
408
|
end
|
461
409
|
end
|
462
410
|
end
|
411
|
+
|
412
|
+
require "github/sql/literal"
|
413
|
+
require "github/sql/rows"
|
414
|
+
require "github/sql/errors"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GitHub
|
2
|
+
class SQL
|
3
|
+
# Public: A superclass for errors.
|
4
|
+
class Error < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
# Public: Raised when a bound ":keyword" value isn't available.
|
8
|
+
class BadBind < Error
|
9
|
+
def initialize(keyword)
|
10
|
+
super "There's no bind value for #{keyword.inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Raised when a bound value can't be sanitized.
|
15
|
+
class BadValue < Error
|
16
|
+
def initialize(value, description = nil)
|
17
|
+
description ||= "a #{value.class.name}"
|
18
|
+
super "Can't sanitize #{description}: #{value.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GitHub
|
2
|
+
class SQL
|
3
|
+
# Internal: a SQL literal value.
|
4
|
+
class Literal
|
5
|
+
# Public: the string value of this literal
|
6
|
+
attr_reader :value
|
7
|
+
|
8
|
+
def initialize(value)
|
9
|
+
@value = value.to_s.dup.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"<#{self.class.name} #{value}>"
|
14
|
+
end
|
15
|
+
|
16
|
+
def bytesize
|
17
|
+
value.bytesize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: prepackaged literal values.
|
22
|
+
NULL = Literal.new "NULL"
|
23
|
+
NOW = Literal.new "NOW()"
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GitHub
|
2
|
+
class SQL
|
3
|
+
# Internal: a list of arrays of values for insertion into SQL.
|
4
|
+
class Rows
|
5
|
+
# Public: the Array of row values
|
6
|
+
attr_reader :values
|
7
|
+
|
8
|
+
def initialize(values)
|
9
|
+
unless values.all? { |v| v.is_a? Array }
|
10
|
+
raise ArgumentError, "cannot instantiate SQL rows with anything but arrays"
|
11
|
+
end
|
12
|
+
@values = values.dup.freeze
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"<#{self.class.name} #{values.inspect}>"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: github-ds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -162,6 +162,9 @@ files:
|
|
162
162
|
- lib/github/kv.rb
|
163
163
|
- lib/github/result.rb
|
164
164
|
- lib/github/sql.rb
|
165
|
+
- lib/github/sql/errors.rb
|
166
|
+
- lib/github/sql/literal.rb
|
167
|
+
- lib/github/sql/rows.rb
|
165
168
|
- script/bootstrap
|
166
169
|
- script/console
|
167
170
|
- script/install
|