rethinkdb 1.16.0.1 → 2.0.0.1
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.
- 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
|