Commit 3f692b06bde751e0c9cf15710f0de932b22f295e

Authored by Andrew Kane
1 parent d5312b89

Added where and rewhere methods on relation

lib/searchkick/relation.rb
... ... @@ -89,6 +89,34 @@ module Searchkick
89 89 end
90 90  
91 91 # experimental
  92 + def where(value)
  93 + clone.where!(value)
  94 + end
  95 +
  96 + # experimental
  97 + def where!(value)
  98 + check_loaded
  99 + if @options[:where]
  100 + @options[:where] = {_and: [@options[:where], ensure_permitted(value)]}
  101 + else
  102 + @options[:where] = ensure_permitted(value)
  103 + end
  104 + self
  105 + end
  106 +
  107 + # experimental
  108 + def rewhere(value)
  109 + clone.rewhere!(value)
  110 + end
  111 +
  112 + # experimental
  113 + def rewhere!(value)
  114 + check_loaded
  115 + @options[:where] = ensure_permitted(value)
  116 + self
  117 + end
  118 +
  119 + # experimental
92 120 def only(*keys)
93 121 Relation.new(@model, @term, **@options.slice(*keys))
94 122 end
... ... @@ -118,5 +146,11 @@ module Searchkick
118 146 # reset query since options will change
119 147 @query = nil
120 148 end
  149 +
  150 + # provides *very* basic protection from unfiltered parameters
  151 + # this is not meant to be comprehensive and may be expanded in the future
  152 + def ensure_permitted(obj)
  153 + obj.to_h
  154 + end
121 155 end
122 156 end
... ...
test/parameters_test.rb
... ... @@ -20,18 +20,56 @@ class ParametersTest < Minitest::Test
20 20 end
21 21 end
22 22  
  23 + def test_where_relation
  24 + params = ActionController::Parameters.new({store_id: 1})
  25 + assert_raises(ActionController::UnfilteredParameters) do
  26 + Product.search("*").where(params)
  27 + end
  28 + end
  29 +
  30 + def test_rewhere_relation
  31 + params = ActionController::Parameters.new({store_id: 1})
  32 + assert_raises(ActionController::UnfilteredParameters) do
  33 + Product.search("*").where(params)
  34 + end
  35 + end
  36 +
23 37 def test_where_permitted
24 38 store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}]
25 39 params = ActionController::Parameters.new({store_id: 1})
26 40 assert_search "product", ["Product A"], where: params.permit(:store_id)
27 41 end
28 42  
  43 + def test_where_permitted_relation
  44 + store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}]
  45 + params = ActionController::Parameters.new({store_id: 1})
  46 + assert_equal ["Product A"], Product.search("product").where(params.permit(:store_id)).map(&:name)
  47 + end
  48 +
  49 + def test_rewhere_permitted_relation
  50 + store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}]
  51 + params = ActionController::Parameters.new({store_id: 1})
  52 + assert_equal ["Product A"], Product.search("product").rewhere(params.permit(:store_id)).map(&:name)
  53 + end
  54 +
29 55 def test_where_value
30 56 store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}]
31 57 params = ActionController::Parameters.new({store_id: 1})
32 58 assert_search "product", ["Product A"], where: {store_id: params[:store_id]}
33 59 end
34 60  
  61 + def test_where_value_relation
  62 + store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}]
  63 + params = ActionController::Parameters.new({store_id: 1})
  64 + assert_equal ["Product A"], Product.search("product").where(store_id: params[:store_id]).map(&:name)
  65 + end
  66 +
  67 + def test_rewhere_value_relation
  68 + store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}]
  69 + params = ActionController::Parameters.new({store_id: 1})
  70 + assert_equal ["Product A"], Product.search("product").where(store_id: params[:store_id]).map(&:name)
  71 + end
  72 +
35 73 def test_where_hash
36 74 params = ActionController::Parameters.new({store_id: {value: 10, boost: 2}})
37 75 error = assert_raises(TypeError) do
... ... @@ -40,6 +78,24 @@ class ParametersTest < Minitest::Test
40 78 assert_equal error.message, "can't cast ActionController::Parameters"
41 79 end
42 80  
  81 + # TODO raise error without to_a
  82 + def test_where_hash_relation
  83 + params = ActionController::Parameters.new({store_id: {value: 10, boost: 2}})
  84 + error = assert_raises(TypeError) do
  85 + Product.search("product").where(store_id: params[:store_id]).to_a
  86 + end
  87 + assert_equal error.message, "can't cast ActionController::Parameters"
  88 + end
  89 +
  90 + # TODO raise error without to_a
  91 + def test_rewhere_hash_relation
  92 + params = ActionController::Parameters.new({store_id: {value: 10, boost: 2}})
  93 + error = assert_raises(TypeError) do
  94 + Product.search("product").rewhere(store_id: params[:store_id]).to_a
  95 + end
  96 + assert_equal error.message, "can't cast ActionController::Parameters"
  97 + end
  98 +
43 99 def test_aggs_where
44 100 params = ActionController::Parameters.new({store_id: 1})
45 101 assert_raises(ActionController::UnfilteredParameters) do
... ...
test/where_test.rb
... ... @@ -82,6 +82,23 @@ class WhereTest < Minitest::Test
82 82 assert_search "product", ["Product B"], where: {user_ids: {_not: [3, nil]}}
83 83 end
84 84  
  85 + def test_where_relation
  86 + now = Time.now
  87 + store [
  88 + {name: "Product A", store_id: 1, in_stock: true, backordered: true, created_at: now, orders_count: 4, user_ids: [1, 2, 3]},
  89 + {name: "Product B", store_id: 2, in_stock: true, backordered: false, created_at: now - 1, orders_count: 3, user_ids: [1]},
  90 + {name: "Product C", store_id: 3, in_stock: false, backordered: true, created_at: now - 2, orders_count: 2, user_ids: [1, 3]},
  91 + {name: "Product D", store_id: 4, in_stock: false, backordered: false, created_at: now - 3, orders_count: 1}
  92 + ]
  93 + assert_equal ["Product A", "Product B"], Product.search("product").where(in_stock: true).map(&:name)
  94 +
  95 + # multiple where
  96 + assert_equal ["Product A"], Product.search("product").where(in_stock: true).where(backordered: true).map(&:name)
  97 +
  98 + # rewhere
  99 + assert_equal ["Product A", "Product C"], Product.search("product").where(in_stock: true).rewhere(backordered: true).map(&:name)
  100 + end
  101 +
85 102 def test_where_string_operators
86 103 error = assert_raises(ArgumentError) do
87 104 assert_search "product", [], where: {store_id: {"lt" => 2}}
... ...