em-pg-client-helper 0.3.1 → 0.3.2
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.
- data/.gitignore +2 -0
- data/.yardopts +1 -0
- data/Rakefile +4 -8
- data/em-pg-client-helper.gemspec +3 -2
- data/lib/em-pg-client-helper.rb +42 -32
- data/lib/em-pg-client-helper/deferrable_group.rb +36 -0
- data/lib/em-pg-client-helper/transaction.rb +23 -14
- metadata +30 -6
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'bundler'
|
1
|
+
exec(*(["bundle", "exec", $PROGRAM_NAME] + ARGV)) if ENV['BUNDLE_GEMFILE'].nil?
|
3
2
|
|
4
3
|
task :default => :test
|
5
4
|
|
@@ -17,13 +16,10 @@ task :release do
|
|
17
16
|
sh "git release"
|
18
17
|
end
|
19
18
|
|
20
|
-
require '
|
19
|
+
require 'yard'
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
rd.title = 'em-pg-client-helper'
|
25
|
-
rd.markup = "markdown"
|
26
|
-
rd.rdoc_files.include("README.md", "lib/**/*.rb")
|
21
|
+
YARD::Rake::YardocTask.new :doc do |yardoc|
|
22
|
+
yardoc.files = %w{lib/**/*.rb - README.md}
|
27
23
|
end
|
28
24
|
|
29
25
|
desc "Run guard"
|
data/em-pg-client-helper.gemspec
CHANGED
@@ -26,7 +26,8 @@ Gem::Specification.new do |s|
|
|
26
26
|
# Needed for guard
|
27
27
|
s.add_development_dependency 'rb-inotify', '~> 0.9'
|
28
28
|
s.add_development_dependency 'pry-debugger'
|
29
|
-
s.add_development_dependency 'rake'
|
30
|
-
s.add_development_dependency '
|
29
|
+
s.add_development_dependency 'rake', '~> 10.4', '>= 1.0.4.2'
|
30
|
+
s.add_development_dependency 'redcarpet'
|
31
31
|
s.add_development_dependency 'rspec'
|
32
|
+
s.add_development_dependency 'yard'
|
32
33
|
end
|
data/lib/em-pg-client-helper.rb
CHANGED
@@ -11,34 +11,37 @@ module PG::EM::Client::Helper
|
|
11
11
|
# a two-element array consisting of the parameterised SQL as the first
|
12
12
|
# element, and the array of parameters as the second element.
|
13
13
|
#
|
14
|
+
# @param tbl [#to_s]
|
15
|
+
#
|
16
|
+
# @param params [Hash<#to_s, Object>]
|
17
|
+
#
|
14
18
|
def insert_sql(tbl, params)
|
15
19
|
keys = params.keys.map { |k| quote_identifier(k.to_s) }.join(',')
|
16
20
|
vals = params.values
|
17
21
|
val_places = (1..vals.length).to_a.map { |i| "$#{i}" }.join(',')
|
18
22
|
|
19
|
-
["INSERT INTO #{quote_identifier(tbl)} (#{keys}) VALUES (#{val_places})", vals]
|
23
|
+
["INSERT INTO #{quote_identifier(tbl.to_s)} (#{keys}) VALUES (#{val_places})", vals]
|
20
24
|
end
|
21
25
|
|
22
26
|
# Run an insert query, without having to write a great pile of SQL all by
|
23
27
|
# yourself.
|
24
28
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# * `db` -- A PG::EM::Client or PG::EM::ConnectionPool instance, against
|
28
|
-
# which all database operations will be executed.
|
29
|
+
# @param db [PG::EM::Client, PG::EM::ConnectionPool] the connection
|
30
|
+
# against which all database operations will be run.
|
29
31
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
+
# @param tbl [#to_s] the name of the table into which you wish to insert
|
33
|
+
# your data. This parameter will be automatically quoted, if
|
34
|
+
# necessary.
|
32
35
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
36
|
+
# @param params [Hash<#to_s, Object>] the fields you wish to insert into
|
37
|
+
# (the keys of the hash) and the values to insert into each field (the
|
38
|
+
# values of the hash). All field names and data will be automatically
|
39
|
+
# quoted and made safe, so you're automatically SQL injection-proof!
|
37
40
|
#
|
38
|
-
#
|
39
|
-
# this means you should attach the code to run after the query
|
40
|
-
# with `#callback`, and you can attach an error handler with
|
41
|
-
# if you like.
|
41
|
+
# @return [EM::Deferrable] the deferrable in which the query is being
|
42
|
+
# called; this means you should attach the code to run after the query
|
43
|
+
# completes with `#callback`, and you can attach an error handler with
|
44
|
+
# `#errback` if you like.
|
42
45
|
#
|
43
46
|
def db_insert(db, tbl, params)
|
44
47
|
db.exec_defer(*insert_sql(tbl, params))
|
@@ -59,23 +62,27 @@ module PG::EM::Client::Helper
|
|
59
62
|
# `db_transaction` returns to specify what to run after the transaction
|
60
63
|
# completes successfully or fails, respectively.
|
61
64
|
#
|
62
|
-
#
|
65
|
+
# @param db [PG::EM::Client, PG::EM::ConnectionPool] the connection
|
66
|
+
# against which the transaction will be executed. If you pass a
|
67
|
+
# `ConnectionPool`, we will automatically hold a single connection for
|
68
|
+
# the transaction to complete against, so you don't have to worry about
|
69
|
+
# that, either.
|
63
70
|
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
71
|
+
# @param blk [Proc] code which will be executed within the context of the
|
72
|
+
# transaction. This block will be passed a
|
73
|
+
# {PG::EM::Client::Helper::Transaction} instance, which has methods to
|
74
|
+
# allow you to commit or rollback the transaction, and execute SQL
|
75
|
+
# statements within the context of the transaction.
|
69
76
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# allow you to commit or rollback the transaction, and execute SQL
|
74
|
-
# statements within the context of the transaction.
|
77
|
+
# @return [EM::Deferrable] on which you can call `#callback` and
|
78
|
+
# `#errback` to define what to do when the transaction succeeds or
|
79
|
+
# fails, respectively.
|
75
80
|
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
81
|
+
# @note Due to the way that transactions detect when they are completed,
|
82
|
+
# every deferrable in the scope of the transaction must be generated
|
83
|
+
# by the transaction. That is, you cannot use objects other than the
|
84
|
+
# transaction asynchronously. This is a known limitation, and will be
|
85
|
+
# addressed in a future version of this library.
|
79
86
|
#
|
80
87
|
def db_transaction(db, opts = {}, &blk)
|
81
88
|
if db.is_a? PG::EM::ConnectionPool
|
@@ -91,11 +98,14 @@ module PG::EM::Client::Helper
|
|
91
98
|
# it so that it will always be valid, no matter what insanity someone's
|
92
99
|
# decided to put in their names.
|
93
100
|
#
|
101
|
+
# @param id [String]
|
102
|
+
#
|
103
|
+
# @return [String] just like `id`, but with added quoting.
|
104
|
+
#
|
94
105
|
def quote_identifier(id)
|
95
106
|
"\"#{id.gsub(/"/, '""')}\""
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
99
|
-
|
100
|
-
|
101
|
-
|
110
|
+
require 'em-pg-client-helper/transaction'
|
111
|
+
require 'em-pg-client-helper/deferrable_group'
|
@@ -7,23 +7,56 @@
|
|
7
7
|
class PG::EM::Client::Helper::DeferrableGroup
|
8
8
|
include ::EventMachine::Deferrable
|
9
9
|
|
10
|
+
# Create a new deferrable group.
|
11
|
+
#
|
10
12
|
def initialize
|
11
13
|
@failed = false
|
14
|
+
@finished = false
|
12
15
|
@first_failure = nil
|
13
16
|
@outstanding = []
|
14
17
|
yield(self) if block_given?
|
15
18
|
end
|
16
19
|
|
20
|
+
# Add a new deferrable to this group.
|
21
|
+
#
|
22
|
+
# @param df [EM::Deferrable] the deferrable to wait on.
|
23
|
+
#
|
24
|
+
# @return [EM::Deferrable] the same deferrable.
|
25
|
+
#
|
26
|
+
# @raise [RuntimeError] if you attempt to add a deferrable after the
|
27
|
+
# group has already "completed" (that is, all deferrables that were
|
28
|
+
# previously added to the group have finished).
|
29
|
+
#
|
17
30
|
def add(df)
|
31
|
+
if @finished
|
32
|
+
raise RuntimeError,
|
33
|
+
"This deferrable group has already completed."
|
34
|
+
end
|
35
|
+
|
18
36
|
@outstanding << df
|
19
37
|
df.callback { completed(df) }.errback { |ex| failed(df, ex) }
|
20
38
|
end
|
21
39
|
|
40
|
+
# Mark a deferrable as having been completed.
|
41
|
+
#
|
42
|
+
# If this is the last deferrable in the group, then the callback/errback
|
43
|
+
# will be triggered.
|
44
|
+
#
|
45
|
+
# @param df [EM::Deferrable]
|
46
|
+
#
|
22
47
|
def completed(df)
|
23
48
|
@outstanding.delete(df)
|
24
49
|
maybe_done
|
25
50
|
end
|
26
51
|
|
52
|
+
# Register that a given deferrable completed, but has failed.
|
53
|
+
#
|
54
|
+
# As soon as `failed` has been called, the deferrable group is guaranteed
|
55
|
+
# to fail, no matter how many of the deferrables in the group succeed.
|
56
|
+
# If this is the first deferrable in the group to have failed, then `ex`
|
57
|
+
# will be the exception passed to the `errback`, otherwise the exception
|
58
|
+
# will unfortunately be eaten by a grue.
|
59
|
+
#
|
27
60
|
def failed(df, ex)
|
28
61
|
@first_failure ||= ex
|
29
62
|
@failed = true
|
@@ -31,8 +64,11 @@ class PG::EM::Client::Helper::DeferrableGroup
|
|
31
64
|
end
|
32
65
|
|
33
66
|
private
|
67
|
+
# Called every time a deferrable finishes, just in case we're ready to
|
68
|
+
# trigger our callbacks.
|
34
69
|
def maybe_done
|
35
70
|
if @outstanding.empty?
|
71
|
+
@finished = true
|
36
72
|
if @failed
|
37
73
|
fail(@first_failure)
|
38
74
|
else
|
@@ -11,16 +11,21 @@ class PG::EM::Client::Helper::Transaction
|
|
11
11
|
|
12
12
|
DeferrableGroup.new do |dg|
|
13
13
|
@dg = dg
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
|
15
|
+
df = conn.exec_defer("BEGIN").callback do
|
16
|
+
begin
|
17
|
+
blk.call(self)
|
18
|
+
rescue StandardError => ex
|
19
|
+
rollback(ex)
|
20
|
+
end
|
21
|
+
end.errback { |ex| rollback(ex) }
|
22
|
+
|
23
|
+
@dg.add(df)
|
24
|
+
end.callback do
|
25
|
+
rollback(RuntimeError.new("txn.commit was not called"))
|
26
|
+
end.errback do |ex|
|
27
|
+
rollback(ex)
|
28
|
+
end
|
24
29
|
end
|
25
30
|
|
26
31
|
# Signal the database to commit this transaction. You must do this
|
@@ -31,10 +36,12 @@ class PG::EM::Client::Helper::Transaction
|
|
31
36
|
#
|
32
37
|
def commit
|
33
38
|
if @active
|
34
|
-
@conn.exec_defer("COMMIT").callback do
|
39
|
+
df = @conn.exec_defer("COMMIT").callback do
|
35
40
|
@active = false
|
36
41
|
self.succeed
|
37
42
|
end.errback { |ex| rollback(ex) }
|
43
|
+
|
44
|
+
@dg.add(df)
|
38
45
|
end
|
39
46
|
end
|
40
47
|
|
@@ -45,10 +52,12 @@ class PG::EM::Client::Helper::Transaction
|
|
45
52
|
#
|
46
53
|
def rollback(ex)
|
47
54
|
if @active
|
48
|
-
@conn.exec_defer("ROLLBACK") do
|
55
|
+
df = @conn.exec_defer("ROLLBACK") do
|
49
56
|
@active = false
|
50
57
|
self.fail(ex)
|
51
58
|
end
|
59
|
+
|
60
|
+
@dg.add(df)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
@@ -70,12 +79,12 @@ class PG::EM::Client::Helper::Transaction
|
|
70
79
|
def exec(sql, values=[], &blk)
|
71
80
|
unless @active
|
72
81
|
raise RuntimeError,
|
73
|
-
|
82
|
+
"Cannot execute a query in a transaction that has been closed"
|
74
83
|
end
|
75
84
|
|
76
85
|
@dg.add(
|
77
86
|
@conn.exec_defer(sql, values).
|
78
|
-
|
87
|
+
tap { |df| df.callback(&blk) if blk }
|
79
88
|
)
|
80
89
|
end
|
81
90
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-pg-client-helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: git-version-bump
|
@@ -157,6 +157,28 @@ dependencies:
|
|
157
157
|
version: '0'
|
158
158
|
- !ruby/object:Gem::Dependency
|
159
159
|
name: rake
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '10.4'
|
166
|
+
- - ! '>='
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: 1.0.4.2
|
169
|
+
type: :development
|
170
|
+
prerelease: false
|
171
|
+
version_requirements: !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ~>
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '10.4'
|
177
|
+
- - ! '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: 1.0.4.2
|
180
|
+
- !ruby/object:Gem::Dependency
|
181
|
+
name: redcarpet
|
160
182
|
requirement: !ruby/object:Gem::Requirement
|
161
183
|
none: false
|
162
184
|
requirements:
|
@@ -172,7 +194,7 @@ dependencies:
|
|
172
194
|
- !ruby/object:Gem::Version
|
173
195
|
version: '0'
|
174
196
|
- !ruby/object:Gem::Dependency
|
175
|
-
name:
|
197
|
+
name: rspec
|
176
198
|
requirement: !ruby/object:Gem::Requirement
|
177
199
|
none: false
|
178
200
|
requirements:
|
@@ -188,7 +210,7 @@ dependencies:
|
|
188
210
|
- !ruby/object:Gem::Version
|
189
211
|
version: '0'
|
190
212
|
- !ruby/object:Gem::Dependency
|
191
|
-
name:
|
213
|
+
name: yard
|
192
214
|
requirement: !ruby/object:Gem::Requirement
|
193
215
|
none: false
|
194
216
|
requirements:
|
@@ -211,6 +233,7 @@ extra_rdoc_files:
|
|
211
233
|
- README.md
|
212
234
|
files:
|
213
235
|
- .gitignore
|
236
|
+
- .yardopts
|
214
237
|
- Gemfile
|
215
238
|
- Guardfile
|
216
239
|
- LICENCE
|
@@ -238,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
261
|
version: '0'
|
239
262
|
segments:
|
240
263
|
- 0
|
241
|
-
hash:
|
264
|
+
hash: 1485031503438797399
|
242
265
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
266
|
none: false
|
244
267
|
requirements:
|
@@ -247,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
247
270
|
version: '0'
|
248
271
|
segments:
|
249
272
|
- 0
|
250
|
-
hash:
|
273
|
+
hash: 1485031503438797399
|
251
274
|
requirements: []
|
252
275
|
rubyforge_project:
|
253
276
|
rubygems_version: 1.8.23
|
@@ -255,3 +278,4 @@ signing_key:
|
|
255
278
|
specification_version: 3
|
256
279
|
summary: Simplify common operations using em-pg-client
|
257
280
|
test_files: []
|
281
|
+
has_rdoc:
|