couchbase 3.0.0.alpha.2 → 3.0.0.alpha.3

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