couchbase-jruby-client 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.jrubyrc +722 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.md +349 -0
- data/Rakefile +10 -0
- data/couchbase-jruby-client.gemspec +31 -0
- data/lib/couchbase/async/callback.rb +19 -0
- data/lib/couchbase/async/queue.rb +26 -0
- data/lib/couchbase/async.rb +140 -0
- data/lib/couchbase/bucket.rb +556 -0
- data/lib/couchbase/cluster.rb +105 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/design_doc.rb +61 -0
- data/lib/couchbase/error.rb +43 -0
- data/lib/couchbase/jruby/couchbase_client.rb +22 -0
- data/lib/couchbase/jruby/future.rb +8 -0
- data/lib/couchbase/operations/arithmetic.rb +301 -0
- data/lib/couchbase/operations/delete.rb +104 -0
- data/lib/couchbase/operations/design_docs.rb +99 -0
- data/lib/couchbase/operations/get.rb +282 -0
- data/lib/couchbase/operations/stats.rb +26 -0
- data/lib/couchbase/operations/store.rb +461 -0
- data/lib/couchbase/operations/touch.rb +136 -0
- data/lib/couchbase/operations/unlock.rb +192 -0
- data/lib/couchbase/operations/utils.rb +44 -0
- data/lib/couchbase/operations.rb +27 -0
- data/lib/couchbase/query.rb +73 -0
- data/lib/couchbase/result.rb +43 -0
- data/lib/couchbase/transcoder.rb +77 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +3 -0
- data/lib/couchbase/view.rb +367 -0
- data/lib/couchbase/view_row.rb +193 -0
- data/lib/couchbase.rb +157 -0
- data/lib/jars/commons-codec-1.5.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0-javadoc.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0-sources.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0.jar +0 -0
- data/lib/jars/httpcore-4.1.1.jar +0 -0
- data/lib/jars/httpcore-nio-4.1.1.jar +0 -0
- data/lib/jars/jettison-1.1.jar +0 -0
- data/lib/jars/netty-3.5.5.Final.jar +0 -0
- data/lib/jars/spymemcached-2.10.0-javadoc.jar +0 -0
- data/lib/jars/spymemcached-2.10.0-sources.jar +0 -0
- data/lib/jars/spymemcached-2.10.0.jar +0 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/.jrubyrc +722 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +168 -0
- data/test/profile/profile.rb +59 -0
- data/test/setup.rb +203 -0
- data/test/test_arithmetic.rb +177 -0
- data/test/test_async.rb +324 -0
- data/test/test_bucket.rb +213 -0
- data/test/test_cas.rb +79 -0
- data/test/test_couchbase.rb +29 -0
- data/test/test_couchbase_rails_cache_store.rb +341 -0
- data/test/test_delete.rb +125 -0
- data/test/test_design_docs.rb +72 -0
- data/test/test_errors.rb +82 -0
- data/test/test_format.rb +161 -0
- data/test/test_get.rb +417 -0
- data/test/test_query.rb +23 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +213 -0
- data/test/test_timer.rb +43 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +121 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +53 -0
- data/test/test_view.rb +94 -0
- 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(¶ms, 0, sizeof(struct cb_params_st));
|
145
|
+
rb_scan_args(argc, argv, "0*&", ¶ms.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(¶ms);
|
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(¶ms);
|
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
|