searchkick 6.0.3 → 6.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf43f99e5f6ced971320bdf629e3454e7c8f2fb111c64a0967182ef51aa942d0
4
- data.tar.gz: a891ac1f9b25f25efc47836887a68a261659fe87e2754cf203f3210b855b2e31
3
+ metadata.gz: 33be926c61ab632ecf611bce7ceecc0f23cec9eedde74758b66c297936e48293
4
+ data.tar.gz: c9dd60ae1fe20336066554d08c042a2fde153d7d1bb2e49bacc32219a3943915
5
5
  SHA512:
6
- metadata.gz: 2a5a20df662acbcea24702c9a5c22327e54ba9bd223896fcfcc9886fd3087edbbf59b8d806a4248e4f65b7e0df530f90788bf9d54bbce796ec5f267f83fd2caf
7
- data.tar.gz: 54567b34c84d4444d12d71546d13c2c8569b1dfe710dbe0de0662cde80f16973afe37125c931733787df729bdb853f9c34a66ceb1a094962b84f4c16c79f42af
6
+ metadata.gz: 95ebb7c3cc4d511a7f75a1cef3f73f64e1bbf8242c18091cbacfe71bcd244840538c11f2c83db0a676f90c442668f4a1cb1c320d6e970a23bec00ee7ccec2935
7
+ data.tar.gz: eb7638d2cda8512314894dbcd205ccff57293b332f3e52e3fdbd4a8bb6359ea8cb309b2bd53b3b7c67515538e07422e16eca919092757106307abd22781df603
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 6.1.0 (2026-02-18)
2
+
3
+ - Added `per` method
4
+ - Fixed error with `aggs` method and non-hash arguments
5
+ - Fixed smart aggs behavior when multiple `where` calls
6
+
1
7
  ## 6.0.3 (2026-01-06)
2
8
 
3
9
  - Fixed `inspect` method for `Relation`
@@ -872,10 +872,21 @@ module Searchkick
872
872
  }
873
873
  end
874
874
 
875
- where = {}
876
- where = ensure_permitted(options[:where] || {}).reject { |k| k == field } unless options[:smart_aggs] == false
877
875
  agg_where = ensure_permitted(agg_options[:where] || {})
878
- agg_filters = where_filters(where.merge(agg_where))
876
+ if options[:smart_aggs] != false && options[:where]
877
+ where = ensure_permitted(options[:where])
878
+ where_without_field = where.reject { |k| k == field }
879
+ # where_without_field = where_without_field(where, field.to_s)
880
+ if where_without_field.any?
881
+ if agg_where.any?
882
+ agg_where = where.merge(agg_where)
883
+ # agg_where = combine_agg_where(agg_where, where_without_field)
884
+ else
885
+ agg_where = where_without_field
886
+ end
887
+ end
888
+ end
889
+ agg_filters = where_filters(agg_where)
879
890
 
880
891
  # only do one level comparison for simplicity
881
892
  filters.select! do |filter|
@@ -902,6 +913,53 @@ module Searchkick
902
913
  end
903
914
  end
904
915
 
916
+ def where_without_field(where, field)
917
+ result = {}
918
+ where.each do |f, v|
919
+ case f
920
+ when :_and
921
+ r = v.map { |v2| where_without_field(v2, field) }.reject(&:empty?)
922
+ result[f] = r unless r.empty?
923
+ when :_or
924
+ r = v.map { |v2| where_without_field(v2, field) }
925
+ result[f] = r unless r.any?(&:empty?)
926
+ when :or
927
+ r = v.map { |v2| v2.map { |v3| where_without_field(v3, field) }.reject { |v2| v2.any?(&:empty?) } }
928
+ result[f] = r unless r.empty?
929
+ when :_not
930
+ r = where_without_field(v, field)
931
+ result[f] = r unless r.empty?
932
+ when :_script
933
+ result[f] = v
934
+ else
935
+ if f.to_s != field
936
+ result[f] = v
937
+ end
938
+ end
939
+ end
940
+ result
941
+ end
942
+
943
+ def combine_agg_where(agg_where, where)
944
+ result = agg_where.dup
945
+ field_keys = result.except(:_and, :_or, :or, :_not, :_script).transform_keys(&:to_s)
946
+ where.each do |f, v|
947
+ case f
948
+ when :_and, :_or, :or, :_not, :_script
949
+ if result.key?(f)
950
+ # combine with _and if needed
951
+ result[:_and] ||= []
952
+ result[:_and] += [{f => v}]
953
+ else
954
+ result[f] = v
955
+ end
956
+ else
957
+ result[f] = v unless field_keys.include?(f.to_s)
958
+ end
959
+ end
960
+ result
961
+ end
962
+
905
963
  def set_knn(payload, knn, per_page, offset)
906
964
  if term != "*"
907
965
  raise ArgumentError, "Use Searchkick.multi_search for hybrid search"
@@ -1049,6 +1107,7 @@ module Searchkick
1049
1107
  (where || {}).each do |field, value|
1050
1108
  field = :_id if field.to_s == "id"
1051
1109
 
1110
+ # update smart aggs when adding new symbol
1052
1111
  if field == :or
1053
1112
  value.each do |or_clause|
1054
1113
  filters << {bool: {should: or_clause.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
@@ -17,7 +17,7 @@ module Searchkick
17
17
  @options = options
18
18
 
19
19
  # generate query to validate options
20
- query
20
+ query if options.any?
21
21
  end
22
22
 
23
23
  # same as Active Record
@@ -27,17 +27,26 @@ module Searchkick
27
27
  "#<#{self.class.name} [#{entries.join(', ')}]>"
28
28
  end
29
29
 
30
- def aggs(value = NO_DEFAULT_VALUE)
31
- if value == NO_DEFAULT_VALUE
30
+ def aggs(*args, **kwargs)
31
+ if args.empty? && kwargs.empty?
32
32
  private_execute.aggs
33
33
  else
34
- clone.aggs!(value)
34
+ clone.aggs!(*args, **kwargs)
35
35
  end
36
36
  end
37
37
 
38
- def aggs!(value)
38
+ def aggs!(*args, **kwargs)
39
39
  check_loaded
40
- (@options[:aggs] ||= {}).merge!(value)
40
+ aggs = {}
41
+ args.flatten.each do |arg|
42
+ if arg.is_a?(Hash)
43
+ aggs.merge!(arg)
44
+ else
45
+ aggs[arg] = {}
46
+ end
47
+ end
48
+ aggs.merge!(kwargs)
49
+ merge_option(:aggs, aggs)
41
50
  self
42
51
  end
43
52
 
@@ -61,7 +70,7 @@ module Searchkick
61
70
 
62
71
  def body_options!(value)
63
72
  check_loaded
64
- (@options[:body_options] ||= {}).merge!(value)
73
+ merge_option(:body_options, value)
65
74
  self
66
75
  end
67
76
 
@@ -86,7 +95,7 @@ module Searchkick
86
95
  elsif !value.is_a?(Hash)
87
96
  value = {value => {factor: 1}}
88
97
  end
89
- (@options[:boost_by] ||= {}).merge!(value)
98
+ merge_option(:boost_by, value)
90
99
  self
91
100
  end
92
101
 
@@ -98,7 +107,7 @@ module Searchkick
98
107
  check_loaded
99
108
  # legacy format
100
109
  value = {value[:field] => value.except(:field)} if value[:field]
101
- (@options[:boost_by_distance] ||= {}).merge!(value)
110
+ merge_option(:boost_by_distance, value)
102
111
  self
103
112
  end
104
113
 
@@ -108,7 +117,7 @@ module Searchkick
108
117
 
109
118
  def boost_by_recency!(value)
110
119
  check_loaded
111
- (@options[:boost_by_recency] ||= {}).merge!(value)
120
+ merge_option(:boost_by_recency, value)
112
121
  self
113
122
  end
114
123
 
@@ -119,7 +128,7 @@ module Searchkick
119
128
  def boost_where!(value)
120
129
  check_loaded
121
130
  # TODO merge duplicate fields
122
- (@options[:boost_where] ||= {}).merge!(value)
131
+ merge_option(:boost_where, value)
123
132
  self
124
133
  end
125
134
 
@@ -189,7 +198,7 @@ module Searchkick
189
198
 
190
199
  def exclude!(*values)
191
200
  check_loaded
192
- (@options[:exclude] ||= []).concat(values.flatten)
201
+ concat_option(:exclude, values.flatten)
193
202
  self
194
203
  end
195
204
 
@@ -209,7 +218,7 @@ module Searchkick
209
218
 
210
219
  def fields!(*values)
211
220
  check_loaded
212
- (@options[:fields] ||= []).concat(values.flatten)
221
+ concat_option(:fields, values.flatten)
213
222
  self
214
223
  end
215
224
 
@@ -229,7 +238,7 @@ module Searchkick
229
238
 
230
239
  def includes!(*values)
231
240
  check_loaded
232
- (@options[:includes] ||= []).concat(values.flatten)
241
+ concat_option(:includes, values.flatten)
233
242
  self
234
243
  end
235
244
 
@@ -243,7 +252,7 @@ module Searchkick
243
252
  if values.all? { |v| v.respond_to?(:searchkick_index) }
244
253
  models!(*values)
245
254
  else
246
- (@options[:index_name] ||= []).concat(values)
255
+ concat_option(:index_name, values)
247
256
  self
248
257
  end
249
258
  end
@@ -254,7 +263,7 @@ module Searchkick
254
263
 
255
264
  def indices_boost!(value)
256
265
  check_loaded
257
- (@options[:indices_boost] ||= {}).merge!(value)
266
+ merge_option(:indices_boost, value)
258
267
  self
259
268
  end
260
269
 
@@ -319,7 +328,7 @@ module Searchkick
319
328
 
320
329
  def models!(*values)
321
330
  check_loaded
322
- (@options[:models] ||= []).concat(values.flatten)
331
+ concat_option(:models, values.flatten)
323
332
  self
324
333
  end
325
334
 
@@ -329,7 +338,7 @@ module Searchkick
329
338
 
330
339
  def model_includes!(*values)
331
340
  check_loaded
332
- (@options[:model_includes] ||= []).concat(values.flatten)
341
+ concat_option(:model_includes, values.flatten)
333
342
  self
334
343
  end
335
344
 
@@ -373,7 +382,7 @@ module Searchkick
373
382
 
374
383
  def order!(*values)
375
384
  check_loaded
376
- (@options[:order] ||= []).concat(values.flatten)
385
+ concat_option(:order, values.flatten)
377
386
  self
378
387
  end
379
388
 
@@ -409,6 +418,10 @@ module Searchkick
409
418
  end
410
419
  end
411
420
 
421
+ def per(value)
422
+ per_page(value)
423
+ end
424
+
412
425
  def per_page!(value)
413
426
  check_loaded
414
427
  # TODO set limit?
@@ -432,7 +445,7 @@ module Searchkick
432
445
 
433
446
  def request_params!(value)
434
447
  check_loaded
435
- (@options[:request_params] ||= {}).merge!(value)
448
+ merge_option(:request_params, value)
436
449
  self
437
450
  end
438
451
 
@@ -482,7 +495,7 @@ module Searchkick
482
495
 
483
496
  def select!(*values)
484
497
  check_loaded
485
- (@options[:select] ||= []).concat(values.flatten)
498
+ concat_option(:select, values.flatten)
486
499
  self
487
500
  end
488
501
 
@@ -546,7 +559,7 @@ module Searchkick
546
559
 
547
560
  def type!(*values)
548
561
  check_loaded
549
- (@options[:type] ||= []).concat(values.flatten)
562
+ concat_option(:type, values.flatten)
550
563
  self
551
564
  end
552
565
 
@@ -560,10 +573,18 @@ module Searchkick
560
573
 
561
574
  def where!(value)
562
575
  check_loaded
576
+ value = ensure_permitted(value)
563
577
  if @options[:where]
564
- @options[:where] = {_and: [@options[:where], ensure_permitted(value)]}
578
+ if @options[:where][:_and].is_a?(Array)
579
+ merge_option(:where, {_and: @options[:where][:_and] + [value]})
580
+ # keep simple when possible for smart aggs
581
+ elsif !@options[:where].keys.intersect?(value.keys)
582
+ merge_option(:where, value)
583
+ else
584
+ @options[:where] = {_and: [@options[:where], value]}
585
+ end
565
586
  else
566
- @options[:where] = ensure_permitted(value)
587
+ @options[:where] = value
567
588
  end
568
589
  self
569
590
  end
@@ -683,7 +704,25 @@ module Searchkick
683
704
 
684
705
  def initialize_copy(other)
685
706
  super
707
+ # shallow dup and avoid updating values in-place
708
+ @options = @options.dup
686
709
  @execute = nil
687
710
  end
711
+
712
+ def concat_option(key, value)
713
+ if @options[key]
714
+ @options[key] += value
715
+ else
716
+ @options[key] = value.to_ary
717
+ end
718
+ end
719
+
720
+ def merge_option(key, value)
721
+ if @options[key]
722
+ @options[key] = @options[key].merge(value)
723
+ else
724
+ @options[key] = value.to_hash
725
+ end
726
+ end
688
727
  end
689
728
  end
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "6.0.3"
2
+ VERSION = "6.1.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.3
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane