couchbase-jruby-client 0.1.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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.jrubyrc +722 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +203 -0
  7. data/README.md +349 -0
  8. data/Rakefile +10 -0
  9. data/couchbase-jruby-client.gemspec +31 -0
  10. data/lib/couchbase/async/callback.rb +19 -0
  11. data/lib/couchbase/async/queue.rb +26 -0
  12. data/lib/couchbase/async.rb +140 -0
  13. data/lib/couchbase/bucket.rb +556 -0
  14. data/lib/couchbase/cluster.rb +105 -0
  15. data/lib/couchbase/constants.rb +12 -0
  16. data/lib/couchbase/design_doc.rb +61 -0
  17. data/lib/couchbase/error.rb +43 -0
  18. data/lib/couchbase/jruby/couchbase_client.rb +22 -0
  19. data/lib/couchbase/jruby/future.rb +8 -0
  20. data/lib/couchbase/operations/arithmetic.rb +301 -0
  21. data/lib/couchbase/operations/delete.rb +104 -0
  22. data/lib/couchbase/operations/design_docs.rb +99 -0
  23. data/lib/couchbase/operations/get.rb +282 -0
  24. data/lib/couchbase/operations/stats.rb +26 -0
  25. data/lib/couchbase/operations/store.rb +461 -0
  26. data/lib/couchbase/operations/touch.rb +136 -0
  27. data/lib/couchbase/operations/unlock.rb +192 -0
  28. data/lib/couchbase/operations/utils.rb +44 -0
  29. data/lib/couchbase/operations.rb +27 -0
  30. data/lib/couchbase/query.rb +73 -0
  31. data/lib/couchbase/result.rb +43 -0
  32. data/lib/couchbase/transcoder.rb +77 -0
  33. data/lib/couchbase/utils.rb +62 -0
  34. data/lib/couchbase/version.rb +3 -0
  35. data/lib/couchbase/view.rb +367 -0
  36. data/lib/couchbase/view_row.rb +193 -0
  37. data/lib/couchbase.rb +157 -0
  38. data/lib/jars/commons-codec-1.5.jar +0 -0
  39. data/lib/jars/couchbase-client-1.2.0-javadoc.jar +0 -0
  40. data/lib/jars/couchbase-client-1.2.0-sources.jar +0 -0
  41. data/lib/jars/couchbase-client-1.2.0.jar +0 -0
  42. data/lib/jars/httpcore-4.1.1.jar +0 -0
  43. data/lib/jars/httpcore-nio-4.1.1.jar +0 -0
  44. data/lib/jars/jettison-1.1.jar +0 -0
  45. data/lib/jars/netty-3.5.5.Final.jar +0 -0
  46. data/lib/jars/spymemcached-2.10.0-javadoc.jar +0 -0
  47. data/lib/jars/spymemcached-2.10.0-sources.jar +0 -0
  48. data/lib/jars/spymemcached-2.10.0.jar +0 -0
  49. data/test/profile/.gitignore +1 -0
  50. data/test/profile/.jrubyrc +722 -0
  51. data/test/profile/Gemfile +6 -0
  52. data/test/profile/benchmark.rb +168 -0
  53. data/test/profile/profile.rb +59 -0
  54. data/test/setup.rb +203 -0
  55. data/test/test_arithmetic.rb +177 -0
  56. data/test/test_async.rb +324 -0
  57. data/test/test_bucket.rb +213 -0
  58. data/test/test_cas.rb +79 -0
  59. data/test/test_couchbase.rb +29 -0
  60. data/test/test_couchbase_rails_cache_store.rb +341 -0
  61. data/test/test_delete.rb +125 -0
  62. data/test/test_design_docs.rb +72 -0
  63. data/test/test_errors.rb +82 -0
  64. data/test/test_format.rb +161 -0
  65. data/test/test_get.rb +417 -0
  66. data/test/test_query.rb +23 -0
  67. data/test/test_stats.rb +57 -0
  68. data/test/test_store.rb +213 -0
  69. data/test/test_timer.rb +43 -0
  70. data/test/test_touch.rb +97 -0
  71. data/test/test_unlock.rb +121 -0
  72. data/test/test_utils.rb +58 -0
  73. data/test/test_version.rb +53 -0
  74. data/test/test_view.rb +94 -0
  75. metadata +255 -0
@@ -0,0 +1,99 @@
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::Operations
19
+ module DesignDocs
20
+
21
+ java_import com.couchbase.client.protocol.views.DesignDocument
22
+ java_import com.couchbase.client.protocol.views.ViewDesign
23
+
24
+ class DesignDocAccess
25
+ def initialize(bucket)
26
+ @bucket = bucket
27
+ end
28
+
29
+ def [](name)
30
+ doc = @bucket.client.getDesignDocument(name)
31
+ Couchbase::DesignDoc.new(@bucket, doc)
32
+ rescue Java::ComCouchbaseClientProtocolViews::InvalidViewException
33
+ nil
34
+ end
35
+ end
36
+
37
+ # Fetch design docs stored in current bucket
38
+ #
39
+ # @since 1.2.0
40
+ #
41
+ # @return [Hash]
42
+ def design_docs
43
+ DesignDocAccess.new(self)
44
+ end
45
+
46
+ # Update or create design doc with supplied views
47
+ #
48
+ # @since 1.2.0
49
+ #
50
+ # @param [Hash, IO, String] data The source object containing JSON
51
+ # encoded design document. It must have +_id+ key set, this key
52
+ # should start with +_design/+.
53
+ #
54
+ # @return [true, false]
55
+ def save_design_doc(data)
56
+ attrs = case data
57
+ when String
58
+ MultiJson.load(data)
59
+ when IO
60
+ MultiJson.load(data.read)
61
+ when Hash
62
+ data
63
+ else
64
+ raise ArgumentError, "Document should be Hash, String or IO instance"
65
+ end
66
+
67
+ id = attrs.delete('_id').to_s.split('/')[1]
68
+
69
+ design_doc = DesignDocument.new(id)
70
+
71
+ attrs['views'].each_pair do |view, functions|
72
+ view_design = if functions['reduce']
73
+ ViewDesign.new(view, functions['map'], functions['reduce'])
74
+ else
75
+ ViewDesign.new(view, functions['map'])
76
+ end
77
+ design_doc.getViews.add(view_design)
78
+ end
79
+
80
+ client.createDesignDoc(design_doc)
81
+ end
82
+
83
+ # Delete design doc with given id and revision.
84
+ #
85
+ # @since 1.2.0
86
+ #
87
+ # @param [String] id Design document id. It might have '_design/'
88
+ # prefix.
89
+ #
90
+ # @param [String] rev Document revision. It uses latest revision if
91
+ # +rev+ parameter is nil.
92
+ #
93
+ # @return [true, false]
94
+ def delete_design_doc(id, rev = nil)
95
+ client.deleteDesignDoc(id)
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,282 @@
1
+ module Couchbase::Operations
2
+ module Get
3
+
4
+ # Obtain an object stored in Couchbase by given key.
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ # @see http://couchbase.com/docs/couchbase-manual-2.0/couchbase-architecture-apis-memcached-protocol-additions.html#couchbase-architecture-apis-memcached-protocol-additions-getl
9
+ #
10
+ # @overload get(*keys, options = {})
11
+ # @param keys [String, Symbol, Array] One or several keys to fetch
12
+ # @param options [Hash] Options for operation.
13
+ # @option options [true, false] :extended (false) If set to +true+, the
14
+ # operation will return a tuple +[value, flags, cas]+, otherwise (by
15
+ # default) it returns just the value.
16
+ # @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
17
+ # Values larger than 30*24*60*60 seconds (30 days) are interpreted as
18
+ # absolute times (from the epoch).
19
+ # @option options [true, false] :quiet (self.quiet) If set to +true+, the
20
+ # operation won't raise error for missing key, it will return +nil+.
21
+ # Otherwise it will raise error in synchronous mode. In asynchronous
22
+ # mode this option ignored.
23
+ # @option options [Symbol] :format (nil) Explicitly choose the decoder
24
+ # for this key (+:plain+, +:document+, +:marshal+). See
25
+ # {Bucket#default_format}.
26
+ # @option options [Fixnum, Boolean] :lock Lock the keys for time span.
27
+ # If this parameter is +true+ the key(s) will be locked for default
28
+ # timeout. Also you can use number to setup your own timeout in
29
+ # seconds. If it will be lower that zero or exceed the maximum, the
30
+ # server will use default value. You can determine actual default and
31
+ # maximum values calling {Bucket#stats} without arguments and
32
+ # inspecting keys "ep_getl_default_timeout" and "ep_getl_max_timeout"
33
+ # correspondingly. See overloaded hash syntax to specify custom timeout
34
+ # per each key.
35
+ # @option options [true, false] :assemble_hash (false) Assemble Hash for
36
+ # results. Hash assembled automatically if +:extended+ option is true
37
+ # or in case of "get and touch" multimple keys.
38
+ # @option options [true, false] :replica (false) Read key from replica
39
+ # node. Options +:ttl+ and +:lock+ are not compatible with +:replica+.
40
+ #
41
+ # @yieldparam ret [Result] the result of operation in asynchronous mode
42
+ # (valid attributes: +error+, +operation+, +key+, +value+, +flags+,
43
+ # +cas+).
44
+ #
45
+ # @return [Object, Array, Hash] the value(s) (or tuples in extended mode)
46
+ # associated with the key.
47
+ #
48
+ # @raise [Couchbase::Error::NotFound] if the key is missing in the
49
+ # bucket.
50
+ #
51
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
52
+ #
53
+ # @raise [ArgumentError] when passing the block in synchronous mode
54
+ #
55
+ # @example Get single value in quiet mode (the default)
56
+ # c.get("foo") #=> the associated value or nil
57
+ #
58
+ # @example Use alternative hash-like syntax
59
+ # c["foo"] #=> the associated value or nil
60
+ #
61
+ # @example Get single value in verbose mode
62
+ # c.get("missing-foo", :quiet => false) #=> raises Couchbase::NotFound
63
+ # c.get("missing-foo", :quiet => true) #=> returns nil
64
+ #
65
+ # @example Get and touch single value. The key won't be accessible after 10 seconds
66
+ # c.get("foo", :ttl => 10)
67
+ #
68
+ # @example Extended get
69
+ # val, flags, cas = c.get("foo", :extended => true)
70
+ #
71
+ # @example Get multiple keys
72
+ # c.get("foo", "bar", "baz") #=> [val1, val2, val3]
73
+ #
74
+ # @example Get multiple keys with assembing result into the Hash
75
+ # c.get("foo", "bar", "baz", :assemble_hash => true)
76
+ # #=> {"foo" => val1, "bar" => val2, "baz" => val3}
77
+ #
78
+ # @example Extended get multiple keys
79
+ # c.get("foo", "bar", :extended => true)
80
+ # #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
81
+ #
82
+ # @example Asynchronous get
83
+ # c.run do
84
+ # c.get("foo", "bar", "baz") do |res|
85
+ # ret.operation #=> :get
86
+ # ret.success? #=> true
87
+ # ret.key #=> "foo", "bar" or "baz" in separate calls
88
+ # ret.value
89
+ # ret.flags
90
+ # ret.cas
91
+ # end
92
+ # end
93
+ #
94
+ # @example Get and lock key using default timeout
95
+ # c.get("foo", :lock => true)
96
+ #
97
+ # @example Determine lock timeout parameters
98
+ # c.stats.values_at("ep_getl_default_timeout", "ep_getl_max_timeout")
99
+ # #=> [{"127.0.0.1:11210"=>"15"}, {"127.0.0.1:11210"=>"30"}]
100
+ #
101
+ # @example Get and lock key using custom timeout
102
+ # c.get("foo", :lock => 3)
103
+ #
104
+ # @example Get and lock multiple keys using custom timeout
105
+ # c.get("foo", "bar", :lock => 3)
106
+ #
107
+ # @overload get(keys, options = {})
108
+ # When the method receive hash map, it will behave like it receive list
109
+ # of keys (+keys.keys+), but also touch each key setting expiry time to
110
+ # the corresponding value. But unlike usual get this command always
111
+ # return hash map +{key => value}+ or +{key => [value, flags, cas]}+.
112
+ #
113
+ # @param keys [Hash] Map key-ttl
114
+ # @param options [Hash] Options for operation. (see options definition
115
+ # above)
116
+ #
117
+ # @return [Hash] the values (or tuples in extended mode) associated with
118
+ # the keys.
119
+ #
120
+ # @example Get and touch multiple keys
121
+ # c.get("foo" => 10, "bar" => 20) #=> {"foo" => val1, "bar" => val2}
122
+ #
123
+ # @example Extended get and touch multiple keys
124
+ # c.get({"foo" => 10, "bar" => 20}, :extended => true)
125
+ # #=> {"foo" => [val1, flags1, cas1], "bar" => [val2, flags2, cas2]}
126
+ #
127
+ # @example Get and lock multiple keys for chosen period in seconds
128
+ # c.get("foo" => 10, "bar" => 20, :lock => true)
129
+ # #=> {"foo" => val1, "bar" => val2}
130
+ #
131
+ def get(*args)
132
+ key, options = expand_get_args(args)
133
+
134
+ if async?
135
+ if block_given?
136
+ async_get(key, &Proc.new)
137
+ else
138
+ async_get(key)
139
+ end
140
+ else
141
+ sync_block_error if block_given?
142
+ case key
143
+ when String, Symbol
144
+ get_single(key, options)
145
+ when Array
146
+ get_bulk(key, options)
147
+ when Hash
148
+ get_and_touch(key, options)
149
+ end
150
+ end
151
+ end
152
+
153
+ def [](key, options = {})
154
+ get(key, options)
155
+ end
156
+
157
+ def get_bulk(keys, options)
158
+ results = if options[:extended]
159
+ get_bulk_extended(keys)
160
+ else
161
+ client_get_bulk(keys)
162
+ end
163
+
164
+ not_found_error(results.size != keys.size, options)
165
+
166
+ if options[:assemble_hash] || options[:extended]
167
+ results
168
+ else
169
+ ordered_multi_values(keys, results)
170
+ end
171
+ end
172
+
173
+ def async_get(key)
174
+ case key
175
+ when String, Symbol
176
+ meta = { op: :get, key: key }
177
+ future = client.asyncGet(key)
178
+ when Array
179
+ meta = { op: :get }
180
+ future = client.asyncGetBulk(keys)
181
+ when Hash
182
+ # async_get_and_touch(key, options, &block)
183
+ end
184
+ register_future(future, meta, &Proc.new) if block_given?
185
+ end
186
+
187
+ private
188
+
189
+ def expand_get_args(args)
190
+ options = extract_options_hash(args)
191
+ key = args.size == 1 ? args.first : args
192
+
193
+ [key, options]
194
+ end
195
+
196
+ def get_single(key, options)
197
+ if options[:lock]
198
+ client_get_and_lock(key, options)
199
+ elsif options[:extended]
200
+ get_extended(key, options)
201
+ else
202
+ value = if options.key?(:ttl)
203
+ client_get_and_touch(key, options[:ttl])
204
+ else
205
+ client.get(key)
206
+ end
207
+
208
+ not_found_error(value.nil?, options)
209
+ value.nil? ? nil : value
210
+ end
211
+ end
212
+
213
+ def get_extended(key, options = {})
214
+ if options.key?(:lock)
215
+ client_get_and_lock(key, options[:lock])
216
+ end
217
+ extended = client_get_extended(key)
218
+ not_found_error(extended.nil?, options)
219
+ extended
220
+ end
221
+
222
+ def get_and_touch(key, options = {})
223
+ if key.size > 1
224
+ get_bulk_and_touch(key, options)
225
+ else
226
+ key, ttl = key.first
227
+ value = client_get_and_touch(key, ttl)
228
+ not_found_error(value.nil?)
229
+ { key => value }
230
+ end
231
+ end
232
+
233
+ def get_bulk_and_touch(keys, options = {})
234
+ options.merge!(assemble_hash: true)
235
+ results = get_bulk(keys.keys, options)
236
+ touch(keys)
237
+ results.to_hash
238
+ end
239
+
240
+ def get_bulk_extended(keys, options = {})
241
+ {}.tap do |results|
242
+ keys.each do |key|
243
+ results[key] = get_extended(key, options)
244
+ end
245
+ end
246
+ end
247
+
248
+ def ordered_multi_values(keys, results)
249
+ keys.map { |key| results[key] }
250
+ end
251
+
252
+ def client_get_and_touch(key, ttl)
253
+ client.getAndTouch(key, ttl).getValue
254
+ end
255
+
256
+ def client_get_and_lock(key, options)
257
+ lock = options[:lock] == true ? 30 : options[:lock]
258
+ cas = client.getAndLock(key, lock)
259
+ if options[:extended]
260
+ [cas.getValue, nil, cas.getCas]
261
+ else
262
+ cas.getValue
263
+ end
264
+ end
265
+
266
+ def client_get_extended(key)
267
+ cas_value = client.gets(key)
268
+
269
+ if cas_value.nil?
270
+ nil
271
+ else
272
+ [cas_value.getValue, nil, cas_value.getCas]
273
+ end
274
+ end
275
+
276
+ def client_get_bulk(keys)
277
+ client.getBulk(keys)
278
+ rescue java.lang.ClassCastException
279
+ raise TypeError.new
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,26 @@
1
+ module Couchbase::Operations
2
+ module Stats
3
+
4
+ def stats(statname = nil)
5
+ sync_block_error if !async? && block_given?
6
+ stats = if statname.nil?
7
+ client.getStats
8
+ else
9
+ client.getStats(statname)
10
+ end
11
+
12
+ stats = stats.to_hash
13
+
14
+ {}.tap do |hash|
15
+ stats.each_pair do |node, values|
16
+ node_value = node.to_s
17
+ values.each_pair do |stat, value|
18
+ hash[stat] ||= {}
19
+ hash[stat][node_value] = value
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+ end