couchbase 3.0.0.alpha.1-universal-darwin-19 → 3.0.0.alpha.2-universal-darwin-19

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.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests-6.0.3.yml +49 -0
  3. data/.github/workflows/tests.yml +47 -0
  4. data/.gitmodules +3 -0
  5. data/.idea/dictionaries/gem_terms.xml +5 -0
  6. data/.idea/inspectionProfiles/Project_Default.xml +1 -0
  7. data/.idea/vcs.xml +1 -0
  8. data/Gemfile +1 -0
  9. data/README.md +55 -2
  10. data/Rakefile +18 -0
  11. data/bin/init-cluster +62 -0
  12. data/bin/setup +1 -0
  13. data/couchbase.gemspec +3 -2
  14. data/examples/crud.rb +1 -2
  15. data/examples/managing_buckets.rb +47 -0
  16. data/examples/managing_collections.rb +58 -0
  17. data/examples/managing_query_indexes.rb +63 -0
  18. data/examples/query.rb +3 -2
  19. data/examples/query_with_consistency.rb +76 -0
  20. data/examples/subdocument.rb +23 -1
  21. data/ext/.clang-format +1 -1
  22. data/ext/.idea/dictionaries/couchbase_terms.xml +2 -0
  23. data/ext/.idea/vcs.xml +1 -0
  24. data/ext/CMakeLists.txt +30 -12
  25. data/ext/build_version.hxx.in +26 -0
  26. data/ext/couchbase/bucket.hxx +69 -8
  27. data/ext/couchbase/cluster.hxx +70 -54
  28. data/ext/couchbase/collections_manifest.hxx +3 -3
  29. data/ext/couchbase/configuration.hxx +14 -0
  30. data/ext/couchbase/couchbase.cxx +2044 -383
  31. data/ext/couchbase/{operations/document_id.hxx → document_id.hxx} +5 -4
  32. data/ext/couchbase/io/http_message.hxx +5 -1
  33. data/ext/couchbase/io/http_parser.hxx +2 -1
  34. data/ext/couchbase/io/http_session.hxx +6 -3
  35. data/ext/couchbase/io/{binary_message.hxx → mcbp_message.hxx} +15 -12
  36. data/ext/couchbase/io/mcbp_parser.hxx +99 -0
  37. data/ext/couchbase/io/{key_value_session.hxx → mcbp_session.hxx} +200 -95
  38. data/ext/couchbase/io/session_manager.hxx +37 -22
  39. data/ext/couchbase/mutation_token.hxx +2 -1
  40. data/ext/couchbase/operations.hxx +38 -8
  41. data/ext/couchbase/operations/bucket_create.hxx +138 -0
  42. data/ext/couchbase/operations/bucket_drop.hxx +65 -0
  43. data/ext/couchbase/operations/bucket_flush.hxx +65 -0
  44. data/ext/couchbase/operations/bucket_get.hxx +69 -0
  45. data/ext/couchbase/operations/bucket_get_all.hxx +62 -0
  46. data/ext/couchbase/operations/bucket_settings.hxx +111 -0
  47. data/ext/couchbase/operations/bucket_update.hxx +115 -0
  48. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +60 -0
  49. data/ext/couchbase/operations/collection_create.hxx +86 -0
  50. data/ext/couchbase/operations/collection_drop.hxx +82 -0
  51. data/ext/couchbase/operations/command.hxx +10 -10
  52. data/ext/couchbase/operations/document_decrement.hxx +80 -0
  53. data/ext/couchbase/operations/document_exists.hxx +80 -0
  54. data/ext/couchbase/operations/{get.hxx → document_get.hxx} +4 -2
  55. data/ext/couchbase/operations/document_get_and_lock.hxx +64 -0
  56. data/ext/couchbase/operations/document_get_and_touch.hxx +64 -0
  57. data/ext/couchbase/operations/document_increment.hxx +80 -0
  58. data/ext/couchbase/operations/document_insert.hxx +74 -0
  59. data/ext/couchbase/operations/{lookup_in.hxx → document_lookup_in.hxx} +2 -2
  60. data/ext/couchbase/operations/{mutate_in.hxx → document_mutate_in.hxx} +11 -2
  61. data/ext/couchbase/operations/{query.hxx → document_query.hxx} +101 -6
  62. data/ext/couchbase/operations/document_remove.hxx +67 -0
  63. data/ext/couchbase/operations/document_replace.hxx +76 -0
  64. data/ext/couchbase/operations/{upsert.hxx → document_touch.hxx} +14 -14
  65. data/ext/couchbase/operations/{remove.hxx → document_unlock.hxx} +12 -10
  66. data/ext/couchbase/operations/document_upsert.hxx +74 -0
  67. data/ext/couchbase/operations/query_index_build_deferred.hxx +85 -0
  68. data/ext/couchbase/operations/query_index_create.hxx +134 -0
  69. data/ext/couchbase/operations/query_index_drop.hxx +108 -0
  70. data/ext/couchbase/operations/query_index_get_all.hxx +106 -0
  71. data/ext/couchbase/operations/scope_create.hxx +81 -0
  72. data/ext/couchbase/operations/scope_drop.hxx +79 -0
  73. data/ext/couchbase/operations/scope_get_all.hxx +72 -0
  74. data/ext/couchbase/protocol/client_opcode.hxx +35 -0
  75. data/ext/couchbase/protocol/client_request.hxx +56 -9
  76. data/ext/couchbase/protocol/client_response.hxx +52 -15
  77. data/ext/couchbase/protocol/cmd_cluster_map_change_notification.hxx +81 -0
  78. data/ext/couchbase/protocol/cmd_decrement.hxx +187 -0
  79. data/ext/couchbase/protocol/cmd_exists.hxx +171 -0
  80. data/ext/couchbase/protocol/cmd_get.hxx +31 -8
  81. data/ext/couchbase/protocol/cmd_get_and_lock.hxx +142 -0
  82. data/ext/couchbase/protocol/cmd_get_and_touch.hxx +142 -0
  83. data/ext/couchbase/protocol/cmd_get_cluster_config.hxx +16 -3
  84. data/ext/couchbase/protocol/cmd_get_collections_manifest.hxx +16 -3
  85. data/ext/couchbase/protocol/cmd_get_error_map.hxx +16 -3
  86. data/ext/couchbase/protocol/cmd_hello.hxx +24 -8
  87. data/ext/couchbase/protocol/cmd_increment.hxx +187 -0
  88. data/ext/couchbase/protocol/cmd_info.hxx +1 -0
  89. data/ext/couchbase/protocol/cmd_insert.hxx +172 -0
  90. data/ext/couchbase/protocol/cmd_lookup_in.hxx +28 -13
  91. data/ext/couchbase/protocol/cmd_mutate_in.hxx +65 -13
  92. data/ext/couchbase/protocol/cmd_remove.hxx +59 -4
  93. data/ext/couchbase/protocol/cmd_replace.hxx +172 -0
  94. data/ext/couchbase/protocol/cmd_sasl_auth.hxx +15 -3
  95. data/ext/couchbase/protocol/cmd_sasl_list_mechs.hxx +15 -3
  96. data/ext/couchbase/protocol/cmd_sasl_step.hxx +15 -3
  97. data/ext/couchbase/protocol/cmd_select_bucket.hxx +14 -2
  98. data/ext/couchbase/protocol/cmd_touch.hxx +102 -0
  99. data/ext/couchbase/protocol/cmd_unlock.hxx +95 -0
  100. data/ext/couchbase/protocol/cmd_upsert.hxx +50 -14
  101. data/ext/couchbase/protocol/durability_level.hxx +67 -0
  102. data/ext/couchbase/protocol/frame_info_id.hxx +187 -0
  103. data/ext/couchbase/protocol/hello_feature.hxx +137 -0
  104. data/ext/couchbase/protocol/server_opcode.hxx +57 -0
  105. data/ext/couchbase/protocol/server_request.hxx +122 -0
  106. data/ext/couchbase/protocol/unsigned_leb128.h +15 -15
  107. data/ext/couchbase/utils/byteswap.hxx +1 -2
  108. data/ext/couchbase/utils/url_codec.hxx +225 -0
  109. data/ext/couchbase/version.hxx +3 -1
  110. data/ext/extconf.rb +4 -1
  111. data/ext/test/main.cxx +37 -113
  112. data/ext/third_party/snappy/.appveyor.yml +36 -0
  113. data/ext/third_party/snappy/.gitignore +8 -0
  114. data/ext/third_party/snappy/.travis.yml +98 -0
  115. data/ext/third_party/snappy/AUTHORS +1 -0
  116. data/ext/third_party/snappy/CMakeLists.txt +345 -0
  117. data/ext/third_party/snappy/CONTRIBUTING.md +26 -0
  118. data/ext/third_party/snappy/COPYING +54 -0
  119. data/ext/third_party/snappy/NEWS +188 -0
  120. data/ext/third_party/snappy/README.md +148 -0
  121. data/ext/third_party/snappy/cmake/SnappyConfig.cmake.in +33 -0
  122. data/ext/third_party/snappy/cmake/config.h.in +59 -0
  123. data/ext/third_party/snappy/docs/README.md +72 -0
  124. data/ext/third_party/snappy/format_description.txt +110 -0
  125. data/ext/third_party/snappy/framing_format.txt +135 -0
  126. data/ext/third_party/snappy/snappy-c.cc +90 -0
  127. data/ext/third_party/snappy/snappy-c.h +138 -0
  128. data/ext/third_party/snappy/snappy-internal.h +315 -0
  129. data/ext/third_party/snappy/snappy-sinksource.cc +121 -0
  130. data/ext/third_party/snappy/snappy-sinksource.h +182 -0
  131. data/ext/third_party/snappy/snappy-stubs-internal.cc +42 -0
  132. data/ext/third_party/snappy/snappy-stubs-internal.h +493 -0
  133. data/ext/third_party/snappy/snappy-stubs-public.h.in +63 -0
  134. data/ext/third_party/snappy/snappy-test.cc +613 -0
  135. data/ext/third_party/snappy/snappy-test.h +526 -0
  136. data/ext/third_party/snappy/snappy.cc +1770 -0
  137. data/ext/third_party/snappy/snappy.h +209 -0
  138. data/ext/third_party/snappy/snappy_compress_fuzzer.cc +60 -0
  139. data/ext/third_party/snappy/snappy_uncompress_fuzzer.cc +58 -0
  140. data/ext/third_party/snappy/snappy_unittest.cc +1512 -0
  141. data/ext/third_party/snappy/testdata/alice29.txt +3609 -0
  142. data/ext/third_party/snappy/testdata/asyoulik.txt +4122 -0
  143. data/ext/third_party/snappy/testdata/baddata1.snappy +0 -0
  144. data/ext/third_party/snappy/testdata/baddata2.snappy +0 -0
  145. data/ext/third_party/snappy/testdata/baddata3.snappy +0 -0
  146. data/ext/third_party/snappy/testdata/fireworks.jpeg +0 -0
  147. data/ext/third_party/snappy/testdata/geo.protodata +0 -0
  148. data/ext/third_party/snappy/testdata/html +1 -0
  149. data/ext/third_party/snappy/testdata/html_x_4 +1 -0
  150. data/ext/third_party/snappy/testdata/kppkn.gtb +0 -0
  151. data/ext/third_party/snappy/testdata/lcet10.txt +7519 -0
  152. data/ext/third_party/snappy/testdata/paper-100k.pdf +600 -2
  153. data/ext/third_party/snappy/testdata/plrabn12.txt +10699 -0
  154. data/ext/third_party/snappy/testdata/urls.10K +10000 -0
  155. data/lib/couchbase/binary_collection.rb +33 -76
  156. data/lib/couchbase/binary_collection_options.rb +94 -0
  157. data/lib/couchbase/bucket.rb +9 -3
  158. data/lib/couchbase/cluster.rb +161 -23
  159. data/lib/couchbase/collection.rb +108 -191
  160. data/lib/couchbase/collection_options.rb +430 -0
  161. data/lib/couchbase/errors.rb +136 -134
  162. data/lib/couchbase/json_transcoder.rb +32 -0
  163. data/lib/couchbase/management/analytics_index_manager.rb +185 -9
  164. data/lib/couchbase/management/bucket_manager.rb +84 -33
  165. data/lib/couchbase/management/collection_manager.rb +166 -1
  166. data/lib/couchbase/management/query_index_manager.rb +261 -0
  167. data/lib/couchbase/management/search_index_manager.rb +291 -0
  168. data/lib/couchbase/management/user_manager.rb +12 -10
  169. data/lib/couchbase/management/view_index_manager.rb +151 -1
  170. data/lib/couchbase/mutation_state.rb +11 -1
  171. data/lib/couchbase/scope.rb +4 -4
  172. data/lib/couchbase/version.rb +1 -1
  173. metadata +113 -18
  174. data/.travis.yml +0 -7
  175. data/ext/couchbase/io/binary_parser.hxx +0 -64
  176. data/lib/couchbase/results.rb +0 -307
@@ -12,9 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'couchbase/common_options'
16
- require 'couchbase/results'
17
- require 'couchbase/subdoc'
15
+ require "couchbase/errors"
16
+ require "couchbase/collection_options"
17
+ require "couchbase/binary_collection"
18
18
 
19
19
  module Couchbase
20
20
  class Collection
@@ -26,8 +26,8 @@ module Couchbase
26
26
 
27
27
  # @param [Couchbase::Backend] backend
28
28
  # @param [String] bucket_name name of the bucket
29
- # @param [String, :default] scope_name name of the scope
30
- # @param [String, :default] collection_name name of the collection
29
+ # @param [String, :_default] scope_name name of the scope
30
+ # @param [String, :_default] collection_name name of the collection
31
31
  def initialize(backend, bucket_name, scope_name, collection_name)
32
32
  @backend = backend
33
33
  @bucket_name = bucket_name
@@ -43,16 +43,18 @@ module Couchbase
43
43
  end
44
44
 
45
45
  # Fetches the full document from the collection
46
- #
46
+ #
47
47
  # @param [String] id the document id which is used to uniquely identify it
48
48
  # @param [GetOptions] options request customization
49
- #
49
+ #
50
50
  # @return [GetResult]
51
51
  def get(id, options = GetOptions.new)
52
- resp = @backend.get(bucket_name, "#{@scope_name}.#{@name}", id)
52
+ resp = @backend.document_get(bucket_name, "#{@scope_name}.#{@name}", id)
53
53
  GetResult.new do |res|
54
+ res.transcoder = options.transcoder
54
55
  res.cas = resp[:cas]
55
- res.content = resp[:content]
56
+ res.flags = resp[:flags]
57
+ res.encoded = resp[:content]
56
58
  end
57
59
  end
58
60
 
@@ -61,24 +63,40 @@ module Couchbase
61
63
  # @param [String] id the document id which is used to uniquely identify it.
62
64
  # @param [Integer] lock_time how long to lock the document (values over 30 seconds will be capped)
63
65
  # @param [GetAndLockOptions] options request customization
64
- #
66
+ #
65
67
  # @return [GetResult]
66
- def get_and_lock(id, lock_time, options = GetAndLockOptions.new) end
68
+ def get_and_lock(id, lock_time, options = GetAndLockOptions.new)
69
+ resp = @backend.document_get_and_lock(bucket_name, "#{@scope_name}.#{@name}", id, lock_time)
70
+ GetResult.new do |res|
71
+ res.transcoder = options.transcoder
72
+ res.cas = resp[:cas]
73
+ res.flags = resp[:flags]
74
+ res.encoded = resp[:content]
75
+ end
76
+ end
67
77
 
68
78
  # Fetches a full document and resets its expiration time to the expiration duration provided
69
79
  #
70
80
  # @param [String] id the document id which is used to uniquely identify it.
71
81
  # @param [Integer] expiration the new expiration time for the document
72
82
  # @param [GetAndTouchOptions] options request customization
73
- #
83
+ #
74
84
  # @return [GetResult]
75
- def get_and_touch(id, expiration, options = GetAndTouchOptions.new) end
85
+ def get_and_touch(id, expiration, options = GetAndTouchOptions.new)
86
+ resp = @backend.document_get_and_touch(bucket_name, "#{@scope_name}.#{@name}", id, expiration)
87
+ GetResult.new do |res|
88
+ res.transcoder = options.transcoder
89
+ res.cas = resp[:cas]
90
+ res.flags = resp[:flags]
91
+ res.encoded = resp[:content]
92
+ end
93
+ end
76
94
 
77
95
  # Reads from all available replicas and the active node and returns the results
78
- #
96
+ #
79
97
  # @param [String] id the document id which is used to uniquely identify it.
80
98
  # @param [GetAllReplicasOptions] options request customization
81
- #
99
+ #
82
100
  # @return [Array<GetReplicaResult>]
83
101
  def get_all_replicas(id, options = GetAllReplicasOptions.new) end
84
102
 
@@ -91,12 +109,19 @@ module Couchbase
91
109
  def get_any_replica(id, options = GetAnyReplicaOptions.new) end
92
110
 
93
111
  # Checks if the given document ID exists on the active partition.
94
- #
112
+ #
95
113
  # @param [String] id the document id which is used to uniquely identify it.
96
114
  # @param [ExistsOptions] options request customization
97
115
  #
98
116
  # @return [ExistsResult]
99
- def exists(id, options = ExistsOptions.new) end
117
+ def exists(id, options = ExistsOptions.new)
118
+ resp = @backend.document_exists(bucket_name, "#{@scope_name}.#{@name}", id)
119
+ ExistsResult.new do |res|
120
+ res.status = resp[:status]
121
+ res.partition_id = resp[:partition_id]
122
+ res.cas = resp[:cas] if res.status != :not_found
123
+ end
124
+ end
100
125
 
101
126
  # Removes a document from the collection
102
127
  #
@@ -105,59 +130,97 @@ module Couchbase
105
130
  #
106
131
  # @return [MutationResult]
107
132
  def remove(id, options = RemoveOptions.new)
108
- resp = @backend.remove(bucket_name, "#{@scope_name}.#{@name}", id)
133
+ resp = @backend.document_remove(bucket_name, "#{@scope_name}.#{@name}", id, {
134
+ durability_level: options.durability_level
135
+ })
109
136
  MutationResult.new do |res|
110
137
  res.cas = resp[:cas]
138
+ res.mutation_token = extract_mutation_token(resp)
111
139
  end
112
140
  end
113
141
 
114
142
  # Inserts a full document which does not exist yet
115
- #
143
+ #
116
144
  # @param [String] id the document id which is used to uniquely identify it.
117
145
  # @param [Object] content the document content to insert
118
146
  # @param [InsertOptions] options request customization
119
147
  #
120
148
  # @return [MutationResult]
121
- def insert(id, content, options = InsertOptions.new) end
149
+ def insert(id, content, options = InsertOptions.new)
150
+ blob, flags = options.transcoder.encode(content)
151
+ resp = @backend.document_insert(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, {
152
+ durability_level: options.durability_level,
153
+ expiration: options.expiration,
154
+ })
155
+ MutationResult.new do |res|
156
+ res.cas = resp[:cas]
157
+ res.mutation_token = extract_mutation_token(resp)
158
+ end
159
+ end
122
160
 
123
161
  # Upserts (inserts or updates) a full document which might or might not exist yet
124
- #
162
+ #
125
163
  # @param [String] id the document id which is used to uniquely identify it.
126
164
  # @param [Object] content the document content to upsert
127
165
  # @param [UpsertOptions] options request customization
128
166
  #
129
167
  # @return [MutationResult]
130
168
  def upsert(id, content, options = UpsertOptions.new)
131
- resp = @backend.upsert(bucket_name, "#{@scope_name}.#{@name}", id, JSON.dump(content))
169
+ blob, flags = options.transcoder.encode(content)
170
+ resp = @backend.document_upsert(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, {
171
+ durability_level: options.durability_level,
172
+ expiration: options.expiration,
173
+ })
132
174
  MutationResult.new do |res|
133
175
  res.cas = resp[:cas]
176
+ res.mutation_token = extract_mutation_token(resp)
134
177
  end
135
178
  end
136
179
 
137
180
  # Replaces a full document which already exists
138
- #
181
+ #
139
182
  # @param [String] id the document id which is used to uniquely identify it.
140
183
  # @param [Object] content the document content to upsert
141
184
  # @param [ReplaceOptions] options request customization
142
185
  #
143
186
  # @return [MutationResult]
144
- def replace(id, content, options = ReplaceOptions.new) end
187
+ def replace(id, content, options = ReplaceOptions.new)
188
+ blob, flags = options.transcoder.encode(content)
189
+ resp = @backend.document_replace(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, {
190
+ durability_level: options.durability_level,
191
+ expiration: options.expiration,
192
+ cas: options.cas,
193
+ })
194
+ MutationResult.new do |res|
195
+ res.cas = resp[:cas]
196
+ res.mutation_token = extract_mutation_token(resp)
197
+ end
198
+ end
145
199
 
146
200
  # Update the expiration of the document with the given id
147
- #
201
+ #
148
202
  # @param [String] id the document id which is used to uniquely identify it.
149
203
  # @param [Integer] expiration new expiration time for the document
150
204
  # @param [TouchOptions] options request customization
151
205
  #
152
206
  # @return [MutationResult]
153
- def touch(id, expiration, options = TouchOptions.new) end
207
+ def touch(id, expiration, options = TouchOptions.new)
208
+ resp = @backend.document_touch(bucket_name, "#{@scope_name}.#{@name}", id, expiration)
209
+ MutationResult.new do |res|
210
+ res.cas = resp[:cas]
211
+ end
212
+ end
154
213
 
155
214
  # Unlocks a document if it has been locked previously
156
- #
215
+ #
157
216
  # @param [String] id the document id which is used to uniquely identify it.
158
217
  # @param [Integer] cas CAS value which is needed to unlock the document
159
- # @param [TouchOptions] options request customization
160
- def unlock(id, cas, options = UnlockOptions.new) end
218
+ # @param [UnlockOptions] options request customization
219
+ #
220
+ # @raise [Error::DocumentNotFound]
221
+ def unlock(id, cas, options = UnlockOptions.new)
222
+ @backend.document_unlock(bucket_name, "#{@scope_name}.#{@name}", id, cas)
223
+ end
161
224
 
162
225
  # Performs lookups to document fragments
163
226
  #
@@ -167,11 +230,12 @@ module Couchbase
167
230
  #
168
231
  # @return [LookupInResult]
169
232
  def lookup_in(id, specs, options = LookupInOptions.new)
170
- resp = @backend.lookup_in(
233
+ resp = @backend.document_lookup_in(
171
234
  bucket_name, "#{@scope_name}.#{@name}", id, options.access_deleted,
172
235
  specs.map { |s| {opcode: s.type, xattr: s.xattr?, path: s.path} }
173
236
  )
174
237
  LookupInResult.new do |res|
238
+ res.transcoder = options.transcoder
175
239
  res.cas = resp[:cas]
176
240
  res.encoded = resp[:fields].map do |field|
177
241
  SubDocumentField.new do |f|
@@ -193,13 +257,17 @@ module Couchbase
193
257
  #
194
258
  # @return [MutateInResult]
195
259
  def mutate_in(id, specs, options = MutateInOptions.new)
196
- resp = @backend.mutate_in(
260
+ resp = @backend.document_mutate_in(
197
261
  bucket_name, "#{@scope_name}.#{@name}", id, options.access_deleted,
198
262
  specs.map { |s| {opcode: s.type, path: s.path, param: s.param,
199
- xattr: s.xattr?, expand_macros: s.expand_macros?, create_parents: s.create_parents?} }
263
+ xattr: s.xattr?, expand_macros: s.expand_macros?, create_parents: s.create_parents?} }, {
264
+ durability_level: options.durability_level
265
+ }
200
266
  )
201
267
  MutateInResult.new do |res|
268
+ res.transcoder = options.transcoder
202
269
  res.cas = resp[:cas]
270
+ res.mutation_token = extract_mutation_token(resp)
203
271
  res.first_error_index = resp[:first_error_index]
204
272
  res.encoded = resp[:fields].map do |field|
205
273
  SubDocumentField.new do |f|
@@ -213,166 +281,15 @@ module Couchbase
213
281
  end
214
282
  end
215
283
 
216
- class GetOptions < CommonOptions
217
- # @return [Boolean] if the expiration should also fetched with get
218
- attr_accessor :with_expiry
219
-
220
- # @return [Proc] transcoder used for decoding
221
- attr_accessor :transcoder
222
-
223
- def initialize
224
- yield self if block_given?
225
- end
226
-
227
- # Allows to specify a custom list paths to fetch from the document instead of the whole.
228
- #
229
- # Note that a maximum of 16 individual paths can be projected at a time due to a server limitation. If you need
230
- # more than that, think about fetching less-generic paths or the full document straight away.
231
- #
232
- # @param [String, Array<String>] paths a path that should be loaded if present.
233
- def project(*paths)
234
- @projections ||= []
235
- @projections |= paths # union with current projections
236
- end
237
- end
238
-
239
- class GetAndLockOptions < CommonOptions
240
- # @return [Proc] transcoder used for decoding
241
- attr_accessor :transcoder
242
-
243
- def initialize
244
- yield self if block_given?
245
- end
246
- end
247
-
248
- class GetAndTouchOptions < CommonOptions
249
- # @return [Proc] transcoder used for decoding
250
- attr_accessor :transcoder
251
-
252
- def initialize
253
- yield self if block_given?
254
- end
255
- end
256
-
257
- class GetAllReplicasOptions < CommonOptions
258
- # @return [Proc] transcoder used for decoding
259
- attr_accessor :transcoder
260
-
261
- def initialize
262
- yield self if block_given?
263
- end
264
- end
265
-
266
- class GetAnyReplicaOptions < CommonOptions
267
- # @return [Proc] transcoder used for decoding
268
- attr_accessor :transcoder
269
-
270
- def initialize
271
- yield self if block_given?
272
- end
273
- end
274
-
275
- class ExistsOptions < CommonOptions
276
- def initialize
277
- yield self if block_given?
278
- end
279
- end
280
-
281
- class RemoveOptions < CommonOptions
282
- # @return [Integer] Specifies a CAS value that will be taken into account on the server side for optimistic concurrency
283
- attr_accessor :cas
284
-
285
- def initialize
286
- yield self if block_given?
287
- end
288
- end
289
-
290
- class InsertOptions < CommonOptions
291
- # @return [Integer] expiration time to associate with the document
292
- attr_accessor :expiration
293
-
294
- # @return [Proc] transcoder used for encoding
295
- attr_accessor :transcoder
296
-
297
- def initialize
298
- yield self if block_given?
299
- end
300
- end
301
-
302
- class UpsertOptions < CommonOptions
303
- # @return [Integer] expiration time to associate with the document
304
- attr_accessor :expiration
305
-
306
- # @return [Proc] transcoder used for encoding
307
- attr_accessor :transcoder
308
-
309
- def initialize
310
- yield self if block_given?
311
- end
312
- end
313
-
314
- class ReplaceOptions < CommonOptions
315
- # @return [Integer] expiration time to associate with the document
316
- attr_accessor :expiration
317
-
318
- # @return [Proc] transcoder used for encoding
319
- attr_accessor :transcoder
320
-
321
- # @return [Integer] Specifies a CAS value that will be taken into account on the server side for optimistic concurrency
322
- attr_accessor :cas
323
-
324
- def initialize
325
- yield self if block_given?
326
- end
327
- end
328
-
329
- class TouchOptions < CommonOptions
330
- def initialize
331
- yield self if block_given?
332
- end
333
- end
334
-
335
- class UnlockOptions < CommonOptions
336
- def initialize
337
- yield self if block_given?
338
- end
339
- end
340
-
341
- class LookupInOptions < CommonOptions
342
- # @return [Boolean] For internal use only: allows access to deleted documents that are in 'tombstone' form
343
- attr_accessor :access_deleted
344
-
345
- def initialize
346
- yield self if block_given?
347
- end
348
- end
349
-
350
- class MutateInOptions < CommonOptions
351
- # @return [Integer] expiration time to associate with the document
352
- attr_accessor :expiration
353
-
354
- # Describes how the outer document store semantics on subdoc should act
355
- #
356
- # * +:replace+: replace the document, fail if it does not exist. This is the default
357
- # * +:upsert+: replace the document or create if it does not exist
358
- # * +:insert+: create the document, fail if it exists
359
- #
360
- # @return [:replace, :upsert, :insert]
361
- attr_accessor :store_semantics
362
-
363
- # @return [Integer] Specifies a CAS value that will be taken into account on the server side for optimistic concurrency
364
- attr_accessor :cas
365
-
366
- # @return [Boolean] For internal use only: allows access to deleted documents that are in 'tombstone' form
367
- attr_accessor :access_deleted
368
-
369
- # @return [Boolean] For internal use only: allows creating documents in 'tombstone' form
370
- attr_accessor :create_as_deleted
284
+ private
371
285
 
372
- def initialize
373
- @store_semantics = :replace
374
- yield self if block_given?
286
+ def extract_mutation_token(resp)
287
+ MutationToken.new do |token|
288
+ token.partition_id = resp[:mutation_token][:partition_id]
289
+ token.partition_uuid = resp[:mutation_token][:partition_uuid]
290
+ token.sequence_number = resp[:mutation_token][:sequence_number]
291
+ token.bucket_name = resp[:mutation_token][:bucket_name]
375
292
  end
376
293
  end
377
294
  end
378
- end
295
+ end
@@ -0,0 +1,430 @@
1
+ # Copyright 2020 Couchbase, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "couchbase/json_transcoder"
16
+ require "couchbase/common_options"
17
+ require "couchbase/subdoc"
18
+ require "couchbase/mutation_state"
19
+
20
+ module Couchbase
21
+ class Collection
22
+ class GetOptions < CommonOptions
23
+ # @return [Boolean] if the expiration should also fetched with get
24
+ attr_accessor :with_expiry
25
+
26
+ # @return [JsonTranscoder] transcoder used for decoding
27
+ attr_accessor :transcoder
28
+
29
+ # @yieldparam [GetOptions] self
30
+ def initialize
31
+ @transcoder = JsonTranscoder.new
32
+ yield self if block_given?
33
+ end
34
+
35
+ # Allows to specify a custom list paths to fetch from the document instead of the whole.
36
+ #
37
+ # Note that a maximum of 16 individual paths can be projected at a time due to a server limitation. If you need
38
+ # more than that, think about fetching less-generic paths or the full document straight away.
39
+ #
40
+ # @param [String, Array<String>] paths a path that should be loaded if present.
41
+ def project(*paths)
42
+ @projections ||= []
43
+ @projections |= paths # union with current projections
44
+ end
45
+ end
46
+
47
+ class GetAndLockOptions < CommonOptions
48
+ # @return [JsonTranscoder] transcoder used for decoding
49
+ attr_accessor :transcoder
50
+
51
+ # @yieldparam [GetAndLockOptions] self
52
+ def initialize
53
+ @transcoder = JsonTranscoder.new
54
+ yield self if block_given?
55
+ end
56
+ end
57
+
58
+ class GetAndTouchOptions < CommonOptions
59
+ # @return [JsonTranscoder] transcoder used for decoding
60
+ attr_accessor :transcoder
61
+
62
+ # @yieldparam [GetAndTouchOptions] self
63
+ def initialize
64
+ @transcoder = JsonTranscoder.new
65
+ yield self if block_given?
66
+ end
67
+ end
68
+
69
+ class GetResult
70
+ # @return [Integer] holds the CAS value of the fetched document
71
+ attr_accessor :cas
72
+
73
+ # @return [Integer] the expiration if fetched and present
74
+ attr_accessor :expiration
75
+
76
+ # @return [String] The encoded content when loading the document
77
+ attr_accessor :encoded
78
+
79
+ # Decodes the content of the document using given (or default transcoder)
80
+ #
81
+ # @param [JsonTranscoder] transcoder custom transcoder
82
+ #
83
+ # @return [Object]
84
+ def content(transcoder = self.transcoder)
85
+ transcoder.decode(@encoded, @flags)
86
+ end
87
+
88
+ # @yieldparam [GetResult] self
89
+ def initialize
90
+ yield self if block_given?
91
+ end
92
+
93
+ # @return [Integer] The flags from the operation
94
+ attr_accessor :flags
95
+
96
+ # @return [JsonTranscoder] The default transcoder which should be used
97
+ attr_accessor :transcoder
98
+ end
99
+
100
+ class GetAllReplicasOptions < CommonOptions
101
+ # @return [JsonTranscoder] transcoder used for decoding
102
+ attr_accessor :transcoder
103
+
104
+ # @yieldparam [GetAllReplicasOptions] self
105
+ def initialize
106
+ yield self if block_given?
107
+ end
108
+ end
109
+
110
+ class GetAnyReplicaOptions < CommonOptions
111
+ # @return [JsonTranscoder] transcoder used for decoding
112
+ attr_accessor :transcoder
113
+
114
+ # @yieldparam [GetAnyReplicaOptions] self
115
+ def initialize
116
+ yield self if block_given?
117
+ end
118
+ end
119
+
120
+ class GetReplicaResult < GetResult
121
+ # @return [Boolean] true if this result came from a replica
122
+ attr_accessor :is_replica
123
+ alias_method :replica?, :is_replica
124
+ end
125
+
126
+ class ExistsOptions < CommonOptions
127
+ # @yieldparam [ExistsOptions] self
128
+ def initialize
129
+ yield self if block_given?
130
+ end
131
+ end
132
+
133
+ class ExistsResult
134
+ # @return [Integer] holds the CAS value of the fetched document
135
+ attr_accessor :cas
136
+
137
+ # @api private
138
+ # @return [:found, :not_found, :persisted, :logically_deleted]
139
+ attr_accessor :status
140
+
141
+ def exists?
142
+ status == :found || status == :persisted
143
+ end
144
+
145
+ # @yieldparam [ExistsResult]
146
+ def initialize
147
+ @durability_level = :none
148
+ yield self if block_given?
149
+ end
150
+
151
+ # @api private
152
+ # @return [Integer] holds the index of the partition, to which the given key is mapped
153
+ attr_accessor :partition_id
154
+ end
155
+
156
+ class RemoveOptions < CommonOptions
157
+ # @return [Integer] Specifies a CAS value that will be taken into account on the server side for optimistic concurrency
158
+ attr_accessor :cas
159
+
160
+ # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
161
+ attr_accessor :durability_level
162
+
163
+ # @yieldparam [RemoveOptions]
164
+ def initialize
165
+ @durability_level = :none
166
+ yield self if block_given?
167
+ end
168
+ end
169
+
170
+ class InsertOptions < CommonOptions
171
+ # @return [Integer] expiration time to associate with the document
172
+ attr_accessor :expiration
173
+
174
+ # @return [Proc] transcoder used for encoding
175
+ attr_accessor :transcoder
176
+
177
+ # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
178
+ attr_accessor :durability_level
179
+
180
+ # @yieldparam [InsertOptions]
181
+ def initialize
182
+ @transcoder = JsonTranscoder.new
183
+ @durability_level = :none
184
+ yield self if block_given?
185
+ end
186
+ end
187
+
188
+ class UpsertOptions < CommonOptions
189
+ # @return [Integer] expiration time to associate with the document
190
+ attr_accessor :expiration
191
+
192
+ # @return [JsonTranscoder] transcoder used for encoding
193
+ attr_accessor :transcoder
194
+
195
+ # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
196
+ attr_accessor :durability_level
197
+
198
+ # @yieldparam [UpsertOptions]
199
+ def initialize
200
+ @transcoder = JsonTranscoder.new
201
+ @durability_level = :none
202
+ yield self if block_given?
203
+ end
204
+ end
205
+
206
+ class ReplaceOptions < CommonOptions
207
+ # @return [Integer] expiration time to associate with the document
208
+ attr_accessor :expiration
209
+
210
+ # @return [JsonTranscoder] transcoder used for encoding
211
+ attr_accessor :transcoder
212
+
213
+ # @return [Integer] Specifies a CAS value that will be taken into account on the server side for optimistic concurrency
214
+ attr_accessor :cas
215
+
216
+ # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
217
+ attr_accessor :durability_level
218
+
219
+ # @yieldparam [ReplaceOptions]
220
+ def initialize
221
+ @transcoder = JsonTranscoder.new
222
+ @durability_level = :none
223
+ yield self if block_given?
224
+ end
225
+ end
226
+
227
+ class MutationResult
228
+ # @return [Integer] holds the CAS value of the document after the mutation
229
+ attr_accessor :cas
230
+
231
+ # @return [MutationToken] if returned, holds the mutation token of the document after the mutation
232
+ attr_accessor :mutation_token
233
+
234
+ # @yieldparam [MutationResult] self
235
+ def initialize
236
+ yield self if block_given?
237
+ end
238
+ end
239
+
240
+ class TouchOptions < CommonOptions
241
+ # @yieldparam [TouchOptions] self
242
+ def initialize
243
+ yield self if block_given?
244
+ end
245
+ end
246
+
247
+ class UnlockOptions < CommonOptions
248
+ # @yieldparam [UnlockOptions] self
249
+ def initialize
250
+ yield self if block_given?
251
+ end
252
+ end
253
+
254
+ class LookupInOptions < CommonOptions
255
+ # @return [Boolean] For internal use only: allows access to deleted documents that are in 'tombstone' form
256
+ attr_accessor :access_deleted
257
+
258
+ # @return [JsonTranscoder] transcoder used for decoding
259
+ attr_accessor :transcoder
260
+
261
+ # @yieldparam [LookupInOptions] self
262
+ def initialize
263
+ @transcoder = JsonTranscoder.new
264
+ yield self if block_given?
265
+ end
266
+ end
267
+
268
+ class LookupInResult
269
+ # @return [Integer] holds the CAS value of the fetched document
270
+ attr_accessor :cas
271
+
272
+ # Decodes the content at the given index
273
+ #
274
+ # @param [Integer] index the index of the subdocument value to decode
275
+ #
276
+ # @return [Object] the decoded
277
+ def content(index, transcoder = self.transcoder)
278
+ transcoder.decode(encoded[index].value, :json)
279
+ end
280
+
281
+ # Allows to check if a value at the given index exists
282
+ #
283
+ # @param [Integer] index the index of the subdocument value to check
284
+ #
285
+ # @return [Boolean] true if a value is present at the index, false otherwise
286
+ def exists?(index)
287
+ encoded[index].exists
288
+ end
289
+
290
+ # @return [Array<SubDocumentField>] holds the encoded subdocument responses
291
+ attr_accessor :encoded
292
+
293
+ # @yieldparam [LookupInResult] self
294
+ def initialize
295
+ yield self if block_given?
296
+ end
297
+
298
+ # @return [JsonTranscoder] The default transcoder which should be used
299
+ attr_accessor :transcoder
300
+ end
301
+
302
+ class MutateInOptions < CommonOptions
303
+ # @return [Integer] expiration time to associate with the document
304
+ attr_accessor :expiration
305
+
306
+ # Describes how the outer document store semantics on subdoc should act
307
+ #
308
+ # * +:replace+: replace the document, fail if it does not exist. This is the default
309
+ # * +:upsert+: replace the document or create if it does not exist
310
+ # * +:insert+: create the document, fail if it exists
311
+ #
312
+ # @return [:replace, :upsert, :insert]
313
+ attr_accessor :store_semantics
314
+
315
+ # @return [Integer] Specifies a CAS value that will be taken into account on the server side for optimistic concurrency
316
+ attr_accessor :cas
317
+
318
+ # @return [Boolean] For internal use only: allows access to deleted documents that are in 'tombstone' form
319
+ attr_accessor :access_deleted
320
+
321
+ # @return [Boolean] For internal use only: allows creating documents in 'tombstone' form
322
+ attr_accessor :create_as_deleted
323
+
324
+ # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
325
+ attr_accessor :durability_level
326
+
327
+ # @yieldparam [MutateInOptions]
328
+ def initialize
329
+ @durability_level = :none
330
+ @store_semantics = :replace
331
+ @transcoder = JsonTranscoder.new
332
+ yield self if block_given?
333
+ end
334
+
335
+ attr_accessor :transcoder
336
+ end
337
+
338
+ class MutateInResult < MutationResult
339
+ # Decodes the content at the given index
340
+ #
341
+ # @param [Integer] index the index of the subdocument value to decode
342
+ #
343
+ # @return [Object] the decoded
344
+ def content(index, transcoder = self.transcoder)
345
+ transcoder.decode(encoded[index].value, :json)
346
+ end
347
+
348
+ # @yieldparam [MutateInResult] self
349
+ def initialize
350
+ yield self if block_given?
351
+ end
352
+
353
+ def success?
354
+ !!first_error_index
355
+ end
356
+
357
+ # @return [Array<SubDocumentField>] holds the encoded subdocument responses
358
+ attr_accessor :encoded
359
+
360
+ # @return [Integer, nil] index of first operation entry that generated an error
361
+ attr_accessor :first_error_index
362
+
363
+ # @return [JsonTranscoder] The default transcoder which should be used
364
+ attr_accessor :transcoder
365
+ end
366
+
367
+ # @api private
368
+ class SubDocumentField
369
+ attr_accessor :error
370
+
371
+ # @return [Boolean] true if the path exists in the document
372
+ attr_accessor :exists
373
+
374
+ # @return [String] value
375
+ attr_accessor :value
376
+
377
+ # @return [String] path
378
+ attr_accessor :path
379
+
380
+ # Operation type
381
+ #
382
+ # * +:set_doc+
383
+ # * +:counter+
384
+ # * +:replace+
385
+ # * +:dict_add+
386
+ # * +:dict_upsert+
387
+ # * +:array_push_first+
388
+ # * +:array_push_last+
389
+ # * +:array_add_unique+
390
+ # * +:array_insert+
391
+ # * +:delete+
392
+ # * +:get+
393
+ # * +:exists+
394
+ # * +:count+
395
+ # * +:get_doc+
396
+ #
397
+ # @return [Symbol]
398
+ attr_accessor :type
399
+
400
+ # Status of the subdocument path operation.
401
+ #
402
+ # [+:success+] Indicates a successful response in general.
403
+ # [+:path_not_found+] The provided path does not exist in the document
404
+ # [+:path_mismatch+] One of path components treats a non-dictionary as a dictionary, or a non-array as an array, or value the path points to is not a number
405
+ # [+:path_invalid+] The path's syntax was incorrect
406
+ # [+:path_too_big+] The path provided is too large: either the string is too long, or it contains too many components
407
+ # [+:value_cannot_insert+] The value provided will invalidate the JSON if inserted
408
+ # [+:doc_not_json+] The existing document is not valid JSON
409
+ # [+:num_range+] The existing number is out of the valid range for arithmetic operations
410
+ # [+:delta_invalid+] The operation would result in a number outside the valid range
411
+ # [+:path_exists+] The requested operation requires the path to not already exist, but it exists
412
+ # [+:value_too_deep+] Inserting the value would cause the document to be too deep
413
+ # [+:invalid_combo+] An invalid combination of commands was specified
414
+ # [+:xattr_invalid_flag_combo+] An invalid combination of operations, using macros when not using extended attributes
415
+ # [+:xattr_invalid_key_combo+] Only single xattr key may be accessed at the same time
416
+ # [+:xattr_unknown_macro+] The server has no knowledge of the requested macro
417
+ # [+:xattr_unknown_vattr+] Unknown virtual attribute.
418
+ # [+:xattr_cannot_modify_vattr+] Cannot modify this virtual attribute.
419
+ # [+:unknown+] Unknown error.
420
+ #
421
+ # @return [Symbol]
422
+ attr_accessor :status
423
+
424
+ # @yieldparam [SubDocumentField] self
425
+ def initialize
426
+ yield self if block_given?
427
+ end
428
+ end
429
+ end
430
+ end