couchbase-jruby-client 0.1.0-java → 0.1.5-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.jrubyrc +722 -0
  3. data/.ruby-version +1 -1
  4. data/README.md +12 -90
  5. data/couchbase-jruby-client.gemspec +6 -6
  6. data/lib/couchbase/async.rb +18 -0
  7. data/lib/couchbase/bucket.rb +90 -180
  8. data/lib/couchbase/constants.rb +17 -0
  9. data/lib/couchbase/design_doc.rb +83 -0
  10. data/lib/couchbase/error.rb +31 -0
  11. data/lib/couchbase/operations/arithmetic.rb +17 -0
  12. data/lib/couchbase/operations/delete.rb +17 -0
  13. data/lib/couchbase/operations/design_docs.rb +99 -0
  14. data/lib/couchbase/operations/get.rb +73 -67
  15. data/lib/couchbase/operations/stats.rb +28 -1
  16. data/lib/couchbase/operations/store.rb +114 -97
  17. data/lib/couchbase/operations/touch.rb +49 -19
  18. data/lib/couchbase/operations/unlock.rb +209 -0
  19. data/lib/couchbase/operations/utils.rb +22 -10
  20. data/lib/couchbase/operations.rb +21 -0
  21. data/lib/couchbase/query.rb +92 -0
  22. data/lib/couchbase/result.rb +18 -1
  23. data/lib/couchbase/transcoder.rb +36 -42
  24. data/lib/couchbase/version.rb +18 -1
  25. data/lib/couchbase/view.rb +30 -172
  26. data/lib/couchbase/view_row.rb +38 -98
  27. data/lib/couchbase.rb +74 -72
  28. data/test/profile/.jrubyrc +722 -0
  29. data/test/profile/Gemfile +5 -5
  30. data/test/profile/benchmark.rb +106 -124
  31. data/test/profile/profile.rb +59 -0
  32. data/test/setup.rb +10 -145
  33. data/test/test_arithmetic.rb +54 -77
  34. data/test/test_async.rb +74 -102
  35. data/test/test_bucket.rb +74 -60
  36. data/test/test_cas.rb +10 -23
  37. data/test/test_couchbase.rb +11 -3
  38. data/test/test_delete.rb +41 -43
  39. data/test/test_design_docs.rb +62 -0
  40. data/test/test_errors.rb +9 -18
  41. data/test/test_format.rb +21 -31
  42. data/test/test_get.rb +107 -151
  43. data/test/test_query.rb +23 -0
  44. data/test/test_stats.rb +9 -24
  45. data/test/test_store.rb +52 -65
  46. data/test/test_timer.rb +4 -12
  47. data/test/test_touch.rb +26 -33
  48. data/test/test_unlock.rb +47 -78
  49. data/test/test_utils.rb +2 -11
  50. data/test/test_version.rb +5 -14
  51. data/test/test_view.rb +87 -0
  52. metadata +27 -14
  53. data/lib/couchbase/jruby/couchbase_client.rb +0 -22
  54. data/lib/couchbase/jruby/future.rb +0 -8
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Couchbase::Jruby::Client
1
+ # Couchbase JRuby Client
2
2
 
3
- Attempt to recreate the ruby Couchbase cient api in Jruby and the
3
+ Attempt to recreate the ruby Couchbase client api in JRuby and the
4
4
  Couchbase Java SDK.
5
5
 
6
6
  ## Installation
@@ -19,12 +19,17 @@ Or install it yourself as:
19
19
 
20
20
  ## Caveat
21
21
 
22
- Please consider this project a very incomplete "alpha" version at best.
23
- Most of your typical operations such as connecting to a Couchbase cluster, storing
24
- and retrieving documents are working, though I'm currently skeptical on the performance
25
- compared to the native Java SDK without this wrapper.
22
+ Please consider this project a very incomplete "alpha" version at best. I'm getting close
23
+ to full coverage, though there are still some missing features. In fact, as I've gotten
24
+ more familiar with the differences between the native ruby api and the java, there are
25
+ definitely some features that don't make sense to implement.
26
26
 
27
- ## Usage (Copied from )
27
+ Ultimately hoping to get to 100% support of the couchbase-ruby-model gem.
28
+
29
+ ## Usage
30
+
31
+ See https://github.com/couchbase/couchbase-ruby-client for usage instructions as
32
+ they are largely the same. Important bits copied below:
28
33
 
29
34
  First of all you need to load library:
30
35
 
@@ -65,89 +70,6 @@ connection options via `Couchbase.connection_options`:
65
70
  Couchbase.bucket.name #=> "blog"
66
71
  Couchbase.bucket.set("foo", "bar") #=> 3289400178357895424
67
72
 
68
- The library supports both synchronous and asynchronous mode. In
69
- asynchronous mode all operations will return control to caller
70
- without blocking current thread. You can pass the block to method and it
71
- will be called with result when the operation will be completed. You
72
- need to run event loop when you scheduled your operations:
73
-
74
- c = Couchbase.connect
75
- c.run do |conn|
76
- conn.get("foo") {|ret| puts ret.value}
77
- conn.set("bar", "baz")
78
- end
79
-
80
- The handlers could be nested
81
-
82
- c.run do |conn|
83
- conn.get("foo") do |ret|
84
- conn.incr(ret.value, :initial => 0)
85
- end
86
- end
87
-
88
- The asynchronous callback receives instance of `Couchbase::Result` which
89
- responds to several methods to figure out what was happened:
90
-
91
- * `success?`. Returns `true` if operation succed.
92
-
93
- * `error`. Returns `nil` or exception object (subclass of
94
- `Couchbase::Error::Base`) if something went wrong.
95
-
96
- * `key`
97
-
98
- * `value`
99
-
100
- * `flags`
101
-
102
- * `cas`. The CAS version tag.
103
-
104
- * `node`. Node address. It is used in flush and stats commands.
105
-
106
- * `operation`. The symbol, representing an operation.
107
-
108
-
109
- To handle global errors in async mode `#on_error` callback should be
110
- used. It can be set in following fashions:
111
-
112
- c.on_error do |opcode, key, exc|
113
- # ...
114
- end
115
-
116
- handler = lambda {|opcode, key, exc| }
117
- c.on_error = handler
118
-
119
- By default connection uses `:quiet` mode. This mean it won't raise
120
- exceptions when the given key is not exists:
121
-
122
- c.get("missing-key") #=> nil
123
-
124
- It could be useful when you are trying to make you code a bit efficient
125
- by avoiding exception handling. (See `#add` and `#replace` operations).
126
- You can turn on these exception by passing `:quiet => false` when you
127
- are instantiating the connection or change corresponding attribute:
128
-
129
- c.quiet = false
130
- c.get("missing-key") #=> raise Couchbase::Error::NotFound
131
- c.get("missing-key", :quiet => true) #=> nil
132
-
133
- The library supports three different formats for representing values:
134
-
135
- * `:document` (default) format supports most of ruby types which could
136
- be mapped to JSON data (hashes, arrays, string, numbers). A future
137
- version will be able to run map/reduce queries on the values in the
138
- document form (hashes)
139
-
140
- * `:plain` This format avoids any conversions to be applied to your
141
- data, but your data should be passed as String. This is useful for
142
- building custom algorithms or formats. For example to implement a set:
143
- http://dustin.github.com/2011/02/17/memcached-set.html
144
-
145
- * `:marshal` Use this format if you'd like to transparently serialize your
146
- ruby object with standard `Marshal.dump` and `Marshal.load` methods
147
-
148
- The couchbase API is the superset of [Memcached binary protocol][5], so
149
- you can use its operations.
150
-
151
73
  ### Get
152
74
 
153
75
  val = c.get("foo")
@@ -12,19 +12,19 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{The unofficial jruby client library for use with Couchbase Server.}
13
13
  s.homepage = 'https://github.com/mje113/couchbase-jruby-client'
14
14
  s.license = 'Apache'
15
- s.platform = Gem::Platform::JAVA
15
+ s.platform = 'java'
16
16
 
17
17
  s.files = `git ls-files`.split($/)
18
18
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
20
  s.require_paths = ['lib']
21
21
 
22
- s.add_runtime_dependency 'multi_json', '~> 1.0'
23
- s.add_runtime_dependency 'atomic', '~> 1.1.14'
22
+ s.add_runtime_dependency 'multi_json', '~> 1.0'
23
+ s.add_runtime_dependency 'thread_safe', '~> 0.1.2'
24
24
 
25
- s.add_development_dependency 'bundler', '~> 1.3'
25
+ s.add_development_dependency 'bundler', '~> 1.3'
26
26
  s.add_development_dependency 'rake'
27
- s.add_development_dependency 'minitest', '~> 5.0.4'
27
+ s.add_development_dependency 'minitest', '~> 5.0.4'
28
+ s.add_development_dependency 'jrjackson', '~> 0.2.3'
28
29
  s.add_development_dependency 'active_support'
29
- s.add_development_dependency 'pry'
30
30
  end
@@ -1,3 +1,20 @@
1
+ # Author:: Mike Evans <mike@urlgonomics.com>
2
+ # Copyright:: 2013 Urlgonomics LLC.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
1
18
  require 'couchbase/async/callback'
2
19
  require 'couchbase/async/queue'
3
20
 
@@ -128,6 +145,7 @@ module Couchbase
128
145
  else
129
146
  register_callback(future, &block)
130
147
  end
148
+ future
131
149
  end
132
150
 
133
151
  def register_callback(future, &block)
@@ -1,31 +1,74 @@
1
- require 'pry'
1
+ # Author:: Mike Evans <mike@urlgonomics.com>
2
+ # Copyright:: 2013 Urlgonomics LLC.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
2
17
 
3
18
  module Couchbase
4
19
 
5
20
  class Bucket
6
21
 
7
- import java.io.IOException
8
- import java.net.SocketAddress
9
- import java.net.URI
10
- import java.net.URISyntaxException
11
- import java.util.ArrayList
12
- import java.util.LinkedList
13
- import java.util.List
14
- import java.util.concurrent.Future
15
- import java.util.concurrent.TimeUnit
16
- import com.couchbase.client.CouchbaseClient
17
- import com.couchbase.client.CouchbaseConnectionFactory
18
- import com.couchbase.client.protocol.views.Query
22
+ java_import java.io.IOException
23
+ java_import java.net.SocketAddress
24
+ java_import java.net.URI
25
+ java_import java.net.URISyntaxException
26
+ java_import java.util.ArrayList
27
+ java_import java.util.LinkedList
28
+ java_import java.util.List
29
+ java_import java.util.concurrent.Future
30
+ java_import java.util.concurrent.TimeUnit
31
+ java_import com.couchbase.client.CouchbaseClient
32
+ java_import com.couchbase.client.CouchbaseConnectionFactory
33
+ java_import com.couchbase.client.CouchbaseConnectionFactoryBuilder
19
34
 
20
35
  include Couchbase::Operations
21
36
  include Couchbase::Async
22
37
 
23
38
  attr_accessor :quiet, :hostname, :port, :pool, :bucket, :username,
24
- :password, :default_ttl, :timeout,
39
+ :password, :default_ttl, :timeout, :default_format,
25
40
  :default_arithmetic_init, :transcoder
26
41
 
27
42
  attr_reader :client, :key_prefix, :default_format
28
43
 
44
+ DEFAULT_OPTIONS = {
45
+ type: nil,
46
+ quiet: false,
47
+ hostname: 'localhost',
48
+ port: 8091,
49
+ pool: 'default',
50
+ bucket: 'default',
51
+ password: '',
52
+ engine: nil,
53
+ default_ttl: 0,
54
+ async: false,
55
+ default_arithmetic_init: 0,
56
+ default_flags: 0,
57
+ default_format: :document,
58
+ default_observe_timeout: 2_500_000,
59
+ on_error: nil,
60
+ on_connect: nil,
61
+ timeout: 0,
62
+ environment: nil,
63
+ key_prefix: nil,
64
+ node_list: nil,
65
+ destroying: 0,
66
+ connected: 0,
67
+ on_connect_proc: nil,
68
+ async_disconnect_hook_set: 0,
69
+ connected: false
70
+ }.freeze
71
+
29
72
  # Initialize new Bucket.
30
73
  #
31
74
  # @since 1.0.0
@@ -119,63 +162,30 @@ module Couchbase
119
162
  # @return [Bucket]
120
163
  #
121
164
  def initialize(url = nil, options = {})
122
- default_options = {
123
- type: nil,
124
- quiet: false,
125
- hostname: 'localhost',
126
- port: 8091,
127
- pool: 'default',
128
- bucket: 'default',
129
- password: '',
130
- engine: nil,
131
- default_ttl: 0,
132
- async: false,
133
- default_arithmetic_init: 0,
134
- default_flags: 0,
135
- default_format: :document,
136
- default_observe_timeout: 2500000,
137
- on_error: nil,
138
- on_connect: nil,
139
- timeout: 0,
140
- environment: nil,
141
- key_prefix: nil,
142
- node_list: nil,
143
- destroying: 0,
144
- connected: 0,
145
- on_connect_proc: nil,
146
- async_disconnect_hook_set: 0,
147
- connected: false
148
- }
149
-
150
165
  url_options = if url.is_a? String
151
- raise ArgumentError.new unless url =~ /^http:\/\//
152
-
166
+ fail ArgumentError.new unless url =~ /^http:\/\//
153
167
  uri = URI.new(url)
154
-
155
- {
156
- host: uri.host,
157
- port: uri.port,
158
- }.merge(path_to_pool_and_bucket(uri.path))
168
+ { hostname: uri.host, port: uri.port }.
169
+ merge(path_to_pool_and_bucket(uri.path))
159
170
  elsif url.nil?
160
171
  {}
161
172
  else
162
173
  url
163
174
  end
164
175
 
165
- connection_options = default_options.merge(options).merge(url_options)
176
+ options = Couchbase.normalize_connection_options(options)
177
+
178
+ connection_options = DEFAULT_OPTIONS.merge(url_options).merge(options)
166
179
 
167
180
  connection_options.each_pair do |key, value|
168
181
  instance_variable_set("@#{key}", value)
169
182
  end
170
183
 
171
- @transcoder = case @default_format
172
- when :document
173
- Transcoder::Document
174
- when :marshal
175
- Transcoder::Marshal
176
- when :plain
177
- Transcoder::Plain
178
- end
184
+ @transcoders = {
185
+ document: Transcoder::Document.new,
186
+ marshal: Transcoder::Marshal.new,
187
+ plain: Transcoder::Plain.new
188
+ }
179
189
 
180
190
  connect unless async?
181
191
  end
@@ -189,9 +199,6 @@ module Couchbase
189
199
  end
190
200
 
191
201
  def connect
192
- # TODO: doesn't work
193
- ObjectSpace.define_finalizer(self, -> conn { conn.disconnect })
194
-
195
202
  uris = if @node_list
196
203
  Array(@node_list).map { |n| URI.new(n) }
197
204
  else
@@ -199,14 +206,15 @@ module Couchbase
199
206
  end
200
207
 
201
208
  begin
202
- @connection_factory = CouchbaseConnectionFactory.new(uris, bucket.to_java_string, password.to_java_string)
203
- @client = CouchbaseClient.new(@connection_factory)
209
+ builder = CouchbaseConnectionFactoryBuilder.new
210
+ builder.setTranscoder(transcoder)
211
+ connection_factory = builder.buildCouchbaseConnection(uris, bucket.to_java_string, password.to_java_string)
212
+ @client = CouchbaseClient.new(connection_factory)
204
213
  @connected = true
205
- rescue Java::ComCouchbaseClientVbucket::ConfigurationException #,
206
- #Java::Io::IOException
207
- raise Couchbase::Error::Auth.new
214
+ rescue Java::ComCouchbaseClientVbucket::ConfigurationException
215
+ fail Couchbase::Error::Auth, 'Couchbase configurations are incorrect.'
208
216
  rescue java.net.ConnectException => e
209
- raise Couchbase::Error::Connect.new
217
+ fail Couchbase::Error::Connect
210
218
  end
211
219
 
212
220
  self
@@ -236,10 +244,14 @@ module Couchbase
236
244
  @connection_factory = nil
237
245
  @connected = false
238
246
  else
239
- raise Couchbase::Error::Connect.new
247
+ fail Couchbase::Error::Connect
240
248
  end
241
249
  end
242
250
 
251
+ def transcoder
252
+ @transcoders[@default_format]
253
+ end
254
+
243
255
  def on_connect(&block)
244
256
  @on_connect = block
245
257
  end
@@ -248,6 +260,14 @@ module Couchbase
248
260
  @on_error = block
249
261
  end
250
262
 
263
+ def version
264
+ {}.tap do |hash|
265
+ @client.getVersions.to_hash.each_pair do |ip, ver|
266
+ hash[ip.to_s] = ver
267
+ end
268
+ end
269
+ end
270
+
251
271
  # Compare and swap value.
252
272
  #
253
273
  # @since 1.0.0
@@ -313,126 +333,16 @@ module Couchbase
313
333
  block = Proc.new
314
334
  get(key) do |ret|
315
335
  val = block.call(ret) # get new value from caller
316
- set(ret.key, val, options.merge(:cas => ret.cas, :flags => ret.flags), &block)
336
+ set(ret.key, val, options.merge(:cas => ret.cas, &block))
317
337
  end
318
338
  else
319
339
  val, flags, ver = get(key, :extended => true)
320
340
  val = yield(val) # get new value from caller
321
- set(key, val, options.merge(:cas => ver, :flags => flags))
341
+ set(key, val, options.merge(:cas => ver))
322
342
  end
323
343
  end
324
344
  alias :compare_and_swap :cas
325
345
 
326
- # Fetch design docs stored in current bucket
327
- #
328
- # @since 1.2.0
329
- #
330
- # @return [Hash]
331
- def design_docs
332
- req = make_http_request("/pools/default/buckets/#{bucket}/ddocs",
333
- :type => :management, :extended => true)
334
- docmap = {}
335
- req.on_body do |body|
336
- res = MultiJson.load(body.value)
337
- res["rows"].each do |obj|
338
- if obj['doc']
339
- obj['doc']['value'] = obj['doc'].delete('json')
340
- end
341
- doc = DesignDoc.wrap(self, obj)
342
- key = doc.id.sub(/^_design\//, '')
343
- next if self.environment == :production && key =~ /dev_/
344
- docmap[key] = doc
345
- end
346
- yield(docmap) if block_given?
347
- end
348
- req.continue
349
- async? ? nil : docmap
350
- end
351
-
352
- # Update or create design doc with supplied views
353
- #
354
- # @since 1.2.0
355
- #
356
- # @param [Hash, IO, String] data The source object containing JSON
357
- # encoded design document. It must have +_id+ key set, this key
358
- # should start with +_design/+.
359
- #
360
- # @return [true, false]
361
- def save_design_doc(data)
362
- attrs = case data
363
- when String
364
- MultiJson.load(data)
365
- when IO
366
- MultiJson.load(data.read)
367
- when Hash
368
- data
369
- else
370
- raise ArgumentError, "Document should be Hash, String or IO instance"
371
- end
372
- rv = nil
373
- id = attrs.delete('_id').to_s
374
- attrs['language'] ||= 'javascript'
375
- if id !~ /\A_design\//
376
- rv = Result.new(:operation => :http_request,
377
- :key => id,
378
- :error => ArgumentError.new("'_id' key must be set and start with '_design/'."))
379
- yield rv if block_given?
380
- raise rv.error unless async?
381
- end
382
- req = make_http_request(id, :body => MultiJson.dump(attrs),
383
- :method => :put, :extended => true)
384
- req.on_body do |res|
385
- rv = res
386
- val = MultiJson.load(res.value)
387
- if block_given?
388
- if res.success? && val['error']
389
- res.error = Error::View.new("save_design_doc", val['error'])
390
- end
391
- yield(res)
392
- end
393
- end
394
- req.continue
395
- unless async?
396
- rv.success? or raise res.error
397
- end
398
- end
399
-
400
- # Delete design doc with given id and revision.
401
- #
402
- # @since 1.2.0
403
- #
404
- # @param [String] id Design document id. It might have '_design/'
405
- # prefix.
406
- #
407
- # @param [String] rev Document revision. It uses latest revision if
408
- # +rev+ parameter is nil.
409
- #
410
- # @return [true, false]
411
- def delete_design_doc(id, rev = nil)
412
- ddoc = design_docs[id.sub(/^_design\//, '')]
413
- unless ddoc
414
- yield nil if block_given?
415
- return nil
416
- end
417
- path = Utils.build_query(ddoc.id, :rev => rev || ddoc.meta['rev'])
418
- req = make_http_request(path, :method => :delete, :extended => true)
419
- rv = nil
420
- req.on_body do |res|
421
- rv = res
422
- val = MultiJson.load(res.value)
423
- if block_given?
424
- if res.success? && val['error']
425
- res.error = Error::View.new("delete_design_doc", val['error'])
426
- end
427
- yield(res)
428
- end
429
- end
430
- req.continue
431
- unless async?
432
- rv.success? or raise res.error
433
- end
434
- end
435
-
436
346
  # Delete contents of the bucket
437
347
  #
438
348
  # @see http://www.couchbase.com/docs/couchbase-manual-2.0/restapi-flushing-bucket.html
@@ -1,3 +1,20 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2011, 2012 Couchbase, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
1
18
  module Couchbase
2
19
  module Constants # :nodoc:
3
20
  S_ID = 'id'.freeze
@@ -0,0 +1,83 @@
1
+ # Author:: Mike Evans <mike@urlgonomics.com>
2
+ # Copyright:: 2013 Urlgonomics LLC.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module Couchbase
19
+ class DesignDoc < ViewRow
20
+
21
+ # It isn't allowed to change design document ID after
22
+ # initialization
23
+ undef id=
24
+
25
+ def initialize(bucket, doc)
26
+ @all_views = {}
27
+ @bucket = bucket
28
+ @name = doc.name
29
+ @views = doc.views
30
+ @spatial = doc.spatial_views
31
+ @doc = {}
32
+ @views.each { |view| @all_views[view.name] = "#{@name}/_view/#{view.name}" }
33
+ @spatial.each { |view| @all_views[view.name] = "#{@name}/_spatial/#{view.name}" }
34
+ end
35
+
36
+ def method_missing(meth, *args)
37
+ if path = @all_views[meth.to_s]
38
+ View.new(@bucket, path, *args)
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ def respond_to_missing?(meth, *args)
45
+ @all_views[meth.to_s] || super
46
+ end
47
+
48
+ # The list of views defined or empty array
49
+ #
50
+ # @since 1.2.1
51
+ #
52
+ # @return [Array<View>]
53
+ attr_accessor :views
54
+
55
+ # The list of spatial views defined or empty array
56
+ #
57
+ # @since 1.2.1
58
+ #
59
+ # @return [Array<View>]
60
+ attr_accessor :spatial
61
+
62
+ # Check if the document has views defines
63
+ #
64
+ # @since 1.2.1
65
+ #
66
+ # @see DesignDoc#views
67
+ #
68
+ # @return [true, false] +true+ if the document have views
69
+ def has_views?
70
+ !@views.empty?
71
+ end
72
+
73
+ def inspect
74
+ desc = "#<#{self.class.name}:#{self.object_id}"
75
+ [:@id, :@views, :@spatial].each do |iv|
76
+ desc << " #{iv}=#{instance_variable_get(iv).inspect}"
77
+ end
78
+ desc << ">"
79
+ desc
80
+ end
81
+
82
+ end
83
+ end
@@ -1,7 +1,32 @@
1
+ # Author:: Mike Evans <mike@urlgonomics.com>
2
+ # Copyright:: 2013 Urlgonomics LLC.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
1
17
 
2
18
  module Couchbase
3
19
  module Error
4
20
  class Base < Exception
21
+ attr_accessor :cas, :error, :inner_exception, :key, :operation, :status
22
+
23
+ def to_s
24
+ if inner_exception
25
+ inner_exception.to_s
26
+ else
27
+ super
28
+ end
29
+ end
5
30
  end
6
31
 
7
32
  class Connect < Base
@@ -24,5 +49,11 @@ module Couchbase
24
49
 
25
50
  class ValueFormat < Base
26
51
  end
52
+
53
+ class TemporaryFail < Base
54
+ end
55
+
56
+ class NotStored < Base
57
+ end
27
58
  end
28
59
  end