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 CHANGED
@@ -1,9 +1,8 @@
1
1
  Async PostgreSQL driver for Ruby/EventMachine
2
- based off Aman Gupta's mysql driver
3
-
4
2
 
5
3
  Requires pg
6
4
 
5
+ To run the specs, you will need rspec, run "rspec spec/postgres_spec.rb"
7
6
 
8
7
 
9
8
  TODOS:
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
- @postgres.send_query(sql)
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
- @postgres.send(method, *args, &blk) if @postres.respond_to? method
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
 
@@ -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, cb, eb)
65
-
63
+
64
+ @connection.execute(sql,params,cb,eb)
66
65
  df
67
66
  end
68
67
  alias :real_query :query
@@ -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
@@ -3,4 +3,4 @@ require "rubygems"
3
3
  require "eventmachine"
4
4
  require "rspec"
5
5
  require "em-postgres"
6
- require "ruby-debug"
6
+ #require "ruby-debug"
@@ -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: false
5
- segments:
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: 2011-08-25 00:00:00 -07:00
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 client API for Ruby/EventMachine
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
- has_rdoc: true
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.3.7
68
+ rubyforge_project: em-postgres
69
+ rubygems_version: 1.8.11
81
70
  signing_key:
82
71
  specification_version: 3
83
- summary: Async PostgreSQL client API for Ruby/EventMachine
72
+ summary: Async PostgreSQL driver for Ruby/Eventmachine
84
73
  test_files: []
85
74