libcouchbase-mapo 1.4.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 +7 -0
- data/.gitignore +20 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/.travis.yml +38 -0
- data/Gemfile +4 -0
- data/LICENSE +24 -0
- data/README.md +445 -0
- data/Rakefile +76 -0
- data/ext/README.md +6 -0
- data/ext/Rakefile +19 -0
- data/lib/libcouchbase.rb +40 -0
- data/lib/libcouchbase/bucket.rb +825 -0
- data/lib/libcouchbase/callbacks.rb +69 -0
- data/lib/libcouchbase/connection.rb +886 -0
- data/lib/libcouchbase/design_docs.rb +92 -0
- data/lib/libcouchbase/error.rb +68 -0
- data/lib/libcouchbase/ext/libcouchbase.rb +1175 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdbase.rb +23 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdcounter.rb +36 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdendure.rb +26 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdfts.rb +24 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdget.rb +30 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdgetreplica.rb +49 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdhttp.rb +58 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdn1ql.rb +40 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdobseqno.rb +33 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdobserve.rb +30 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdstore.rb +40 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdstoredur.rb +45 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +61 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdverbosity.rb +29 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdviewquery.rb +61 -0
- data/lib/libcouchbase/ext/libcouchbase/contigbuf.rb +14 -0
- data/lib/libcouchbase/ext/libcouchbase/create_st.rb +15 -0
- data/lib/libcouchbase/ext/libcouchbase/create_st0.rb +23 -0
- data/lib/libcouchbase/ext/libcouchbase/create_st1.rb +26 -0
- data/lib/libcouchbase/ext/libcouchbase/create_st2.rb +32 -0
- data/lib/libcouchbase/ext/libcouchbase/create_st3.rb +26 -0
- data/lib/libcouchbase/ext/libcouchbase/crst_u.rb +20 -0
- data/lib/libcouchbase/ext/libcouchbase/durability_opts_st_v.rb +11 -0
- data/lib/libcouchbase/ext/libcouchbase/durability_opts_t.rb +14 -0
- data/lib/libcouchbase/ext/libcouchbase/durabilityopt_sv0.rb +63 -0
- data/lib/libcouchbase/ext/libcouchbase/enums.rb +1007 -0
- data/lib/libcouchbase/ext/libcouchbase/fragbuf.rb +18 -0
- data/lib/libcouchbase/ext/libcouchbase/ftshandle.rb +7 -0
- data/lib/libcouchbase/ext/libcouchbase/histogram.rb +34 -0
- data/lib/libcouchbase/ext/libcouchbase/http_request_t.rb +7 -0
- data/lib/libcouchbase/ext/libcouchbase/keybuf.rb +20 -0
- data/lib/libcouchbase/ext/libcouchbase/multicmd_ctx.rb +30 -0
- data/lib/libcouchbase/ext/libcouchbase/mutation_token.rb +17 -0
- data/lib/libcouchbase/ext/libcouchbase/n1qlhandle.rb +7 -0
- data/lib/libcouchbase/ext/libcouchbase/n1qlparams.rb +7 -0
- data/lib/libcouchbase/ext/libcouchbase/respbase.rb +29 -0
- data/lib/libcouchbase/ext/libcouchbase/respcounter.rb +32 -0
- data/lib/libcouchbase/ext/libcouchbase/respendure.rb +49 -0
- data/lib/libcouchbase/ext/libcouchbase/respfts.rb +40 -0
- data/lib/libcouchbase/ext/libcouchbase/respget.rb +44 -0
- data/lib/libcouchbase/ext/libcouchbase/resphttp.rb +48 -0
- data/lib/libcouchbase/ext/libcouchbase/respmcversion.rb +38 -0
- data/lib/libcouchbase/ext/libcouchbase/respn1ql.rb +41 -0
- data/lib/libcouchbase/ext/libcouchbase/respobseqno.rb +52 -0
- data/lib/libcouchbase/ext/libcouchbase/respobserve.rb +41 -0
- data/lib/libcouchbase/ext/libcouchbase/respserverbase.rb +32 -0
- data/lib/libcouchbase/ext/libcouchbase/respstats.rb +38 -0
- data/lib/libcouchbase/ext/libcouchbase/respstore.rb +32 -0
- data/lib/libcouchbase/ext/libcouchbase/respstoredur.rb +38 -0
- data/lib/libcouchbase/ext/libcouchbase/respsubdoc.rb +35 -0
- data/lib/libcouchbase/ext/libcouchbase/respviewquery.rb +67 -0
- data/lib/libcouchbase/ext/libcouchbase/sdentry.rb +22 -0
- data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +31 -0
- data/lib/libcouchbase/ext/libcouchbase/t.rb +7 -0
- data/lib/libcouchbase/ext/libcouchbase/valbuf.rb +22 -0
- data/lib/libcouchbase/ext/libcouchbase/valbuf_u_buf.rb +14 -0
- data/lib/libcouchbase/ext/libcouchbase/viewhandle.rb +7 -0
- data/lib/libcouchbase/ext/libcouchbase_libuv.rb +22 -0
- data/lib/libcouchbase/ext/tasks.rb +39 -0
- data/lib/libcouchbase/n1ql.rb +78 -0
- data/lib/libcouchbase/query_full_text.rb +147 -0
- data/lib/libcouchbase/query_n1ql.rb +123 -0
- data/lib/libcouchbase/query_view.rb +135 -0
- data/lib/libcouchbase/results_fiber.rb +281 -0
- data/lib/libcouchbase/results_native.rb +220 -0
- data/lib/libcouchbase/subdoc_request.rb +139 -0
- data/lib/libcouchbase/version.rb +5 -0
- data/libcouchbase.gemspec +68 -0
- data/spec/bucket_spec.rb +290 -0
- data/spec/connection_spec.rb +257 -0
- data/spec/design_docs_spec.rb +31 -0
- data/spec/error_spec.rb +26 -0
- data/spec/fts_spec.rb +135 -0
- data/spec/n1ql_spec.rb +206 -0
- data/spec/results_libuv_spec.rb +244 -0
- data/spec/results_native_spec.rb +259 -0
- data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/design.json +1 -0
- data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/data-0000.cbb +0 -0
- data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/failover.json +1 -0
- data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/meta.json +1 -0
- data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/seqno.json +1 -0
- data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/snapshot_markers.json +1 -0
- data/spec/subdoc_spec.rb +192 -0
- data/spec/view_spec.rb +201 -0
- data/windows_build.md +36 -0
- metadata +265 -0
data/spec/n1ql_spec.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'libcouchbase'
|
4
|
+
|
5
|
+
|
6
|
+
describe Libcouchbase::N1QL, n1ql_query: true do
|
7
|
+
before :each do
|
8
|
+
@bucket = Libcouchbase::Bucket.new
|
9
|
+
@n1ql = @bucket.n1ql
|
10
|
+
@log = []
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
@bucket = nil
|
15
|
+
@log = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should build a basic query" do
|
19
|
+
@n1ql.select('*').from(:default).where('port == 10001')
|
20
|
+
expect(@n1ql.to_s).to eq("SELECT *\nFROM default\nWHERE port == 10001\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'perform native queries' do
|
24
|
+
before :each do
|
25
|
+
@n1ql.select('*').from(:default).where('type == "mod"')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should iterate results" do
|
29
|
+
results = @n1ql.results
|
30
|
+
@log << results.to_a.count
|
31
|
+
@log << results.count
|
32
|
+
@log << results.collect { |res| res.nil? }
|
33
|
+
expect(@log).to eq([12, 12,
|
34
|
+
[false, false, false, false, false,
|
35
|
+
false, false, false, false, false,
|
36
|
+
false, false
|
37
|
+
]])
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should cancel iteration when an error occurs" do
|
41
|
+
results = @n1ql.results
|
42
|
+
begin
|
43
|
+
count = 0
|
44
|
+
results.collect { |res|
|
45
|
+
raise 'err' if count > 0
|
46
|
+
@log << res.nil?
|
47
|
+
count += 1
|
48
|
+
}
|
49
|
+
rescue => e
|
50
|
+
@log << :error
|
51
|
+
end
|
52
|
+
@log << results.count
|
53
|
+
expect(@log).to eq([false, :error, 12])
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should cancel iteration when an error occurs in row modifer" do
|
57
|
+
count = 0
|
58
|
+
results = @n1ql.results do |row|
|
59
|
+
raise 'err' if count > 0
|
60
|
+
count += 1
|
61
|
+
row
|
62
|
+
end
|
63
|
+
|
64
|
+
begin
|
65
|
+
count = 0
|
66
|
+
results.collect { |res|
|
67
|
+
@log << res.nil?
|
68
|
+
}
|
69
|
+
rescue => e
|
70
|
+
@log << e.message
|
71
|
+
end
|
72
|
+
expect(@log).to eq([false, 'err'])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'perform queries in libuv reactor' do
|
77
|
+
before :each do
|
78
|
+
@n1ql.select('*').from(:default).where('type == "mod"')
|
79
|
+
@reactor = ::Libuv::Reactor.default
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should iterate results" do
|
83
|
+
@reactor.run { |reactor|
|
84
|
+
results = @n1ql.results
|
85
|
+
@log << results.to_a.count
|
86
|
+
@log << results.count
|
87
|
+
@log << results.collect { |res| res.nil? }
|
88
|
+
}
|
89
|
+
|
90
|
+
expect(@log).to eq([12, 12,
|
91
|
+
[false, false, false, false, false,
|
92
|
+
false, false, false, false, false,
|
93
|
+
false, false
|
94
|
+
]]
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should cancel iteration when an error occurs" do
|
99
|
+
@reactor.run { |reactor|
|
100
|
+
results = @n1ql.results
|
101
|
+
begin
|
102
|
+
count = 0
|
103
|
+
results.collect { |res|
|
104
|
+
raise 'err' if count > 0
|
105
|
+
@log << res.nil?
|
106
|
+
count += 1
|
107
|
+
}
|
108
|
+
rescue => e
|
109
|
+
@log << :error
|
110
|
+
end
|
111
|
+
@log << results.count
|
112
|
+
}
|
113
|
+
expect(@log).to eq([false, :error, 12])
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should cancel iteration when an error occurs in row modifer" do
|
117
|
+
@reactor.run { |reactor|
|
118
|
+
count = 0
|
119
|
+
results = @n1ql.results do |row|
|
120
|
+
raise 'err' if count > 0
|
121
|
+
count += 1
|
122
|
+
row
|
123
|
+
end
|
124
|
+
|
125
|
+
begin
|
126
|
+
count = 0
|
127
|
+
results.collect { |res|
|
128
|
+
@log << res.nil?
|
129
|
+
}
|
130
|
+
rescue => e
|
131
|
+
@log << e.message
|
132
|
+
end
|
133
|
+
}
|
134
|
+
expect(@log).to eq([false, 'err'])
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'perform queries in event machine' do
|
139
|
+
require 'em-synchrony'
|
140
|
+
|
141
|
+
before :each do
|
142
|
+
@n1ql.select('*').from(:default).where('type == "mod"')
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should iterate results" do
|
146
|
+
EM.synchrony {
|
147
|
+
results = @n1ql.results
|
148
|
+
@log << results.to_a.count
|
149
|
+
@log << results.count
|
150
|
+
@log << results.collect { |res| res.nil? }
|
151
|
+
|
152
|
+
EM.stop
|
153
|
+
}
|
154
|
+
|
155
|
+
expect(@log).to eq([12, 12,
|
156
|
+
[false, false, false, false, false,
|
157
|
+
false, false, false, false, false,
|
158
|
+
false, false
|
159
|
+
]]
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should cancel iteration when an error occurs" do
|
164
|
+
EM.synchrony {
|
165
|
+
results = @n1ql.results
|
166
|
+
begin
|
167
|
+
count = 0
|
168
|
+
results.collect { |res|
|
169
|
+
raise 'err' if count > 0
|
170
|
+
@log << res.nil?
|
171
|
+
count += 1
|
172
|
+
}
|
173
|
+
rescue => e
|
174
|
+
@log << :error
|
175
|
+
end
|
176
|
+
@log << results.count
|
177
|
+
|
178
|
+
EM.stop
|
179
|
+
}
|
180
|
+
expect(@log).to eq([false, :error, 12])
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should cancel iteration when an error occurs in row modifer" do
|
184
|
+
EM.synchrony {
|
185
|
+
count = 0
|
186
|
+
results = @n1ql.results do |row|
|
187
|
+
raise 'err' if count > 0
|
188
|
+
count += 1
|
189
|
+
row
|
190
|
+
end
|
191
|
+
|
192
|
+
begin
|
193
|
+
count = 0
|
194
|
+
results.collect { |res|
|
195
|
+
@log << res.nil?
|
196
|
+
}
|
197
|
+
rescue => e
|
198
|
+
@log << e.message
|
199
|
+
end
|
200
|
+
|
201
|
+
EM.stop
|
202
|
+
}
|
203
|
+
expect(@log).to eq([false, 'err'])
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'libcouchbase'
|
4
|
+
require 'uv-rays'
|
5
|
+
|
6
|
+
|
7
|
+
class MockQuery
|
8
|
+
def initialize(log, preloaded = 0)
|
9
|
+
@count = 4
|
10
|
+
@preloaded = preloaded
|
11
|
+
@log = log
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :preloaded
|
15
|
+
|
16
|
+
def get_count(metadata)
|
17
|
+
metadata[:total_rows]
|
18
|
+
end
|
19
|
+
|
20
|
+
def perform(limit: @count, **options, &blk)
|
21
|
+
@curr = 0
|
22
|
+
@callback = blk
|
23
|
+
@limit = limit
|
24
|
+
|
25
|
+
if @sched
|
26
|
+
@sched.cancel
|
27
|
+
@sched = nil
|
28
|
+
end
|
29
|
+
@error = nil
|
30
|
+
|
31
|
+
preloaded.times { |i| blk.call(false, i) }
|
32
|
+
next_item(preloaded)
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_item(i = 0)
|
36
|
+
if i == @limit
|
37
|
+
@sched = reactor.scheduler.in(50) do
|
38
|
+
@callback.call(:final, {total_rows: @count})
|
39
|
+
end
|
40
|
+
else
|
41
|
+
@sched = reactor.scheduler.in(100) do
|
42
|
+
@log << :new_row
|
43
|
+
next_item(i + 1)
|
44
|
+
@callback.call(false, i)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def cancel
|
50
|
+
return if @error
|
51
|
+
if @sched
|
52
|
+
@sched.cancel
|
53
|
+
@sched = nil
|
54
|
+
end
|
55
|
+
@error = :cancelled
|
56
|
+
@sched = reactor.scheduler.in(50) do
|
57
|
+
@callback.call(:final, {total_rows: @count})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
describe Libcouchbase::ResultsLibuv do
|
64
|
+
before :each do
|
65
|
+
@log = []
|
66
|
+
@reactor = ::Libuv::Reactor.default
|
67
|
+
@reactor.notifier do |err|
|
68
|
+
@reactor.stop
|
69
|
+
@log << err
|
70
|
+
end
|
71
|
+
@timeout = @reactor.timer do
|
72
|
+
@timeout.close
|
73
|
+
@reactor.stop
|
74
|
+
@log << "test timed out"
|
75
|
+
end
|
76
|
+
@timeout.start(5000)
|
77
|
+
@timeout.unref
|
78
|
+
@query = MockQuery.new(@log)
|
79
|
+
@view = Libcouchbase::ResultsLibuv.new(@query)
|
80
|
+
expect(@log).to eq([])
|
81
|
+
end
|
82
|
+
|
83
|
+
after :each do
|
84
|
+
@timeout.close
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should stream the response" do
|
88
|
+
@reactor.run { |reactor|
|
89
|
+
@view.each {|i| @log << i }
|
90
|
+
}
|
91
|
+
|
92
|
+
expect(@log).to eq([:new_row, 0, :new_row, 1, :new_row, 2, :new_row, 3])
|
93
|
+
expect(@view.complete_result_set).to be(true)
|
94
|
+
expect(@view.query_in_progress).to be(false)
|
95
|
+
expect(@view.query_completed).to be(true)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should continue to stream the response even if some has already been loaded" do
|
99
|
+
@reactor.run { |reactor|
|
100
|
+
@query.preloaded = 2
|
101
|
+
@view.each {|i| @log << i }
|
102
|
+
}
|
103
|
+
|
104
|
+
expect(@view.complete_result_set).to be(true)
|
105
|
+
expect(@view.query_in_progress).to be(false)
|
106
|
+
expect(@view.query_completed).to be(true)
|
107
|
+
expect(@log).to eq([0, 1, :new_row, 2, :new_row, 3])
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should only load what is required" do
|
111
|
+
@reactor.run { |reactor|
|
112
|
+
@log << @view.take(2)
|
113
|
+
@log << @view.first
|
114
|
+
expect(@view.complete_result_set).to be(false)
|
115
|
+
expect(@view.query_in_progress).to be(false)
|
116
|
+
expect(@view.query_completed).to be(true)
|
117
|
+
@log << @view.to_a
|
118
|
+
}
|
119
|
+
|
120
|
+
expect(@view.complete_result_set).to be(true)
|
121
|
+
expect(@view.query_in_progress).to be(false)
|
122
|
+
expect(@view.query_completed).to be(true)
|
123
|
+
expect(@log).to eq([:new_row, :new_row, [0, 1], 0, :new_row, :new_row, :new_row, :new_row, [0, 1, 2, 3]])
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should load only once" do
|
127
|
+
@reactor.run { |reactor|
|
128
|
+
@log << @view.to_a
|
129
|
+
@log << @view.to_a
|
130
|
+
}
|
131
|
+
|
132
|
+
expect(@log).to eq([:new_row, :new_row, :new_row, :new_row, [0, 1, 2, 3], [0, 1, 2, 3]])
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should work as an enumerable" do
|
136
|
+
@reactor.run { |reactor|
|
137
|
+
enum = @view.each
|
138
|
+
@log << enum.next
|
139
|
+
@log << enum.next
|
140
|
+
}
|
141
|
+
|
142
|
+
expect(@log).to eq([:new_row, :new_row, :new_row, :new_row, 0, 1])
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should return count" do
|
146
|
+
@reactor.run { |reactor|
|
147
|
+
@log << @view.count
|
148
|
+
@log << @view.count
|
149
|
+
}
|
150
|
+
|
151
|
+
expect(@log).to eq([:new_row, 4, 4])
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should handle exceptions" do
|
155
|
+
@reactor.run { |reactor|
|
156
|
+
begin
|
157
|
+
@view.each {|i|
|
158
|
+
@log << i
|
159
|
+
raise 'what what'
|
160
|
+
}
|
161
|
+
rescue => e
|
162
|
+
@log << e.message
|
163
|
+
end
|
164
|
+
}
|
165
|
+
|
166
|
+
expect(@log).to eq([:new_row, 0, 'what what'])
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should handle row modifier exceptions" do
|
170
|
+
count = 0
|
171
|
+
|
172
|
+
@view = Libcouchbase::ResultsLibuv.new(@query) { |view|
|
173
|
+
if count == 1
|
174
|
+
raise 'what what'
|
175
|
+
end
|
176
|
+
count += 1
|
177
|
+
view
|
178
|
+
}
|
179
|
+
|
180
|
+
@reactor.run { |reactor|
|
181
|
+
begin
|
182
|
+
@view.each {|i| @log << i }
|
183
|
+
rescue => e
|
184
|
+
@log << e.message
|
185
|
+
end
|
186
|
+
}
|
187
|
+
|
188
|
+
expect(@log).to eq([:new_row, 0, :new_row, 'what what'])
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should handle row modifier exceptions on a short query" do
|
192
|
+
count = 0
|
193
|
+
|
194
|
+
@view = Libcouchbase::ResultsLibuv.new(@query) { |view|
|
195
|
+
raise 'what what'
|
196
|
+
}
|
197
|
+
|
198
|
+
@reactor.run { |reactor|
|
199
|
+
begin
|
200
|
+
@view.first
|
201
|
+
rescue => e
|
202
|
+
@log << e.message
|
203
|
+
end
|
204
|
+
}
|
205
|
+
|
206
|
+
expect(@log).to eq([:new_row, 'what what'])
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should handle multiple exceptions" do
|
210
|
+
count = 0
|
211
|
+
|
212
|
+
@view = Libcouchbase::ResultsLibuv.new(@query) { |view|
|
213
|
+
if count == 1
|
214
|
+
raise 'second'
|
215
|
+
end
|
216
|
+
count += 1
|
217
|
+
view
|
218
|
+
}
|
219
|
+
|
220
|
+
@reactor.run { |reactor|
|
221
|
+
begin
|
222
|
+
@view.each {|i|
|
223
|
+
@log << i
|
224
|
+
raise 'first'
|
225
|
+
}
|
226
|
+
rescue => e
|
227
|
+
@log << e.message
|
228
|
+
end
|
229
|
+
}
|
230
|
+
|
231
|
+
expect(@log).to eq([:new_row, 0, 'first'])
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should support streaming the response so results are not all stored in memory" do
|
235
|
+
@reactor.run { |reactor|
|
236
|
+
@view.stream {|i| @log << i }
|
237
|
+
}
|
238
|
+
|
239
|
+
expect(@view.complete_result_set).to be(false)
|
240
|
+
expect(@view.query_in_progress).to be(false)
|
241
|
+
expect(@view.query_completed).to be(true)
|
242
|
+
expect(@log).to eq([:new_row, 0, :new_row, 1, :new_row, 2, :new_row, 3])
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'libcouchbase'
|
4
|
+
require 'uv-rays'
|
5
|
+
|
6
|
+
|
7
|
+
class NativeMockQuery
|
8
|
+
def initialize(log, thread = nil, preloaded = 0)
|
9
|
+
@count = 4
|
10
|
+
@preloaded = preloaded
|
11
|
+
@log = log
|
12
|
+
@thread = thread
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :preloaded
|
16
|
+
|
17
|
+
def get_count(metadata)
|
18
|
+
metadata[:total_rows]
|
19
|
+
end
|
20
|
+
|
21
|
+
def perform(limit: @count, **options, &blk)
|
22
|
+
@wait = Thread.new do
|
23
|
+
@thread.run {
|
24
|
+
@curr = 0
|
25
|
+
@callback = blk
|
26
|
+
@limit = limit
|
27
|
+
@error = nil
|
28
|
+
|
29
|
+
preloaded.times { |i| blk.call(false, i) }
|
30
|
+
next_item(preloaded)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def wait_join
|
36
|
+
@wait.join
|
37
|
+
end
|
38
|
+
|
39
|
+
def next_item(i = 0)
|
40
|
+
if i == @limit
|
41
|
+
@sched = @thread.scheduler.in(50) do
|
42
|
+
@sched = nil
|
43
|
+
@callback.call(:final, {total_rows: @count})
|
44
|
+
end
|
45
|
+
else
|
46
|
+
@sched = @thread.scheduler.in(100) do
|
47
|
+
@log << :new_row
|
48
|
+
next_item(i + 1)
|
49
|
+
@callback.call(false, i)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def cancel
|
55
|
+
return if @error
|
56
|
+
@error = :cancelled
|
57
|
+
|
58
|
+
@thread.schedule {
|
59
|
+
if @sched
|
60
|
+
@sched.cancel
|
61
|
+
@sched = @thread.scheduler.in(50) do
|
62
|
+
@sched = nil
|
63
|
+
@callback.call(:final, {total_rows: @count})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
describe Libcouchbase::ResultsNative do
|
72
|
+
before :each do
|
73
|
+
reactor = ::Libuv::Reactor.default
|
74
|
+
@qlog = []
|
75
|
+
@query = NativeMockQuery.new(@qlog, reactor)
|
76
|
+
@log = []
|
77
|
+
@view = Libcouchbase::ResultsNative.new(@query)
|
78
|
+
expect(@log).to eq([])
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should stream the response" do
|
82
|
+
@view.each {|i| @log << i }
|
83
|
+
|
84
|
+
@query.wait_join
|
85
|
+
|
86
|
+
expect(@view.complete_result_set).to be(true)
|
87
|
+
expect(@view.query_in_progress).to be(false)
|
88
|
+
expect(@view.query_completed).to be(true)
|
89
|
+
expect(@qlog).to eq([:new_row, :new_row, :new_row, :new_row])
|
90
|
+
expect(@log).to eq([0, 1, 2, 3])
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should continue to stream the response even if some has already been loaded" do
|
94
|
+
@query.preloaded = 2
|
95
|
+
@view.each {|i| @log << i }
|
96
|
+
|
97
|
+
@query.wait_join
|
98
|
+
|
99
|
+
expect(@view.complete_result_set).to be(true)
|
100
|
+
expect(@view.query_in_progress).to be(false)
|
101
|
+
expect(@view.query_completed).to be(true)
|
102
|
+
expect(@qlog).to eq([:new_row, :new_row])
|
103
|
+
expect(@log).to eq([0, 1, 2, 3])
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should only load what is required" do
|
107
|
+
@log << @view.take(2)
|
108
|
+
expect(@view.complete_result_set).to be(false)
|
109
|
+
expect(@view.query_in_progress).to be(false)
|
110
|
+
expect(@view.query_completed).to be(true)
|
111
|
+
|
112
|
+
@log << @view.first
|
113
|
+
expect(@view.complete_result_set).to be(false)
|
114
|
+
expect(@view.query_in_progress).to be(false)
|
115
|
+
expect(@view.query_completed).to be(true)
|
116
|
+
|
117
|
+
# Wait join here as the default loop will
|
118
|
+
# be started again on a new thread
|
119
|
+
# without this wait we might end up in a deadlock...
|
120
|
+
# Don't worry, the test is sound - seriously
|
121
|
+
@query.wait_join
|
122
|
+
|
123
|
+
@log << @view.to_a
|
124
|
+
expect(@view.complete_result_set).to be(true)
|
125
|
+
expect(@view.query_in_progress).to be(false)
|
126
|
+
expect(@view.query_completed).to be(true)
|
127
|
+
|
128
|
+
@query.wait_join
|
129
|
+
|
130
|
+
expect(@qlog).to eq([:new_row, :new_row, :new_row, :new_row, :new_row, :new_row])
|
131
|
+
expect(@log).to eq([[0, 1], 0, [0, 1, 2, 3]])
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should load only once" do
|
135
|
+
@log << @view.to_a
|
136
|
+
@log << @view.to_a
|
137
|
+
|
138
|
+
@query.wait_join
|
139
|
+
expect(@qlog).to eq([:new_row, :new_row, :new_row, :new_row])
|
140
|
+
expect(@log).to eq([[0, 1, 2, 3], [0, 1, 2, 3]])
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should work as an enumerable" do
|
144
|
+
enum = @view.each
|
145
|
+
@log << enum.next
|
146
|
+
@log << enum.next
|
147
|
+
|
148
|
+
@query.wait_join
|
149
|
+
|
150
|
+
expect(@qlog).to eq([:new_row, :new_row, :new_row, :new_row])
|
151
|
+
expect(@log).to eq([0, 1])
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should return count" do
|
155
|
+
@log << @view.count
|
156
|
+
@log << @view.count
|
157
|
+
|
158
|
+
@query.wait_join
|
159
|
+
|
160
|
+
expect(@qlog).to eq([:new_row])
|
161
|
+
expect(@log).to eq([4, 4])
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should handle exceptions" do
|
165
|
+
begin
|
166
|
+
@view.each {|i|
|
167
|
+
@log << i
|
168
|
+
raise 'what what'
|
169
|
+
}
|
170
|
+
rescue => e
|
171
|
+
@log << e.message
|
172
|
+
end
|
173
|
+
|
174
|
+
@query.wait_join
|
175
|
+
|
176
|
+
expect(@qlog).to eq([:new_row])
|
177
|
+
expect(@log).to eq([0, 'what what'])
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should handle row modifier exceptions" do
|
181
|
+
count = 0
|
182
|
+
|
183
|
+
@view = Libcouchbase::ResultsNative.new(@query) { |view|
|
184
|
+
if count == 1
|
185
|
+
raise 'what what'
|
186
|
+
end
|
187
|
+
count += 1
|
188
|
+
view
|
189
|
+
}
|
190
|
+
|
191
|
+
begin
|
192
|
+
@view.each {|i| @log << i }
|
193
|
+
rescue => e
|
194
|
+
@log << e.message
|
195
|
+
end
|
196
|
+
|
197
|
+
@query.wait_join
|
198
|
+
|
199
|
+
expect(@qlog).to eq([:new_row, :new_row])
|
200
|
+
expect(@log).to eq([0, 'what what'])
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should handle row modifier exceptions on a short query" do
|
204
|
+
count = 0
|
205
|
+
|
206
|
+
@view = Libcouchbase::ResultsNative.new(@query) { |view|
|
207
|
+
raise 'what what'
|
208
|
+
}
|
209
|
+
|
210
|
+
begin
|
211
|
+
@view.first
|
212
|
+
rescue => e
|
213
|
+
@log << e.message
|
214
|
+
end
|
215
|
+
|
216
|
+
@query.wait_join
|
217
|
+
|
218
|
+
expect(@qlog).to eq([:new_row])
|
219
|
+
expect(@log).to eq(['what what'])
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should handle multiple exceptions" do
|
223
|
+
count = 0
|
224
|
+
|
225
|
+
@view = Libcouchbase::ResultsNative.new(@query) { |view|
|
226
|
+
if count == 1
|
227
|
+
raise 'second'
|
228
|
+
end
|
229
|
+
count += 1
|
230
|
+
view
|
231
|
+
}
|
232
|
+
|
233
|
+
begin
|
234
|
+
@view.each {|i|
|
235
|
+
@log << i
|
236
|
+
raise 'first'
|
237
|
+
}
|
238
|
+
rescue => e
|
239
|
+
@log << e.message
|
240
|
+
end
|
241
|
+
|
242
|
+
@query.wait_join
|
243
|
+
|
244
|
+
expect(@qlog).to eq([:new_row])
|
245
|
+
expect(@log).to eq([0, 'first'])
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should support streaming the response so results are not all stored in memory" do
|
249
|
+
@view.stream {|i| @log << i }
|
250
|
+
|
251
|
+
@query.wait_join
|
252
|
+
|
253
|
+
expect(@view.complete_result_set).to be(false)
|
254
|
+
expect(@view.query_in_progress).to be(false)
|
255
|
+
expect(@view.query_completed).to be(true)
|
256
|
+
expect(@qlog).to eq([:new_row, :new_row, :new_row, :new_row])
|
257
|
+
expect(@log).to eq([0, 1, 2, 3])
|
258
|
+
end
|
259
|
+
end
|