libcouchbase-mapo 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +38 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +24 -0
  8. data/README.md +445 -0
  9. data/Rakefile +76 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +19 -0
  12. data/lib/libcouchbase.rb +40 -0
  13. data/lib/libcouchbase/bucket.rb +825 -0
  14. data/lib/libcouchbase/callbacks.rb +69 -0
  15. data/lib/libcouchbase/connection.rb +886 -0
  16. data/lib/libcouchbase/design_docs.rb +92 -0
  17. data/lib/libcouchbase/error.rb +68 -0
  18. data/lib/libcouchbase/ext/libcouchbase.rb +1175 -0
  19. data/lib/libcouchbase/ext/libcouchbase/cmdbase.rb +23 -0
  20. data/lib/libcouchbase/ext/libcouchbase/cmdcounter.rb +36 -0
  21. data/lib/libcouchbase/ext/libcouchbase/cmdendure.rb +26 -0
  22. data/lib/libcouchbase/ext/libcouchbase/cmdfts.rb +24 -0
  23. data/lib/libcouchbase/ext/libcouchbase/cmdget.rb +30 -0
  24. data/lib/libcouchbase/ext/libcouchbase/cmdgetreplica.rb +49 -0
  25. data/lib/libcouchbase/ext/libcouchbase/cmdhttp.rb +58 -0
  26. data/lib/libcouchbase/ext/libcouchbase/cmdn1ql.rb +40 -0
  27. data/lib/libcouchbase/ext/libcouchbase/cmdobseqno.rb +33 -0
  28. data/lib/libcouchbase/ext/libcouchbase/cmdobserve.rb +30 -0
  29. data/lib/libcouchbase/ext/libcouchbase/cmdstore.rb +40 -0
  30. data/lib/libcouchbase/ext/libcouchbase/cmdstoredur.rb +45 -0
  31. data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +61 -0
  32. data/lib/libcouchbase/ext/libcouchbase/cmdverbosity.rb +29 -0
  33. data/lib/libcouchbase/ext/libcouchbase/cmdviewquery.rb +61 -0
  34. data/lib/libcouchbase/ext/libcouchbase/contigbuf.rb +14 -0
  35. data/lib/libcouchbase/ext/libcouchbase/create_st.rb +15 -0
  36. data/lib/libcouchbase/ext/libcouchbase/create_st0.rb +23 -0
  37. data/lib/libcouchbase/ext/libcouchbase/create_st1.rb +26 -0
  38. data/lib/libcouchbase/ext/libcouchbase/create_st2.rb +32 -0
  39. data/lib/libcouchbase/ext/libcouchbase/create_st3.rb +26 -0
  40. data/lib/libcouchbase/ext/libcouchbase/crst_u.rb +20 -0
  41. data/lib/libcouchbase/ext/libcouchbase/durability_opts_st_v.rb +11 -0
  42. data/lib/libcouchbase/ext/libcouchbase/durability_opts_t.rb +14 -0
  43. data/lib/libcouchbase/ext/libcouchbase/durabilityopt_sv0.rb +63 -0
  44. data/lib/libcouchbase/ext/libcouchbase/enums.rb +1007 -0
  45. data/lib/libcouchbase/ext/libcouchbase/fragbuf.rb +18 -0
  46. data/lib/libcouchbase/ext/libcouchbase/ftshandle.rb +7 -0
  47. data/lib/libcouchbase/ext/libcouchbase/histogram.rb +34 -0
  48. data/lib/libcouchbase/ext/libcouchbase/http_request_t.rb +7 -0
  49. data/lib/libcouchbase/ext/libcouchbase/keybuf.rb +20 -0
  50. data/lib/libcouchbase/ext/libcouchbase/multicmd_ctx.rb +30 -0
  51. data/lib/libcouchbase/ext/libcouchbase/mutation_token.rb +17 -0
  52. data/lib/libcouchbase/ext/libcouchbase/n1qlhandle.rb +7 -0
  53. data/lib/libcouchbase/ext/libcouchbase/n1qlparams.rb +7 -0
  54. data/lib/libcouchbase/ext/libcouchbase/respbase.rb +29 -0
  55. data/lib/libcouchbase/ext/libcouchbase/respcounter.rb +32 -0
  56. data/lib/libcouchbase/ext/libcouchbase/respendure.rb +49 -0
  57. data/lib/libcouchbase/ext/libcouchbase/respfts.rb +40 -0
  58. data/lib/libcouchbase/ext/libcouchbase/respget.rb +44 -0
  59. data/lib/libcouchbase/ext/libcouchbase/resphttp.rb +48 -0
  60. data/lib/libcouchbase/ext/libcouchbase/respmcversion.rb +38 -0
  61. data/lib/libcouchbase/ext/libcouchbase/respn1ql.rb +41 -0
  62. data/lib/libcouchbase/ext/libcouchbase/respobseqno.rb +52 -0
  63. data/lib/libcouchbase/ext/libcouchbase/respobserve.rb +41 -0
  64. data/lib/libcouchbase/ext/libcouchbase/respserverbase.rb +32 -0
  65. data/lib/libcouchbase/ext/libcouchbase/respstats.rb +38 -0
  66. data/lib/libcouchbase/ext/libcouchbase/respstore.rb +32 -0
  67. data/lib/libcouchbase/ext/libcouchbase/respstoredur.rb +38 -0
  68. data/lib/libcouchbase/ext/libcouchbase/respsubdoc.rb +35 -0
  69. data/lib/libcouchbase/ext/libcouchbase/respviewquery.rb +67 -0
  70. data/lib/libcouchbase/ext/libcouchbase/sdentry.rb +22 -0
  71. data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +31 -0
  72. data/lib/libcouchbase/ext/libcouchbase/t.rb +7 -0
  73. data/lib/libcouchbase/ext/libcouchbase/valbuf.rb +22 -0
  74. data/lib/libcouchbase/ext/libcouchbase/valbuf_u_buf.rb +14 -0
  75. data/lib/libcouchbase/ext/libcouchbase/viewhandle.rb +7 -0
  76. data/lib/libcouchbase/ext/libcouchbase_libuv.rb +22 -0
  77. data/lib/libcouchbase/ext/tasks.rb +39 -0
  78. data/lib/libcouchbase/n1ql.rb +78 -0
  79. data/lib/libcouchbase/query_full_text.rb +147 -0
  80. data/lib/libcouchbase/query_n1ql.rb +123 -0
  81. data/lib/libcouchbase/query_view.rb +135 -0
  82. data/lib/libcouchbase/results_fiber.rb +281 -0
  83. data/lib/libcouchbase/results_native.rb +220 -0
  84. data/lib/libcouchbase/subdoc_request.rb +139 -0
  85. data/lib/libcouchbase/version.rb +5 -0
  86. data/libcouchbase.gemspec +68 -0
  87. data/spec/bucket_spec.rb +290 -0
  88. data/spec/connection_spec.rb +257 -0
  89. data/spec/design_docs_spec.rb +31 -0
  90. data/spec/error_spec.rb +26 -0
  91. data/spec/fts_spec.rb +135 -0
  92. data/spec/n1ql_spec.rb +206 -0
  93. data/spec/results_libuv_spec.rb +244 -0
  94. data/spec/results_native_spec.rb +259 -0
  95. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/design.json +1 -0
  96. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/data-0000.cbb +0 -0
  97. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/failover.json +1 -0
  98. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/meta.json +1 -0
  99. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/seqno.json +1 -0
  100. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/snapshot_markers.json +1 -0
  101. data/spec/subdoc_spec.rb +192 -0
  102. data/spec/view_spec.rb +201 -0
  103. data/windows_build.md +36 -0
  104. metadata +265 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 64cdecfc1eaee7330781885e072e3c9c6352b3ed90b646698f4fdd744a229010
4
+ data.tar.gz: 72030cf452aa9dc8e059714d94dd448095e6ead7eeb2a0f01ff660b627b14d5b
5
+ SHA512:
6
+ metadata.gz: 9b4155a992c3ad673c993e888f584d389b5fa9f278d631a77b788cda52a8dd5bcd9a9cdbbbfd7632773c3802f82f5c0c126d146cee8b4fd9b6f4dbeb900fee4e
7
+ data.tar.gz: 503ed09a72fd82edf1394c9c6337472326b1c7abe6c4cc596e5a725e468f67e8bfcc41d57075054bac8be9bca61fc784364493a8926730b37f51706890166bd6
@@ -0,0 +1,20 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ html
6
+ pkg
7
+ doc
8
+ tmp
9
+ rerun.txt
10
+ Gemfile.lock
11
+ .bundle
12
+ .idea
13
+ *.rbc
14
+ .yardoc
15
+ bin
16
+ Gemfile-custom
17
+
18
+ *.gem
19
+
20
+ *.dll
@@ -0,0 +1,3 @@
1
+ [submodule "ext/libcouchbase"]
2
+ path = ext/libcouchbase
3
+ url = https://github.com/couchbase/libcouchbase.git
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --format progress
@@ -0,0 +1,38 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-2.4.2
4
+ - ruby-2.3.5
5
+ - ruby-head
6
+ - jruby-9.1.13.0
7
+ - jruby-head
8
+ - rubinius
9
+ - rubinius-3.86
10
+ branches:
11
+ only:
12
+ - master
13
+ before_install:
14
+ - git submodule update --init --recursive
15
+ - gem install ffi
16
+ - sudo apt-get install libev-dev python-httplib2
17
+ - sudo wget https://packages.couchbase.com/releases/5.1.0/couchbase-server-enterprise_5.1.0-ubuntu14.04_amd64.deb
18
+ - sudo dpkg -i couchbase-server-enterprise_5.1.0-ubuntu14.04_amd64.deb
19
+ - sleep 8
20
+ - sudo service couchbase-server status
21
+ - /opt/couchbase/bin/couchbase-cli cluster-init -c 127.0.0.1:8091 --cluster-username=admin --cluster-password=password --cluster-ramsize=320 --cluster-index-ramsize=256 --cluster-fts-ramsize=256 --services=data,index,query,fts
22
+ - sleep 5
23
+ - /opt/couchbase/bin/couchbase-cli server-info -c 127.0.0.1:8091 -u admin -p password
24
+ - /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=default --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --wait
25
+ - /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1:8091 -u admin -p password --bucket=test --bucket-type=couchbase --bucket-ramsize=160 --bucket-replica=0 --enable-flush=1 --wait
26
+ - sleep 1
27
+ - /opt/couchbase/bin/couchbase-cli user-manage -c 127.0.0.1:8091 -u admin -p password --set --rbac-username tester --rbac-password password123 --rbac-name "Auto Tester" --roles admin --auth-domain local
28
+ - /opt/couchbase/bin/cbrestore -x rehash=1 -b default -B default -u admin -p password ./spec/seed http://127.0.0.1:8091
29
+ before_script:
30
+ - rake compile
31
+ matrix:
32
+ allow_failures:
33
+ - rvm: jruby-head
34
+ - rvm: ruby-head
35
+ - rvm: rubinius
36
+ - rvm: rubinius-3.86
37
+ sudo: required
38
+ dist: trusty
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
4
+ gem "rubysl", :platform => :rbx
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2016 ACAProjects
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
21
+ ===
22
+
23
+ This license applies to all parts of the libcouchbase gem (Ruby FFI bindings for libcouchbase only)
24
+ Libcouchbase itself [is using the Couchbase license](https://github.com/couchbase/libcouchbase/blob/master/LICENSE)
@@ -0,0 +1,445 @@
1
+ # libcouchbase FFI bindings for Ruby
2
+
3
+ [![Build Status](https://secure.travis-ci.org/cotag/libcouchbase.svg)](http://travis-ci.org/cotag/libcouchbase)
4
+
5
+ An alternative to the official [couchbase-client](https://github.com/couchbase/couchbase-ruby-client)
6
+
7
+ * This client is non-blocking where possible using Fibers, which makes it simple to write performant code in Frameworks like [Rails](http://rubyonrails.org/).
8
+ * Client is threadsafe and reentrant
9
+
10
+ This is a low level wrapper around libcouchbase. For a more friendly ActiveModel interface see [couchbase-orm](https://github.com/acaprojects/couchbase-orm)
11
+
12
+ ## Couchbase 5 Changes
13
+
14
+ The Couchbase 5 Admin Console blows away flags on documents if you edit them in the interface.
15
+ Flags were being used to store document formats, however these were mainly implemented for compatibility with the defunct official client.
16
+
17
+
18
+ To prevent this being an issue we've made the following changes from version 1.2 of this library:
19
+
20
+ 1. All writes will result in valid JSON being saved to the database
21
+ * No more `raw strings` they will be saved as `"raw strings"`
22
+ * Existing raw strings will still be read correctly
23
+ 2. Since there are no more raw strings, append / prepend are no longer needed (not that we ever used them)
24
+
25
+
26
+ ## Runtime Support:
27
+
28
+ * Native Ruby
29
+ * Blocks the current thread while performing operations
30
+ * Multiple operations can occur simultaneously on different threads
31
+ * For [Rails](http://rubyonrails.org/) and similar, this has optimal performance when running on [Puma](http://puma.io/)
32
+ * [EventMachine](https://github.com/eventmachine/eventmachine)
33
+ * Requires the use of [em-synchrony](https://github.com/igrigorik/em-synchrony) or for the EM run block to be [wrapped by a fiber](https://github.com/igrigorik/em-http-request/blob/master/examples/fibered-http.rb#L27)
34
+ * When running [Rails](http://rubyonrails.org/) you'll have best results with [Thin](https://github.com/macournoyer/thin) and [Rack Fiber Pool](https://github.com/alebsack/rack-fiber_pool)
35
+ * Requests block the current Fiber, yielding so the reactor loop is not blocked
36
+ * [Libuv](https://github.com/cotag/libuv)
37
+ * When running [Rails](http://rubyonrails.org/) you'll have best results with [SpiderGazelle](https://github.com/cotag/spider-gazelle)
38
+ * Requests block the current Fiber, yielding so the reactor loop is not blocked
39
+
40
+ Syntax is the same across all runtimes and you can perform multiple operations simultaneously then wait for the results of those operations.
41
+
42
+ Operations are also aware of the context they are being executed in.
43
+ For instance if you perform a request in an EventMachine thread pool, it will execute as Native Ruby and on the event loop it'll be non-blocking.
44
+
45
+
46
+ ## Installation
47
+
48
+ This GEM includes the [libcouchbase c-library](https://github.com/couchbase/libcouchbase) with requires [cmake](https://cmake.org/) for the build process.
49
+ The library is built on installation.
50
+
51
+ * Ensure [cmake](https://cmake.org/install/) is installed
52
+ * Run `gem install libcouchbase`
53
+
54
+
55
+ The library is designed to run anywhere [Rails](http://rubyonrails.org/) runs:
56
+
57
+ * Ruby 2.2+
58
+ * JRuby 9.1+
59
+ * Rubinius 3.76+
60
+
61
+
62
+ Tested on the following Operating Systems:
63
+
64
+ * OSX / MacOS
65
+ * Linux
66
+ * Windows
67
+ * Ruby x64 2.4+ with MSYS2 DevKit
68
+
69
+
70
+ ## Usage
71
+
72
+ First, you need to load the library:
73
+
74
+ ```ruby
75
+ require 'libcouchbase'
76
+ ```
77
+
78
+ The client will automatically adjust configuration when the cluster rebalances its nodes when nodes are added or deleted therefore this client is "smart".
79
+ By default the client will connect to the default bucket on localhost.
80
+
81
+ ```ruby
82
+ bucket = Libcouchbase::Bucket.new
83
+ ```
84
+
85
+ To connect to other buckets, other than the default
86
+
87
+ ```ruby
88
+ # Same as Libcouchbase::Bucket.new
89
+ bucket = Libcouchbase::Bucket.new(hosts: '127.0.0.1', bucket: 'default', password: nil)
90
+
91
+ # To connect to other buckets, you can also specify multiple hosts:
92
+ bucket = Libcouchbase::Bucket.new(hosts: ['cb1.org', 'cb2.org'], bucket: 'app_data', password: 'goodluck')
93
+ ```
94
+
95
+ Connections can be configured to use `:quiet` mode. This mean it won't raise
96
+ exceptions when the given key does not exist:
97
+
98
+ ```ruby
99
+ bucket.quiet = true
100
+ bucket.get(:missing_key) #=> nil
101
+ ```
102
+
103
+ It could be useful avoiding exception handling. (See `#add` and `#replace` operations).
104
+ You can turn off these exceptions by passing `:quiet => true` when you
105
+ are instantiating the connection or change corresponding attribute:
106
+
107
+ ```ruby
108
+ bucket.quiet = false
109
+ bucket.get("missing-key") #=> raise Libcouchbase::Error::KeyNotFound
110
+ bucket.get("missing-key", :quiet => true) #=> nil
111
+ ```
112
+
113
+
114
+ The library supports both synchronous and asynchronous operations.
115
+ In asynchronous mode all operations will return control to caller
116
+ without blocking current thread. By default all operations are
117
+ synchronous, using Fibers on event loops to prevent blocking the
118
+ reactor. Use asynchronous operations if you want mulitple operations
119
+ to execute in parallel.
120
+
121
+
122
+ ```ruby
123
+ # Perform operations in Async and then wait for the results
124
+ results = []
125
+ results << bucket.get(:key1, async: true)
126
+ results << bucket.get(:key2, async: true)
127
+ bucket.wait_results(results) #=> ['key1_val', 'key2_val']
128
+
129
+ # Is equivalent to:
130
+ bucket.get(:key1, :key2) #=> ['key1_val', 'key2_val']
131
+
132
+ # Process result without waiting or blocking the thread at all
133
+ # This will execute on the couchbase reactor loop so it is
134
+ # recommended not to block in the callback - spin up a new thread
135
+ # or schedule the work to occur next_tick etc
136
+ promise = bucket.get(:key1, async: true)
137
+ promise.then { |result| puts result }
138
+ promise.catch { |error| puts error }
139
+ promise.finally { puts 'operation complete' }
140
+ ```
141
+
142
+
143
+ ### Get
144
+
145
+ ```ruby
146
+ val = bucket.get("foo")
147
+
148
+ # Get extended details
149
+ result = bucket.get("foo", extended: true)
150
+ result.key #=> "foo"
151
+ result.value #=> {some: "value"}
152
+ result.cas #=> 123445
153
+ result.metadata #=> {flags: 0}
154
+ ```
155
+
156
+
157
+ Get multiple values. In quiet mode will put `nil` values on missing
158
+ positions:
159
+
160
+ ```ruby
161
+ vals = bucket.get(:foo, :bar, "baz")
162
+ ```
163
+
164
+ Hash-like syntax
165
+
166
+ ```ruby
167
+ val = bucket[:foo]
168
+ ```
169
+
170
+ Return a key-value hash
171
+
172
+ ```ruby
173
+ val = bucket.get(:foo, :bar, "baz", assemble_hash: true)
174
+ val #=> {:foo => val1, :bar => val2, "baz" => val3}
175
+ ```
176
+
177
+
178
+ ### Touch
179
+
180
+ ```ruby
181
+ # Expire in 30 seconds
182
+ bucket.touch(:foo, expire_in: 30
183
+ bucket.touch(:foo, ttl: 30)
184
+ bucket.touch(:foo, expire_at: (Time.now + 30))
185
+ ```
186
+
187
+
188
+ ### Set
189
+
190
+ The set command will unconditionally store an object in couchbase.
191
+
192
+ ```ruby
193
+ bucket.add("foo", "bar")
194
+ bucket.add("foo", "bar", ttl: 30)
195
+ ```
196
+
197
+
198
+ ### Add
199
+
200
+ The add command will fail if the key already exists.
201
+
202
+ ```ruby
203
+ bucket.add("foo", "bar")
204
+ bucket.add("foo", "bar", ttl: 30)
205
+ ```
206
+
207
+
208
+ ### Replace
209
+
210
+ The replace command will fail if the key doesn't already exist.
211
+
212
+ ```ruby
213
+ bucket.replace("foo", "bar")
214
+ ```
215
+
216
+
217
+ ### Increment/Decrement
218
+
219
+ These commands increment the value assigned to the key.
220
+ A Couchbase increment is atomic on a distributed system.
221
+
222
+ ```ruby
223
+ bucket.set(:foo, 1)
224
+ bucket.incr(:foo) #=> 2
225
+ bucket.incr(:foo, delta: 2) #=> 4
226
+ bucket.incr(:foo, 2) #=> 6
227
+ bucket.incr(:foo, -1) #=> 5
228
+
229
+ bucket.decr(:foo) #=> 4
230
+ bucket.decr(:foo, 2) #=> 2
231
+
232
+ bucket.incr(:missing1, initial: 10) #=> 10
233
+ bucket.incr(:missing1, initial: 10) #=> 11
234
+ bucket.incr(:missing2, create: true) #=> 0
235
+ bucket.incr(:missing2, create: true) #=> 1
236
+ ```
237
+
238
+
239
+ ### Delete
240
+
241
+ ```ruby
242
+ bucket.delete(:foo)
243
+ bucket.delete(:foo, cas: 8835713818674332672)
244
+ ```
245
+
246
+
247
+ ### Flush
248
+
249
+ Delete all items in the bucket. This must be enabled on the cluster to work
250
+
251
+ ```ruby
252
+ bucket.flush
253
+ ```
254
+
255
+ ### Subdocument queries
256
+
257
+ These allow you to modify keys within documents. There is a block form.
258
+
259
+ ```ruby
260
+ c.subdoc(:foo) { |subdoc|
261
+ subdoc.get('sub.key')
262
+ subdoc.exists?('other.key')
263
+ subdoc.get_count('some.array')
264
+ } # => ["sub key val", true, 23]
265
+ ```
266
+
267
+ There is an inline form
268
+
269
+ ```ruby
270
+ c.subdoc(:foo).get(:bob).execute! # => { age: 13, working: false }
271
+ c.subdoc(:foo)
272
+ .get(:bob)
273
+ .get(:jane)
274
+ .execute! # => [{ age: 13, working: false }, { age: 47, working: true }]
275
+ ```
276
+
277
+ You can't perform lookups and mutations in the same request.
278
+
279
+ ```ruby
280
+ # multi-mutation example
281
+ c.subdoc(:foo)
282
+ .counter('bob.age', 1)
283
+ .dict_upsert('bob.address', {
284
+ number: 23
285
+ street: 'Daily Ave'
286
+ suburb: 'Some Town'
287
+ }).execute! # => 14 (the new counter value)
288
+ ```
289
+
290
+ By default, subkeys are created if they don't exist
291
+
292
+ ```ruby
293
+ c.put(:some_key, {name: 'bob'})
294
+ c.subdoc(:some_key).dict_add('non.existant.key', {
295
+ random: 123,
296
+ hash: 'values'
297
+ }).execute!
298
+ ```
299
+
300
+ Possible lookup operations are:
301
+
302
+ * `get`
303
+ * `exists?`
304
+ * `get_count`
305
+
306
+ Possible mutation operations
307
+
308
+ * `counter` increments the subkey by integer value passed
309
+ * `dict_upsert` replaces the subkey with value passed
310
+ * `dict_add`
311
+ * `array_add_first`
312
+ * `array_add_last`
313
+ * `array_add_unique`
314
+ * `array_insert`
315
+ * `replace`
316
+
317
+ You can see additional docs here: https://developer.couchbase.com/documentation/server/current/sdk/subdocument-operations.html
318
+
319
+
320
+ ### Views (Map/Reduce queries)
321
+
322
+ If you store structured data, they will be treated as documents and you
323
+ can handle them in map/reduce function from Couchbase Views. For example,
324
+ store a couple of posts using memcached API:
325
+
326
+ ```ruby
327
+ c['biking'] = {:title => 'Biking',
328
+ :body => 'My biggest hobby is mountainbiking. The other day...',
329
+ :date => '2009/01/30 18:04:11'}
330
+ c['bought-a-cat'] = {:title => 'Bought a Cat',
331
+ :body => 'I went to the the pet store earlier and brought home a little kitty...',
332
+ :date => '2009/01/30 20:04:11'}
333
+ c['hello-world'] = {:title => 'Hello World',
334
+ :body => 'Well hello and welcome to my new blog...',
335
+ :date => '2009/01/15 15:52:20'}
336
+ ```
337
+
338
+ Now let's create design doc with sample view and save it in file
339
+ 'blog.json':
340
+
341
+ ```JSON
342
+ {
343
+ "_id": "_design/blog",
344
+ "language": "javascript",
345
+ "views": {
346
+ "recent_posts": {
347
+ "map": "function(doc){if(doc.date && doc.title){emit(doc.date, doc.title);}}"
348
+ }
349
+ }
350
+ }
351
+ ```
352
+
353
+ This design document could be loaded into the database like this (also you can
354
+ pass the ruby Hash or String with JSON encoded document):
355
+
356
+ ```ruby
357
+ c.save_design_doc(File.open('blog.json'))
358
+ ```
359
+
360
+ To execute view you need to fetch it from design document `_design/blog`:
361
+
362
+ ```ruby
363
+ blog = c.design_docs['blog']
364
+ blog.views #=> ["recent_posts"]
365
+
366
+ # Returns an Enumerator
367
+ res = blog.view('recent_posts') #=> #<Libcouchbase::Results:0x007fbaed12c988>
368
+
369
+ # Results are lazily loaded by the enumerator
370
+ # Results are stored for re-use until `res` goes out of scope
371
+ # Actual database query happens here, by default documents are included
372
+ res.each do |row|
373
+ # Returns extended results by default
374
+ row.key
375
+ row.value
376
+ row.cas
377
+ row.metadata #=> {emitted: val, geometry: spatial_val, format: :document, flags: 0}
378
+ end
379
+
380
+ # You can however stream results to save memory and the results are not saved
381
+ res.stream do |row|
382
+ # Row is cleaned up as soon as possible
383
+ end
384
+
385
+ # For IDs only:
386
+ res = blog.view(:recent_posts, include_docs: false)
387
+ ```
388
+
389
+
390
+ ### N1QL Queries
391
+
392
+ If N1QL indexes have been created, then you can query them
393
+
394
+ ```ruby
395
+ results = bucket.n1ql
396
+ .select('*')
397
+ .from(:default)
398
+ .where('port == 10001')
399
+ .results
400
+
401
+ # Results are lazily loaded by the enumerator
402
+ # Results are stored for re-use until `results` goes out of scope
403
+ # Actual database query happens here
404
+ results.each do |row|
405
+ # Each row is a Hash of the data requested
406
+ end
407
+
408
+ # You can however stream results to save memory and the results are not saved
409
+ results.stream do |row|
410
+ # Row is cleaned up as soon as possible
411
+ end
412
+ ```
413
+
414
+
415
+ ### Full Text Search
416
+
417
+ If Full Text Search indexes have been created, then you can query them
418
+
419
+ ```ruby
420
+ results = bucket.full_text_search(:index_name, 'query')
421
+
422
+ # Results are lazily loaded by the enumerator
423
+ # Results are stored for re-use until `res` goes out of scope
424
+ # Actual database query happens here
425
+ results.each do |row|
426
+ # Each row is a Hash of the data requested
427
+ end
428
+
429
+ # You can however stream results to save memory and the results are not saved
430
+ results.stream do |row|
431
+ # Row is cleaned up as soon as possible
432
+ end
433
+ ```
434
+
435
+ Full text search supports more complex queries, you can pass in a Hash as the query
436
+ and provide any other options supported by FTS: http://developer.couchbase.com/documentation/server/current/fts/fts-queries.html
437
+
438
+ ```ruby
439
+ bucket.full_text_search(:index_name, {
440
+ boost: 1,
441
+ query: "geo.accuracy:rooftop"
442
+ }, size: 10, from: 0, explain: true, fields: ['*'])
443
+ ```
444
+
445
+