couchbase-jruby-client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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