couchbase 3.5.0-x86_64-linux-musl

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 (125) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +202 -0
  3. data/README.md +154 -0
  4. data/ext/extconf.rb +0 -0
  5. data/lib/active_support/cache/couchbase_store.rb +339 -0
  6. data/lib/couchbase/3.1/libcouchbase.so +0 -0
  7. data/lib/couchbase/3.2/libcouchbase.so +0 -0
  8. data/lib/couchbase/3.3/libcouchbase.so +0 -0
  9. data/lib/couchbase/analytics_options.rb +107 -0
  10. data/lib/couchbase/authenticator.rb +64 -0
  11. data/lib/couchbase/binary_collection.rb +128 -0
  12. data/lib/couchbase/binary_collection_options.rb +24 -0
  13. data/lib/couchbase/bucket.rb +144 -0
  14. data/lib/couchbase/cluster.rb +460 -0
  15. data/lib/couchbase/cluster_registry.rb +49 -0
  16. data/lib/couchbase/collection.rb +705 -0
  17. data/lib/couchbase/collection_options.rb +399 -0
  18. data/lib/couchbase/config_profiles.rb +55 -0
  19. data/lib/couchbase/configuration.rb +56 -0
  20. data/lib/couchbase/datastructures/couchbase_list.rb +160 -0
  21. data/lib/couchbase/datastructures/couchbase_map.rb +194 -0
  22. data/lib/couchbase/datastructures/couchbase_queue.rb +134 -0
  23. data/lib/couchbase/datastructures/couchbase_set.rb +128 -0
  24. data/lib/couchbase/datastructures.rb +24 -0
  25. data/lib/couchbase/diagnostics.rb +181 -0
  26. data/lib/couchbase/errors.rb +376 -0
  27. data/lib/couchbase/json_transcoder.rb +39 -0
  28. data/lib/couchbase/key_value_scan.rb +117 -0
  29. data/lib/couchbase/libcouchbase.rb +6 -0
  30. data/lib/couchbase/logger.rb +85 -0
  31. data/lib/couchbase/management/analytics_index_manager.rb +1127 -0
  32. data/lib/couchbase/management/bucket_manager.rb +443 -0
  33. data/lib/couchbase/management/collection_manager.rb +470 -0
  34. data/lib/couchbase/management/collection_query_index_manager.rb +222 -0
  35. data/lib/couchbase/management/query_index_manager.rb +617 -0
  36. data/lib/couchbase/management/scope_search_index_manager.rb +198 -0
  37. data/lib/couchbase/management/search_index_manager.rb +424 -0
  38. data/lib/couchbase/management/user_manager.rb +468 -0
  39. data/lib/couchbase/management/view_index_manager.rb +237 -0
  40. data/lib/couchbase/management.rb +29 -0
  41. data/lib/couchbase/mutation_state.rb +63 -0
  42. data/lib/couchbase/options.rb +2837 -0
  43. data/lib/couchbase/protostellar/binary_collection.rb +55 -0
  44. data/lib/couchbase/protostellar/bucket.rb +51 -0
  45. data/lib/couchbase/protostellar/client.rb +99 -0
  46. data/lib/couchbase/protostellar/cluster.rb +163 -0
  47. data/lib/couchbase/protostellar/collection.rb +152 -0
  48. data/lib/couchbase/protostellar/connect_options.rb +63 -0
  49. data/lib/couchbase/protostellar/error_handling.rb +203 -0
  50. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +61 -0
  51. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +35 -0
  52. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +57 -0
  53. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +36 -0
  54. data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +61 -0
  55. data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +37 -0
  56. data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +72 -0
  57. data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +44 -0
  58. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +52 -0
  59. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +30 -0
  60. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +70 -0
  61. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +36 -0
  62. data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +97 -0
  63. data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +46 -0
  64. data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +57 -0
  65. data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +30 -0
  66. data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +52 -0
  67. data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +30 -0
  68. data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +99 -0
  69. data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +30 -0
  70. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +57 -0
  71. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +36 -0
  72. data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +51 -0
  73. data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +30 -0
  74. data/lib/couchbase/protostellar/generated.rb +9 -0
  75. data/lib/couchbase/protostellar/management/bucket_manager.rb +67 -0
  76. data/lib/couchbase/protostellar/management/collection_manager.rb +94 -0
  77. data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +124 -0
  78. data/lib/couchbase/protostellar/management/query_index_manager.rb +112 -0
  79. data/lib/couchbase/protostellar/management.rb +24 -0
  80. data/lib/couchbase/protostellar/request.rb +78 -0
  81. data/lib/couchbase/protostellar/request_behaviour.rb +42 -0
  82. data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +124 -0
  83. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +94 -0
  84. data/lib/couchbase/protostellar/request_generator/admin/query.rb +130 -0
  85. data/lib/couchbase/protostellar/request_generator/admin.rb +24 -0
  86. data/lib/couchbase/protostellar/request_generator/kv.rb +474 -0
  87. data/lib/couchbase/protostellar/request_generator/query.rb +133 -0
  88. data/lib/couchbase/protostellar/request_generator/search.rb +387 -0
  89. data/lib/couchbase/protostellar/request_generator.rb +26 -0
  90. data/lib/couchbase/protostellar/response_converter/admin/bucket.rb +55 -0
  91. data/lib/couchbase/protostellar/response_converter/admin/collection.rb +42 -0
  92. data/lib/couchbase/protostellar/response_converter/admin/query.rb +59 -0
  93. data/lib/couchbase/protostellar/response_converter/admin.rb +24 -0
  94. data/lib/couchbase/protostellar/response_converter/kv.rb +151 -0
  95. data/lib/couchbase/protostellar/response_converter/query.rb +84 -0
  96. data/lib/couchbase/protostellar/response_converter/search.rb +136 -0
  97. data/lib/couchbase/protostellar/response_converter.rb +26 -0
  98. data/lib/couchbase/protostellar/retry/action.rb +38 -0
  99. data/lib/couchbase/protostellar/retry/orchestrator.rb +60 -0
  100. data/lib/couchbase/protostellar/retry/reason.rb +67 -0
  101. data/lib/couchbase/protostellar/retry/strategies/best_effort.rb +49 -0
  102. data/lib/couchbase/protostellar/retry/strategies.rb +26 -0
  103. data/lib/couchbase/protostellar/retry.rb +28 -0
  104. data/lib/couchbase/protostellar/scope.rb +57 -0
  105. data/lib/couchbase/protostellar/timeout_defaults.rb +30 -0
  106. data/lib/couchbase/protostellar/timeouts.rb +83 -0
  107. data/lib/couchbase/protostellar.rb +29 -0
  108. data/lib/couchbase/query_options.rb +120 -0
  109. data/lib/couchbase/railtie.rb +45 -0
  110. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  111. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  112. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  113. data/lib/couchbase/scope.rb +256 -0
  114. data/lib/couchbase/search_options.rb +1622 -0
  115. data/lib/couchbase/subdoc.rb +290 -0
  116. data/lib/couchbase/transcoder_flags.rb +62 -0
  117. data/lib/couchbase/utils/generic_logger_adapter.rb +38 -0
  118. data/lib/couchbase/utils/stdlib_logger_adapter.rb +65 -0
  119. data/lib/couchbase/utils/time.rb +69 -0
  120. data/lib/couchbase/utils.rb +21 -0
  121. data/lib/couchbase/version.rb +23 -0
  122. data/lib/couchbase/view_options.rb +65 -0
  123. data/lib/couchbase.rb +28 -0
  124. data/lib/rails/generators/couchbase/config/config_generator.rb +27 -0
  125. metadata +190 -0
@@ -0,0 +1,1622 @@
1
+ # Copyright 2020-2021 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
+ module Couchbase
16
+ class SearchRequest
17
+ # Creates a search request, used to perform operations against the Full Text Search (FTS) Couchbase service.
18
+ #
19
+ # @overload new(search_query)
20
+ # Will run an FTS +SearchQuery+
21
+ # @param [SearchQuery] search_query
22
+ #
23
+ # @overload new(vector_search)
24
+ # Will run a +VectorSearch+
25
+ # @param [VectorSearch] vector_search
26
+ #
27
+ # @!macro uncommitted
28
+ def initialize(search)
29
+ case search
30
+ when SearchQuery
31
+ @search_query = search
32
+ when VectorSearch
33
+ @vector_search = search
34
+ else
35
+ raise Error::InvalidArgument, "Search type must be either SearchQuery or VectorSearch, #{search.class} given"
36
+ end
37
+ end
38
+
39
+ # Can be used to run a +SearchQuery+ together with an existing +VectorSearch+
40
+ # Note that a maximum of one +SearchQuery+ can be provided.
41
+ #
42
+ # @param [SearchQuery] query
43
+ #
44
+ # @return [SearchRequest] for chaining purposes
45
+ def search_query(query)
46
+ raise Error::InvalidArgument, "A SearchQuery has already been specified" unless @search_query.nil?
47
+
48
+ @search_query = query
49
+ self
50
+ end
51
+
52
+ # Can be used to run a +VectorSearch+ together with an existing +SearchQuery+
53
+ # Note that a maximum of one +VectorSearch+ can be provided.
54
+ #
55
+ # @param [VectorSearch] query
56
+ #
57
+ # @return [SearchRequest] for chaining purposes
58
+ #
59
+ # @!macro uncommitted
60
+ def vector_search(query)
61
+ raise Error::InvalidArgument, "A VectorSearch has already been specified" unless @vector_search.nil?
62
+
63
+ @vector_search = query
64
+ self
65
+ end
66
+
67
+ # @api private
68
+ def to_backend
69
+ [
70
+ (@search_query || SearchQuery.match_none).to_json,
71
+ {
72
+ vector_search: @vector_search&.to_backend,
73
+ },
74
+ ]
75
+ end
76
+ end
77
+
78
+ class SearchQuery
79
+ # @return [Hash<Symbol, #to_json>]
80
+ def to_h
81
+ {}
82
+ end
83
+
84
+ # @return [String]
85
+ def to_json(*args)
86
+ to_h.to_json(*args)
87
+ end
88
+
89
+ # Prepare {MatchQuery} body
90
+ #
91
+ # @param [String] match
92
+ # @yieldparam [MatchQuery] query
93
+ #
94
+ # @return [MatchQuery]
95
+ def self.match(match, &block)
96
+ MatchQuery.new(match, &block)
97
+ end
98
+
99
+ # A match query analyzes the input text and uses that analyzed text to query the index.
100
+ class MatchQuery < SearchQuery
101
+ # @return [Float]
102
+ attr_accessor :boost
103
+
104
+ # @return [String]
105
+ attr_accessor :field
106
+
107
+ # @return [String]
108
+ attr_accessor :analyzer
109
+
110
+ # @return [Integer]
111
+ attr_accessor :prefix_length
112
+
113
+ # @return [Integer]
114
+ attr_accessor :fuzziness
115
+
116
+ # @return [nil, :or, :and]
117
+ attr_accessor :operator
118
+
119
+ # @param [String] match
120
+ # @yieldparam [MatchQuery] self
121
+ def initialize(match)
122
+ super()
123
+ @match = match
124
+ yield self if block_given?
125
+ end
126
+
127
+ # @return [Hash<Symbol, #to_json>]
128
+ def to_h
129
+ data = {:match => @match}
130
+ data[:boost] = boost if boost
131
+ data[:field] = field if field
132
+ data[:analyzer] = analyzer if analyzer
133
+ data[:operator] = operator if operator
134
+ data[:fuzziness] = fuzziness if fuzziness
135
+ data[:prefix_length] = prefix_length if prefix_length
136
+ data
137
+ end
138
+ end
139
+
140
+ # Prepare {MatchPhraseQuery} body
141
+ #
142
+ # @param [String] match_phrase
143
+ # @yieldparam [MatchPhraseQuery] query
144
+ #
145
+ # @return [MatchPhraseQuery]
146
+ def self.match_phrase(match_phrase, &block)
147
+ MatchPhraseQuery.new(match_phrase, &block)
148
+ end
149
+
150
+ # The input text is analyzed and a phrase query is built with the terms resulting from the analysis.
151
+ class MatchPhraseQuery < SearchQuery
152
+ # @return [Float]
153
+ attr_accessor :boost
154
+
155
+ # @return [String]
156
+ attr_accessor :field
157
+
158
+ # @return [String]
159
+ attr_accessor :analyzer
160
+
161
+ # @param [String] match_phrase
162
+ #
163
+ # @yieldparam [MatchPhraseQuery] self
164
+ def initialize(match_phrase)
165
+ super()
166
+ @match_phrase = match_phrase
167
+ yield self if block_given?
168
+ end
169
+
170
+ # @return [Hash<Symbol, #to_json>]
171
+ def to_h
172
+ data = {:match_phrase => @match_phrase}
173
+ data[:boost] = boost if boost
174
+ data[:field] = field if field
175
+ data[:analyzer] = analyzer if analyzer
176
+ data
177
+ end
178
+ end
179
+
180
+ # Prepare {RegexpQuery} body
181
+ #
182
+ # @param [String] regexp
183
+ # @yieldparam [RegexpQuery] query
184
+ #
185
+ # @return [RegexpQuery]
186
+ def self.regexp(regexp, &block)
187
+ RegexpQuery.new(regexp, &block)
188
+ end
189
+
190
+ # Finds documents containing terms that match the specified regular expression.
191
+ class RegexpQuery < SearchQuery
192
+ # @return [Float]
193
+ attr_accessor :boost
194
+
195
+ # @return [String]
196
+ attr_accessor :field
197
+
198
+ # @param [String] regexp
199
+ #
200
+ # @yieldparam [RegexpQuery] self
201
+ def initialize(regexp)
202
+ super()
203
+ @regexp = regexp
204
+ yield self if block_given?
205
+ end
206
+
207
+ # @return [Hash<Symbol, #to_json>]
208
+ def to_h
209
+ data = {:regexp => @regexp}
210
+ data[:boost] = boost if boost
211
+ data[:field] = field if field
212
+ data
213
+ end
214
+ end
215
+
216
+ # Prepare {QueryStringQuery} body
217
+ #
218
+ # @param [String] query_string
219
+ # @yieldparam [QueryStringQuery] query
220
+ #
221
+ # @return [QueryStringQuery]
222
+ def self.query_string(query_string, &block)
223
+ QueryStringQuery.new(query_string, &block)
224
+ end
225
+
226
+ # The query string query allows humans to describe complex queries using a simple syntax.
227
+ class QueryStringQuery < SearchQuery
228
+ # @return [Float]
229
+ attr_accessor :boost
230
+
231
+ # @param [String] query_string
232
+ #
233
+ # @yieldparam [QueryStringQuery] self
234
+ def initialize(query_string)
235
+ super()
236
+ @query_string = query_string
237
+ yield self if block_given?
238
+ end
239
+
240
+ # @return [Hash<Symbol, #to_json>]
241
+ def to_h
242
+ data = {:query => @query_string}
243
+ data[:boost] = boost if boost
244
+ data
245
+ end
246
+ end
247
+
248
+ # Prepare {WildcardQuery} body
249
+ #
250
+ # @param [String] wildcard
251
+ # @yieldparam [WildcardQuery] query
252
+ #
253
+ # @return [WildcardQuery]
254
+ def self.wildcard(wildcard, &block)
255
+ WildcardQuery.new(wildcard, &block)
256
+ end
257
+
258
+ # Interprets * and ? wildcards as found in a lot of applications, for an easy implementation of such a search feature.
259
+ class WildcardQuery < SearchQuery
260
+ # @return [Float]
261
+ attr_accessor :boost
262
+
263
+ # @return [String]
264
+ attr_accessor :field
265
+
266
+ # @param [String] wildcard
267
+ #
268
+ # @yieldparam [WildcardQuery] self
269
+ def initialize(wildcard)
270
+ super()
271
+ @wildcard = wildcard
272
+ yield self if block_given?
273
+ end
274
+
275
+ # @return [Hash<Symbol, #to_json>]
276
+ def to_h
277
+ data = {:wildcard => @wildcard}
278
+ data[:boost] = boost if boost
279
+ data[:field] = field if field
280
+ data
281
+ end
282
+ end
283
+
284
+ # Prepare {DocIdQuery} body
285
+ #
286
+ # @param [String...] doc_ids
287
+ # @yieldparam [DocIdQuery] query
288
+ #
289
+ # @return [DocIdQuery]
290
+ def self.doc_id(*doc_ids)
291
+ DocIdQuery.new(*doc_ids)
292
+ end
293
+
294
+ # Allows to restrict matches to a set of specific documents.
295
+ class DocIdQuery < SearchQuery
296
+ # @return [Float]
297
+ attr_accessor :boost
298
+
299
+ # @param [String...] doc_ids
300
+ #
301
+ # @yieldparam [DocIdQuery] self
302
+ def initialize(*doc_ids)
303
+ super()
304
+ @doc_ids = doc_ids
305
+ yield self if block_given?
306
+ end
307
+
308
+ # @return [Hash<Symbol, #to_json>]
309
+ def to_h
310
+ data = {:ids => @doc_ids.flatten.uniq}
311
+ data[:boost] = boost if boost
312
+ data
313
+ end
314
+ end
315
+
316
+ # Prepare {BooleanFieldQuery} body
317
+ #
318
+ # @param [Boolean] value
319
+ # @yieldparam [BooleanFieldQuery] query
320
+ #
321
+ # @return [BooleanFieldQuery]
322
+ def self.boolean_field(value)
323
+ BooleanFieldQuery.new(value)
324
+ end
325
+
326
+ # Allow to match `true`/`false` in a field mapped as boolean.
327
+ class BooleanFieldQuery < SearchQuery
328
+ # @return [Float]
329
+ attr_accessor :boost
330
+
331
+ # @return [String]
332
+ attr_accessor :field
333
+
334
+ # @param [Boolean] value
335
+ #
336
+ # @yieldparam [BooleanFieldQuery] self
337
+ def initialize(value)
338
+ super()
339
+ @value = value
340
+ yield self if block_given?
341
+ end
342
+
343
+ # @return [Hash<Symbol, #to_json>]
344
+ def to_h
345
+ data = {:bool => @value}
346
+ data[:boost] = boost if boost
347
+ data[:field] = field if field
348
+ data
349
+ end
350
+ end
351
+
352
+ # Prepare {DateRangeQuery} body
353
+ #
354
+ # @yieldparam [DateRangeQuery] query
355
+ #
356
+ # @return [DateRangeQuery]
357
+ def self.date_range(&block)
358
+ DateRangeQuery.new(&block)
359
+ end
360
+
361
+ # The date range query finds documents containing a date value in the specified field within the specified range.
362
+ class DateRangeQuery < SearchQuery
363
+ # @return [Float]
364
+ attr_accessor :boost
365
+
366
+ # @return [String]
367
+ attr_accessor :field
368
+
369
+ # @return [String]
370
+ attr_accessor :date_time_parser
371
+
372
+ # Sets the lower boundary of the range.
373
+ #
374
+ # @note The lower boundary is considered inclusive by default on the server side.
375
+ #
376
+ # @param [Time, String] time_point start time. When +Time+ object is passed {#date_time_parser} must be +nil+ (to use server
377
+ # default)
378
+ # @param [Boolean] inclusive
379
+ def start_time(time_point, inclusive = nil)
380
+ @start_time = time_point
381
+ @start_inclusive = inclusive
382
+ end
383
+
384
+ # Sets the upper boundary of the range.
385
+ #
386
+ # @note The upper boundary is considered exclusive by default on the server side.
387
+ #
388
+ # @param [Time, String] time_point end time. When +Time+ object is passed {#date_time_parser} must be +nil+ (to use server default)
389
+ # @param [Boolean] inclusive
390
+ def end_time(time_point, inclusive = nil)
391
+ @end_time = time_point
392
+ @end_inclusive = inclusive
393
+ end
394
+
395
+ # @yieldparam [DateRangeQuery] self
396
+ def initialize
397
+ super
398
+ @start_time = nil
399
+ @start_inclusive = nil
400
+ @end_time = nil
401
+ @end_inclusive = nil
402
+ yield self if block_given?
403
+ end
404
+
405
+ DATE_FORMAT_RFC3339 = "%Y-%m-%dT%H:%M:%S%:z".freeze
406
+
407
+ # @return [Hash<Symbol, #to_json>]
408
+ def to_h
409
+ raise ArgumentError, "either start_time or end_time must be set for DateRangeQuery" if @start_time.nil? && @end_time.nil?
410
+
411
+ data = {}
412
+ data[:boost] = boost if boost
413
+ data[:field] = field if field
414
+ data[:datetime_parser] = date_time_parser if date_time_parser
415
+ if @start_time
416
+ data[:start] = if @start_time.respond_to?(:strftime)
417
+ @start_time.strftime(DATE_FORMAT_RFC3339)
418
+ else
419
+ @start_time
420
+ end
421
+ data[:inclusive_start] = @start_inclusive unless @start_inclusive.nil?
422
+ end
423
+ if @end_time
424
+ data[:end] = if @end_time.respond_to?(:strftime)
425
+ @end_time.strftime(DATE_FORMAT_RFC3339)
426
+ else
427
+ @end_time
428
+ end
429
+ data[:inclusive_end] = @end_inclusive unless @end_inclusive.nil?
430
+ end
431
+ data
432
+ end
433
+ end
434
+
435
+ # Prepare {NumericRangeQuery} body
436
+ #
437
+ # @yieldparam [NumericRangeQuery] query
438
+ #
439
+ # @return [NumericRangeQuery]
440
+ def self.numeric_range(&block)
441
+ NumericRangeQuery.new(&block)
442
+ end
443
+
444
+ # The numeric range query finds documents containing a numeric value in the specified field within the specified range.
445
+ class NumericRangeQuery < SearchQuery
446
+ # @return [Float]
447
+ attr_accessor :boost
448
+
449
+ # @return [String]
450
+ attr_accessor :field
451
+
452
+ # Sets lower bound of the range.
453
+ #
454
+ # The lower boundary is considered inclusive by default on the server side.
455
+ #
456
+ # @param [Numeric] lower_bound
457
+ # @param [Boolean] inclusive
458
+ def min(lower_bound, inclusive = nil)
459
+ @min = lower_bound
460
+ @min_inclusive = inclusive
461
+ end
462
+
463
+ # Sets upper bound of the range.
464
+ #
465
+ # The upper boundary is considered exclusive by default on the server side.
466
+ #
467
+ # @param [Numeric] upper_bound
468
+ # @param [Boolean] inclusive
469
+ def max(upper_bound, inclusive = nil)
470
+ @max = upper_bound
471
+ @max_inclusive = inclusive
472
+ end
473
+
474
+ # @yieldparam [NumericRangeQuery] self
475
+ def initialize
476
+ super
477
+ @min = nil
478
+ @min_inclusive = nil
479
+ @max = nil
480
+ @max_inclusive = nil
481
+ yield self if block_given?
482
+ end
483
+
484
+ # @return [Hash<Symbol, #to_json>]
485
+ def to_h
486
+ raise ArgumentError, "either min or max must be set for NumericRangeQuery" if @min.nil? && @max.nil?
487
+
488
+ data = {}
489
+ data[:boost] = boost if boost
490
+ data[:field] = field if field
491
+ if @min
492
+ data[:min] = @min
493
+ data[:inclusive_min] = @min_inclusive unless @min_inclusive.nil?
494
+ end
495
+ if @max
496
+ data[:max] = @max
497
+ data[:inclusive_max] = @max_inclusive unless @max_inclusive.nil?
498
+ end
499
+ data
500
+ end
501
+ end
502
+
503
+ # Prepare {TermRangeQuery} body
504
+ #
505
+ # @yieldparam [TermRangeQuery] query
506
+ #
507
+ # @return [TermRangeQuery]
508
+ def self.term_range(&block)
509
+ TermRangeQuery.new(&block)
510
+ end
511
+
512
+ # The term range query finds documents containing a string value in the specified field within the specified range.
513
+ class TermRangeQuery < SearchQuery
514
+ # @return [Float]
515
+ attr_accessor :boost
516
+
517
+ # @return [String]
518
+ attr_accessor :field
519
+
520
+ # Sets lower bound of the range.
521
+ #
522
+ # The lower boundary is considered inclusive by default on the server side.
523
+ #
524
+ # @param [String] lower_bound
525
+ # @param [Boolean] inclusive
526
+ def min(lower_bound, inclusive = nil)
527
+ @min = lower_bound
528
+ @min_inclusive = inclusive
529
+ end
530
+
531
+ # Sets upper bound of the range.
532
+ #
533
+ # The upper boundary is considered exclusive by default on the server side.
534
+ #
535
+ # @param [String] upper_bound
536
+ # @param [Boolean] inclusive
537
+ def max(upper_bound, inclusive = nil)
538
+ @max = upper_bound
539
+ @max_inclusive = inclusive
540
+ end
541
+
542
+ # @yieldparam [TermRangeQuery] self
543
+ def initialize
544
+ super
545
+ @min = nil
546
+ @min_inclusive = nil
547
+ @max = nil
548
+ @max_inclusive = nil
549
+ yield self if block_given?
550
+ end
551
+
552
+ # @return [Hash<Symbol, #to_json>]
553
+ def to_h
554
+ raise ArgumentError, "either min or max must be set for TermRangeQuery" if @min.nil? && @max.nil?
555
+
556
+ data = {}
557
+ data[:boost] = boost if boost
558
+ data[:field] = field if field
559
+ if @min
560
+ data[:min] = @min
561
+ data[:inclusive_min] = @min_inclusive unless @min_inclusive.nil?
562
+ end
563
+ if @max
564
+ data[:max] = @max
565
+ data[:inclusive_max] = @max_inclusive unless @max_inclusive.nil?
566
+ end
567
+ data
568
+ end
569
+ end
570
+
571
+ # Prepare {GeoDistanceQuery} body
572
+ #
573
+ # @yieldparam [GeoDistanceQuery] query
574
+ #
575
+ # @param [Float] latitude location latitude
576
+ # @param [Float] longitude location longitude
577
+ # @param [String] distance how big is area (number with units)
578
+ #
579
+ # @return [GeoDistanceQuery]
580
+ def self.geo_distance(longitude, latitude, distance, &block)
581
+ GeoDistanceQuery.new(longitude, latitude, distance, &block)
582
+ end
583
+
584
+ # Finds `geopoint` indexed matches around a point with the given distance.
585
+ class GeoDistanceQuery < SearchQuery
586
+ # @return [Float]
587
+ attr_accessor :boost
588
+
589
+ # @return [String]
590
+ attr_accessor :field
591
+
592
+ # @yieldparam [GeoDistanceQuery] self
593
+ # @param [Float] longitude
594
+ # @param [Float] latitude
595
+ # @param [Float] distance
596
+ def initialize(longitude, latitude, distance)
597
+ super()
598
+ @longitude = longitude
599
+ @latitude = latitude
600
+ @distance = distance
601
+ yield self if block_given?
602
+ end
603
+
604
+ # @return [Hash<Symbol, #to_json>]
605
+ def to_h
606
+ data = {
607
+ :location => [@longitude, @latitude],
608
+ :distance => @distance,
609
+ }
610
+ data[:boost] = boost if boost
611
+ data[:field] = field if field
612
+ data
613
+ end
614
+ end
615
+
616
+ # Prepare {GeoBoundingBoxQuery} body
617
+ #
618
+ # @yieldparam [GeoBoundingBoxQuery] query
619
+ #
620
+ # @param [Float] top_left_longitude
621
+ # @param [Float] top_left_latitude
622
+ # @param [Float] bottom_right_longitude
623
+ # @param [Float] bottom_right_latitude
624
+ #
625
+ # @return [GeoBoundingBoxQuery]
626
+ def self.geo_bounding_box(top_left_longitude, top_left_latitude, bottom_right_longitude, bottom_right_latitude, &block)
627
+ GeoBoundingBoxQuery.new(top_left_longitude, top_left_latitude, bottom_right_longitude, bottom_right_latitude, &block)
628
+ end
629
+
630
+ # Finds `geopoint` indexed matches in a given bounding box.
631
+ class GeoBoundingBoxQuery < SearchQuery
632
+ # @return [Float]
633
+ attr_accessor :boost
634
+
635
+ # @return [String]
636
+ attr_accessor :field
637
+
638
+ # @yieldparam [GeoBoundingBoxQuery] self
639
+ #
640
+ # @param [Float] top_left_longitude
641
+ # @param [Float] top_left_latitude
642
+ # @param [Float] bottom_right_longitude
643
+ # @param [Float] bottom_right_latitude
644
+ def initialize(top_left_longitude, top_left_latitude, bottom_right_longitude, bottom_right_latitude)
645
+ super()
646
+ @top_left_longitude = top_left_longitude
647
+ @top_left_latitude = top_left_latitude
648
+ @bottom_right_longitude = bottom_right_longitude
649
+ @bottom_right_latitude = bottom_right_latitude
650
+ yield self if block_given?
651
+ end
652
+
653
+ # @return [Hash<Symbol, #to_json>]
654
+ def to_h
655
+ data = {
656
+ :top_left => [@top_left_longitude, @top_left_latitude],
657
+ :bottom_right => [@bottom_right_longitude, @bottom_right_latitude],
658
+ }
659
+ data[:boost] = boost if boost
660
+ data[:field] = field if field
661
+ data
662
+ end
663
+ end
664
+
665
+ # A coordinate is a tuple of a latitude and a longitude.
666
+ #
667
+ # @see GeoPolygonQuery
668
+ # @see SearchQuery.geo_polygon
669
+ class Coordinate
670
+ # @return [Float]
671
+ attr_accessor :longitude
672
+
673
+ # @return [Float]
674
+ attr_accessor :latitude
675
+
676
+ def initialize(longitude, latitude)
677
+ @longitude = longitude
678
+ @latitude = latitude
679
+ end
680
+ end
681
+
682
+ # Prepare {GeoPolygonQuery} body
683
+ #
684
+ # @yieldparam [GeoPolygonQuery] query
685
+ #
686
+ # @param [Array<Coordinate>] coordinates list of coordinates that forms polygon
687
+ #
688
+ # @return [GeoPolygonQuery]
689
+ #
690
+ # @!macro uncommitted
691
+ def self.geo_polygon(coordinates, &block)
692
+ GeoPolygonQuery.new(coordinates, &block)
693
+ end
694
+
695
+ # A search query which allows to match inside a geo polygon.
696
+ class GeoPolygonQuery < SearchQuery
697
+ # @return [Float]
698
+ attr_accessor :boost
699
+
700
+ # @return [String]
701
+ attr_accessor :field
702
+
703
+ # @yieldparam [GeoPolygonQuery] self
704
+ #
705
+ # @param [Array<Coordinate>] coordinates list of coordinates that forms polygon
706
+ def initialize(coordinates)
707
+ super()
708
+ @coordinates = coordinates
709
+ yield self if block_given?
710
+ end
711
+
712
+ # @return [Hash<Symbol, #to_json>]
713
+ def to_h
714
+ data = {
715
+ :polygon_points => @coordinates.map { |coord| [coord.longitude, coord.latitude] },
716
+ }
717
+ data[:boost] = boost if boost
718
+ data[:field] = field if field
719
+ data
720
+ end
721
+ end
722
+
723
+ # Prepare {ConjunctionQuery} body
724
+ #
725
+ # @yieldparam [ConjunctionQuery] query
726
+ #
727
+ # @return [ConjunctionQuery]
728
+ def self.conjuncts(...)
729
+ ConjunctionQuery.new(...)
730
+ end
731
+
732
+ # Result documents must satisfy all of the child queries.
733
+ class ConjunctionQuery < SearchQuery
734
+ # @return [Float]
735
+ attr_accessor :boost
736
+
737
+ # @yieldparam [ConjunctionQuery] self
738
+ #
739
+ # @param [*SearchQuery] queries
740
+ def initialize(*queries)
741
+ super()
742
+ @queries = queries.flatten
743
+ yield self if block_given?
744
+ end
745
+
746
+ # @param [*SearchQuery] queries
747
+ def and_also(*queries)
748
+ @queries |= queries.flatten
749
+ end
750
+
751
+ def empty?
752
+ @queries.empty?
753
+ end
754
+
755
+ # @return [Hash<Symbol, #to_json>]
756
+ def to_h
757
+ raise ArgumentError, "compound conjunction query must have sub-queries" if @queries.nil? || @queries.empty?
758
+
759
+ data = {:conjuncts => @queries.uniq.map(&:to_h)}
760
+ data[:boost] = boost if boost
761
+ data
762
+ end
763
+ end
764
+
765
+ # Prepare {ConjunctionQuery} body
766
+ #
767
+ # @yieldparam [DisjunctionQuery] query
768
+ #
769
+ # @return [DisjunctionQuery]
770
+ def self.disjuncts(...)
771
+ DisjunctionQuery.new(...)
772
+ end
773
+
774
+ # Result documents must satisfy a configurable min number of child queries.
775
+ class DisjunctionQuery < SearchQuery
776
+ # @return [Float]
777
+ attr_accessor :boost
778
+
779
+ # @return [Integer]
780
+ attr_accessor :min
781
+
782
+ # @yieldparam [DisjunctionQuery] self
783
+ #
784
+ # @param [*SearchQuery] queries
785
+ def initialize(*queries)
786
+ super()
787
+ @queries = queries.flatten
788
+ yield self if block_given?
789
+ end
790
+
791
+ # @param [*SearchQuery] queries
792
+ def or_else(*queries)
793
+ @queries |= queries.flatten
794
+ end
795
+
796
+ def empty?
797
+ @queries.empty?
798
+ end
799
+
800
+ # @return [Hash<Symbol, #to_json>]
801
+ def to_h
802
+ raise ArgumentError, "compound disjunction query must have sub-queries" if @queries.nil? || @queries.empty?
803
+
804
+ data = {:disjuncts => @queries.uniq.map(&:to_h)}
805
+ if min
806
+ raise ArgumentError, "disjunction query has fewer sub-queries than configured minimum" if @queries.size < min
807
+
808
+ data[:min] = min
809
+ end
810
+ data[:boost] = boost if boost
811
+ data
812
+ end
813
+ end
814
+
815
+ # Prepare {BooleanQuery} body
816
+ #
817
+ # @yieldparam [BooleanQuery] query
818
+ #
819
+ # @return [BooleanQuery]
820
+ def self.booleans(&block)
821
+ BooleanQuery.new(&block)
822
+ end
823
+
824
+ # The boolean query is a useful combination of conjunction and disjunction queries.
825
+ class BooleanQuery < SearchQuery
826
+ # @return [Float]
827
+ attr_accessor :boost
828
+
829
+ # @yieldparam [BooleanQuery] self
830
+ def initialize
831
+ super()
832
+ @must = ConjunctionQuery.new
833
+ @must_not = DisjunctionQuery.new
834
+ @should = DisjunctionQuery.new
835
+ yield self if block_given?
836
+ end
837
+
838
+ # @param [Integer] min minimal value for "should" disjunction query
839
+ def should_min(min)
840
+ @should.min = min
841
+ self
842
+ end
843
+
844
+ # @param [*SearchQuery] queries
845
+ def must(*queries)
846
+ @must.and_also(*queries)
847
+ self
848
+ end
849
+
850
+ # @param [*SearchQuery] queries
851
+ def must_not(*queries)
852
+ @must_not.or_else(*queries)
853
+ self
854
+ end
855
+
856
+ # @param [*SearchQuery] queries
857
+ def should(*queries)
858
+ @should.or_else(*queries)
859
+ self
860
+ end
861
+
862
+ # @return [Hash<Symbol, #to_json>]
863
+ def to_h
864
+ raise ArgumentError, "BooleanQuery must have at least one non-empty sub-query" if @must.empty? && @must_not.empty? && @should.empty?
865
+
866
+ data = {}
867
+ data[:must] = @must.to_h unless @must.empty?
868
+ data[:must_not] = @must_not.to_h unless @must_not.empty?
869
+ data[:should] = @should.to_h unless @should.empty?
870
+ data[:boost] = boost if boost
871
+ data
872
+ end
873
+ end
874
+
875
+ # Prepare {TermQuery} body
876
+ #
877
+ # @yieldparam [TermQuery] query
878
+ # @param [String] term
879
+ #
880
+ # @return [TermQuery]
881
+ def self.term(term, &block)
882
+ TermQuery.new(term, &block)
883
+ end
884
+
885
+ # A query that looks for **exact** matches of the term in the index (no analyzer, no stemming). Useful to check what the actual
886
+ # content of the index is. It can also apply fuzziness on the term. Usual better alternative is `MatchQuery`.
887
+ class TermQuery < SearchQuery
888
+ # @return [Float]
889
+ attr_accessor :boost
890
+
891
+ # @return [String]
892
+ attr_accessor :field
893
+
894
+ # @return [Integer]
895
+ attr_accessor :fuzziness
896
+
897
+ # @return [Integer]
898
+ attr_accessor :prefix_length
899
+
900
+ # @yieldparam [TermQuery] self
901
+ #
902
+ # @param [String] term
903
+ def initialize(term)
904
+ super()
905
+ @term = term
906
+ yield self if block_given?
907
+ end
908
+
909
+ # @return [Hash<Symbol, #to_json>]
910
+ def to_h
911
+ data = {:term => @term}
912
+ data[:boost] = boost if boost
913
+ data[:field] = field if field
914
+ if fuzziness
915
+ data[:fuzziness] = fuzziness
916
+ data[:prefix_length] = prefix_length if prefix_length
917
+ end
918
+ data
919
+ end
920
+ end
921
+
922
+ # Prepare {PrefixQuery} body
923
+ #
924
+ # @yieldparam [PrefixQuery] query
925
+ # @param [String] prefix
926
+ #
927
+ # @return [PrefixQuery]
928
+ def self.prefix(prefix, &block)
929
+ PrefixQuery.new(prefix, &block)
930
+ end
931
+
932
+ # The prefix query finds documents containing terms that start with the provided prefix. Usual better alternative is `MatchQuery`.
933
+ class PrefixQuery < SearchQuery
934
+ # @return [Float]
935
+ attr_accessor :boost
936
+
937
+ # @return [nil, :or, :and]
938
+ attr_accessor :operator
939
+
940
+ # @return [String]
941
+ attr_accessor :field
942
+
943
+ # @yieldparam [PrefixQuery] self
944
+ #
945
+ # @param [String] prefix
946
+ def initialize(prefix)
947
+ super()
948
+ @prefix = prefix
949
+ yield self if block_given?
950
+ end
951
+
952
+ # @return [Hash<Symbol, #to_json>]
953
+ def to_h
954
+ data = {:prefix => @prefix}
955
+ data[:boost] = boost if boost
956
+ data[:field] = field if field
957
+ data
958
+ end
959
+ end
960
+
961
+ # Prepare {PhraseQuery} body
962
+ #
963
+ # Creates a new instances {PhraseQuery} passing all parameters into {PhraseQuery#initialize}.
964
+ #
965
+ # @return [PhraseQuery]
966
+ def self.phrase(...)
967
+ PhraseQuery.new(...)
968
+ end
969
+
970
+ # A query that looks for **exact** match of several terms (in the exact order) in the index. Usual better alternative is
971
+ # {MatchPhraseQuery}.
972
+ class PhraseQuery < SearchQuery
973
+ # @return [Float]
974
+ attr_accessor :boost
975
+
976
+ # @return [String]
977
+ attr_accessor :field
978
+
979
+ # @yieldparam [PhraseQuery] self
980
+ #
981
+ # @param [*String] terms
982
+ def initialize(*terms)
983
+ super()
984
+ @terms = terms.flatten
985
+ yield self if block_given?
986
+ end
987
+
988
+ # @return [Hash<Symbol, #to_json>]
989
+ def to_h
990
+ data = {:terms => @terms.flatten.uniq}
991
+ data[:boost] = boost if boost
992
+ data[:field] = field if field
993
+ data
994
+ end
995
+ end
996
+
997
+ # Prepare {MatchAllQuery} body
998
+ #
999
+ # @yieldparam [MatchAllQuery] query
1000
+ #
1001
+ # @return [MatchAllQuery]
1002
+ def self.match_all(&block)
1003
+ MatchAllQuery.new(&block)
1004
+ end
1005
+
1006
+ # A query that matches all indexed documents.
1007
+ class MatchAllQuery < SearchQuery
1008
+ # @yieldparam [MatchAllQuery] self
1009
+ def initialize
1010
+ super()
1011
+ yield self if block_given?
1012
+ end
1013
+
1014
+ # @return [Hash<Symbol, #to_json>]
1015
+ def to_h
1016
+ {:match_all => nil}
1017
+ end
1018
+ end
1019
+
1020
+ # Prepare {MatchNoneQuery} body
1021
+ #
1022
+ # @yieldparam [MatchNoneQuery] query
1023
+ #
1024
+ # @return [MatchNoneQuery]
1025
+ def self.match_none(&block)
1026
+ MatchNoneQuery.new(&block)
1027
+ end
1028
+
1029
+ # A query that matches nothing.
1030
+ class MatchNoneQuery < SearchQuery
1031
+ # @yieldparam [MatchNoneQuery] self
1032
+ def initialize
1033
+ super()
1034
+ yield self if block_given?
1035
+ end
1036
+
1037
+ # @return [Hash<Symbol, #to_json>]
1038
+ def to_h
1039
+ {:match_none => nil}
1040
+ end
1041
+ end
1042
+ end
1043
+
1044
+ # @!macro uncommitted
1045
+ class VectorSearch
1046
+ # Constructs a +VectorSearch+ instance, which allows one or more individual vector queries to be executed.
1047
+ #
1048
+ # @param [VectorQuery, Array<VectorQuery>] vector_queries vector queries/query to execute
1049
+ # @param [Options::VectorSearch] options
1050
+ def initialize(vector_queries, options = Options::VectorSearch::DEFAULT)
1051
+ @vector_queries = vector_queries.respond_to?(:each) ? vector_queries : [vector_queries]
1052
+ @options = options
1053
+ end
1054
+
1055
+ # @api private
1056
+ def to_backend
1057
+ {vector_queries: @vector_queries.map(&:to_h).to_json}.merge(@options.to_backend)
1058
+ end
1059
+ end
1060
+
1061
+ # @!macro uncommitted
1062
+ class VectorQuery
1063
+ # @return [Integer, nil]
1064
+ attr_accessor :num_candidates
1065
+
1066
+ # @return [Float, nil]
1067
+ attr_accessor :boost
1068
+
1069
+ # Constructs a +VectorQuery+ instance
1070
+ #
1071
+ # @param [String] vector_field_name the document field that contains the vector.
1072
+ # @param [Array<Float>] vector_query the vector query to run.
1073
+ #
1074
+ # @yieldparam [MatchPhraseQuery] self
1075
+ def initialize(vector_field_name, vector_query)
1076
+ @vector_field_name = vector_field_name
1077
+ @vector_query = vector_query
1078
+
1079
+ yield self if block_given?
1080
+ end
1081
+
1082
+ # @api private
1083
+ def to_h
1084
+ if !num_candidates.nil? && num_candidates < 1
1085
+ raise Error::InvalidArgument,
1086
+ "Number of candidates must be at least 1, #{num_candidates} given"
1087
+ end
1088
+
1089
+ {
1090
+ field: @vector_field_name,
1091
+ vector: @vector_query,
1092
+ k: num_candidates || 3,
1093
+ boost: boost,
1094
+ }.compact
1095
+ end
1096
+
1097
+ # @api private
1098
+ def to_json(*args)
1099
+ to_h.to_json(*args)
1100
+ end
1101
+ end
1102
+
1103
+ class SearchSort
1104
+ # @yieldparam [SearchSortScore]
1105
+ # @return [SearchSortScore]
1106
+ def self.score(&block)
1107
+ SearchSortScore.new(&block)
1108
+ end
1109
+
1110
+ # @yieldparam [SearchSortId]
1111
+ # @return [SearchSortScore]
1112
+ def self.id(&block)
1113
+ SearchSortId.new(&block)
1114
+ end
1115
+
1116
+ # @param [String] name field name
1117
+ # @yieldparam [SearchSortField]
1118
+ # @return [SearchSortField]
1119
+ def self.field(name, &block)
1120
+ SearchSortField.new(name, &block)
1121
+ end
1122
+
1123
+ # @param [String] name field name
1124
+ # @param [Float] longitude
1125
+ # @param [Float] latitude
1126
+ # @yieldparam [SearchSortField]
1127
+ # @return [SearchSortGeoDistance]
1128
+ def self.geo_distance(name, longitude, latitude, &block)
1129
+ SearchSortGeoDistance.new(name, longitude, latitude, &block)
1130
+ end
1131
+
1132
+ class SearchSortScore < SearchSort
1133
+ # @return [Boolean] if descending order should be applied
1134
+ attr_accessor :desc
1135
+
1136
+ # @yieldparam [SearchSortScore]
1137
+ def initialize
1138
+ super
1139
+ yield self if block_given?
1140
+ end
1141
+
1142
+ # @api private
1143
+ def to_json(*args)
1144
+ {by: :score, desc: desc}.to_json(*args)
1145
+ end
1146
+ end
1147
+
1148
+ class SearchSortId < SearchSort
1149
+ # @return [Boolean] if descending order should be applied
1150
+ attr_accessor :desc
1151
+
1152
+ # @yieldparam [SearchSortId]
1153
+ def initialize
1154
+ super
1155
+ yield self if block_given?
1156
+ end
1157
+
1158
+ # @api private
1159
+ def to_json(*args)
1160
+ {by: :id, desc: desc}.to_json(*args)
1161
+ end
1162
+ end
1163
+
1164
+ class SearchSortField < SearchSort
1165
+ # @return [String] name of the field to sort by
1166
+ attr_reader :field
1167
+
1168
+ # @return [Boolean] if descending order should be applied
1169
+ attr_accessor :desc
1170
+
1171
+ # @return [:auto, :string, :number, :date]
1172
+ attr_accessor :type
1173
+
1174
+ # @return [:first, :last] where the documents with missing field should be placed
1175
+ attr_accessor :missing
1176
+
1177
+ # @return [:default, :min, :max]
1178
+ attr_accessor :mode
1179
+
1180
+ # @param [String] field the name of the filed for ordering
1181
+ # @yieldparam [SearchSortField]
1182
+ def initialize(field)
1183
+ super()
1184
+ @field = field
1185
+ yield self if block_given?
1186
+ end
1187
+
1188
+ # @api private
1189
+ def to_json(*args)
1190
+ {by: :field, field: field, desc: desc, type: type, missing: missing, mode: mode}.to_json(*args)
1191
+ end
1192
+ end
1193
+
1194
+ class SearchSortGeoDistance < SearchSort
1195
+ # @return [String] name of the field to sort by
1196
+ attr_reader :field
1197
+
1198
+ # @return [Boolean] if descending order should be applied
1199
+ attr_accessor :desc
1200
+
1201
+ # @return [Float]
1202
+ attr_reader :longitude
1203
+
1204
+ # @return [Float]
1205
+ attr_reader :latitude
1206
+
1207
+ # @return [:meters, :miles, :centimeters, :millimeters, :kilometers, :nauticalmiles, :feet, :yards, :inch]
1208
+ attr_accessor :unit
1209
+
1210
+ # @param [String] field field name
1211
+ # @param [Float] longitude
1212
+ # @param [Float] latitude
1213
+ # @yieldparam [SearchSortGeoDistance]
1214
+ def initialize(field, longitude, latitude)
1215
+ super()
1216
+ @field = field
1217
+ @longitude = longitude
1218
+ @latitude = latitude
1219
+ yield self if block_given?
1220
+ end
1221
+
1222
+ # @api private
1223
+ def to_json(*args)
1224
+ {by: :geo_distance, field: field, desc: desc, location: [longitude, latitude], unit: unit}.to_json(*args)
1225
+ end
1226
+ end
1227
+ end
1228
+
1229
+ class SearchFacet
1230
+ # @param [String] field_name
1231
+ # @return [SearchFacetTerm]
1232
+ def self.term(field_name, &block)
1233
+ SearchFacetTerm.new(field_name, &block)
1234
+ end
1235
+
1236
+ # @param [String] field_name
1237
+ # @return [SearchFacetNumericRange]
1238
+ def self.numeric_range(field_name, &block)
1239
+ SearchFacetNumericRange.new(field_name, &block)
1240
+ end
1241
+
1242
+ # @param [String] field_name
1243
+ # @return [SearchFacetDateRange]
1244
+ def self.date_range(field_name, &block)
1245
+ SearchFacetDateRange.new(field_name, &block)
1246
+ end
1247
+
1248
+ class SearchFacetTerm
1249
+ # @return [String]
1250
+ attr_reader :field
1251
+
1252
+ # @return [Integer]
1253
+ attr_accessor :size
1254
+
1255
+ # @param [String] field name of the field
1256
+ def initialize(field)
1257
+ @field = field
1258
+ yield self if block_given?
1259
+ end
1260
+
1261
+ # @api private
1262
+ def to_json(*args)
1263
+ {field: field, size: size}.to_json(*args)
1264
+ end
1265
+ end
1266
+
1267
+ class SearchFacetNumericRange
1268
+ # @return [String]
1269
+ attr_reader :field
1270
+
1271
+ # @return [Integer]
1272
+ attr_accessor :size
1273
+
1274
+ # @param [String] field name of the field
1275
+ def initialize(field)
1276
+ @field = field
1277
+ @ranges = []
1278
+ yield self if block_given?
1279
+ end
1280
+
1281
+ # @param [String] name the name of the range
1282
+ # @param [Integer, Float, nil] min lower bound of the range (pass +nil+ if there is no lower bound)
1283
+ # @param [Integer, Float, nil] max upper bound of the range (pass +nil+ if there is no upper bound)
1284
+ def add(name, min, max)
1285
+ @ranges.append({name: name, min: min, max: max})
1286
+ end
1287
+
1288
+ # @api private
1289
+ def to_json(*args)
1290
+ {field: field, size: size, numeric_ranges: @ranges}.to_json(*args)
1291
+ end
1292
+ end
1293
+
1294
+ class SearchFacetDateRange
1295
+ # @return [String]
1296
+ attr_reader :field
1297
+
1298
+ # @return [Integer]
1299
+ attr_accessor :size
1300
+
1301
+ # @param [String] field name of the field
1302
+ def initialize(field)
1303
+ super()
1304
+ @field = field
1305
+ @ranges = []
1306
+ yield self if block_given?
1307
+ end
1308
+
1309
+ DATE_FORMAT_RFC3339 = "%Y-%m-%dT%H:%M:%S%:z".freeze
1310
+
1311
+ # @param [String] name the name of the range
1312
+ # @param [Time, String, nil] start_time lower bound of the range (pass +nil+ if there is no lower bound)
1313
+ # @param [Time, String, nil] end_time lower bound of the range (pass +nil+ if there is no lower bound)
1314
+ def add(name, start_time, end_time)
1315
+ start_time = start_time.strftime(DATE_FORMAT_RFC3339) if start_time.respond_to?(:strftime)
1316
+ end_time = end_time.strftime(DATE_FORMAT_RFC3339) if end_time.respond_to?(:strftime)
1317
+ @ranges.append({name: name, start: start_time, end: end_time})
1318
+ end
1319
+
1320
+ # @api private
1321
+ def to_json(*args)
1322
+ {field: field, size: size, date_ranges: @ranges}.to_json(*args)
1323
+ end
1324
+ end
1325
+ end
1326
+
1327
+ class SearchRowLocation
1328
+ # @return [String]
1329
+ attr_accessor :field
1330
+
1331
+ # @return [String]
1332
+ attr_accessor :term
1333
+
1334
+ # @return [Integer] the position of the term within the field, starting at 1
1335
+ attr_accessor :position
1336
+
1337
+ # @return [Integer] start byte offset of the term in the field
1338
+ attr_accessor :start_offset
1339
+
1340
+ # @return [Integer] end byte offset of the term in the field
1341
+ attr_accessor :end_offset
1342
+
1343
+ # @return [Array<Integer>] the positions of the term within any elements.
1344
+ attr_accessor :array_positions
1345
+
1346
+ # @yieldparam [SearchRowLocation] self
1347
+ def initialize
1348
+ yield self if block_given?
1349
+ end
1350
+ end
1351
+
1352
+ class SearchRowLocations
1353
+ # Lists all locations (any field, any term)
1354
+ #
1355
+ # @return [Array<SearchRowLocation>]
1356
+ def get_all
1357
+ @locations
1358
+ end
1359
+
1360
+ # Lists all locations for a given field (any term)
1361
+ #
1362
+ # @return [Array<SearchRowLocation>]
1363
+ def get_for_field(name)
1364
+ @locations.select { |location| location.field == name }
1365
+ end
1366
+
1367
+ # Lists all locations for a given field and term
1368
+ #
1369
+ # @return [Array<SearchRowLocation>]
1370
+ def get_for_field_and_term(name, term)
1371
+ @locations.select { |location| location.field == name && location.term == term }
1372
+ end
1373
+
1374
+ # Lists the fields in this location
1375
+ #
1376
+ # @return [Array<String>]
1377
+ def fields
1378
+ @locations.map(&:field).uniq
1379
+ end
1380
+
1381
+ # Lists all terms in this locations, considering all fields
1382
+ #
1383
+ # @return [Array<String>]
1384
+ def terms
1385
+ @locations.map(&:term).uniq
1386
+ end
1387
+
1388
+ # Lists the terms for a given field
1389
+ #
1390
+ # @return [Array<String>]
1391
+ def terms_for_field(name)
1392
+ get_for_field(name).map(&:term).uniq
1393
+ end
1394
+
1395
+ # @param [Array<SearchRowLocation>] locations
1396
+ def initialize(locations)
1397
+ super()
1398
+ @locations = locations
1399
+ end
1400
+ end
1401
+
1402
+ # An individual facet result has both metadata and details, as each facet can define ranges into which results are categorized
1403
+ class SearchFacetResult
1404
+ # @return [String]
1405
+ attr_accessor :name
1406
+
1407
+ # @return [String]
1408
+ attr_accessor :field
1409
+
1410
+ # @return [Integer]
1411
+ attr_accessor :total
1412
+
1413
+ # @return [Integer]
1414
+ attr_accessor :missing
1415
+
1416
+ # @return [Integer]
1417
+ attr_accessor :other
1418
+
1419
+ class TermFacetResult < SearchFacetResult
1420
+ # @return [Array<TermFacet>]
1421
+ attr_accessor :terms
1422
+
1423
+ def type
1424
+ :term_facet
1425
+ end
1426
+
1427
+ # @yieldparam [TermFacetResult] self
1428
+ def initialize
1429
+ super
1430
+ yield self if block_given?
1431
+ end
1432
+
1433
+ class TermFacet
1434
+ # @return [String]
1435
+ attr_reader :term
1436
+
1437
+ # @return [Integer]
1438
+ attr_reader :count
1439
+
1440
+ def initialize(term, count)
1441
+ super()
1442
+ @term = term
1443
+ @count = count
1444
+ end
1445
+ end
1446
+ end
1447
+
1448
+ class DateRangeFacetResult < SearchFacetResult
1449
+ # @return [Array<DateRangeFacet>]
1450
+ attr_accessor :date_ranges
1451
+
1452
+ def type
1453
+ :date_range_facet
1454
+ end
1455
+
1456
+ # @yieldparam [DateRangeFacetResult] self
1457
+ def initialize
1458
+ super
1459
+ yield self if block_given?
1460
+ end
1461
+
1462
+ class DateRangeFacet
1463
+ # @return [String]
1464
+ attr_reader :name
1465
+
1466
+ # @return [Integer]
1467
+ attr_reader :count
1468
+
1469
+ # @return [String]
1470
+ attr_reader :start_time
1471
+
1472
+ # @return [String]
1473
+ attr_reader :end_time
1474
+
1475
+ def initialize(name, count, start_time, end_time)
1476
+ @name = name
1477
+ @count = count
1478
+ @start_time = start_time
1479
+ @end_time = end_time
1480
+ end
1481
+ end
1482
+ end
1483
+
1484
+ class NumericRangeFacetResult < SearchFacetResult
1485
+ # @return [Array<NumericRangeFacet>]
1486
+ attr_accessor :numeric_ranges
1487
+
1488
+ def type
1489
+ :numeric_range_facet
1490
+ end
1491
+
1492
+ # @yieldparam [NumericRangeFacetResult] self
1493
+ def initialize
1494
+ super
1495
+ yield self if block_given?
1496
+ end
1497
+
1498
+ class NumericRangeFacet
1499
+ # @return [String]
1500
+ attr_reader :name
1501
+
1502
+ # @return [Integer]
1503
+ attr_reader :count
1504
+
1505
+ # @return [Integer, Float, nil]
1506
+ attr_reader :min
1507
+
1508
+ # @return [Integer, Float, nil]
1509
+ attr_reader :max
1510
+
1511
+ def initialize(name, count, min, max)
1512
+ @name = name
1513
+ @count = count
1514
+ @min = min
1515
+ @max = max
1516
+ end
1517
+ end
1518
+ end
1519
+ end
1520
+
1521
+ class SearchRow
1522
+ # @return [String] name of the index
1523
+ attr_accessor :index
1524
+
1525
+ # @return [String] document identifier
1526
+ attr_accessor :id
1527
+
1528
+ # @return [Float]
1529
+ attr_accessor :score
1530
+
1531
+ # @return [SearchRowLocations]
1532
+ attr_accessor :locations
1533
+
1534
+ # @return [Hash]
1535
+ attr_accessor :explanation
1536
+
1537
+ # @return [Hash<String => Array<String>>]
1538
+ attr_accessor :fragments
1539
+
1540
+ # @return [JsonTranscoder] transcoder to use for the fields
1541
+ attr_accessor :transcoder
1542
+
1543
+ def fields
1544
+ @transcoder.decode(@fields, :json) if @fields && @transcoder
1545
+ end
1546
+
1547
+ # @yieldparam [SearchRow] self
1548
+ def initialize
1549
+ @fields = nil
1550
+ yield self if block_given?
1551
+ end
1552
+ end
1553
+
1554
+ class SearchMetrics
1555
+ # @return [Integer] time spent executing the query (in milliseconds)
1556
+ attr_accessor :took
1557
+
1558
+ # @return [Integer]
1559
+ attr_accessor :total_rows
1560
+
1561
+ # @return [Float]
1562
+ attr_accessor :max_score
1563
+
1564
+ # @return [Integer]
1565
+ attr_accessor :success_partition_count
1566
+
1567
+ # @return [Integer]
1568
+ attr_accessor :error_partition_count
1569
+
1570
+ # @return [Integer]
1571
+ def total_partition_count
1572
+ success_partition_count + error_partition_count
1573
+ end
1574
+ end
1575
+
1576
+ class SearchMetaData
1577
+ # @return [SearchMetrics]
1578
+ attr_accessor :metrics
1579
+
1580
+ # @return [Hash<String => String>]
1581
+ attr_accessor :errors
1582
+
1583
+ # @yieldparam [SearchMetaData] self
1584
+ def initialize
1585
+ @metrics = SearchMetrics.new
1586
+ yield self if block_given?
1587
+ end
1588
+ end
1589
+
1590
+ class SearchResult
1591
+ # @return [Array<SearchRow>]
1592
+ attr_accessor :rows
1593
+
1594
+ # @return [Hash<String => SearchFacetResult>]
1595
+ attr_accessor :facets
1596
+
1597
+ # @return [SearchMetaData]
1598
+ attr_accessor :meta_data
1599
+
1600
+ def success?
1601
+ meta_data.errors.nil? || meta_data.errors.empty?
1602
+ end
1603
+
1604
+ # @yieldparam [SearchResult] self
1605
+ def initialize
1606
+ yield self if block_given?
1607
+ end
1608
+ end
1609
+
1610
+ class Cluster
1611
+ SearchQuery = Couchbase::SearchQuery
1612
+ SearchSort = Couchbase::SearchSort
1613
+ SearchFacet = Couchbase::SearchFacet
1614
+ SearchRowLocation = Couchbase::SearchRowLocation
1615
+ SearchRowLocations = Couchbase::SearchRowLocations
1616
+ SearchFacetResult = Couchbase::SearchFacetResult
1617
+ SearchRow = Couchbase::SearchRow
1618
+ SearchResult = Couchbase::SearchResult
1619
+ SearchMetaData = Couchbase::SearchMetaData
1620
+ SearchMetrics = Couchbase::SearchMetrics
1621
+ end
1622
+ end