stub_solr 0.0.5 → 0.0.6
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 +4 -4
- data/.codeclimate.yml +23 -0
- data/.rubocop.yml +4 -0
- data/README.md +50 -12
- data/lib/stub_solr/extra_dsl.rb +144 -0
- data/lib/stub_solr/search.rb +107 -0
- data/lib/stub_solr/search_helper.rb +168 -0
- data/lib/stub_solr/stub_session_proxy.rb +27 -0
- data/lib/stub_solr/version.rb +1 -1
- data/lib/stub_solr.rb +7 -2
- data/stub_solr.gemspec +1 -3
- metadata +9 -33
- data/lib/stub_solr/sunspot_rails_stub_session_proxy.rb +0 -363
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d7ccf1ca8364cbe78d549c7adee20fc57e6657b
|
4
|
+
data.tar.gz: e7373b1aad31088dd937d28cf6c7559acc1bc1fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c63a06b47829d41038bb6f581742ba546ea37aa3a0e12d5c9accadd8a371abae23b04c8c5daf860eb753ad30397b2c95d204404227d5c9e066bdeef5e60c6ab2
|
7
|
+
data.tar.gz: cd6bfc624908d13a46bdbc8d53c3f350f4823eed7c3a3e4ca5535e21a4d600a931fd66c30bf81fc189518e17612822fdaf79c239bf7e25493bf0ff87e9813536
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
engines:
|
2
|
+
duplication:
|
3
|
+
enabled: true
|
4
|
+
config:
|
5
|
+
languages:
|
6
|
+
- ruby
|
7
|
+
fixme:
|
8
|
+
enabled: true
|
9
|
+
rubocop:
|
10
|
+
enabled: true
|
11
|
+
ratings:
|
12
|
+
paths:
|
13
|
+
- "**.js"
|
14
|
+
- "**.jsx"
|
15
|
+
- "**.module"
|
16
|
+
- "**.rb"
|
17
|
+
exclude_paths:
|
18
|
+
- test/
|
19
|
+
- Rakefile
|
20
|
+
- gemfiles/
|
21
|
+
- dev_tasks/
|
22
|
+
- bin/
|
23
|
+
- tmp/
|
data/.rubocop.yml
CHANGED
@@ -6,6 +6,7 @@ AllCops:
|
|
6
6
|
- gemfiels/*
|
7
7
|
- test/**/*
|
8
8
|
- tmp/**/*
|
9
|
+
- Rakefile
|
9
10
|
TargetRubyVersion: 2.3
|
10
11
|
|
11
12
|
Rails:
|
@@ -25,3 +26,6 @@ Style/EmptyLinesAroundClassBody:
|
|
25
26
|
|
26
27
|
Style/EmptyLinesAroundMethodBody:
|
27
28
|
Enabled: false
|
29
|
+
|
30
|
+
Style/FrozenStringLiteralComment:
|
31
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
`Sunspot.session = Sunspot::Rails::StubSessionProxy.new(Sunspot.session)` is enough for most of cases but if you want more than `allow_any_instance_of(Sunspot::Rails::StubSessionProxy::Search).to receive(:results).and_return(myExpectedResults)` this gem can be helpful. `kaminari` for pagination and plain AR to mimic resutls.
|
7
7
|
|
8
|
-
this gem depends on `2.2.
|
8
|
+
this gem depends on `2.2.x` version of sunspot, sunspot_rails.
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
@@ -15,17 +15,49 @@ Add this line to your application's Gemfile:
|
|
15
15
|
gem 'stub_solr'
|
16
16
|
```
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
$ bundle
|
21
|
-
|
22
|
-
Or install it yourself as:
|
18
|
+
## Usage
|
23
19
|
|
24
|
-
|
20
|
+
`test_helper` file should have `require 'stub_solr'`. Given a sunspot search block as following codes,
|
25
21
|
|
26
|
-
|
22
|
+
```ruby
|
23
|
+
class ActivitiesController < ApplicationController
|
24
|
+
def search
|
25
|
+
...
|
26
|
+
search = Sunspot.search Excercise, Activity do
|
27
|
+
any_of do
|
28
|
+
with :blocked, false
|
29
|
+
without :exhausted, true
|
30
|
+
end
|
31
|
+
|
32
|
+
if min && max
|
33
|
+
any_of do
|
34
|
+
all_of do
|
35
|
+
with :start_limit_number, nil
|
36
|
+
with(:end_limit_number).less_than_or_equal_to max
|
37
|
+
end
|
38
|
+
all_of do
|
39
|
+
with :end_limit_number, nil
|
40
|
+
with(:start_limit_number).greater_than_or_equal_to min
|
41
|
+
end
|
42
|
+
all_of do
|
43
|
+
without(:start_limit_number, nil)
|
44
|
+
without(:end_limit_number, nil)
|
45
|
+
with(:start_limit_number).greater_than_or_equal_to min
|
46
|
+
with(:end_limit_number).less_than_or_equal_to max
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
## search by text
|
51
|
+
fulltext params[:search] if params[:search].present?
|
52
|
+
order_by :created_at, :asc
|
53
|
+
paginate page: page, per_page: per_page
|
54
|
+
end
|
55
|
+
...
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
27
59
|
|
28
|
-
|
60
|
+
You can write expected results like this. use `concat` for `any_of` block and `array_1 & array_2` for `all_of` block.
|
29
61
|
|
30
62
|
```ruby
|
31
63
|
class ActivitiesControllerTest < ActionDispatch::IntegrationTest
|
@@ -41,9 +73,15 @@ class ActivitiesControllerTest < ActionDispatch::IntegrationTest
|
|
41
73
|
super
|
42
74
|
end
|
43
75
|
|
44
|
-
test '
|
45
|
-
|
46
|
-
|
76
|
+
test 'filter with number range' do
|
77
|
+
pool_1 = Activity.where(blocked: false).to_a.concat(Activity.where(exhausted: false).to_a).uniq
|
78
|
+
target_1 = Activity.where("end_limit_number <= ? AND start_limit_number = ?", 18, nil).to_a
|
79
|
+
target_2 = Activity.where("start_limit_number >= ? AND end_limit_number = ?", 3, nil).to_a
|
80
|
+
target_3 = Activity.where("start_limit_number >= ?", 3).where("end_limit_number <= ?", 18).to_a
|
81
|
+
pool_2 = target_1.concat(target_2).concat(target_3)
|
82
|
+
expected = pool_1 & pool_2
|
83
|
+
|
84
|
+
get search_activities_url(params: { limits: [3, 18] })
|
47
85
|
res = ActiveSupport::JSON.decode(response.body)["activities"]
|
48
86
|
res.size.must_equal expected.size
|
49
87
|
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
class Sunspot::Rails::StubSessionProxy
|
2
|
+
# with and fulltext can be called multiple times
|
3
|
+
# based on the block. that's why i am mutating @results
|
4
|
+
#
|
5
|
+
# for all and any block, we need to consult
|
6
|
+
# sunspot/lib/sunspot/dsl/standard_query.rb
|
7
|
+
#
|
8
|
+
class Search
|
9
|
+
def hits
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
# Added to pass .group_by
|
14
|
+
# Idea is save grouped hash result seperately and then
|
15
|
+
# access it with [] method.
|
16
|
+
#
|
17
|
+
# initial_grouped_hits = initial.hits.group_by(&:class_name)
|
18
|
+
# initial_grouped_hits["Activity"]
|
19
|
+
def [](key)
|
20
|
+
return if @grouped_results.empty? || @grouped_results[key].nil?
|
21
|
+
@group_key = key
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
# possible situation
|
26
|
+
#
|
27
|
+
# initial_grouped_hits = initial.hits.group_by(&:class_name)
|
28
|
+
# initial_grouped_hits["Activity"].map(&:primary_key)
|
29
|
+
def map(&_pr)
|
30
|
+
return unless @grouped_results[@group_key]
|
31
|
+
@grouped_results[@group_key].map(&:id)
|
32
|
+
end
|
33
|
+
|
34
|
+
# possible situation
|
35
|
+
#
|
36
|
+
# initial_grouped_hits = initial.hits.group_by(&:class_name)
|
37
|
+
def group_by(_ = nil)
|
38
|
+
return self if final_results.empty?
|
39
|
+
@types.each do |type|
|
40
|
+
@grouped_results[type.name] = sorted_temp_result.group_by do |i|
|
41
|
+
i.class.name == type.name
|
42
|
+
end[true]
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def phrase_fields(arg)
|
48
|
+
@operation_context.first[:textsearch_priorities] = arg
|
49
|
+
return self if @operation_context.first[:search_term].empty?
|
50
|
+
fulltext(@operation_context.first[:search_term])
|
51
|
+
end
|
52
|
+
|
53
|
+
def query_phrase_slop(_)
|
54
|
+
fulltext(@operation_context.first[:search_term])
|
55
|
+
end
|
56
|
+
|
57
|
+
# with default `StubSessionProxy`, the results is blank whatever
|
58
|
+
# argument or options you put in the search block
|
59
|
+
def fulltext(term, _opt = {}, &bl)
|
60
|
+
matches = []
|
61
|
+
@operation_context.first[:search_term] = term
|
62
|
+
Sunspot::Util::ContextBoundDelegate
|
63
|
+
.instance_eval_with_context(self, &bl) unless bl.nil?
|
64
|
+
# if there is phrase_fields option then we only search for the field
|
65
|
+
# to mimic the priority search. #string_text_fields
|
66
|
+
@types.each do |type|
|
67
|
+
string_text_fields(type).each do |field|
|
68
|
+
if type.has_attribute?(field.to_sym)
|
69
|
+
matches << type.where(type.arel_table[field.to_sym].
|
70
|
+
matches("%#{term}%")).to_a
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
calculated = (result_for_current_context & matches.flatten.uniq)
|
75
|
+
operation_context_result(calculated)
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def order_by(attribute, direction)
|
80
|
+
@operation_context.first[:order_key] = attribute
|
81
|
+
@operation_context.first[:order_direction] = direction
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def in_radius(*args)
|
86
|
+
calculated = result_for_current_context.select do |r|
|
87
|
+
distance = r&.location&.distance_from([args[0], args[1]])
|
88
|
+
distance && distance < args[2].to_i
|
89
|
+
end
|
90
|
+
operation_context_result(calculated)
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def greater_than(time)
|
95
|
+
calculated = filter(result_for_current_context) do |x|
|
96
|
+
x.read_attribute(@range_search_field) > time
|
97
|
+
end
|
98
|
+
operation_context_result(calculated)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def greater_than_or_equal_to(time)
|
103
|
+
calculated = filter(result_for_current_context) do |x|
|
104
|
+
x.read_attribute(@range_search_field) >= time
|
105
|
+
end
|
106
|
+
operation_context_result(calculated)
|
107
|
+
self
|
108
|
+
end
|
109
|
+
|
110
|
+
def less_than(time)
|
111
|
+
calculated = filter(result_for_current_context) do |x|
|
112
|
+
x.read_attribute(@range_search_field) < time
|
113
|
+
end
|
114
|
+
operation_context_result(calculated)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def less_than_or_equal_to(time)
|
119
|
+
calculated = filter(result_for_current_context) do |x|
|
120
|
+
x.read_attribute(@range_search_field) <= time
|
121
|
+
end
|
122
|
+
operation_context_result(calculated)
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def paginate(args = {})
|
127
|
+
@operation_context.first[:page] = args[:page]
|
128
|
+
@operation_context.first[:per_page] = args[:page]
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
def total
|
133
|
+
@operation_context.last[:result].size
|
134
|
+
end
|
135
|
+
|
136
|
+
def filter(array)
|
137
|
+
array.select do |i|
|
138
|
+
i.read_attribute(@range_search_field) &&
|
139
|
+
!i.read_attribute(@range_search_field).nil? &&
|
140
|
+
yield(i)
|
141
|
+
end.uniq
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.expand_path('search_helper', File.dirname(__FILE__))
|
2
|
+
require File.expand_path('extra_dsl', File.dirname(__FILE__))
|
3
|
+
class Sunspot::Rails::StubSessionProxy
|
4
|
+
# with and fulltext can be called multiple times
|
5
|
+
# based on the block. that's why i am mutating @results
|
6
|
+
#
|
7
|
+
# for all and any block, we need to consult
|
8
|
+
# sunspot/lib/sunspot/dsl/standard_query.rb
|
9
|
+
#
|
10
|
+
class Search
|
11
|
+
attr_reader :block, :types, :page, :per_page, :grouped_results
|
12
|
+
|
13
|
+
def initialize(results = [], types = [], &block)
|
14
|
+
@types = types
|
15
|
+
@grouped_results= {}
|
16
|
+
@group_key = ''
|
17
|
+
@range_search_field = nil
|
18
|
+
@operation_context = [{
|
19
|
+
operation: 'all', result: results, order_key: nil, order_direction: nil,
|
20
|
+
page: 1, per_page: 30, search_term: '', textsearch_priorities: {}
|
21
|
+
}]
|
22
|
+
@current_index = 0
|
23
|
+
run_proc_block(&block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def final_results
|
27
|
+
@operation_context.last[:result]
|
28
|
+
end
|
29
|
+
|
30
|
+
def results
|
31
|
+
return PaginatedCollection.new if sorted_temp_result.empty?
|
32
|
+
if final_results.is_a? Kaminari::PaginatableArray
|
33
|
+
return sorted_temp_result
|
34
|
+
end
|
35
|
+
Kaminari.paginate_array(sorted_temp_result).
|
36
|
+
page(@operation_context.first[:page]).
|
37
|
+
per(@operation_context.first[:per_page])
|
38
|
+
end
|
39
|
+
|
40
|
+
def any_of(&bl)
|
41
|
+
previous_result = result_for_current_context
|
42
|
+
push(previous_result, :any)
|
43
|
+
Sunspot::Util::ContextBoundDelegate.instance_eval_with_context(self, &bl)
|
44
|
+
after_results = temp_result_for_current_context
|
45
|
+
pop unless @current_index == 0
|
46
|
+
# parent is now current context
|
47
|
+
if parent_temp_result
|
48
|
+
@operation_context[@current_index][:temp_result] =
|
49
|
+
parent_temp_result.concat(after_results)
|
50
|
+
else
|
51
|
+
@operation_context[@current_index][:result] =
|
52
|
+
after_results
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def all_of(&bl)
|
58
|
+
previous_result = result_for_current_context
|
59
|
+
push(previous_result, :all)
|
60
|
+
Sunspot::Util::ContextBoundDelegate.instance_eval_with_context(self, &bl)
|
61
|
+
after_results = result_for_current_context
|
62
|
+
parent_temp_result =
|
63
|
+
@operation_context[@current_index - 1][:temp_result]
|
64
|
+
pop unless @current_index == 0
|
65
|
+
# parent is now current context
|
66
|
+
if parent_temp_result
|
67
|
+
@operation_context[@current_index][:temp_result] =
|
68
|
+
parent_temp_result.concat(after_results)
|
69
|
+
else
|
70
|
+
@operation_context[@current_index][:result] =
|
71
|
+
(previous_result & after_results).uniq
|
72
|
+
end
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def with(att, val = 'no_value')
|
77
|
+
# return_early_for_with_blocks(att, val, :with)
|
78
|
+
return self if range_no_value?(att, val) && skip_it(att, val)
|
79
|
+
return self if range_value_nil?(val, att) && deal_with_nil(att, :with)
|
80
|
+
return self if val == 'no_value' || att == :location
|
81
|
+
return self if (att == :search_class) && filter_class
|
82
|
+
matches = if val.class.name == 'Array'
|
83
|
+
select_result_for_array_val(att)
|
84
|
+
elsif @types.map{ |x| x.has_attribute?(att)}.include?(true)
|
85
|
+
select_result_attr_is_val(att, val)
|
86
|
+
else
|
87
|
+
result_for_current_context.select { |x| x.send(att) == val }
|
88
|
+
end
|
89
|
+
operation_context_result(matches)
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
def without(att, val = 'no_value')
|
94
|
+
# return_early_for_with_blocks(att, val, :without)
|
95
|
+
return self if range_no_value?(att, val) && skip_it(att, val)
|
96
|
+
return self if range_value_nil?(val, att) && deal_with_nil(att, :without)
|
97
|
+
return self if val == 'no_value' || att == :location
|
98
|
+
matches = if val.class.name == 'Array'
|
99
|
+
select_result_attr_cant_send_val(att, val)
|
100
|
+
else
|
101
|
+
select_result_attr_is_not_value(att, val)
|
102
|
+
end
|
103
|
+
operation_context_result(matches)
|
104
|
+
self
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# serach helper
|
2
|
+
|
3
|
+
class Sunspot::Rails::StubSessionProxy
|
4
|
+
# with and fulltext can be called multiple times
|
5
|
+
# based on the block. that's why i am mutating @results
|
6
|
+
#
|
7
|
+
# for all and any block, we need to consult
|
8
|
+
# sunspot/lib/sunspot/dsl/standard_query.rb
|
9
|
+
#
|
10
|
+
class Search
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def instance_eval_with_context(&block)
|
15
|
+
Sunspot::Util::ContextBoundDelegate.
|
16
|
+
instance_eval_with_context(self, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
# iterate the given block and change @operation_context
|
20
|
+
# block may cotain with, without, fulltext, paginate, in_raius, order_by
|
21
|
+
def run_proc_block(&block)
|
22
|
+
result = @operation_context.last[:result]
|
23
|
+
return PaginatedCollection.new if result.empty?
|
24
|
+
instance_eval_with_context(&block)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def current_operation
|
29
|
+
@operation_context[@current_index][:operation]
|
30
|
+
end
|
31
|
+
|
32
|
+
def result_for_current_context
|
33
|
+
@operation_context[@current_index][:result]
|
34
|
+
end
|
35
|
+
|
36
|
+
def temp_result_for_current_context
|
37
|
+
@operation_context[@current_index][:temp_result]
|
38
|
+
end
|
39
|
+
|
40
|
+
def parent_temp_result
|
41
|
+
@operation_context[@current_index - 1][:temp_result]
|
42
|
+
end
|
43
|
+
|
44
|
+
def operation_context_result(after_results)
|
45
|
+
previous_result = result_for_current_context
|
46
|
+
unless current_operation == 'any'
|
47
|
+
return @operation_context[@current_index][:result] =
|
48
|
+
(previous_result & after_results).uniq
|
49
|
+
end
|
50
|
+
@operation_context[@current_index][:result] =
|
51
|
+
previous_result.concat(after_results).uniq
|
52
|
+
if temp_result_for_current_context
|
53
|
+
@operation_context[@current_index][:temp_result] =
|
54
|
+
temp_result_for_current_context.concat(after_results)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def pop
|
59
|
+
@current_index -= 1
|
60
|
+
@operation_context.pop
|
61
|
+
end
|
62
|
+
|
63
|
+
def push(data, type)
|
64
|
+
if type == :any
|
65
|
+
@operation_context.push(operation: 'any', result: data, temp_result: [])
|
66
|
+
else
|
67
|
+
@operation_context.push(operation: 'all', result: data)
|
68
|
+
end
|
69
|
+
@current_index += 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def filter_class
|
73
|
+
matches = result_for_current_context.select { |x| x.class.name == value }
|
74
|
+
operation_context_result(matches)
|
75
|
+
end
|
76
|
+
|
77
|
+
def range_value_nil?(value, attribute)
|
78
|
+
value.nil? && attribute_is_about_range?(attribute)
|
79
|
+
end
|
80
|
+
|
81
|
+
def range_no_value?(attribute, value)
|
82
|
+
(value == 'no_value') && attribute_is_about_range?(attribute)
|
83
|
+
end
|
84
|
+
|
85
|
+
def skip_it(attribute, value)
|
86
|
+
matches = result_for_current_context.select do |x|
|
87
|
+
x.has_attribute?(attribute)
|
88
|
+
end
|
89
|
+
operation_context_result(matches)
|
90
|
+
end
|
91
|
+
|
92
|
+
def deal_with_nil(attribute, operation)
|
93
|
+
matches = if operation == :with
|
94
|
+
selelct_result_for_nil(attribute)
|
95
|
+
else
|
96
|
+
select_result_for_not_nil(attribute)
|
97
|
+
end
|
98
|
+
operation_context_result(matches)
|
99
|
+
end
|
100
|
+
|
101
|
+
def string_text_fields(type)
|
102
|
+
pr = @operation_context.first[:textsearch_priorities]
|
103
|
+
return pr.keys unless pr.keys.empty?
|
104
|
+
type.columns_hash.select { |k,v| [:string, :text].include? v.type }.keys
|
105
|
+
end
|
106
|
+
|
107
|
+
def attribute_is_about_range?(attribute)
|
108
|
+
matched = nil
|
109
|
+
Sunspot.session.range_fields.each do |x|
|
110
|
+
if attribute.to_s.include? x
|
111
|
+
matched = true
|
112
|
+
@range_search_field = attribute
|
113
|
+
next
|
114
|
+
end
|
115
|
+
end
|
116
|
+
matched
|
117
|
+
end
|
118
|
+
|
119
|
+
def sorted_temp_result
|
120
|
+
key = @operation_context.first[:order_key]
|
121
|
+
direction = @operation_context.first[:order_direction]
|
122
|
+
return final_results unless direction
|
123
|
+
asc = final_results.sort_by { |x| x[key] }
|
124
|
+
return asc if direction.to_s.downcase.include?('asc')
|
125
|
+
asc.reverse
|
126
|
+
end
|
127
|
+
|
128
|
+
def selelct_result_for_nil(attribute)
|
129
|
+
result_for_current_context.select do |x|
|
130
|
+
x.has_attribute?(attribute) &&
|
131
|
+
x.read_attribute(attribute).nil?
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def select_result_for_not_nil(attribute)
|
136
|
+
result_for_current_context.select do |x|
|
137
|
+
x.has_attribute?(attribute) &&
|
138
|
+
!x.read_attribute(attribute).nil?
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def select_result_for_array_val(attribute)
|
143
|
+
result_for_current_context.select do |x|
|
144
|
+
value.include?(x.send(attribute))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def select_result_attr_is_val(attribute, value)
|
149
|
+
result_for_current_context.select do |x|
|
150
|
+
x.read_attribute(attribute) == value
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def select_result_attr_cant_send_val(attribute, value)
|
155
|
+
result_for_current_context.select do |x|
|
156
|
+
x.has_attribute?(attribute) && !value.include?(x.send(attribute))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def select_result_attr_is_not_value(attribute, value)
|
161
|
+
result_for_current_context.select do |x|
|
162
|
+
x.has_attribute?(attribute) &&
|
163
|
+
!x.read_attribute(attribute).nil? &&
|
164
|
+
(x.read_attribute(attribute) != value)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path('search', File.dirname(__FILE__))
|
2
|
+
# stub solr with "dara" array for testing.
|
3
|
+
# if there is no data then it will behave like default blank search
|
4
|
+
# this stub uses Kaminari for pagination
|
5
|
+
# once the data is given, solr search block will call search
|
6
|
+
# and that will create a new Search with arguments.
|
7
|
+
# With the search, it passes the given data as @operation_context.
|
8
|
+
# And "run_proc_block" method will go through each search conditions
|
9
|
+
# in the block. while going through the block, it will change @operation_context
|
10
|
+
#
|
11
|
+
class Sunspot::Rails::StubSessionProxy
|
12
|
+
attr_reader :block, :data, :range_fields
|
13
|
+
|
14
|
+
def initialize(original_session, data = [])
|
15
|
+
@original_session = original_session
|
16
|
+
@data = data
|
17
|
+
@range_fields = %w[time month created_at start end]
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_range_fields(arr)
|
21
|
+
@range_fields = arr
|
22
|
+
end
|
23
|
+
|
24
|
+
def search(*types, &block)
|
25
|
+
Search.new(@data, types, &block)
|
26
|
+
end
|
27
|
+
end
|
data/lib/stub_solr/version.rb
CHANGED
data/lib/stub_solr.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
+
## requires all necessary fiels
|
1
2
|
require 'kaminari'
|
3
|
+
##
|
4
|
+
# previous_page method doesn't exist in Kaminari
|
5
|
+
# but we use it for pagination
|
2
6
|
module Kaminari::PageScopeMethods
|
3
7
|
alias_method :previous_page, :prev_page
|
4
8
|
end
|
5
9
|
require 'sunspot'
|
6
10
|
require 'sunspot_rails'
|
7
11
|
require 'rails'
|
8
|
-
require
|
9
|
-
require File.expand_path('stub_solr/
|
12
|
+
require 'stub_solr/version'
|
13
|
+
require File.expand_path('stub_solr/stub_session_proxy',
|
14
|
+
File.dirname(__FILE__))
|
data/stub_solr.gemspec
CHANGED
@@ -20,9 +20,7 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
21
|
|
22
22
|
gem.add_dependency 'kaminari', '~> 0.17.0'
|
23
|
-
gem.add_dependency '
|
24
|
-
gem.add_dependency 'sunspot_solr', '~> 2.2.6'
|
25
|
-
gem.add_dependency 'sunspot_rails', '~> 2.2.6'
|
23
|
+
gem.add_dependency 'sunspot_rails', '~> 2.2.5'
|
26
24
|
gem.add_dependency 'rails', '>= 4'
|
27
25
|
|
28
26
|
# gem.add_development_dependency 'simplecov', '~> 0.12.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stub_solr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jaigouk Kim
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kaminari
|
@@ -24,48 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.17.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: sunspot
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 2.2.6
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 2.2.6
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sunspot_solr
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 2.2.6
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 2.2.6
|
55
27
|
- !ruby/object:Gem::Dependency
|
56
28
|
name: sunspot_rails
|
57
29
|
requirement: !ruby/object:Gem::Requirement
|
58
30
|
requirements:
|
59
31
|
- - "~>"
|
60
32
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.2.
|
33
|
+
version: 2.2.5
|
62
34
|
type: :runtime
|
63
35
|
prerelease: false
|
64
36
|
version_requirements: !ruby/object:Gem::Requirement
|
65
37
|
requirements:
|
66
38
|
- - "~>"
|
67
39
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.2.
|
40
|
+
version: 2.2.5
|
69
41
|
- !ruby/object:Gem::Dependency
|
70
42
|
name: rails
|
71
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,6 +101,7 @@ executables: []
|
|
129
101
|
extensions: []
|
130
102
|
extra_rdoc_files: []
|
131
103
|
files:
|
104
|
+
- ".codeclimate.yml"
|
132
105
|
- ".gitignore"
|
133
106
|
- ".rubocop.yml"
|
134
107
|
- Gemfile
|
@@ -141,7 +114,10 @@ files:
|
|
141
114
|
- gemfiles/.bundle/config
|
142
115
|
- gemfiles/rails-5.0.0.1
|
143
116
|
- lib/stub_solr.rb
|
144
|
-
- lib/stub_solr/
|
117
|
+
- lib/stub_solr/extra_dsl.rb
|
118
|
+
- lib/stub_solr/search.rb
|
119
|
+
- lib/stub_solr/search_helper.rb
|
120
|
+
- lib/stub_solr/stub_session_proxy.rb
|
145
121
|
- lib/stub_solr/version.rb
|
146
122
|
- stub_solr.gemspec
|
147
123
|
homepage: https://github.com/jaigouk/stub_solr
|
@@ -1,363 +0,0 @@
|
|
1
|
-
|
2
|
-
# stub solr with "dara" array for testing.
|
3
|
-
# if there is no data then it will behave like default blank search
|
4
|
-
# this stub uses Kaminari for pagination
|
5
|
-
# once the data is given, solr search block will call search
|
6
|
-
# and that will create a new Search with arguments.
|
7
|
-
# With the search, it passes the given data as @operation_context.
|
8
|
-
# And "run_proc_block" method will go through each search conditions
|
9
|
-
# in the block. while going through the block, it will change @operation_context
|
10
|
-
#
|
11
|
-
class Sunspot::Rails::StubSessionProxy
|
12
|
-
attr_reader :block, :data, :range_fields
|
13
|
-
|
14
|
-
def initialize(original_session, data = [])
|
15
|
-
@original_session = original_session
|
16
|
-
@data = data
|
17
|
-
@range_fields = %w[time month created_at start end]
|
18
|
-
end
|
19
|
-
|
20
|
-
def set_range_fields(arr)
|
21
|
-
@range_fields = arr
|
22
|
-
end
|
23
|
-
|
24
|
-
def search(*types, &block)
|
25
|
-
Search.new(@data, types, &block)
|
26
|
-
end
|
27
|
-
|
28
|
-
# with and fulltext can be called multiple times
|
29
|
-
# based on the block. that's why i am mutating @results
|
30
|
-
#
|
31
|
-
# for all and any block, we need to consult sunspot/lib/sunspot/dsl/standard_query.rb
|
32
|
-
#
|
33
|
-
class Search
|
34
|
-
attr_reader :block, :types, :page, :per_page, :grouped_results
|
35
|
-
def initialize(results = [], types = [], &block)
|
36
|
-
@facets = {}
|
37
|
-
@search_data = results
|
38
|
-
@block = block
|
39
|
-
@types = types
|
40
|
-
@page = 1
|
41
|
-
@per_page = 30
|
42
|
-
@grouped_results = {}
|
43
|
-
@group_key = ""
|
44
|
-
@range_search_field = nil
|
45
|
-
@operation_context = [{operation: "all", result: @search_data}]
|
46
|
-
@current_context_index = 0
|
47
|
-
@order_key = nil
|
48
|
-
@order_direction = nil
|
49
|
-
@textsearch_priorities = {}
|
50
|
-
@search_term = ""
|
51
|
-
run_proc_block
|
52
|
-
end
|
53
|
-
|
54
|
-
def final_results
|
55
|
-
@operation_context.last[:result]
|
56
|
-
end
|
57
|
-
|
58
|
-
def results
|
59
|
-
return PaginatedCollection.new if sorted_temp_result.empty?
|
60
|
-
return sorted_temp_result if final_results.is_a? Kaminari::PaginatableArray
|
61
|
-
Kaminari.paginate_array(sorted_temp_result).page(@page).per(@per_page)
|
62
|
-
end
|
63
|
-
|
64
|
-
def any_of(&bl)
|
65
|
-
previous_result = result_for_current_context
|
66
|
-
@operation_context.push({operation: "any", result: previous_result, temp_result: []})
|
67
|
-
@current_context_index += 1
|
68
|
-
|
69
|
-
Sunspot::Util::ContextBoundDelegate.instance_eval_with_context(self, &bl)
|
70
|
-
after_results = @operation_context[@current_context_index][:temp_result]
|
71
|
-
|
72
|
-
parent_temp_result = @operation_context[@current_context_index - 1][:temp_result]
|
73
|
-
|
74
|
-
|
75
|
-
unless @current_context_index == 0
|
76
|
-
@current_context_index -= 1
|
77
|
-
@operation_context.pop
|
78
|
-
end
|
79
|
-
# parent is now current context
|
80
|
-
if parent_temp_result
|
81
|
-
@operation_context[@current_context_index][:temp_result] = parent_temp_result.concat(after_results)
|
82
|
-
else
|
83
|
-
@operation_context[@current_context_index][:result] = after_results
|
84
|
-
end
|
85
|
-
self
|
86
|
-
end
|
87
|
-
|
88
|
-
def all_of(&bl)
|
89
|
-
previous_result = result_for_current_context
|
90
|
-
@operation_context.push({operation: "all", result: previous_result})
|
91
|
-
@current_context_index += 1
|
92
|
-
|
93
|
-
Sunspot::Util::ContextBoundDelegate.instance_eval_with_context(self, &bl)
|
94
|
-
after_results = result_for_current_context
|
95
|
-
parent_temp_result = @operation_context[@current_context_index - 1][:temp_result]
|
96
|
-
|
97
|
-
unless @current_context_index == 0
|
98
|
-
@current_context_index -= 1
|
99
|
-
@operation_context.pop
|
100
|
-
end
|
101
|
-
|
102
|
-
# parent is now current context
|
103
|
-
if parent_temp_result
|
104
|
-
@operation_context[@current_context_index][:temp_result] = parent_temp_result.concat(after_results)
|
105
|
-
else
|
106
|
-
@operation_context[@current_context_index][:result] = (previous_result & after_results).uniq
|
107
|
-
end
|
108
|
-
|
109
|
-
self
|
110
|
-
end
|
111
|
-
|
112
|
-
def with(attribute, value = "no_value")
|
113
|
-
skip_no_value(attribute, value)
|
114
|
-
|
115
|
-
if attribute == :search_class
|
116
|
-
matches = result_for_current_context.select {|x| x.class.name == value }
|
117
|
-
operation_context_result(matches)
|
118
|
-
return self
|
119
|
-
end
|
120
|
-
|
121
|
-
if value == nil && attribute_is_about_range?(attribute)
|
122
|
-
matches = result_for_current_context.select {|x| x.has_attribute?(attribute) && (x.read_attribute(attribute) == value)}
|
123
|
-
operation_context_result(matches)
|
124
|
-
return self
|
125
|
-
end
|
126
|
-
|
127
|
-
return self if value == "no_value" || attribute == :location
|
128
|
-
|
129
|
-
matches = if value.class.name == "Array"
|
130
|
-
result_for_current_context.select {|x| value.include?(x.send(attribute)) }
|
131
|
-
elsif @types.map{|x| x.has_attribute?(attribute)}.include?(true)
|
132
|
-
result_for_current_context.select {|x| x.read_attribute(attribute) == value }
|
133
|
-
else
|
134
|
-
result_for_current_context.select {|x| x.send(attribute) == value }
|
135
|
-
end
|
136
|
-
operation_context_result(matches)
|
137
|
-
self
|
138
|
-
end
|
139
|
-
|
140
|
-
def without(attribute, value = "no_value")
|
141
|
-
skip_no_value(attribute, value)
|
142
|
-
if value == nil && attribute_is_about_range?(attribute)
|
143
|
-
matches = result_for_current_context.select {|x| x.has_attribute?(attribute) && !(x.read_attribute(attribute) == value)}
|
144
|
-
operation_context_result(matches)
|
145
|
-
return self
|
146
|
-
end
|
147
|
-
|
148
|
-
return self if value == "no_value" || attribute == :location
|
149
|
-
matches = if value.class.name == "Array"
|
150
|
-
result_for_current_context.select {|x| x.has_attribute?(attribute) && !value.include?(x.send(attribute)) }
|
151
|
-
else
|
152
|
-
result_for_current_context.select {|x| x.has_attribute?(attribute) && !x.read_attribute(attribute).nil? && (x.read_attribute(attribute) != value) }
|
153
|
-
end
|
154
|
-
operation_context_result(matches)
|
155
|
-
self
|
156
|
-
end
|
157
|
-
|
158
|
-
def hits
|
159
|
-
self
|
160
|
-
end
|
161
|
-
|
162
|
-
# Added to pass .group_by
|
163
|
-
# Idea is save grouped hash result seperately and then
|
164
|
-
# access it with [] method.
|
165
|
-
#
|
166
|
-
# initial_grouped_hits = initial.hits.group_by(&:class_name)
|
167
|
-
# initial_grouped_hits["Activity"]
|
168
|
-
def [](key)
|
169
|
-
return if @grouped_results.empty? || @grouped_results[key].nil?
|
170
|
-
@group_key = key
|
171
|
-
self
|
172
|
-
end
|
173
|
-
|
174
|
-
# possible situation
|
175
|
-
#
|
176
|
-
# initial_grouped_hits = initial.hits.group_by(&:class_name)
|
177
|
-
# initial_grouped_hits["Activity"].map(&:primary_key)
|
178
|
-
def map(&pr)
|
179
|
-
return unless @grouped_results[@group_key]
|
180
|
-
@grouped_results[@group_key].map{|x| x.id}
|
181
|
-
end
|
182
|
-
|
183
|
-
# possible situation
|
184
|
-
#
|
185
|
-
# initial_grouped_hits = initial.hits.group_by(&:class_name)
|
186
|
-
def group_by(class_name = nil)
|
187
|
-
return self if final_results.empty?
|
188
|
-
@types.each do |type|
|
189
|
-
@grouped_results[type.name] = sorted_temp_result.group_by{|i| i.class.name == type.name }[true]
|
190
|
-
end
|
191
|
-
self
|
192
|
-
end
|
193
|
-
|
194
|
-
def phrase_fields(arg)
|
195
|
-
@textsearch_priorities = arg
|
196
|
-
return self if @search_term.empty?
|
197
|
-
fulltext(@search_term)
|
198
|
-
end
|
199
|
-
|
200
|
-
def query_phrase_slop(*args)
|
201
|
-
fulltext(@search_term)
|
202
|
-
end
|
203
|
-
|
204
|
-
# with default `StubSessionProxy`, the results is blank whatever
|
205
|
-
# argument or options you put in the search block
|
206
|
-
def fulltext(term, opt={}, &bl)
|
207
|
-
matches = []
|
208
|
-
@search_term = term
|
209
|
-
Sunspot::Util::ContextBoundDelegate.instance_eval_with_context(self, &bl) if !bl.nil?
|
210
|
-
# if there is phrase_fields option then we only search for the field
|
211
|
-
# to mimic the priority search. #string_text_fields
|
212
|
-
@types.each do |type|
|
213
|
-
string_text_fields(type).each do |field|
|
214
|
-
if type.has_attribute?(field.to_sym)
|
215
|
-
matches << type.where(type.arel_table[field.to_sym].matches("%#{term}%")).to_a
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
calculated = (result_for_current_context & matches.flatten.uniq)
|
220
|
-
operation_context_result(calculated)
|
221
|
-
self
|
222
|
-
end
|
223
|
-
|
224
|
-
def order_by(attribute, direction)
|
225
|
-
@order_key = attribute
|
226
|
-
@order_direction = direction
|
227
|
-
self
|
228
|
-
end
|
229
|
-
|
230
|
-
def in_radius(*args)
|
231
|
-
calculated = result_for_current_context.select do |r|
|
232
|
-
distance = r&.location&.distance_from([args[0], args[1]])
|
233
|
-
distance && distance < args[2].to_i
|
234
|
-
end
|
235
|
-
operation_context_result(calculated)
|
236
|
-
self
|
237
|
-
end
|
238
|
-
|
239
|
-
def greater_than(time)
|
240
|
-
calculated = result_for_current_context.select do |x|
|
241
|
-
has_attribute_and_not_nil(x) &&
|
242
|
-
x.read_attribute(@range_search_field) > time
|
243
|
-
end.uniq
|
244
|
-
operation_context_result(calculated)
|
245
|
-
self
|
246
|
-
end
|
247
|
-
|
248
|
-
def greater_than_or_equal_to(time)
|
249
|
-
calculated = result_for_current_context.select do |x|
|
250
|
-
has_attribute_and_not_nil(x) &&
|
251
|
-
x.read_attribute(@range_search_field) >= time
|
252
|
-
end.uniq
|
253
|
-
operation_context_result(calculated)
|
254
|
-
self
|
255
|
-
end
|
256
|
-
|
257
|
-
def less_than(time)
|
258
|
-
calculated = result_for_current_context.select do |x|
|
259
|
-
has_attribute_and_not_nil(x) &&
|
260
|
-
x.read_attribute(@range_search_field) < time
|
261
|
-
end.uniq
|
262
|
-
operation_context_result(calculated)
|
263
|
-
self
|
264
|
-
end
|
265
|
-
|
266
|
-
def less_than_or_equal_to(time)
|
267
|
-
calculated = result_for_current_context.select do |x|
|
268
|
-
has_attribute_and_not_nil(x) &&
|
269
|
-
x.read_attribute(@range_search_field) <= time
|
270
|
-
end.uniq
|
271
|
-
operation_context_result(calculated)
|
272
|
-
self
|
273
|
-
end
|
274
|
-
|
275
|
-
def paginate(args={})
|
276
|
-
@page = args[:page]
|
277
|
-
@per_page = args[:per_page]
|
278
|
-
self
|
279
|
-
end
|
280
|
-
|
281
|
-
def total
|
282
|
-
@operation_context.last[:result].size
|
283
|
-
end
|
284
|
-
|
285
|
-
private
|
286
|
-
|
287
|
-
# iterate the given block and change @operation_context
|
288
|
-
# block may cotain with, without, fulltext, paginate, in_raius, order_by
|
289
|
-
def run_proc_block
|
290
|
-
result = @operation_context.last[:result]
|
291
|
-
return PaginatedCollection.new if result.empty?
|
292
|
-
|
293
|
-
Sunspot::Util::ContextBoundDelegate.instance_eval_with_context(self, &@block)
|
294
|
-
# @operation_context.last[:result] = @operation_context.last[:result].uniq
|
295
|
-
self
|
296
|
-
end
|
297
|
-
|
298
|
-
def current_operation
|
299
|
-
@operation_context[@current_context_index][:operation]
|
300
|
-
end
|
301
|
-
|
302
|
-
def result_for_current_context
|
303
|
-
@operation_context[@current_context_index][:result]
|
304
|
-
end
|
305
|
-
|
306
|
-
def temp_result_for_current_context
|
307
|
-
@operation_context[@current_context_index][:temp_result]
|
308
|
-
end
|
309
|
-
|
310
|
-
def operation_context_result(after_results)
|
311
|
-
previous_result = result_for_current_context
|
312
|
-
# parent_result = @operation_context[@current_context_index -1][:result]
|
313
|
-
temp_result = @operation_context[@current_context_index][:temp_result]
|
314
|
-
if current_operation == "any"
|
315
|
-
@operation_context[@current_context_index][:result] = previous_result.concat(after_results).uniq
|
316
|
-
if temp_result
|
317
|
-
@operation_context[@current_context_index][:temp_result] = temp_result.concat(after_results)
|
318
|
-
end
|
319
|
-
else
|
320
|
-
@operation_context[@current_context_index][:result] = (previous_result & after_results).uniq
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
def skip_no_value(attribute, value)
|
325
|
-
if value == "no_value" && attribute_is_about_range?(attribute)
|
326
|
-
matches = result_for_current_context.select {|x| x.has_attribute?(attribute)}
|
327
|
-
operation_context_result(matches)
|
328
|
-
return self
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
def has_attribute_and_not_nil(x)
|
333
|
-
x.read_attribute(@range_search_field) &&
|
334
|
-
!x.read_attribute(@range_search_field).nil?
|
335
|
-
end
|
336
|
-
|
337
|
-
def string_text_fields(type)
|
338
|
-
return @textsearch_priorities.keys unless @textsearch_priorities.keys.empty?
|
339
|
-
type.columns.collect { |c| {"#{c.type}":"#{c.name}"} }
|
340
|
-
.map{|hash| hash.select{|k,v| [:string, :text].include? k} }.uniq
|
341
|
-
.map{|x| x.values}.flatten
|
342
|
-
end
|
343
|
-
|
344
|
-
def attribute_is_about_range?(attribute)
|
345
|
-
matched = nil
|
346
|
-
Sunspot.session.range_fields.each do |x|
|
347
|
-
if attribute.to_s.include? x
|
348
|
-
matched = true
|
349
|
-
@range_search_field = attribute
|
350
|
-
break
|
351
|
-
end
|
352
|
-
end
|
353
|
-
matched
|
354
|
-
end
|
355
|
-
|
356
|
-
def sorted_temp_result
|
357
|
-
return final_results unless @order_direction
|
358
|
-
asc = final_results.sort_by{|x| x[@order_key]}
|
359
|
-
return asc if @order_direction.to_s.downcase.include?("asc")
|
360
|
-
asc.reverse
|
361
|
-
end
|
362
|
-
end
|
363
|
-
end
|