em-postgres 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|