em-postgres 0.0.1 → 0.0.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/README +1 -2
- data/VERSION +1 -0
- data/lib/em-postgres/connection.rb +19 -15
- data/lib/em-postgres/postgres.rb +3 -4
- data/lib/sequel/async.rb +184 -0
- data/spec/helper.rb +1 -1
- data/spec/postgres_spec.rb +40 -4
- data/test.rb +59 -0
- metadata +14 -25
data/README
CHANGED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.2
|
@@ -83,7 +83,7 @@ module EventMachine
|
|
83
83
|
|
84
84
|
def notify_readable
|
85
85
|
if item = @current
|
86
|
-
sql, cblk, eblk, retries = item
|
86
|
+
sql,params, cblk, eblk, retries = item
|
87
87
|
#results = []
|
88
88
|
#result = nil
|
89
89
|
#@postgres.get_result{|r| result = r}
|
@@ -100,7 +100,6 @@ module EventMachine
|
|
100
100
|
end
|
101
101
|
#puts "\n\nQuery result:\n%p\n" % [ result.values ]
|
102
102
|
end
|
103
|
-
|
104
103
|
unless @postgres.error_message == ""
|
105
104
|
#TODO this is wrong
|
106
105
|
eb = (eblk || @opts[:on_error])
|
@@ -130,7 +129,7 @@ module EventMachine
|
|
130
129
|
next_query
|
131
130
|
|
132
131
|
elsif DisconnectErrors.include? e.message
|
133
|
-
@queue << [sql, cblk, eblk, retries + 1]
|
132
|
+
@queue << [sql,params, cblk, eblk, retries + 1]
|
134
133
|
return #close
|
135
134
|
|
136
135
|
elsif cb = (eblk || @opts[:on_error])
|
@@ -158,7 +157,6 @@ module EventMachine
|
|
158
157
|
end
|
159
158
|
|
160
159
|
def reconnect
|
161
|
-
puts "DDDDD"
|
162
160
|
@processing = false
|
163
161
|
@postgres = @conn.connect_socket(@opts)
|
164
162
|
@fd = @postgres.socket
|
@@ -173,35 +171,41 @@ module EventMachine
|
|
173
171
|
EM.add_timer(1) { reconnect }
|
174
172
|
end
|
175
173
|
|
176
|
-
|
177
|
-
def execute(sql, cblk = nil, eblk = nil, retries = 0)
|
178
|
-
|
174
|
+
def execute(sql,params=nil, cblk = nil, eblk = nil, retries = 0)
|
179
175
|
begin
|
180
176
|
if not @processing or not @connected
|
181
177
|
#if !@processing || !@connected
|
182
178
|
@processing = true
|
183
|
-
|
184
|
-
|
179
|
+
|
180
|
+
if sql =~ /\s+/
|
181
|
+
@postgres.send_query(sql,params)
|
182
|
+
else
|
183
|
+
@postgres.send_query_prepared(sql,params)
|
184
|
+
end
|
185
185
|
else
|
186
|
-
@queue << [sql, cblk, eblk, retries]
|
186
|
+
@queue << [sql,params, cblk, eblk, retries]
|
187
187
|
return
|
188
188
|
end
|
189
189
|
|
190
190
|
rescue Exception => e
|
191
191
|
puts "error in execute #{e}"
|
192
192
|
if DisconnectErrors.include? e.message
|
193
|
-
@queue << [sql, cblk, eblk, retries]
|
193
|
+
@queue << [sql,params, cblk, eblk, retries]
|
194
194
|
return #close
|
195
195
|
else
|
196
196
|
raise e
|
197
197
|
end
|
198
198
|
end
|
199
|
-
@current = [sql, cblk, eblk, retries]
|
199
|
+
@current = [sql,params, cblk, eblk, retries]
|
200
200
|
end
|
201
201
|
|
202
202
|
# act like the pg driver
|
203
203
|
def method_missing(method, *args, &blk)
|
204
|
-
|
204
|
+
if @postgres.respond_to? method
|
205
|
+
@postgres.send(method, *args, &blk)
|
206
|
+
else
|
207
|
+
super
|
208
|
+
end
|
205
209
|
end
|
206
210
|
|
207
211
|
def close
|
@@ -215,8 +219,8 @@ module EventMachine
|
|
215
219
|
|
216
220
|
def next_query
|
217
221
|
if @connected and !@processing and pending = @queue.shift
|
218
|
-
sql, cblk, eblk = pending
|
219
|
-
execute(sql, cblk, eblk)
|
222
|
+
sql, params, cblk, eblk = pending
|
223
|
+
execute(sql, params, cblk, eblk)
|
220
224
|
end
|
221
225
|
end
|
222
226
|
|
data/lib/em-postgres/postgres.rb
CHANGED
@@ -56,13 +56,12 @@ module EventMachine
|
|
56
56
|
@connection.close
|
57
57
|
end
|
58
58
|
|
59
|
-
def query(sql, &blk)
|
59
|
+
def query(sql,params=[], &blk)
|
60
60
|
df = EventMachine::DefaultDeferrable.new
|
61
61
|
cb = blk || Proc.new { |r| df.succeed(r) }
|
62
62
|
eb = Proc.new { |r| df.fail(r) }
|
63
|
-
|
64
|
-
@connection.execute(sql,
|
65
|
-
|
63
|
+
|
64
|
+
@connection.execute(sql,params,cb,eb)
|
66
65
|
df
|
67
66
|
end
|
68
67
|
alias :real_query :query
|
data/lib/sequel/async.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
# async sequel extensions, for use with em-mysql
|
2
|
+
#
|
3
|
+
# require 'em/mysql'
|
4
|
+
# DB = Sequel.connect(:adapter => 'mysql', :user => 'root', :database => 'test', ...)
|
5
|
+
# EventedMysql.settings.update(..., :on_error => proc{|e| log 'error', e })
|
6
|
+
#
|
7
|
+
# def log *args
|
8
|
+
# p [Time.now, *args]
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# DB[:table].where(:id < 100).async_update(:field => 'new value') do |num_updated|
|
12
|
+
# log "done updating #{num_updated} rows"
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# DB[:table].async_insert(:field => 'value') do |insert_id|
|
16
|
+
# log "inserted row #{insert_id}"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# DB[:table].async_multi_insert([:field], [ ['one'], ['two'], ['three'] ]) do
|
20
|
+
# log "done inserting 3 rows"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# DB[:table].limit(10).async_each do |row|
|
24
|
+
# log "got a row", row
|
25
|
+
# end; log "this will be printed before the query returns"
|
26
|
+
#
|
27
|
+
# DB[:table].async_all do |rows|
|
28
|
+
# DB[:table].async_multi_insert([:field], rows.map{|r| "new_#{r[:field]}" })
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# DB[:table].async_all do |rows|
|
32
|
+
# num = rows.size
|
33
|
+
#
|
34
|
+
# rows.each{ |r|
|
35
|
+
# DB[:table].where(:id => r[:id]).async_update(:field => rand(10000).to_s) do
|
36
|
+
# num = num-1
|
37
|
+
# if num == 0
|
38
|
+
# log "last update completed"
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# }
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# DB[:table].async_count do |num_rows|
|
45
|
+
# log "table has #{num_rows} rows"
|
46
|
+
# end
|
47
|
+
|
48
|
+
require 'sequel'
|
49
|
+
raise 'need Sequel >= 3.2.0' unless Sequel::MAJOR == 3 and Sequel::MINOR >= 2
|
50
|
+
|
51
|
+
module Sequel
|
52
|
+
class Dataset
|
53
|
+
def async_insert *args, &cb
|
54
|
+
EventedMysql.insert insert_sql(*args), &cb
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def async_insert_ignore *args, &cb
|
59
|
+
EventedMysql.insert insert_ignore.insert_sql(*args), &cb
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def async_update *args, &cb
|
64
|
+
EventedMysql.update update_sql(*args), &cb
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def async_delete &cb
|
69
|
+
EventedMysql.execute delete_sql, &cb
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def async_multi_insert *args, &cb
|
74
|
+
EventedMysql.execute multi_insert_sql(*args).first, &cb
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def async_multi_insert_ignore *args, &cb
|
79
|
+
EventedMysql.execute insert_ignore.multi_insert_sql(*args).first, &cb
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def async_fetch_rows sql, iter = :each
|
84
|
+
EventedMysql.raw(sql) do |m|
|
85
|
+
r = m.result
|
86
|
+
|
87
|
+
i = -1
|
88
|
+
cols = r.fetch_fields.map{|f| [output_identifier(f.name), Sequel::MySQL::MYSQL_TYPES[f.type], i+=1]}
|
89
|
+
@columns = cols.map{|c| c.first}
|
90
|
+
rows = []
|
91
|
+
while row = r.fetch_row
|
92
|
+
h = {}
|
93
|
+
cols.each{|n, p, i| v = row[i]; h[n] = (v && p) ? p.call(v) : v}
|
94
|
+
if iter == :each
|
95
|
+
yield h
|
96
|
+
else
|
97
|
+
rows << h
|
98
|
+
end
|
99
|
+
end
|
100
|
+
yield rows if iter == :all
|
101
|
+
end
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def async_each
|
106
|
+
async_fetch_rows(select_sql, :each) do |r|
|
107
|
+
if row_proc = @row_proc
|
108
|
+
yield row_proc.call(r)
|
109
|
+
else
|
110
|
+
yield r
|
111
|
+
end
|
112
|
+
end
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def async_all
|
117
|
+
async_fetch_rows(sql, :all) do |rows|
|
118
|
+
if row_proc = @row_proc
|
119
|
+
yield(rows.map{|r| row_proc.call(r) })
|
120
|
+
else
|
121
|
+
yield(rows)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def async_count &cb
|
128
|
+
if options_overlap(COUNT_FROM_SELF_OPTS)
|
129
|
+
from_self.async_count(&cb)
|
130
|
+
else
|
131
|
+
clone(STOCK_COUNT_OPTS).async_each{|r|
|
132
|
+
yield r.is_a?(Hash) ? r.values.first.to_i : r.values.values.first.to_i
|
133
|
+
}
|
134
|
+
end
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Model
|
140
|
+
def async_update *args, &cb
|
141
|
+
this.async_update(*args, &cb)
|
142
|
+
set(*args)
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
def async_delete &cb
|
147
|
+
this.async_delete(&cb)
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
class << self
|
152
|
+
[ :async_insert,
|
153
|
+
:async_insert_ignore,
|
154
|
+
:async_multi_insert,
|
155
|
+
:async_multi_insert_ignore,
|
156
|
+
:async_each,
|
157
|
+
:async_all,
|
158
|
+
:async_update,
|
159
|
+
:async_count ].each do |method|
|
160
|
+
class_eval %[
|
161
|
+
def #{method} *args, &cb
|
162
|
+
dataset.#{method}(*args, &cb)
|
163
|
+
end
|
164
|
+
]
|
165
|
+
end
|
166
|
+
|
167
|
+
# async version of Model#[]
|
168
|
+
def async_lookup args
|
169
|
+
unless Hash === args
|
170
|
+
args = primary_key_hash(args)
|
171
|
+
end
|
172
|
+
|
173
|
+
dataset.where(args).limit(1).async_all{ |rows|
|
174
|
+
if rows.any?
|
175
|
+
yield rows.first
|
176
|
+
else
|
177
|
+
yield nil
|
178
|
+
end
|
179
|
+
}
|
180
|
+
nil
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/spec/helper.rb
CHANGED
data/spec/postgres_spec.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
$LOAD_PATH << File.join(File.dirname(__FILE__))
|
2
2
|
require "helper"
|
3
|
-
require "ruby-debug"
|
4
3
|
describe EventMachine::Postgres do
|
5
4
|
|
6
5
|
it "should be true" do
|
@@ -54,7 +53,17 @@ describe EventMachine::Postgres do
|
|
54
53
|
}
|
55
54
|
end
|
56
55
|
|
57
|
-
|
56
|
+
it "should accept paramaters" do
|
57
|
+
EventMachine.run {
|
58
|
+
conn = EventMachine::Postgres.new(:database => 'test')
|
59
|
+
conn.execute("select $1::int AS first,$2::int AS second,$3::varchar AS third;",[1,nil,'']) { |res|
|
60
|
+
res.first["first"].should == "1"
|
61
|
+
res.first["second"].should == nil
|
62
|
+
res.first["third"].should == ""
|
63
|
+
EventMachine.stop
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
58
67
|
|
59
68
|
it "allow custom error callbacks for each query" do
|
60
69
|
EventMachine.run {
|
@@ -75,11 +84,9 @@ describe EventMachine::Postgres do
|
|
75
84
|
conn = EventMachine::Postgres.new(:database => 'test')
|
76
85
|
|
77
86
|
results = []
|
78
|
-
#debugger
|
79
87
|
conn.execute("select 1 AS x;") {|res| puts res.inspect; results.push(res.first["x"].to_i)}
|
80
88
|
conn.execute("select 2 AS x;") {|res| puts res.inspect;results.push(res.first["x"].to_i)}
|
81
89
|
conn.execute("select 3 AS x;") {|res| puts res.inspect;results.push(res.first["x"].to_i)}
|
82
|
-
#debugger
|
83
90
|
EventMachine.add_timer(0.05) {
|
84
91
|
results.should == [1,2,3]
|
85
92
|
#conn.connection_pool.first.close
|
@@ -124,6 +131,35 @@ describe EventMachine::Postgres do
|
|
124
131
|
}
|
125
132
|
end
|
126
133
|
|
134
|
+
it "should work with bind parameters" do
|
135
|
+
EventMachine.run {
|
136
|
+
conn = EventMachine::Postgres.new(:database=> 'test')
|
137
|
+
conn.execute("select $1::int as bind1;",[4]){|r|
|
138
|
+
r.first["bind1"].to_i.should == 4
|
139
|
+
}
|
140
|
+
conn.execute("select $1::text as bind1;",['four']){|r|
|
141
|
+
r.first["bind1"].should == 'four'
|
142
|
+
EventMachine.stop
|
143
|
+
}
|
144
|
+
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should allow the creation of a prepare statement" do
|
149
|
+
EventMachine.run {
|
150
|
+
conn = EventMachine::Postgres.new(:database=> 'test')
|
151
|
+
prepare_name = "random#{rand(69)}"
|
152
|
+
i = rand(69)
|
153
|
+
conn.prepare(prepare_name,"select #{i};")
|
154
|
+
conn.execute(prepare_name){|r|
|
155
|
+
r.first["?column?"].to_i.should == i
|
156
|
+
EventMachine.stop
|
157
|
+
}
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
|
127
163
|
=begin
|
128
164
|
it "should work with synchronous commands" do
|
129
165
|
EventMachine.run {
|
data/test.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'lib/em/postgres'
|
2
|
+
|
3
|
+
# EM.kqueue
|
4
|
+
# EM.epoll
|
5
|
+
EM.run{
|
6
|
+
EM.start_server '127.0.0.1', 12345 do |c|
|
7
|
+
def c.receive_data data
|
8
|
+
p 'sending http response'
|
9
|
+
send_data "hello"
|
10
|
+
close_connection_after_writing
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
SQL = EventedPostgres
|
15
|
+
def SQL(query, &blk) SQL.select(query, &blk) end
|
16
|
+
|
17
|
+
if true
|
18
|
+
|
19
|
+
SQL.settings.update :logging => true,
|
20
|
+
:database => 'test',
|
21
|
+
:connections => 1
|
22
|
+
|
23
|
+
SQL.execute('select 1+2')
|
24
|
+
|
25
|
+
EM.add_timer(1){
|
26
|
+
3.times do SQL.select('select sleep(0.5)+1'){|r| p(r) } end
|
27
|
+
}
|
28
|
+
|
29
|
+
elsif false
|
30
|
+
|
31
|
+
SQL.settings.update :logging => true,
|
32
|
+
:database => 'test',
|
33
|
+
:connections => 10
|
34
|
+
|
35
|
+
EM.add_timer(2.5){ SQL.all('use test') }
|
36
|
+
|
37
|
+
else
|
38
|
+
|
39
|
+
SQL.settings.update :logging => true,
|
40
|
+
:database => 'test',
|
41
|
+
:connections => 10,
|
42
|
+
:timeout => 1
|
43
|
+
|
44
|
+
n = 0
|
45
|
+
|
46
|
+
SQL.execute('drop table if exists testingabc'){
|
47
|
+
SQL.execute('create table testingabc (a int, b int, c int)'){
|
48
|
+
EM.add_periodic_timer(0.2) do
|
49
|
+
cur_num = n+=1
|
50
|
+
SQL.execute("insert into testingabc values (1,2,#{cur_num})"){
|
51
|
+
SQL("select * from testingabc where c = #{cur_num} limit 1"){ |res| puts;puts }
|
52
|
+
}
|
53
|
+
end
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
}
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-postgres
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
version: 0.0.1
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.2
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Jason Toy
|
@@ -14,8 +10,7 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date:
|
18
|
-
default_executable:
|
13
|
+
date: 2012-01-20 00:00:00 Z
|
19
14
|
dependencies:
|
20
15
|
- !ruby/object:Gem::Dependency
|
21
16
|
name: eventmachine
|
@@ -25,31 +20,29 @@ dependencies:
|
|
25
20
|
requirements:
|
26
21
|
- - ">="
|
27
22
|
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 0
|
30
|
-
- 12
|
31
|
-
- 9
|
32
23
|
version: 0.12.9
|
33
24
|
type: :runtime
|
34
25
|
version_requirements: *id001
|
35
|
-
description: Async PostgreSQL
|
26
|
+
description: Async PostgreSQL driver for Ruby/Eventmachine
|
36
27
|
email: jtoy@jtoy.net
|
37
28
|
executables: []
|
38
29
|
|
39
30
|
extensions: []
|
40
31
|
|
41
|
-
extra_rdoc_files:
|
42
|
-
|
32
|
+
extra_rdoc_files:
|
33
|
+
- README
|
43
34
|
files:
|
44
35
|
- README
|
45
36
|
- Rakefile
|
37
|
+
- VERSION
|
46
38
|
- em-postgres.gemspec
|
47
|
-
- lib/em-postgres/postgres.rb
|
48
|
-
- lib/em-postgres/connection.rb
|
49
39
|
- lib/em-postgres.rb
|
40
|
+
- lib/em-postgres/connection.rb
|
41
|
+
- lib/em-postgres/postgres.rb
|
42
|
+
- lib/sequel/async.rb
|
50
43
|
- spec/helper.rb
|
51
44
|
- spec/postgres_spec.rb
|
52
|
-
|
45
|
+
- test.rb
|
53
46
|
homepage: http://github.com/jtoy/em-postgres
|
54
47
|
licenses: []
|
55
48
|
|
@@ -63,23 +56,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
63
56
|
requirements:
|
64
57
|
- - ">="
|
65
58
|
- !ruby/object:Gem::Version
|
66
|
-
segments:
|
67
|
-
- 0
|
68
59
|
version: "0"
|
69
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
61
|
none: false
|
71
62
|
requirements:
|
72
63
|
- - ">="
|
73
64
|
- !ruby/object:Gem::Version
|
74
|
-
segments:
|
75
|
-
- 0
|
76
65
|
version: "0"
|
77
66
|
requirements: []
|
78
67
|
|
79
|
-
rubyforge_project:
|
80
|
-
rubygems_version: 1.
|
68
|
+
rubyforge_project: em-postgres
|
69
|
+
rubygems_version: 1.8.11
|
81
70
|
signing_key:
|
82
71
|
specification_version: 3
|
83
|
-
summary: Async PostgreSQL
|
72
|
+
summary: Async PostgreSQL driver for Ruby/Eventmachine
|
84
73
|
test_files: []
|
85
74
|
|