couchbase 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.markdown +6 -0
- data/README.markdown +18 -10
- data/ext/couchbase_ext/couchbase_ext.c +39 -12
- data/lib/couchbase/version.rb +1 -1
- data/test/test_get.rb +19 -0
- metadata +126 -103
data/HISTORY.markdown
CHANGED
data/README.markdown
CHANGED
@@ -81,26 +81,34 @@ as the endpoint. The client will automatically adjust configuration when
|
|
81
81
|
the cluster will rebalance its nodes when nodes are added or deleted
|
82
82
|
therefore this client is "smart".
|
83
83
|
|
84
|
-
c = Couchbase.
|
84
|
+
c = Couchbase.connect
|
85
85
|
|
86
86
|
This is equivalent to following forms:
|
87
87
|
|
88
|
-
c = Couchbase.
|
89
|
-
c = Couchbase.
|
90
|
-
c = Couchbase.
|
91
|
-
c = Couchbase.
|
92
|
-
c = Couchbase.
|
93
|
-
c = Couchbase.
|
88
|
+
c = Couchbase.connect("http://localhost:8091/pools/default/buckets/default")
|
89
|
+
c = Couchbase.connect("http://localhost:8091/pools/default")
|
90
|
+
c = Couchbase.connect("http://localhost:8091")
|
91
|
+
c = Couchbase.connect(:hostname => "localhost")
|
92
|
+
c = Couchbase.connect(:hostname => "localhost", :port => 8091)
|
93
|
+
c = Couchbase.connect(:pool => "default", :bucket => "default")
|
94
94
|
|
95
95
|
The hash parameters take precedence on string URL.
|
96
96
|
|
97
|
+
There is also handy method `Couchbase.bucket` which uses thread local
|
98
|
+
storage to keep the reference to default connection. You can set the
|
99
|
+
connection options via `Couchbase.connection_options`:
|
100
|
+
|
101
|
+
Couchbase.connection_options = {:bucket => 'blog'}
|
102
|
+
Couchbase.bucket.name #=> "blog"
|
103
|
+
Couchbase.bucket.set("foo", "bar") #=> 3289400178357895424
|
104
|
+
|
97
105
|
The library supports both synchronous and asynchronous mode. In
|
98
106
|
asynchronous mode all operations will return control to caller
|
99
107
|
without blocking current thread. You can pass the block to method and it
|
100
108
|
will be called with result when the operation will be completed. You
|
101
109
|
need to run event loop when you scheduled your operations:
|
102
110
|
|
103
|
-
c = Couchbase.
|
111
|
+
c = Couchbase.connect
|
104
112
|
c.run do |conn|
|
105
113
|
conn.get("foo") {|ret| puts ret.value}
|
106
114
|
conn.set("bar", "baz")
|
@@ -166,12 +174,12 @@ The library supports three different formats for representing values:
|
|
166
174
|
version will be able to run map/reduce queries on the values in the
|
167
175
|
document form (hashes)
|
168
176
|
|
169
|
-
* `:
|
177
|
+
* `:plain` This format avoids any conversions to be applied to your
|
170
178
|
data, but your data should be passed as String. This is useful for
|
171
179
|
building custom algorithms or formats. For example to implement a set:
|
172
180
|
http://dustin.github.com/2011/02/17/memcached-set.html
|
173
181
|
|
174
|
-
* `:
|
182
|
+
* `:marshal` Use this format if you'd like to transparently serialize your
|
175
183
|
ruby object with standard `Marshal.dump` and `Marshal.load` methods
|
176
184
|
|
177
185
|
The couchbase API is the superset of [Memcached binary protocol][5], so
|
@@ -73,6 +73,7 @@ typedef struct
|
|
73
73
|
VALUE proc;
|
74
74
|
void *rv;
|
75
75
|
VALUE exception;
|
76
|
+
VALUE force_format;
|
76
77
|
int quiet;
|
77
78
|
int arithm; /* incr: +1, decr: -1, other: 0 */
|
78
79
|
} context_t;
|
@@ -88,6 +89,7 @@ struct key_traits
|
|
88
89
|
int explicit_ttl;
|
89
90
|
int quiet;
|
90
91
|
int mgat;
|
92
|
+
VALUE force_format;
|
91
93
|
};
|
92
94
|
|
93
95
|
static VALUE mCouchbase, mError, mJSON, mURI, mMarshal, cBucket, cResult;
|
@@ -190,6 +192,9 @@ cb_proc_call(VALUE recv, int argc, ...)
|
|
190
192
|
int ii;
|
191
193
|
|
192
194
|
arity = FIX2INT(rb_funcall(recv, id_arity, 0));
|
195
|
+
if (arity < 0) {
|
196
|
+
arity = argc;
|
197
|
+
}
|
193
198
|
if (arity > 0) {
|
194
199
|
va_init_list(ar, argc);
|
195
200
|
argv = ALLOCA_N(VALUE, argc);
|
@@ -202,7 +207,6 @@ cb_proc_call(VALUE recv, int argc, ...)
|
|
202
207
|
}
|
203
208
|
va_end(ar);
|
204
209
|
} else {
|
205
|
-
arity = 0;
|
206
210
|
argv = NULL;
|
207
211
|
}
|
208
212
|
return rb_funcall2(recv, id_call, arity, argv);
|
@@ -367,18 +371,30 @@ do_encode(VALUE *args)
|
|
367
371
|
do_decode(VALUE *args)
|
368
372
|
{
|
369
373
|
VALUE blob = args[0];
|
370
|
-
|
374
|
+
VALUE force_format = args[2];
|
371
375
|
|
372
|
-
|
373
|
-
|
376
|
+
if (TYPE(force_format) == T_SYMBOL) {
|
377
|
+
if (force_format == sym_document) {
|
374
378
|
return rb_funcall(mJSON, id_load, 1, blob);
|
375
|
-
|
379
|
+
} else if (force_format == sym_marshal) {
|
376
380
|
return rb_funcall(mMarshal, id_load, 1, blob);
|
377
|
-
|
378
|
-
/* fall through */
|
379
|
-
default:
|
380
|
-
/* all other formats treated as plain */
|
381
|
+
} else { /* sym_plain and any other symbol */
|
381
382
|
return blob;
|
383
|
+
}
|
384
|
+
} else {
|
385
|
+
uint32_t flags = ((uint32_t)args[1] & FMT_MASK);
|
386
|
+
|
387
|
+
switch (flags) {
|
388
|
+
case FMT_DOCUMENT:
|
389
|
+
return rb_funcall(mJSON, id_load, 1, blob);
|
390
|
+
case FMT_MARSHAL:
|
391
|
+
return rb_funcall(mMarshal, id_load, 1, blob);
|
392
|
+
case FMT_PLAIN:
|
393
|
+
/* fall through */
|
394
|
+
default:
|
395
|
+
/* all other formats treated as plain */
|
396
|
+
return blob;
|
397
|
+
}
|
382
398
|
}
|
383
399
|
}
|
384
400
|
|
@@ -404,9 +420,9 @@ encode_value(VALUE val, uint32_t flags)
|
|
404
420
|
}
|
405
421
|
|
406
422
|
static VALUE
|
407
|
-
decode_value(VALUE blob, uint32_t flags)
|
423
|
+
decode_value(VALUE blob, uint32_t flags, VALUE force_format)
|
408
424
|
{
|
409
|
-
VALUE val, args[
|
425
|
+
VALUE val, args[3];
|
410
426
|
|
411
427
|
/* first it must be bytestring */
|
412
428
|
if (TYPE(blob) != T_STRING) {
|
@@ -414,6 +430,7 @@ decode_value(VALUE blob, uint32_t flags)
|
|
414
430
|
}
|
415
431
|
args[0] = blob;
|
416
432
|
args[1] = (VALUE)flags;
|
433
|
+
args[2] = (VALUE)force_format;
|
417
434
|
val = rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
|
418
435
|
return val;
|
419
436
|
}
|
@@ -465,6 +482,10 @@ cb_args_scan_keys(long argc, VALUE argv, bucket_t *bucket, struct key_traits *tr
|
|
465
482
|
if (RTEST(rb_funcall(opts, id_has_key_p, 1, sym_quiet))) {
|
466
483
|
traits->quiet = RTEST(rb_hash_aref(opts, sym_quiet));
|
467
484
|
}
|
485
|
+
traits->force_format = rb_hash_aref(opts, sym_format);
|
486
|
+
if (traits->force_format != Qnil) {
|
487
|
+
Check_Type(traits->force_format, T_SYMBOL);
|
488
|
+
}
|
468
489
|
ext = rb_hash_aref(opts, sym_extended);
|
469
490
|
ttl = rb_hash_aref(opts, sym_ttl);
|
470
491
|
if (ttl != Qnil) {
|
@@ -644,9 +665,11 @@ get_callback(libcouchbase_t handle, const void *cookie,
|
|
644
665
|
f = ULONG2NUM(flags);
|
645
666
|
c = ULL2NUM(cas);
|
646
667
|
if (nbytes != 0) {
|
647
|
-
v = decode_value(rb_str_new((const char*)bytes, nbytes), flags);
|
668
|
+
v = decode_value(rb_str_new((const char*)bytes, nbytes), flags, ctx->force_format);
|
648
669
|
if (v == Qundef) {
|
649
670
|
ctx->exception = rb_exc_new2(eValueFormatError, "unable to convert value");
|
671
|
+
rb_ivar_set(ctx->exception, id_iv_operation, sym_get);
|
672
|
+
rb_ivar_set(ctx->exception, id_iv_key, k);
|
650
673
|
v = Qnil;
|
651
674
|
}
|
652
675
|
} else {
|
@@ -2082,6 +2105,9 @@ cb_bucket_decr(int argc, VALUE *argv, VALUE self)
|
|
2082
2105
|
* operation won't raise error for missing key, it will return +nil+.
|
2083
2106
|
* Otherwise it will raise error in synchronous mode. In asynchronous
|
2084
2107
|
* mode this option ignored.
|
2108
|
+
* @option options [Symbol] :format (nil) Explicitly choose the decoder
|
2109
|
+
* for this key (+:plain+, +:document+, +:marshal+). See
|
2110
|
+
* {Bucket#default_format}.
|
2085
2111
|
*
|
2086
2112
|
* @yieldparam ret [Result] the result of operation in asynchronous mode
|
2087
2113
|
* (valid attributes: +error+, +operation+, +key+, +value+, +flags+,
|
@@ -2184,6 +2210,7 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
|
|
2184
2210
|
ctx->bucket = bucket;
|
2185
2211
|
ctx->extended = traits->extended;
|
2186
2212
|
ctx->quiet = traits->quiet;
|
2213
|
+
ctx->force_format = traits->force_format;
|
2187
2214
|
rv = rb_hash_new();
|
2188
2215
|
ctx->rv = &rv;
|
2189
2216
|
ctx->exception = Qnil;
|
data/lib/couchbase/version.rb
CHANGED
data/test/test_get.rb
CHANGED
@@ -308,4 +308,23 @@ class TestGet < MiniTest::Unit::TestCase
|
|
308
308
|
assert_equal nil, connection.get(uniq_id, :quiet => false)
|
309
309
|
end
|
310
310
|
|
311
|
+
def test_format_forcing
|
312
|
+
connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
|
313
|
+
|
314
|
+
connection.set(uniq_id, '{"foo":"bar"}', :format => :plain)
|
315
|
+
value, flags, _ = connection.get(uniq_id, :extended => true)
|
316
|
+
assert_equal '{"foo":"bar"}', value
|
317
|
+
assert_equal 0x02, flags
|
318
|
+
|
319
|
+
value, flags, _ = connection.get(uniq_id, :extended => true, :format => :document)
|
320
|
+
expected = {"foo" => "bar"}
|
321
|
+
assert_equal expected, value
|
322
|
+
assert_equal 0x02, flags
|
323
|
+
|
324
|
+
connection.prepend(uniq_id, "NOT-A-JSON")
|
325
|
+
assert_raises Couchbase::Error::ValueFormat do
|
326
|
+
connection.get(uniq_id, :format => :document)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
311
330
|
end
|
metadata
CHANGED
@@ -1,111 +1,149 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchbase
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 1.1.1
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Couchbase
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
requirement: &
|
17
|
+
|
18
|
+
date: 2012-03-19 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
22
|
none: false
|
18
|
-
requirements:
|
23
|
+
requirements:
|
19
24
|
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
hash: 19
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 1
|
30
|
+
- 0
|
21
31
|
version: 1.1.0
|
22
32
|
type: :runtime
|
33
|
+
name: yajl-ruby
|
34
|
+
version_requirements: *id001
|
23
35
|
prerelease: false
|
24
|
-
|
25
|
-
|
26
|
-
name: rake
|
27
|
-
requirement: &12068240 !ruby/object:Gem::Requirement
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
38
|
none: false
|
29
|
-
requirements:
|
39
|
+
requirements:
|
30
40
|
- - ~>
|
31
|
-
- !ruby/object:Gem::Version
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 49
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
- 8
|
46
|
+
- 7
|
32
47
|
version: 0.8.7
|
33
48
|
type: :development
|
49
|
+
name: rake
|
50
|
+
version_requirements: *id002
|
34
51
|
prerelease: false
|
35
|
-
|
36
|
-
|
37
|
-
name: minitest
|
38
|
-
requirement: &12067280 !ruby/object:Gem::Requirement
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
39
54
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
44
62
|
type: :development
|
63
|
+
name: minitest
|
64
|
+
version_requirements: *id003
|
45
65
|
prerelease: false
|
46
|
-
|
47
|
-
|
48
|
-
name: rake-compiler
|
49
|
-
requirement: &12056580 !ruby/object:Gem::Requirement
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
50
68
|
none: false
|
51
|
-
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 9
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
- 7
|
76
|
+
- 5
|
54
77
|
version: 0.7.5
|
55
78
|
type: :development
|
79
|
+
name: rake-compiler
|
80
|
+
version_requirements: *id004
|
56
81
|
prerelease: false
|
57
|
-
|
58
|
-
|
59
|
-
name: rdiscount
|
60
|
-
requirement: &12055480 !ruby/object:Gem::Requirement
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
61
84
|
none: false
|
62
|
-
requirements:
|
63
|
-
- -
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
66
92
|
type: :development
|
93
|
+
name: rdiscount
|
94
|
+
version_requirements: *id005
|
67
95
|
prerelease: false
|
68
|
-
|
69
|
-
|
70
|
-
name: yard
|
71
|
-
requirement: &12054260 !ruby/object:Gem::Requirement
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
72
98
|
none: false
|
73
|
-
requirements:
|
74
|
-
- -
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
77
106
|
type: :development
|
107
|
+
name: yard
|
108
|
+
version_requirements: *id006
|
78
109
|
prerelease: false
|
79
|
-
|
80
|
-
|
81
|
-
name: mini_portile
|
82
|
-
requirement: &12053280 !ruby/object:Gem::Requirement
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
83
112
|
none: false
|
84
|
-
requirements:
|
85
|
-
- -
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
hash: 3
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
version: "0"
|
88
120
|
type: :development
|
121
|
+
name: mini_portile
|
122
|
+
version_requirements: *id007
|
89
123
|
prerelease: false
|
90
|
-
|
91
|
-
|
92
|
-
name: ruby-debug19
|
93
|
-
requirement: &12052340 !ruby/object:Gem::Requirement
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
94
126
|
none: false
|
95
|
-
requirements:
|
96
|
-
- -
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
hash: 3
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
version: "0"
|
99
134
|
type: :development
|
135
|
+
name: ruby-debug
|
136
|
+
version_requirements: *id008
|
100
137
|
prerelease: false
|
101
|
-
version_requirements: *12052340
|
102
138
|
description: The official client library for use with Couchbase Server.
|
103
139
|
email: support@couchbase.com
|
104
140
|
executables: []
|
105
|
-
|
141
|
+
|
142
|
+
extensions:
|
106
143
|
- ext/couchbase_ext/extconf.rb
|
107
144
|
extra_rdoc_files: []
|
108
|
-
|
145
|
+
|
146
|
+
files:
|
109
147
|
- .gitignore
|
110
148
|
- .travis.yml
|
111
149
|
- .yardopts
|
@@ -144,52 +182,37 @@ files:
|
|
144
182
|
- test/test_touch.rb
|
145
183
|
- test/test_version.rb
|
146
184
|
homepage: http://couchbase.org
|
147
|
-
licenses:
|
185
|
+
licenses:
|
148
186
|
- ASL-2
|
149
187
|
post_install_message:
|
150
188
|
rdoc_options: []
|
151
|
-
|
189
|
+
|
190
|
+
require_paths:
|
152
191
|
- lib
|
153
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
192
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
193
|
none: false
|
155
|
-
requirements:
|
156
|
-
- -
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
|
159
|
-
segments:
|
194
|
+
requirements:
|
195
|
+
- - ">="
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
hash: 3
|
198
|
+
segments:
|
160
199
|
- 0
|
161
|
-
|
162
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
|
+
version: "0"
|
201
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
202
|
none: false
|
164
|
-
requirements:
|
165
|
-
- -
|
166
|
-
- !ruby/object:Gem::Version
|
167
|
-
|
168
|
-
segments:
|
203
|
+
requirements:
|
204
|
+
- - ">="
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
hash: 3
|
207
|
+
segments:
|
169
208
|
- 0
|
170
|
-
|
209
|
+
version: "0"
|
171
210
|
requirements: []
|
211
|
+
|
172
212
|
rubyforge_project:
|
173
|
-
rubygems_version: 1.8.
|
213
|
+
rubygems_version: 1.8.18
|
174
214
|
signing_key:
|
175
215
|
specification_version: 3
|
176
216
|
summary: Couchbase ruby driver
|
177
|
-
test_files:
|
178
|
-
|
179
|
-
- test/profile/Gemfile
|
180
|
-
- test/profile/benchmark.rb
|
181
|
-
- test/setup.rb
|
182
|
-
- test/test_arithmetic.rb
|
183
|
-
- test/test_async.rb
|
184
|
-
- test/test_bucket.rb
|
185
|
-
- test/test_cas.rb
|
186
|
-
- test/test_couchbase.rb
|
187
|
-
- test/test_delete.rb
|
188
|
-
- test/test_errors.rb
|
189
|
-
- test/test_flush.rb
|
190
|
-
- test/test_format.rb
|
191
|
-
- test/test_get.rb
|
192
|
-
- test/test_stats.rb
|
193
|
-
- test/test_store.rb
|
194
|
-
- test/test_touch.rb
|
195
|
-
- test/test_version.rb
|
217
|
+
test_files: []
|
218
|
+
|