rethinkdb 1.16.0.1 → 2.0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/exc.rb +4 -28
- data/lib/func.rb +6 -6
- data/lib/net.rb +489 -103
- data/lib/ql2.pb.rb +16 -6
- data/lib/rpp.rb +9 -8
- data/lib/shim.rb +0 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dae3d5d3b038eca2d30595a269cb259351d5bd98
|
4
|
+
data.tar.gz: 7a03e7c5f271bbb2a7e2e63f74a2757864c4cdbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 308251a1089f50555e2e8177af64235bea9b5a36d35615aca7852f8f72530f17cb0c70569d6a727012aad0f273c6912262cedd9e6b6e1748d60d59e5ec4feb91
|
7
|
+
data.tar.gz: 6f31e8e16757cdaa9fc98137fd732323fa32c7d03c0af3edc2fcad299dfa9dff0c3bad2db838e2e7db1426c07bf3ed3729b8c723b38d3f784396722b3ccfbe5a
|
data/lib/exc.rb
CHANGED
@@ -1,30 +1,6 @@
|
|
1
1
|
module RethinkDB
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# class Error < StandardError
|
8
|
-
# def initialize(msg, bt)
|
9
|
-
# @msg = msg
|
10
|
-
# @bt = bt
|
11
|
-
# @pp_query_bt = "UNIMPLEMENTED #{bt.inspect}"
|
12
|
-
# super inspect
|
13
|
-
# end
|
14
|
-
# def inspect
|
15
|
-
# "#{@msg}\n#{@pp_query_bt}"
|
16
|
-
# end
|
17
|
-
# attr_accessor :msg, :bt, :pp_query_bt
|
18
|
-
# end
|
19
|
-
|
20
|
-
# class Connection_Error < Error; end
|
21
|
-
|
22
|
-
# class Compile_Error < Error; end
|
23
|
-
# class Malformed_Protobuf_Error < Compile_Error; end
|
24
|
-
# class Malformed_Query_Error < Compile_Error; end
|
25
|
-
|
26
|
-
# class Runtime_Error < Error; end
|
27
|
-
# class Data_Error < Runtime_Error; end
|
28
|
-
# class Type_Error < Data_Error; end
|
29
|
-
# class Resource_Error < Runtime_Error; end
|
2
|
+
RqlError = Class.new(RuntimeError)
|
3
|
+
RqlRuntimeError = Class.new(RqlError)
|
4
|
+
RqlDriverError = Class.new(RqlError)
|
5
|
+
RqlCompileError = Class.new(RqlError)
|
30
6
|
end
|
data/lib/func.rb
CHANGED
@@ -60,8 +60,8 @@ module RethinkDB
|
|
60
60
|
:mul => :*,
|
61
61
|
:div => :/,
|
62
62
|
:mod => :%,
|
63
|
-
:
|
64
|
-
:
|
63
|
+
:or => :"|",
|
64
|
+
:and => :"&",
|
65
65
|
:order_by => :orderby,
|
66
66
|
:concat_map => :concatmap,
|
67
67
|
:for_each => :foreach,
|
@@ -82,7 +82,7 @@ module RethinkDB
|
|
82
82
|
|
83
83
|
if [:<, :<=, :>, :>=, :+, :-, :*, :/, :%].include?(__method__)
|
84
84
|
a.each {|arg|
|
85
|
-
if arg.
|
85
|
+
if arg.is_a?(RQL) && arg.bitop
|
86
86
|
err = "Calling #{__method__} on result of infix bitwise operator:\n" +
|
87
87
|
"#{arg.inspect}.\n" +
|
88
88
|
"This is almost always a precedence error.\n" +
|
@@ -94,7 +94,7 @@ module RethinkDB
|
|
94
94
|
end
|
95
95
|
|
96
96
|
if (opt_offset = @@optarg_offsets[termtype.downcase])
|
97
|
-
if opt_offset.
|
97
|
+
if opt_offset.is_a?(Hash)
|
98
98
|
opt_offset = opt_offset[b ? :with_block : :without]
|
99
99
|
end
|
100
100
|
# TODO: This should drop the Hash comparison or at least
|
@@ -102,7 +102,7 @@ module RethinkDB
|
|
102
102
|
# Any time one of these operations is changed to support a
|
103
103
|
# hash argument, we'll have to remember to fix
|
104
104
|
# @@optarg_offsets, otherwise.
|
105
|
-
optargs = a.delete_at(opt_offset) if a[opt_offset].
|
105
|
+
optargs = a.delete_at(opt_offset) if a[opt_offset].is_a?(Hash)
|
106
106
|
end
|
107
107
|
|
108
108
|
args = ((@body != RQL) ? [self] : []) + a + (b ? [new_func(&b)] : [])
|
@@ -131,7 +131,7 @@ module RethinkDB
|
|
131
131
|
def -@; RQL.new.sub(0, self); end
|
132
132
|
|
133
133
|
def [](ind)
|
134
|
-
if ind.
|
134
|
+
if ind.is_a?(Range)
|
135
135
|
return slice(ind.begin, ind.end, :right_bound =>
|
136
136
|
(ind.exclude_end? ? 'open' : 'closed'))
|
137
137
|
else
|
data/lib/net.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
require 'set'
|
1
3
|
require 'socket'
|
2
4
|
require 'thread'
|
3
5
|
require 'timeout'
|
@@ -9,14 +11,285 @@ module RethinkDB
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
14
|
+
class EM_Guard
|
15
|
+
@@mutex = Mutex.new
|
16
|
+
@@registered = false
|
17
|
+
@@conns = Set.new
|
18
|
+
def self.register(conn)
|
19
|
+
@@mutex.synchronize {
|
20
|
+
if !@@registered
|
21
|
+
@@registered = true
|
22
|
+
EM.add_shutdown_hook {
|
23
|
+
EM_Guard.remove_em_waiters
|
24
|
+
}
|
25
|
+
end
|
26
|
+
@@conns += [conn]
|
27
|
+
}
|
28
|
+
end
|
29
|
+
def self.unregister(conn)
|
30
|
+
@@mutex.synchronize {
|
31
|
+
@@conns -= [conn]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
def self.remove_em_waiters
|
35
|
+
old_conns = Set.new
|
36
|
+
@@mutex.synchronize {
|
37
|
+
@@registered = false
|
38
|
+
@@conns, old_conns = old_conns, @@conns
|
39
|
+
}
|
40
|
+
# This function acquires `@mon` on the connections, so it's
|
41
|
+
# safer to do this outside our own synchronization.
|
42
|
+
old_conns.each {|conn|
|
43
|
+
conn.remove_em_waiters
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Handler
|
49
|
+
def initialize
|
50
|
+
@stopped = false
|
51
|
+
end
|
52
|
+
def handle(m, args, caller)
|
53
|
+
if !stopped?
|
54
|
+
if method(m).arity == args.size
|
55
|
+
send(m, *args)
|
56
|
+
else
|
57
|
+
send(m, *args, caller)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_open(caller)
|
63
|
+
end
|
64
|
+
def on_close(caller)
|
65
|
+
end
|
66
|
+
def on_wait_complete(caller)
|
67
|
+
end
|
68
|
+
|
69
|
+
def on_error(err, caller)
|
70
|
+
raise err
|
71
|
+
end
|
72
|
+
def on_val(val, caller)
|
73
|
+
end
|
74
|
+
def on_array(arr, caller)
|
75
|
+
if method(:on_atom).owner != Handler
|
76
|
+
handle(:on_atom, [arr], caller)
|
77
|
+
else
|
78
|
+
arr.each {|x|
|
79
|
+
break if stopped?
|
80
|
+
handle(:on_stream_val, [x], caller)
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
def on_atom(val, caller)
|
85
|
+
handle(:on_val, [val], caller)
|
86
|
+
end
|
87
|
+
def on_stream_val(val, caller)
|
88
|
+
handle(:on_val, [val], caller)
|
89
|
+
end
|
90
|
+
|
91
|
+
def on_unhandled_change(val, caller)
|
92
|
+
handle(:on_stream_val, [val], caller)
|
93
|
+
end
|
94
|
+
|
95
|
+
def stop
|
96
|
+
@stopped = true
|
97
|
+
end
|
98
|
+
def stopped?
|
99
|
+
@stopped
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class CallbackHandler < Handler
|
104
|
+
def initialize(callback)
|
105
|
+
if callback.arity > 2 || callback.arity < -3
|
106
|
+
raise ArgumentError, "Wrong number of arguments for callback (callback " +
|
107
|
+
"accepts #{callback.arity} arguments, but it should accept 0, 1 or 2)."
|
108
|
+
end
|
109
|
+
@callback = callback
|
110
|
+
end
|
111
|
+
def do_call(err, val)
|
112
|
+
if @callback.arity == 0
|
113
|
+
raise err if err
|
114
|
+
@callback.call
|
115
|
+
elsif @callback.arity == 1
|
116
|
+
raise err if err
|
117
|
+
@callback.call(val)
|
118
|
+
else
|
119
|
+
@callback.call(err, val)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
def on_val(x)
|
123
|
+
do_call(nil, x)
|
124
|
+
end
|
125
|
+
def on_error(err)
|
126
|
+
do_call(err, nil)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class QueryHandle
|
131
|
+
def initialize(handler, msg, all_opts, token, conn)
|
132
|
+
@handler = handler
|
133
|
+
@msg = msg
|
134
|
+
@all_opts = all_opts
|
135
|
+
@token = token
|
136
|
+
@conn = conn
|
137
|
+
@opened = false
|
138
|
+
@closed = false
|
139
|
+
end
|
140
|
+
def closed?
|
141
|
+
@closed
|
142
|
+
end
|
143
|
+
def close
|
144
|
+
if !@closed
|
145
|
+
handle_close
|
146
|
+
return @conn.stop(@token)
|
147
|
+
end
|
148
|
+
return false
|
149
|
+
end
|
150
|
+
def handle(m, *args)
|
151
|
+
@handler.handle(m, args, self)
|
152
|
+
end
|
153
|
+
def handle_open
|
154
|
+
if !@opened
|
155
|
+
@opened = true
|
156
|
+
handle(:on_open)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
def handle_close
|
160
|
+
if !@closed
|
161
|
+
@closed = true
|
162
|
+
handle(:on_close)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
def safe_next_tick(&b)
|
166
|
+
EM.next_tick {
|
167
|
+
b.call if !@closed
|
168
|
+
}
|
169
|
+
end
|
170
|
+
def callback(res)
|
171
|
+
begin
|
172
|
+
if @handler.stopped? || !EM.reactor_running?
|
173
|
+
@closed = true
|
174
|
+
@conn.stop(@token)
|
175
|
+
return
|
176
|
+
elsif res
|
177
|
+
is_cfeed = (res['n'] & [Response::ResponseNote::SEQUENCE_FEED,
|
178
|
+
Response::ResponseNote::ATOM_FEED,
|
179
|
+
Response::ResponseNote::ORDER_BY_LIMIT_FEED,
|
180
|
+
Response::ResponseNote::UNIONED_FEED]) != []
|
181
|
+
if (res['t'] == Response::ResponseType::SUCCESS_PARTIAL) ||
|
182
|
+
(res['t'] == Response::ResponseType::SUCCESS_SEQUENCE)
|
183
|
+
safe_next_tick {
|
184
|
+
handle_open
|
185
|
+
if res['t'] == Response::ResponseType::SUCCESS_PARTIAL
|
186
|
+
@conn.register_query(@token, @all_opts, self) if !@conn.closed?
|
187
|
+
@conn.dispatch([Query::QueryType::CONTINUE], @token) if !@conn.closed?
|
188
|
+
end
|
189
|
+
Shim.response_to_native(res, @msg, @all_opts).each {|row|
|
190
|
+
if is_cfeed
|
191
|
+
if (row.has_key?('new_val') && row.has_key?('old_val') &&
|
192
|
+
@handler.respond_to?(:on_change))
|
193
|
+
handle(:on_change, row['old_val'], row['new_val'])
|
194
|
+
elsif (row.has_key?('new_val') && !row.has_key?('old_val') &&
|
195
|
+
@handler.respond_to?(:on_initial_val))
|
196
|
+
handle(:on_initial_val, row['new_val'])
|
197
|
+
elsif row.has_key?('error') && @handler.respond_to?(:on_change_error)
|
198
|
+
handle(:on_change_error, row['error'])
|
199
|
+
elsif row.has_key?('state') && @handler.respond_to?(:on_state)
|
200
|
+
handle(:on_state, row['state'])
|
201
|
+
else
|
202
|
+
handle(:on_unhandled_change, row)
|
203
|
+
end
|
204
|
+
else
|
205
|
+
handle(:on_stream_val, row)
|
206
|
+
end
|
207
|
+
}
|
208
|
+
if (res['t'] == Response::ResponseType::SUCCESS_SEQUENCE ||
|
209
|
+
@conn.closed?)
|
210
|
+
handle_close
|
211
|
+
end
|
212
|
+
}
|
213
|
+
elsif res['t'] == Response::ResponseType::SUCCESS_ATOM
|
214
|
+
safe_next_tick {
|
215
|
+
return if @closed
|
216
|
+
handle_open
|
217
|
+
val = Shim.response_to_native(res, @msg, @all_opts)
|
218
|
+
if val.is_a?(Array)
|
219
|
+
handle(:on_array, val)
|
220
|
+
else
|
221
|
+
handle(:on_atom, val)
|
222
|
+
end
|
223
|
+
handle_close
|
224
|
+
}
|
225
|
+
elsif res['t'] == Response::ResponseType::WAIT_COMPLETE
|
226
|
+
safe_next_tick {
|
227
|
+
return if @closed
|
228
|
+
handle_open
|
229
|
+
handle(:on_wait_complete)
|
230
|
+
handle_close
|
231
|
+
}
|
232
|
+
else
|
233
|
+
exc = nil
|
234
|
+
begin
|
235
|
+
exc = Shim.response_to_native(res, @msg, @all_opts)
|
236
|
+
rescue Exception => e
|
237
|
+
exc = e
|
238
|
+
end
|
239
|
+
safe_next_tick {
|
240
|
+
return if @closed
|
241
|
+
handle_open
|
242
|
+
handle(:on_error, e)
|
243
|
+
handle_close
|
244
|
+
}
|
245
|
+
end
|
246
|
+
else
|
247
|
+
safe_next_tick {
|
248
|
+
return if @closed
|
249
|
+
handle_close
|
250
|
+
}
|
251
|
+
end
|
252
|
+
rescue Exception => e
|
253
|
+
safe_next_tick {
|
254
|
+
return if @closed
|
255
|
+
handle_open
|
256
|
+
handle(:on_error, e)
|
257
|
+
handle_close
|
258
|
+
}
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
12
263
|
class RQL
|
13
264
|
@@default_conn = nil
|
14
265
|
def self.set_default_conn c; @@default_conn = c; end
|
15
|
-
def
|
16
|
-
|
17
|
-
|
266
|
+
def parse(*args, &b)
|
267
|
+
conn = nil
|
268
|
+
opts = nil
|
269
|
+
block = nil
|
270
|
+
args = args.map{|x| x.is_a?(Class) ? x.new : x}
|
271
|
+
args.each {|arg|
|
272
|
+
case arg
|
273
|
+
when RethinkDB::Connection
|
274
|
+
raise ArgumentError, "Unexpected second Connection #{arg.inspect}." if conn
|
275
|
+
conn = arg
|
276
|
+
when Hash
|
277
|
+
raise ArgumentError, "Unexpected second Hash #{arg.inspect}." if opts
|
278
|
+
opts = arg
|
279
|
+
when Proc
|
280
|
+
raise ArgumentError, "Unexpected second callback #{arg.inspect}." if block
|
281
|
+
block = arg
|
282
|
+
when Handler
|
283
|
+
raise ArgumentError, "Unexpected second callback #{arg.inspect}." if block
|
284
|
+
block = arg
|
285
|
+
else
|
286
|
+
raise ArgumentError, "Unexpected argument #{arg.inspect} " +
|
287
|
+
"(got #{args.inspect})."
|
288
|
+
end
|
289
|
+
}
|
290
|
+
conn = @@default_conn if !conn
|
18
291
|
opts = {} if !opts
|
19
|
-
|
292
|
+
block = b if !block
|
20
293
|
if (tf = opts[:time_format])
|
21
294
|
opts[:time_format] = (tf = tf.to_s)
|
22
295
|
if tf != 'raw' && tf != 'native'
|
@@ -35,11 +308,37 @@ module RethinkDB
|
|
35
308
|
raise ArgumentError, "`binary_format` must be 'raw' or 'native' (got `#{bf}`)."
|
36
309
|
end
|
37
310
|
end
|
38
|
-
if !
|
311
|
+
if !conn
|
39
312
|
raise ArgumentError, "No connection specified!\n" \
|
40
313
|
"Use `query.run(conn)` or `conn.repl(); query.run`."
|
41
314
|
end
|
42
|
-
|
315
|
+
{conn: conn, opts: opts, block: block}
|
316
|
+
end
|
317
|
+
def run(*args, &b)
|
318
|
+
unbound_if(@body == RQL)
|
319
|
+
args = parse(*args, &b)
|
320
|
+
args[:conn].run(@body, args[:opts], args[:block])
|
321
|
+
end
|
322
|
+
def em_run(*args, &b)
|
323
|
+
if !EM.reactor_running?
|
324
|
+
raise RuntimeError, "RethinkDB::RQL::em_run can only be called inside `EM.run`"
|
325
|
+
end
|
326
|
+
unbound_if(@body == RQL)
|
327
|
+
args = parse(*args, &b)
|
328
|
+
if args[:block].is_a?(Proc)
|
329
|
+
args[:block] = CallbackHandler.new(args[:block])
|
330
|
+
end
|
331
|
+
if !args[:block].is_a?(Handler)
|
332
|
+
raise ArgumentError, "No handler specified."
|
333
|
+
end
|
334
|
+
|
335
|
+
# If the user has defined the `on_state` method, we assume they want states.
|
336
|
+
if args[:block].respond_to?(:on_state)
|
337
|
+
args[:opts] = args[:opts].merge(include_states: true)
|
338
|
+
end
|
339
|
+
|
340
|
+
EM_Guard.register(args[:conn])
|
341
|
+
args[:conn].run(@body, args[:opts], args[:block])
|
43
342
|
end
|
44
343
|
end
|
45
344
|
|
@@ -57,11 +356,11 @@ module RethinkDB
|
|
57
356
|
preview = preview_res.pretty_inspect[0...-1]
|
58
357
|
state = @run ? "(exhausted)" : "(enumerable)"
|
59
358
|
extra = out_of_date ? " (Connection #{@conn.inspect} is closed.)" : ""
|
60
|
-
"#<RethinkDB::Cursor:#{
|
359
|
+
"#<RethinkDB::Cursor:#{object_id} #{state}#{extra}: #{RPP.pp(@msg)}" +
|
61
360
|
(@run ? "" : "\n#{preview}") + ">"
|
62
361
|
end
|
63
362
|
|
64
|
-
def initialize(results, msg, connection, opts, token, more
|
363
|
+
def initialize(results, msg, connection, opts, token, more) # :nodoc:
|
65
364
|
@more = more
|
66
365
|
@results = results
|
67
366
|
@msg = msg
|
@@ -73,43 +372,64 @@ module RethinkDB
|
|
73
372
|
fetch_batch
|
74
373
|
end
|
75
374
|
|
76
|
-
def each
|
375
|
+
def each(&block) # :nodoc:
|
77
376
|
raise RqlRuntimeError, "Can only iterate over a cursor once." if @run
|
78
|
-
return
|
377
|
+
return enum_for(:each) if !block
|
79
378
|
@run = true
|
80
379
|
while true
|
81
380
|
@results.each(&block)
|
82
381
|
return self if !@more
|
83
382
|
raise RqlRuntimeError, "Connection is closed." if @more && out_of_date
|
84
|
-
|
383
|
+
wait_for_batch(nil)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def close
|
388
|
+
if @more
|
389
|
+
@more = false
|
390
|
+
@conn.stop(@token)
|
391
|
+
return true
|
392
|
+
end
|
393
|
+
return false
|
394
|
+
end
|
395
|
+
|
396
|
+
def wait_for_batch(timeout)
|
397
|
+
res = @conn.wait(@token, timeout)
|
85
398
|
@results = Shim.response_to_native(res, @msg, @opts)
|
86
399
|
if res['t'] == Response::ResponseType::SUCCESS_SEQUENCE
|
87
400
|
@more = false
|
88
401
|
else
|
89
402
|
fetch_batch
|
90
403
|
end
|
91
|
-
end
|
92
404
|
end
|
93
405
|
|
94
|
-
def
|
406
|
+
def fetch_batch
|
95
407
|
if @more
|
96
|
-
@
|
97
|
-
@conn.
|
98
|
-
q = [Query::QueryType::STOP]
|
99
|
-
res = @conn.run_internal(q, @opts, @token)
|
100
|
-
if ((res['t'] != Response::ResponseType::SUCCESS_SEQUENCE &&
|
101
|
-
res['t'] != Response::ResponseType::SUCCESS_FEED &&
|
102
|
-
res['t'] != Response::ResponseType::SUCCESS_ATOM_FEED) ||
|
103
|
-
res['r'] != [])
|
104
|
-
raise RqlRuntimeError, "Server sent malformed STOP response #{PP.pp(res, "")}"
|
105
|
-
end
|
106
|
-
return true
|
408
|
+
@conn.register_query(@token, @opts)
|
409
|
+
@conn.dispatch([Query::QueryType::CONTINUE], @token)
|
107
410
|
end
|
108
411
|
end
|
109
412
|
|
110
|
-
def
|
111
|
-
|
112
|
-
|
413
|
+
def next(wait=true)
|
414
|
+
if @run
|
415
|
+
raise RqlRuntimeError, "Cannot call `next` on a cursor after calling `each`."
|
416
|
+
end
|
417
|
+
if @more && out_of_date
|
418
|
+
raise RqlRuntimeError, "Connection is closed."
|
419
|
+
end
|
420
|
+
timeout = wait
|
421
|
+
if wait == true
|
422
|
+
timeout = nil
|
423
|
+
elsif !wait
|
424
|
+
timeout = 0
|
425
|
+
end
|
426
|
+
|
427
|
+
while @results.length == 0
|
428
|
+
raise StopIteration if !@more
|
429
|
+
wait_for_batch(timeout)
|
430
|
+
end
|
431
|
+
|
432
|
+
@results.shift
|
113
433
|
end
|
114
434
|
end
|
115
435
|
|
@@ -127,11 +447,14 @@ module RethinkDB
|
|
127
447
|
@abort_module = Faux_Abort
|
128
448
|
end
|
129
449
|
|
130
|
-
opts = {
|
450
|
+
opts = Hash[opts.map{|(k,v)| [k.to_sym,v]}] if opts.is_a?(Hash)
|
451
|
+
opts = {:host => opts} if opts.is_a?(String)
|
131
452
|
@host = opts[:host] || "localhost"
|
132
|
-
@port = opts[:port] || 28015
|
453
|
+
@port = (opts[:port] || 28015).to_i
|
133
454
|
@default_db = opts[:db]
|
134
455
|
@auth_key = opts[:auth_key] || ""
|
456
|
+
@timeout = opts[:timeout].to_i
|
457
|
+
@timeout = 20 if @timeout <= 0
|
135
458
|
|
136
459
|
@@last = self
|
137
460
|
@default_opts = @default_db ? {:db => RQL.new.db(@default_db)} : {}
|
@@ -140,7 +463,7 @@ module RethinkDB
|
|
140
463
|
@token_cnt = 0
|
141
464
|
@token_cnt_mutex = Mutex.new
|
142
465
|
|
143
|
-
|
466
|
+
connect()
|
144
467
|
end
|
145
468
|
attr_reader :host, :port, :default_db, :conn_id
|
146
469
|
|
@@ -148,12 +471,13 @@ module RethinkDB
|
|
148
471
|
@token_cnt_mutex.synchronize{@token_cnt += 1}
|
149
472
|
end
|
150
473
|
|
151
|
-
def register_query(token, opts)
|
474
|
+
def register_query(token, opts, callback=nil)
|
152
475
|
if !opts[:noreply]
|
153
|
-
@
|
154
|
-
|
155
|
-
|
156
|
-
|
476
|
+
@mon.synchronize {
|
477
|
+
if @waiters.has_key?(token)
|
478
|
+
raise RqlDriverError, "Internal driver error, token already in use."
|
479
|
+
end
|
480
|
+
@waiters[token] = callback ? callback : @mon.new_cond
|
157
481
|
@opts[token] = opts
|
158
482
|
}
|
159
483
|
end
|
@@ -161,11 +485,17 @@ module RethinkDB
|
|
161
485
|
def run_internal(q, opts, token)
|
162
486
|
register_query(token, opts)
|
163
487
|
dispatch(q, token)
|
164
|
-
opts[:noreply] ? nil : wait(token)
|
488
|
+
opts[:noreply] ? nil : wait(token, nil)
|
489
|
+
end
|
490
|
+
def stop(token)
|
491
|
+
dispatch([Query::QueryType::STOP], token)
|
492
|
+
@mon.synchronize {
|
493
|
+
!!@waiters.delete(token)
|
494
|
+
}
|
165
495
|
end
|
166
|
-
def run(msg, opts,
|
167
|
-
reconnect(:noreply_wait => false) if @auto_reconnect && !
|
168
|
-
raise RqlRuntimeError, "Connection is closed." if !
|
496
|
+
def run(msg, opts, b)
|
497
|
+
reconnect(:noreply_wait => false) if @auto_reconnect && !is_open()
|
498
|
+
raise RqlRuntimeError, "Connection is closed." if !is_open()
|
169
499
|
|
170
500
|
global_optargs = {}
|
171
501
|
all_opts = @default_opts.merge(opts)
|
@@ -177,40 +507,45 @@ module RethinkDB
|
|
177
507
|
q = [Query::QueryType::START,
|
178
508
|
msg,
|
179
509
|
Hash[all_opts.map {|k,v|
|
180
|
-
[k.to_s, (v.
|
510
|
+
[k.to_s, (v.is_a?(RQL) ? v.to_pb : RQL.new.expr(v).to_pb)]
|
181
511
|
}]]
|
182
512
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
value = Cursor.new(Shim.response_to_native(res, msg, opts),
|
189
|
-
msg, self, opts, token, true)
|
190
|
-
elsif res['t'] == Response::ResponseType::SUCCESS_SEQUENCE
|
191
|
-
value = Cursor.new(Shim.response_to_native(res, msg, opts),
|
192
|
-
msg, self, opts, token, false)
|
513
|
+
if b.is_a? Handler
|
514
|
+
callback = QueryHandle.new(b, msg, all_opts, token, self)
|
515
|
+
register_query(token, all_opts, callback)
|
516
|
+
dispatch(q, token)
|
517
|
+
return callback
|
193
518
|
else
|
194
|
-
|
195
|
-
|
519
|
+
res = run_internal(q, all_opts, token)
|
520
|
+
return res if !res
|
521
|
+
if res['t'] == Response::ResponseType::SUCCESS_PARTIAL
|
522
|
+
value = Cursor.new(Shim.response_to_native(res, msg, opts),
|
523
|
+
msg, self, opts, token, true)
|
524
|
+
elsif res['t'] == Response::ResponseType::SUCCESS_SEQUENCE
|
525
|
+
value = Cursor.new(Shim.response_to_native(res, msg, opts),
|
526
|
+
msg, self, opts, token, false)
|
527
|
+
else
|
528
|
+
value = Shim.response_to_native(res, msg, opts)
|
529
|
+
end
|
196
530
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
531
|
+
if res['p']
|
532
|
+
real_val = {
|
533
|
+
"profile" => res['p'],
|
534
|
+
"value" => value
|
535
|
+
}
|
536
|
+
else
|
537
|
+
real_val = value
|
538
|
+
end
|
205
539
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
540
|
+
if b
|
541
|
+
begin
|
542
|
+
b.call(real_val)
|
543
|
+
ensure
|
544
|
+
value.close if value.is_a?(Cursor)
|
545
|
+
end
|
546
|
+
else
|
547
|
+
real_val
|
211
548
|
end
|
212
|
-
else
|
213
|
-
real_val
|
214
549
|
end
|
215
550
|
end
|
216
551
|
|
@@ -232,21 +567,38 @@ module RethinkDB
|
|
232
567
|
return token
|
233
568
|
end
|
234
569
|
|
235
|
-
def wait(token)
|
570
|
+
def wait(token, timeout)
|
236
571
|
begin
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
res = @data.delete(token)
|
241
|
-
if res == nil
|
242
|
-
@waiters[token].wait(@listener_mutex)
|
572
|
+
@mon.synchronize {
|
573
|
+
end_time = timeout ? Time.now.to_f + timeout : nil
|
574
|
+
loop {
|
243
575
|
res = @data.delete(token)
|
244
|
-
|
245
|
-
|
576
|
+
return res if res
|
577
|
+
|
578
|
+
# Theoretically we only need to check the second property,
|
579
|
+
# but this is safer in case someone makes changes to
|
580
|
+
# `close` in the future.
|
581
|
+
if !is_open() || !@waiters.has_key?(token)
|
582
|
+
raise RqlRuntimeError, "Connection is closed."
|
583
|
+
end
|
584
|
+
|
585
|
+
if end_time
|
586
|
+
cur_time = Time.now.to_f
|
587
|
+
if cur_time >= end_time
|
588
|
+
raise Timeout::Error, "Timed out waiting for cursor response."
|
589
|
+
else
|
590
|
+
# We can't use `wait_while` because it doesn't take a
|
591
|
+
# timeout, and we can't use an external `timeout {
|
592
|
+
# ... }` block because in Ruby 1.9.1 it seems to confuse
|
593
|
+
# the synchronization in `@mon` to be timed out while
|
594
|
+
# waiting in a synchronize block.
|
595
|
+
@waiters[token].wait(end_time - cur_time)
|
596
|
+
end
|
597
|
+
else
|
598
|
+
@waiters[token].wait
|
599
|
+
end
|
600
|
+
}
|
246
601
|
}
|
247
|
-
raise RqlRuntimeError, "Connection is closed." if res.nil? && !self.is_open()
|
248
|
-
raise RqlDriverError, "Internal driver error, no response found." if res.nil?
|
249
|
-
return res
|
250
602
|
rescue @abort_module::Abort => e
|
251
603
|
print "\nAborting query and reconnecting...\n"
|
252
604
|
reconnect(:noreply_wait => false)
|
@@ -263,12 +615,12 @@ module RethinkDB
|
|
263
615
|
def inspect
|
264
616
|
db = @default_opts[:db] || RQL.new.db('test')
|
265
617
|
properties = "(#{@host}:#{@port}) (Default DB: #{db.inspect})"
|
266
|
-
state =
|
267
|
-
"#<RethinkDB::Connection:#{
|
618
|
+
state = is_open() ? "(open)" : "(closed)"
|
619
|
+
"#<RethinkDB::Connection:#{object_id} #{properties} #{state}>"
|
268
620
|
end
|
269
621
|
|
270
622
|
@@last = nil
|
271
|
-
@@magic_number = VersionDummy::Version::
|
623
|
+
@@magic_number = VersionDummy::Version::V0_4
|
272
624
|
@@wire_protocol = VersionDummy::Protocol::JSON
|
273
625
|
|
274
626
|
def debug_socket; @socket; end
|
@@ -278,14 +630,15 @@ module RethinkDB
|
|
278
630
|
# enumerables on the client.
|
279
631
|
def reconnect(opts={})
|
280
632
|
raise ArgumentError, "Argument to reconnect must be a hash." if opts.class != Hash
|
281
|
-
|
282
|
-
|
633
|
+
close(opts)
|
634
|
+
connect()
|
283
635
|
end
|
284
636
|
|
285
637
|
def connect()
|
286
638
|
raise RuntimeError, "Connection must be closed before calling connect." if @socket
|
287
639
|
@socket = TCPSocket.open(@host, @port)
|
288
|
-
@
|
640
|
+
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
641
|
+
@mon = Monitor.new
|
289
642
|
@waiters = {}
|
290
643
|
@opts = {}
|
291
644
|
@data = {}
|
@@ -294,11 +647,15 @@ module RethinkDB
|
|
294
647
|
self
|
295
648
|
end
|
296
649
|
|
297
|
-
def is_open
|
650
|
+
def is_open
|
298
651
|
@socket && @listener
|
299
652
|
end
|
653
|
+
def closed?
|
654
|
+
!is_open
|
655
|
+
end
|
300
656
|
|
301
657
|
def close(opts={})
|
658
|
+
EM_Guard.unregister(self)
|
302
659
|
raise ArgumentError, "Argument to close must be a hash." if opts.class != Hash
|
303
660
|
if !(opts.keys - [:noreply_wait]).empty?
|
304
661
|
raise ArgumentError, "close does not understand these options: " +
|
@@ -306,7 +663,22 @@ module RethinkDB
|
|
306
663
|
end
|
307
664
|
opts[:noreply_wait] = true if !opts.keys.include?(:noreply_wait)
|
308
665
|
|
309
|
-
|
666
|
+
@mon.synchronize {
|
667
|
+
@opts.clear
|
668
|
+
@data.clear
|
669
|
+
@waiters.each {|k,v|
|
670
|
+
case v
|
671
|
+
when QueryHandle
|
672
|
+
v.handle_close
|
673
|
+
when MonitorMixin::ConditionVariable
|
674
|
+
@waiters[k] = nil
|
675
|
+
v.signal
|
676
|
+
end
|
677
|
+
}
|
678
|
+
@waiters.clear
|
679
|
+
}
|
680
|
+
|
681
|
+
noreply_wait() if opts[:noreply_wait] && is_open()
|
310
682
|
if @listener
|
311
683
|
@listener.terminate
|
312
684
|
@listener.join
|
@@ -314,17 +686,11 @@ module RethinkDB
|
|
314
686
|
@socket.close if @socket
|
315
687
|
@listener = nil
|
316
688
|
@socket = nil
|
317
|
-
@listener_mutex.synchronize {
|
318
|
-
@opts.clear
|
319
|
-
@data.clear
|
320
|
-
@waiters.values.each{ |w| w.signal }
|
321
|
-
@waiters.clear
|
322
|
-
}
|
323
689
|
self
|
324
690
|
end
|
325
691
|
|
326
692
|
def noreply_wait
|
327
|
-
raise RqlRuntimeError, "Connection is closed." if !
|
693
|
+
raise RqlRuntimeError, "Connection is closed." if !is_open()
|
328
694
|
q = [Query::QueryType::NOREPLY_WAIT]
|
329
695
|
res = run_internal(q, {noreply: false}, new_token)
|
330
696
|
if res['t'] != Response::ResponseType::WAIT_COMPLETE
|
@@ -338,12 +704,31 @@ module RethinkDB
|
|
338
704
|
raise RqlRuntimeError, "No last connection. Use RethinkDB::Connection.new."
|
339
705
|
end
|
340
706
|
|
707
|
+
def remove_em_waiters
|
708
|
+
@mon.synchronize {
|
709
|
+
@waiters.each {|k,v|
|
710
|
+
if v.is_a? QueryHandle
|
711
|
+
v.handle_close
|
712
|
+
@waiters.delete(k)
|
713
|
+
end
|
714
|
+
}
|
715
|
+
}
|
716
|
+
end
|
717
|
+
|
341
718
|
def note_data(token, data) # Synchronize around this!
|
342
|
-
raise RqlDriverError, "Unknown token in response." if !@waiters.has_key?(token)
|
343
|
-
@data[token] = data
|
344
719
|
@opts.delete(token)
|
345
|
-
w = @waiters
|
346
|
-
|
720
|
+
w = @waiters.delete(token)
|
721
|
+
case w
|
722
|
+
when MonitorMixin::ConditionVariable
|
723
|
+
@data[token] = data
|
724
|
+
w.signal
|
725
|
+
when QueryHandle
|
726
|
+
w.callback(data)
|
727
|
+
when nil
|
728
|
+
# nothing
|
729
|
+
else
|
730
|
+
raise RqlDriverError, "Unrecognized value #{w.inspect} in `@waiters`."
|
731
|
+
end
|
347
732
|
end
|
348
733
|
|
349
734
|
def note_error(token, e) # Synchronize around this!
|
@@ -374,15 +759,16 @@ module RethinkDB
|
|
374
759
|
@auth_key + [@@wire_protocol].pack('L<'))
|
375
760
|
response = ""
|
376
761
|
while response[-1..-1] != "\0"
|
377
|
-
response += @socket.read_exn(1,
|
762
|
+
response += @socket.read_exn(1, @timeout)
|
378
763
|
end
|
379
764
|
response = response[0...-1]
|
380
765
|
if response != "SUCCESS"
|
381
766
|
raise RqlRuntimeError, "Server dropped connection with message: \"#{response}\""
|
382
767
|
end
|
383
768
|
|
384
|
-
|
385
|
-
|
769
|
+
if @listener
|
770
|
+
raise RqlDriverError, "Internal driver error, listener already started."
|
771
|
+
end
|
386
772
|
@listener = Thread.new {
|
387
773
|
while true
|
388
774
|
begin
|
@@ -396,9 +782,9 @@ module RethinkDB
|
|
396
782
|
raise RqlRuntimeError, "Bad response, server is buggy.\n" +
|
397
783
|
"#{e.inspect}\n" + response
|
398
784
|
end
|
399
|
-
@
|
785
|
+
@mon.synchronize{note_data(token, data)}
|
400
786
|
rescue Exception => e
|
401
|
-
@
|
787
|
+
@mon.synchronize {
|
402
788
|
@waiters.keys.each{ |k| note_error(k, e) }
|
403
789
|
@listener = nil
|
404
790
|
Thread.current.terminate
|
data/lib/ql2.pb.rb
CHANGED
@@ -7,6 +7,7 @@ module RethinkDB
|
|
7
7
|
V0_1 = 1063369270
|
8
8
|
V0_2 = 1915781601
|
9
9
|
V0_3 = 1601562686
|
10
|
+
V0_4 = 1074539808
|
10
11
|
end
|
11
12
|
|
12
13
|
module Protocol
|
@@ -42,13 +43,19 @@ module RethinkDB
|
|
42
43
|
SUCCESS_ATOM = 1
|
43
44
|
SUCCESS_SEQUENCE = 2
|
44
45
|
SUCCESS_PARTIAL = 3
|
45
|
-
SUCCESS_FEED = 5
|
46
46
|
WAIT_COMPLETE = 4
|
47
|
-
SUCCESS_ATOM_FEED = 6
|
48
47
|
CLIENT_ERROR = 16
|
49
48
|
COMPILE_ERROR = 17
|
50
49
|
RUNTIME_ERROR = 18
|
51
50
|
end
|
51
|
+
|
52
|
+
module ResponseNote
|
53
|
+
SEQUENCE_FEED = 1
|
54
|
+
ATOM_FEED = 2
|
55
|
+
ORDER_BY_LIMIT_FEED = 3
|
56
|
+
UNIONED_FEED = 4
|
57
|
+
INCLUDES_STATES = 5
|
58
|
+
end
|
52
59
|
end
|
53
60
|
|
54
61
|
module Datum
|
@@ -103,7 +110,7 @@ module RethinkDB
|
|
103
110
|
SLICE = 30
|
104
111
|
SKIP = 70
|
105
112
|
LIMIT = 71
|
106
|
-
|
113
|
+
OFFSETS_OF = 87
|
107
114
|
CONTAINS = 93
|
108
115
|
GET_FIELD = 31
|
109
116
|
KEYS = 94
|
@@ -113,7 +120,8 @@ module RethinkDB
|
|
113
120
|
PLUCK = 33
|
114
121
|
WITHOUT = 34
|
115
122
|
MERGE = 35
|
116
|
-
|
123
|
+
BETWEEN_DEPRECATED = 36
|
124
|
+
BETWEEN = 182
|
117
125
|
REDUCE = 37
|
118
126
|
MAP = 38
|
119
127
|
FILTER = 39
|
@@ -160,8 +168,8 @@ module RethinkDB
|
|
160
168
|
INDEX_RENAME = 156
|
161
169
|
FUNCALL = 64
|
162
170
|
BRANCH = 65
|
163
|
-
|
164
|
-
|
171
|
+
OR = 66
|
172
|
+
AND = 67
|
165
173
|
FOR_EACH = 68
|
166
174
|
FUNC = 69
|
167
175
|
ASC = 73
|
@@ -237,6 +245,8 @@ module RethinkDB
|
|
237
245
|
FILL = 167
|
238
246
|
GET_NEAREST = 168
|
239
247
|
POLYGON_SUB = 171
|
248
|
+
MINVAL = 180
|
249
|
+
MAXVAL = 181
|
240
250
|
end
|
241
251
|
|
242
252
|
module AssocPair
|
data/lib/rpp.rb
CHANGED
@@ -102,18 +102,19 @@ module RethinkDB
|
|
102
102
|
args[0][0] != Term::TermType::DB)
|
103
103
|
return false
|
104
104
|
else
|
105
|
-
return !["db", "db_create", "db_drop", "json", "funcall",
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
return !["db", "db_create", "db_drop", "json", "funcall",
|
106
|
+
"args", "branch", "http", "binary", "javascript", "random",
|
107
|
+
"time", "iso8601", "epoch_time", "now", "geojson", "point",
|
108
|
+
"circle", "line", "polygon", "asc", "desc", "literal",
|
109
|
+
"range", "error"].include?(name)
|
109
110
|
end
|
110
111
|
end
|
111
112
|
def self.pp_int(q, term, bt, pre_dot=false)
|
112
113
|
q.text("\x7", 0) if bt == []
|
113
114
|
|
114
|
-
term = term.to_pb if term.
|
115
|
+
term = term.to_pb if term.is_a?(RQL)
|
115
116
|
if term.class != Array
|
116
|
-
if term.
|
117
|
+
if term.is_a?(Hash)
|
117
118
|
if not pp_pseudotype(q, term, bt)
|
118
119
|
pp_int_optargs(q, term, bt, pre_dot)
|
119
120
|
end
|
@@ -178,7 +179,7 @@ module RethinkDB
|
|
178
179
|
q.text("r")
|
179
180
|
arg_offset = 0
|
180
181
|
end
|
181
|
-
if name == "
|
182
|
+
if name == "bracket"
|
182
183
|
argstart, argstop = "[", "]"
|
183
184
|
else
|
184
185
|
q.text(".")
|
@@ -186,7 +187,7 @@ module RethinkDB
|
|
186
187
|
argstart, argstop = "(", ")"
|
187
188
|
end
|
188
189
|
|
189
|
-
if args[-1] && args[-1].
|
190
|
+
if args[-1] && args[-1].is_a?(Array) && args[-1][0] == Term::TermType::FUNC
|
190
191
|
func_bt = bt_consume(bt, args.size() - 1 + arg_offset)
|
191
192
|
func = args.pop
|
192
193
|
end
|
data/lib/shim.rb
CHANGED
@@ -60,8 +60,6 @@ module RethinkDB
|
|
60
60
|
begin
|
61
61
|
case r['t']
|
62
62
|
when rt::SUCCESS_ATOM then r['r'][0]
|
63
|
-
when rt::SUCCESS_FEED then r['r']
|
64
|
-
when rt::SUCCESS_ATOM_FEED then r['r']
|
65
63
|
when rt::SUCCESS_PARTIAL then r['r']
|
66
64
|
when rt::SUCCESS_SEQUENCE then r['r']
|
67
65
|
when rt::RUNTIME_ERROR then raise RqlRuntimeError, r['r'][0]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rethinkdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RethinkDB Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|