Commit a43437726e4b22e541e93498c0e3473663d4644c

Authored by Andrew Kane
1 parent 0c5c0dd1

Added advanced facet options

README.md
... ... @@ -73,6 +73,12 @@ explain: true
73 73 Product.search "2% Milk", facets: [:store_id, :aisle_id]
74 74 ```
75 75  
  76 +Advanced
  77 +
  78 +```ruby
  79 +Product.search "2% Milk", facets: {store_id: {where: {in_stock: true}}}
  80 +```
  81 +
76 82 ### Synonyms
77 83  
78 84 ```ruby
... ...
lib/searchkick/search.rb
... ... @@ -54,54 +54,82 @@ module Searchkick
54 54  
55 55 # where
56 56 # TODO expand or
57   - (options[:where] || {}).each do |field, value|
58   - if field == :or
59   - value.each do |or_clause|
60   - filter :or, or_clause.map{|or_statement| {term: or_statement} }
61   - end
62   - else
63   - # expand ranges
64   - if value.is_a?(Range)
65   - value = {gte: value.first, (value.exclude_end? ? :lt : :lte) => value.last}
66   - end
67 57  
68   - if value.is_a?(Array) # in query
69   - filter :terms, {field => value}
70   - elsif value.is_a?(Hash)
71   - value.each do |op, op_value|
72   - if op == :not
73   - if op_value.is_a?(Array)
74   - filter :not, {terms: {field => op_value}}
75   - else
76   - filter :not, {term: {field => op_value}}
77   - end
78   - else
79   - range_query =
80   - case op
81   - when :gt
82   - {from: op_value, include_lower: false}
83   - when :gte
84   - {from: op_value, include_lower: true}
85   - when :lt
86   - {to: op_value, include_upper: false}
87   - when :lte
88   - {to: op_value, include_upper: true}
  58 + where_filters =
  59 + proc do |where|
  60 + filters = []
  61 + (where || {}).each do |field, value|
  62 + if field == :or
  63 + value.each do |or_clause|
  64 + filters << {or: or_clause.map{|or_statement| {term: or_statement} }}
  65 + end
  66 + else
  67 + # expand ranges
  68 + if value.is_a?(Range)
  69 + value = {gte: value.first, (value.exclude_end? ? :lt : :lte) => value.last}
  70 + end
  71 +
  72 + if value.is_a?(Array) # in query
  73 + filters << {terms: {field => value}}
  74 + elsif value.is_a?(Hash)
  75 + value.each do |op, op_value|
  76 + if op == :not # not equal
  77 + if op_value.is_a?(Array)
  78 + filters << {not: {terms: {field => op_value}}}
  79 + else
  80 + filters << {not: {term: {field => op_value}}}
  81 + end
89 82 else
90   - raise "Unknown where operator"
  83 + range_query =
  84 + case op
  85 + when :gt
  86 + {from: op_value, include_lower: false}
  87 + when :gte
  88 + {from: op_value, include_lower: true}
  89 + when :lt
  90 + {to: op_value, include_upper: false}
  91 + when :lte
  92 + {to: op_value, include_upper: true}
  93 + else
  94 + raise "Unknown where operator"
  95 + end
  96 + filters << {range: {field => range_query}}
91 97 end
92   - filter :range, field => range_query
  98 + end
  99 + else
  100 + filters << {term: {field => value}}
93 101 end
94 102 end
95   - else
96   - filter :term, {field => value}
97 103 end
  104 + filters
98 105 end
  106 +
  107 + where_filters.call(options[:where]).each do |f|
  108 + type, value = f.first
  109 + filter type, value
99 110 end
100   - (options[:facets] || []).each do |field|
101   - facet field do
102   - terms field
  111 +
  112 + # facets
  113 + if options[:facets]
  114 + facets = options[:facets] || {}
  115 + if facets.is_a?(Array) # convert to more advanced syntax
  116 + facets = Hash[ facets.map{|f| [f, {}] } ]
  117 + end
  118 +
  119 + facets.each do |field, facet_options|
  120 + facet_filters = where_filters.call(facet_options[:where])
  121 + facet field do
  122 + terms field
  123 + if facet_filters.size == 1
  124 + type, value = facet_filters.first.first
  125 + facet_filter type, value
  126 + elsif facet_filters.size > 1
  127 + facet_filter :and, *facet_filters
  128 + end
  129 + end
103 130 end
104 131 end
  132 +
105 133 end
106 134 end
107 135 end
... ...
test/searchkick_test.rb
... ... @@ -248,10 +248,13 @@ class TestSearchkick &lt; Minitest::Unit::TestCase
248 248  
249 249 def test_facets
250 250 store [
251   - {name: "Product Show", store_id: 1},
252   - {name: "Product Hide", store_id: 2}
  251 + {name: "Product Show", store_id: 1, in_stock: true, color: "blue"},
  252 + {name: "Product Hide", store_id: 2, in_stock: false, color: "green"},
  253 + {name: "Product B", store_id: 2, in_stock: false, color: "red"}
253 254 ]
254 255 assert_equal 2, Product.search("Product", facets: [:store_id]).facets["store_id"]["terms"].size
  256 + assert_equal 1, Product.search("Product", facets: {store_id: {where: {in_stock: true}}}).facets["store_id"]["terms"].size
  257 + assert_equal 1, Product.search("Product", facets: {store_id: {where: {in_stock: true, color: "blue"}}}).facets["store_id"]["terms"].size
255 258 end
256 259  
257 260 protected
... ...