Commit 3f692b06bde751e0c9cf15710f0de932b22f295e
1 parent
d5312b89
Exists in
master
and in
1 other branch
Added where and rewhere methods on relation
Showing
3 changed files
with
107 additions
and
0 deletions
Show diff stats
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}} | ... | ... |