diff --git a/.gitignore b/.gitignore index edb9f95d6..6247deeb6 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ test/version_tmp tmp *.log .DS_Store +.ruby-* diff --git a/README.md b/README.md index 39d4cc407..fe9aeafc4 100644 --- a/README.md +++ b/README.md @@ -416,6 +416,14 @@ price_ranges = [{to: 20}, {from: 20, to: 50}, {from: 50}] Product.search "*", facets: {price: {ranges: price_ranges}} ``` +With basic constrains + +* `include_constraints` - if set to true will use constrains from basic query inside facets + +```ruby +Product.search('*', where: { color: 'red' }, facets: {store_id: {where: {in_stock: false}}}, include_constraints: true) +``` + ### Highlight Highlight the search query in the results. diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index 48181f1a0..2dd3f0f4f 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -239,6 +239,7 @@ def initialize(klass, term, options = {}) # offset is not possible # http://elasticsearch-users.115913.n3.nabble.com/Is-pagination-possible-in-termsStatsFacet-td3422943.html + facet_options.deep_merge!(where: options[:where].reject{|k| k == field}) if options[:include_constraints] == true facet_filters = where_filters(facet_options[:where]) if facet_filters.any? payload[:facets][field][:facet_filter] = { @@ -428,4 +429,4 @@ def term_filters(field, value) end end -end \ No newline at end of file +end diff --git a/test/facets_test.rb b/test/facets_test.rb index 22f9814b1..7ee39c027 100644 --- a/test/facets_test.rb +++ b/test/facets_test.rb @@ -5,9 +5,10 @@ class TestFacets < Minitest::Unit::TestCase def setup super store [ - {name: "Product Show", store_id: 1, in_stock: true, color: "blue", price: 21}, - {name: "Product Hide", store_id: 2, in_stock: false, color: "green", price: 25}, - {name: "Product B", store_id: 2, in_stock: false, color: "red", price: 5} + {name: "Product Show", latitude: 37.7833, longitude: 12.4167, store_id: 1, in_stock: true, color: "blue", price: 21}, + {name: "Product Hide", latitude: 29.4167, longitude: -98.5000, store_id: 2, in_stock: false, color: "green", price: 25}, + {name: "Product B", latitude: 43.9333, longitude: -122.4667, store_id: 2, in_stock: false, color: "red", price: 5}, + {name: "Foo", latitude: 43.9333, longitude: 12.4667, store_id: 3, in_stock: false, color: "yellow", price: 15} ] end @@ -37,4 +38,73 @@ def test_ranges assert_equal 0, facet["ranges"][1]["count"] assert_equal 2, facet["ranges"][2]["count"] end + def test_constraints + facets = Product.search("Product", where: { in_stock: true }, + facets: [:store_id], include_constraints: true).facets + + assert_equal 1, facets['store_id']['terms'].size + assert_equal [1], facets['store_id']['terms'].map{|f| f['term']} + end + + def test_constraints_with_location + facets = Product.search("Product", where: {location: {near: [37, -122], within: "2000mi"}}, + facets: [:store_id], include_constraints: true).facets + + assert_equal 1, facets['store_id']['terms'].size + assert_equal 2, facets['store_id']['terms'][0]['term'] + end + + def test_constraints_with_location_and_or_statement + facets = Product.search("Product", where: {or: [[ + { location: {near: [37, -122], within: "2000mi"}}, {color: 'blue'} + ]]}, facets: [:store_id], include_constraints: true).facets + + assert_equal 2, facets['store_id']['terms'].size + assert_equal [1, 2], facets['store_id']['terms'].map{|f| f['term']}.sort + end + + def test_facets_and_basic_constrains_together + facets = Product.search("Product", where: { color: 'red' }, + facets: {store_id: {where: {in_stock: false}}}, include_constraints: true).facets + + assert_equal 1, facets['store_id']['terms'].size + assert_equal 2, facets['store_id']['terms'][0]['term'] + assert_equal 1, facets['store_id']['terms'][0]['count'] + end + + def test_facets_without_basic_constrains + facets = Product.search("Product", where: { color: 'red' }, + facets: {store_id: {where: {in_stock: false}}}, include_constraints: false).facets + + assert_equal 1, facets['store_id']['terms'].size + assert_equal 2, facets['store_id']['terms'][0]['term'] + assert_equal 2, facets['store_id']['terms'][0]['count'] + end + + def test_do_not_include_current_facets_filter + facets = Product.search("Product", where: { store_id: 2 }, + facets: [:store_id], include_constraints: true).facets + + assert_equal 2, facets['store_id']['terms'].size + assert_equal [1, 2], facets['store_id']['terms'].map{|f| f['term']}.sort + end + + def test_do_not_include_current_facets_filter_with_complex_call + facets = Product.search("Product", where: { store_id: 2, price: {gte: 4 }}, + facets: [:store_id], include_constraints: true).facets + + assert_equal 2, facets['store_id']['terms'].size + assert_equal [1, 2], facets['store_id']['terms'].map{|f| f['term']}.sort + end + + def test_should_still_limit_results + results = Product.search("*", where: { store_id: 2, price: {gte: 4 }}, + facets: [:in_stock, :store_id, :color], include_constraints: false) + + facets = results.facets + assert_equal 2, results.size + assert_equal ["Product B", "Product Hide"], results.map(&:name).sort + assert_equal 3, facets['store_id']['terms'].size + assert_equal [1, 2, 3], facets['store_id']['terms'].map{|f| f['term']}.sort + end end