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.
- 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
|