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,192 @@
1
+ module Couchbase::Operations
2
+ module Unlock
3
+
4
+ # Unlock key
5
+ #
6
+ # @since 1.2.0
7
+ #
8
+ # The +unlock+ method allow you to unlock key once locked by {Bucket#get}
9
+ # with +:lock+ option.
10
+ #
11
+ # @overload unlock(key, options = {})
12
+ # @param key [String, Symbol] Key used to reference the value.
13
+ # @param options [Hash] Options for operation.
14
+ # @option options [Fixnum] :cas The CAS value must match the current one
15
+ # from the storage.
16
+ # @option options [true, false] :quiet (self.quiet) If set to +true+, the
17
+ # operation won't raise error for missing key, it will return +nil+.
18
+ #
19
+ # @return [true, false] +true+ if the operation was successful and +false+
20
+ # otherwise.
21
+ #
22
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
23
+ #
24
+ # @raise [ArgumentError] when passing the block in synchronous mode
25
+ #
26
+ # @raise [Couchbase::Error::NotFound] if key(s) not found in the storage
27
+ #
28
+ # @raise [Couchbase::Error::TemporaryFail] if either the key wasn't
29
+ # locked or given CAS value doesn't match to actual in the storage
30
+ #
31
+ # @example Unlock the single key
32
+ # val, _, cas = c.get("foo", :lock => true, :extended => true)
33
+ # c.unlock("foo", :cas => cas)
34
+ #
35
+ # @overload unlock(keys)
36
+ # @param keys [Hash] The Hash where keys represent the keys in the
37
+ # database, values -- the CAS for corresponding key.
38
+ #
39
+ # @yieldparam ret [Result] the result of operation for each key in
40
+ # asynchronous mode (valid attributes: +error+, +operation+, +key+).
41
+ #
42
+ # @return [Hash] Mapping keys to result of unlock operation (+true+ if the
43
+ # operation was successful and +false+ otherwise)
44
+ #
45
+ # @example Unlock several keys
46
+ # c.unlock("foo" => cas1, :bar => cas2) #=> {"foo" => true, "bar" => true}
47
+ #
48
+ # @example Unlock several values in async mode
49
+ # c.run do
50
+ # c.unlock("foo" => 10, :bar => 20) do |ret|
51
+ # ret.operation #=> :unlock
52
+ # ret.success? #=> true
53
+ # ret.key #=> "foo" and "bar" in separate calls
54
+ # end
55
+ # end
56
+ #
57
+
58
+ def unlock(key, options = {})
59
+ cas = options.respond_to?(:to_hash) ? options[:cas] : options
60
+ if client.unlock(key.to_s, cas)
61
+ true
62
+ else
63
+ raise Couchbase::Error::TemporaryFail.new
64
+ end
65
+ end
66
+
67
+ def async_unlock(key, options = {})
68
+
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+ __END__
75
+
76
+ /*
77
+ * Unlock key
78
+ *
79
+ * @since 1.2.0
80
+ *
81
+ * The +unlock+ method allow you to unlock key once locked by {Bucket#get}
82
+ * with +:lock+ option.
83
+ *
84
+ * @overload unlock(key, options = {})
85
+ * @param key [String, Symbol] Key used to reference the value.
86
+ * @param options [Hash] Options for operation.
87
+ * @option options [Fixnum] :cas The CAS value must match the current one
88
+ * from the storage.
89
+ * @option options [true, false] :quiet (self.quiet) If set to +true+, the
90
+ * operation won't raise error for missing key, it will return +nil+.
91
+ *
92
+ * @return [true, false] +true+ if the operation was successful and +false+
93
+ * otherwise.
94
+ *
95
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
96
+ *
97
+ * @raise [ArgumentError] when passing the block in synchronous mode
98
+ *
99
+ * @raise [Couchbase::Error::NotFound] if key(s) not found in the storage
100
+ *
101
+ * @raise [Couchbase::Error::TemporaryFail] if either the key wasn't
102
+ * locked or given CAS value doesn't match to actual in the storage
103
+ *
104
+ * @example Unlock the single key
105
+ * val, _, cas = c.get("foo", :lock => true, :extended => true)
106
+ * c.unlock("foo", :cas => cas)
107
+ *
108
+ * @overload unlock(keys)
109
+ * @param keys [Hash] The Hash where keys represent the keys in the
110
+ * database, values -- the CAS for corresponding key.
111
+ *
112
+ * @yieldparam ret [Result] the result of operation for each key in
113
+ * asynchronous mode (valid attributes: +error+, +operation+, +key+).
114
+ *
115
+ * @return [Hash] Mapping keys to result of unlock operation (+true+ if the
116
+ * operation was successful and +false+ otherwise)
117
+ *
118
+ * @example Unlock several keys
119
+ * c.unlock("foo" => cas1, :bar => cas2) #=> {"foo" => true, "bar" => true}
120
+ *
121
+ * @example Unlock several values in async mode
122
+ * c.run do
123
+ * c.unlock("foo" => 10, :bar => 20) do |ret|
124
+ * ret.operation #=> :unlock
125
+ * ret.success? #=> true
126
+ * ret.key #=> "foo" and "bar" in separate calls
127
+ * end
128
+ * end
129
+ *
130
+ */
131
+ VALUE
132
+ cb_bucket_unlock(int argc, VALUE *argv, VALUE self)
133
+ {
134
+ struct cb_bucket_st *bucket = DATA_PTR(self);
135
+ struct cb_context_st *ctx;
136
+ VALUE rv, proc, exc;
137
+ lcb_error_t err;
138
+ struct cb_params_st params;
139
+
140
+ if (!cb_bucket_connected_bang(bucket, cb_sym_unlock)) {
141
+ return Qnil;
142
+ }
143
+
144
+ memset(&params, 0, sizeof(struct cb_params_st));
145
+ rb_scan_args(argc, argv, "0*&", &params.args, &proc);
146
+ if (!bucket->async && proc != Qnil) {
147
+ rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
148
+ }
149
+ rb_funcall(params.args, cb_id_flatten_bang, 0);
150
+ params.type = cb_cmd_unlock;
151
+ params.bucket = bucket;
152
+ cb_params_build(&params);
153
+ ctx = cb_context_alloc_common(bucket, proc, params.cmd.unlock.num);
154
+ ctx->quiet = params.cmd.unlock.quiet;
155
+ err = lcb_unlock(bucket->handle, (const void *)ctx,
156
+ params.cmd.unlock.num, params.cmd.unlock.ptr);
157
+ cb_params_destroy(&params);
158
+ exc = cb_check_error(err, "failed to schedule unlock request", Qnil);
159
+ if (exc != Qnil) {
160
+ cb_context_free(ctx);
161
+ rb_exc_raise(exc);
162
+ }
163
+ bucket->nbytes += params.npayload;
164
+ if (bucket->async) {
165
+ cb_maybe_do_loop(bucket);
166
+ return Qnil;
167
+ } else {
168
+ if (ctx->nqueries > 0) {
169
+ /* we have some operations pending */
170
+ lcb_wait(bucket->handle);
171
+ }
172
+ exc = ctx->exception;
173
+ rv = ctx->rv;
174
+ cb_context_free(ctx);
175
+ if (exc != Qnil) {
176
+ rb_exc_raise(exc);
177
+ }
178
+ exc = bucket->exception;
179
+ if (exc != Qnil) {
180
+ bucket->exception = Qnil;
181
+ rb_exc_raise(exc);
182
+ }
183
+ if (params.cmd.unlock.num > 1) {
184
+ return rv; /* return as a hash {key => true, ...} */
185
+ } else {
186
+ VALUE vv = Qnil;
187
+ rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
188
+ return vv;
189
+ }
190
+ }
191
+ }
192
+
@@ -0,0 +1,44 @@
1
+ module Couchbase::Operations
2
+ module Utils
3
+
4
+ private
5
+
6
+ def validate_key(key)
7
+ if key_prefix
8
+ "#{key_prefix}key"
9
+ else
10
+ key.to_s
11
+ end
12
+ end
13
+
14
+ def extract_options_hash(args)
15
+ if args.size > 1 && args.last.respond_to?(:to_hash)
16
+ args.pop
17
+ else
18
+ {}
19
+ end
20
+ end
21
+
22
+ def sync_block_error
23
+ raise ArgumentError, "synchronous mode doesn't support callbacks"
24
+ end
25
+
26
+ def not_found_error(error, options = {})
27
+ if error
28
+ if options.key?(:quiet)
29
+ raise Couchbase::Error::NotFound.new if !options[:quiet]
30
+ elsif !quiet?
31
+ raise Couchbase::Error::NotFound.new
32
+ end
33
+ end
34
+ end
35
+
36
+ def future_cas(future)
37
+ future.get && future.getCas
38
+ rescue Java::JavaLang::UnsupportedOperationException
39
+ # TODO: don't return fake cas
40
+ 1
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ require 'couchbase/operations/touch'
2
+ require 'couchbase/operations/store'
3
+ require 'couchbase/operations/get'
4
+ require 'couchbase/operations/delete'
5
+ require 'couchbase/operations/unlock'
6
+ require 'couchbase/operations/arithmetic'
7
+ require 'couchbase/operations/stats'
8
+ require 'couchbase/operations/design_docs'
9
+ require 'couchbase/operations/utils'
10
+
11
+ module Couchbase
12
+ module Operations
13
+
14
+ def self.included(klass)
15
+ klass.send(:include, Store)
16
+ klass.send(:include, Get)
17
+ klass.send(:include, Touch)
18
+ klass.send(:include, Delete)
19
+ klass.send(:include, Unlock)
20
+ klass.send(:include, Arithmetic)
21
+ klass.send(:include, Stats)
22
+ klass.send(:include, DesignDocs)
23
+ klass.send(:include, Utils)
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,73 @@
1
+ module Couchbase
2
+ class Query
3
+
4
+ java_import com.couchbase.client.protocol.views.Stale
5
+
6
+ METHOD_MAPPING = {
7
+ :include_docs => :setIncludeDocs,
8
+ :descending => :setDescending,
9
+ :key => :setKey,
10
+ :keys => :setKeys,
11
+ :start_key => :setRangeStart,
12
+ :startkey => :setRangeStart,
13
+ :startkey_docid => :setStartkeyDocID,
14
+ :endkey => :setRangeEnd,
15
+ :endkey_docid => :setEndkeyDocID,
16
+ :inclusive_end => :setInclusiveEnd,
17
+ :limit => :setLimit,
18
+ :skip => :setSkip,
19
+ :reduce => :setReduce,
20
+ :group => :setGroup,
21
+ :group_level => :setGroupLevel,
22
+ :connection_timeout => nil
23
+ }.freeze
24
+
25
+ def initialize(params)
26
+ @params = params
27
+ end
28
+
29
+ def generate
30
+ query = Java::ComCouchbaseClientProtocolViews::Query.new
31
+
32
+ if stale = @params.delete(:stale)
33
+ case stale
34
+ when :after_update
35
+ query.setStale(Stale::UPDATE_AFTER)
36
+ when :ok
37
+ query.setStale(Stale::OK)
38
+ when false
39
+ query.setStale(Stale::FALSE)
40
+ end
41
+ end
42
+
43
+ @params.each_pair do |meth, val|
44
+ if METHOD_MAPPING.key?(meth)
45
+ if java_meth = METHOD_MAPPING[meth]
46
+ query.send(java_meth, val)
47
+ end
48
+ else
49
+ fail ArgumentError, "Query does not support #{meth}"
50
+ end
51
+ end
52
+
53
+
54
+ # @option params [true, false] :quiet (true) Do not raise error if
55
+ # associated document not found in the memory. If the parameter +true+
56
+ # will use +nil+ value instead.
57
+ # @option params [String, Symbol] :on_error (:continue) Sets the
58
+ # response in the event of an error. Supported values:
59
+ # :continue:: Continue to generate view information in the event of an
60
+ # error, including the error information in the view
61
+ # response stream.
62
+ # :stop:: Stop immediately when an error condition occurs. No
63
+ # further view information will be returned.
64
+ # @option params [Fixnum] :connection_timeout (75000) Timeout before the
65
+ # view request is dropped (milliseconds)
66
+
67
+
68
+ # @option params [Hash] :body
69
+ query
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,43 @@
1
+ module Couchbase
2
+ class Result
3
+
4
+ attr_accessor :error
5
+
6
+ def initialize(attrs = {})
7
+ @bucket = attrs[:bucket]
8
+ @key = attrs[:key]
9
+ @operation = attrs[:op]
10
+ @future = attrs[:future]
11
+ end
12
+
13
+ def operation
14
+ @operation
15
+ end
16
+
17
+ def success?
18
+ @future.get
19
+ end
20
+
21
+ def error
22
+ @error
23
+ end
24
+
25
+ def key
26
+ @key || @future.getKey
27
+ end
28
+
29
+ def value
30
+ @future.get
31
+ rescue MultiJson::LoadError
32
+ nil
33
+ end
34
+
35
+ def cas
36
+ @future.getCas if @future.respond_to?(:getCas)
37
+ end
38
+
39
+ def node
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,77 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2013 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
+
18
+ require 'multi_json'
19
+
20
+ module Couchbase
21
+
22
+ module Transcoder
23
+
24
+ class Base < Java::NetSpyMemcachedTranscoders::SerializingTranscoder
25
+ end
26
+
27
+ class Document < Base
28
+
29
+ def decode(d)
30
+ data = case decoded = super
31
+ when String
32
+ decoded
33
+ else
34
+ decoded.getData.to_s
35
+ end
36
+
37
+ MultiJson.load(data)
38
+ rescue MultiJson::LoadError
39
+ ::Marshal.load(data)
40
+ end
41
+
42
+ def encode(o)
43
+ super MultiJson.dump(o)
44
+ rescue ArgumentError => e
45
+ ex = Couchbase::Error::ValueFormat.new
46
+ ex.inner_exception = e
47
+ fail ex
48
+ end
49
+ end
50
+
51
+ class Marshal < Base
52
+
53
+ def decode(d)
54
+ ::Marshal.load super.getData.to_s
55
+ end
56
+
57
+ def encode(o)
58
+ super ::Marshal.dump(o)
59
+ end
60
+ end
61
+
62
+ class Plain < Base
63
+
64
+ def decode(d)
65
+ super
66
+ end
67
+
68
+ def encode(o)
69
+ super(o.to_str)
70
+ rescue NoMethodError
71
+ raise Couchbase::Error::ValueFormat
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,62 @@
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
+
18
+ module Couchbase
19
+
20
+ class Utils
21
+
22
+ def self.encode_params(params)
23
+ params.map do |k, v|
24
+ next if !v && k.to_s == "group"
25
+ if %w{key keys startkey endkey start_key end_key}.include?(k.to_s)
26
+ v = MultiJson.dump(v)
27
+ end
28
+ if v.class == Array
29
+ build_query(v.map { |x| [k, x] })
30
+ else
31
+ "#{escape(k)}=#{escape(v)}"
32
+ end
33
+ end.compact.join("&")
34
+ end
35
+
36
+ def self.build_query(uri, params = nil)
37
+ uri = uri.dup
38
+ return uri if params.nil? || params.empty?
39
+ uri << "?" << encode_params(params)
40
+ end
41
+
42
+ def self.escape(s)
43
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/nu) {
44
+ '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
45
+ }.tr(' ', '+')
46
+ end
47
+
48
+ # Return the bytesize of String; uses String#size under Ruby 1.8 and
49
+ # String#bytesize under 1.9.
50
+ if ''.respond_to?(:bytesize)
51
+ def self.bytesize(string)
52
+ string.bytesize
53
+ end
54
+ else
55
+ def self.bytesize(string)
56
+ string.size
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,3 @@
1
+ module Couchbase
2
+ VERSION = '0.1.1'
3
+ end