em-pg-client-helper 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|