forty_facets 0.0.14 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/forty_facets.gemspec +1 -1
- data/lib/forty_facets/facet_search.rb +4 -0
- data/lib/forty_facets/filter/sql_facet_filter_definition.rb +94 -0
- data/lib/forty_facets/version.rb +1 -1
- data/lib/forty_facets.rb +1 -0
- data/test/fixtures.rb +5 -1
- data/test/smoke_test.rb +48 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2775c3dbeacb02d6a306671c1f46306f03baaa7c
|
4
|
+
data.tar.gz: 007b804dc78ebe61b1aff29a41f276f2986d62ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86d860f3463b9c264010489f2520cf4ac8e216f7f2cfe94ba0e1a5839439e1d799275ccc88281636e5b6a1f0911f26744a826e0a9ca93929eb6c0fb68082800b
|
7
|
+
data.tar.gz: 51c6d45ef8c18c8185d142baac5cbb7bccc1cd54888fb2453f7157d9559657b86d151fc72b5da83bf0cb708c456f2691a593b66210b8e63b2f39392a9507489f
|
data/forty_facets.gemspec
CHANGED
@@ -24,5 +24,5 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency "sqlite3"
|
25
25
|
spec.add_development_dependency "coveralls"
|
26
26
|
spec.add_development_dependency "activerecord", "= 4.1.0"
|
27
|
-
#
|
27
|
+
#spec.add_development_dependency "byebug" # travis doenst like byebug
|
28
28
|
end
|
@@ -40,6 +40,10 @@ module FortyFacets
|
|
40
40
|
definitions << FacetFilterDefinition.new(self, path, opts)
|
41
41
|
end
|
42
42
|
|
43
|
+
def sql_facet(queries, opts = {})
|
44
|
+
definitions << SqlFacetFilterDefinition.new(self, queries, opts)
|
45
|
+
end
|
46
|
+
|
43
47
|
def orders(name_and_order_options)
|
44
48
|
@order_definitions = name_and_order_options.to_a.inject([]) {|ods, no| ods << OrderDefinition.new(no.first, no.last)}
|
45
49
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module FortyFacets
|
2
|
+
class SqlFacetFilterDefinition < FilterDefinition
|
3
|
+
attr_reader(:queries)
|
4
|
+
|
5
|
+
def initialize(search, queries, opts)
|
6
|
+
@search = search
|
7
|
+
@queries = queries
|
8
|
+
@path = Array(opts[:path]) if opts[:path].present?
|
9
|
+
@path ||= @queries.keys
|
10
|
+
@options = opts
|
11
|
+
end
|
12
|
+
|
13
|
+
def request_param
|
14
|
+
path.join("-")
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_filter(search_instance, param_value)
|
18
|
+
ScopeFacetFilter.new(self, search_instance, param_value)
|
19
|
+
end
|
20
|
+
|
21
|
+
class ScopeFacetFilter < Filter
|
22
|
+
def values
|
23
|
+
@values ||= Array.wrap(value).sort.uniq
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_scope
|
27
|
+
return Proc.new { |base| base } if empty?
|
28
|
+
|
29
|
+
Proc.new do |base|
|
30
|
+
# intersection of values and definition queries
|
31
|
+
base.where(selected_queries.values.map do |query|
|
32
|
+
"(#{query})"
|
33
|
+
end.join(" OR "))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def selected
|
38
|
+
values
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove(value)
|
42
|
+
new_params = search_instance.params || {}
|
43
|
+
old_values = new_params[definition.request_param]
|
44
|
+
old_values.delete(value.to_s)
|
45
|
+
new_params.delete(definition.request_param) if old_values.empty?
|
46
|
+
search_instance.class.new_unwrapped(new_params, search_instance.root)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add(value)
|
50
|
+
new_params = search_instance.params || {}
|
51
|
+
old_values = new_params[definition.request_param] ||= []
|
52
|
+
old_values << value.to_s
|
53
|
+
search_instance.class.new_unwrapped(new_params, search_instance.root)
|
54
|
+
end
|
55
|
+
|
56
|
+
def facet
|
57
|
+
query = definition.queries.map do |key, sql_query|
|
58
|
+
"(#{sql_query}) as #{key}"
|
59
|
+
end.join(", ")
|
60
|
+
query += ", count(*) as occurrences"
|
61
|
+
|
62
|
+
counts = without.result.reorder("")
|
63
|
+
.select(query)
|
64
|
+
.group(definition.queries.keys)
|
65
|
+
counts.includes_values = []
|
66
|
+
|
67
|
+
result = {}
|
68
|
+
|
69
|
+
counts.map do |count|
|
70
|
+
definition.queries.each do |key, _|
|
71
|
+
result[key] ||= 0
|
72
|
+
if [1, "1", true].include?(count[key])
|
73
|
+
result[key] += count.occurrences
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
result.map do |key, count|
|
79
|
+
key = key.to_sym
|
80
|
+
is_selected = selected_queries.keys.include?(key)
|
81
|
+
FacetValue.new(key, count, is_selected)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def selected_queries
|
88
|
+
@selected_queries ||= definition.queries.select do |key, _|
|
89
|
+
values.map(&:to_sym).include? key
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/forty_facets/version.rb
CHANGED
data/lib/forty_facets.rb
CHANGED
@@ -10,4 +10,5 @@ require "forty_facets/filter_definition"
|
|
10
10
|
require "forty_facets/filter/range_filter_definition"
|
11
11
|
require "forty_facets/filter/text_filter_definition"
|
12
12
|
require "forty_facets/filter/facet_filter_definition"
|
13
|
+
require "forty_facets/filter/sql_facet_filter_definition"
|
13
14
|
require "forty_facets/facet_search"
|
data/test/fixtures.rb
CHANGED
@@ -86,6 +86,9 @@ class Movie < ActiveRecord::Base
|
|
86
86
|
has_and_belongs_to_many :genres
|
87
87
|
has_and_belongs_to_many :actors
|
88
88
|
has_and_belongs_to_many :writers
|
89
|
+
|
90
|
+
scope :classics, -> { where("year <= ?", 1980) }
|
91
|
+
scope :non_classics, -> { where("year > ?", 1980) }
|
89
92
|
end
|
90
93
|
|
91
94
|
LOREM = %w{Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren}
|
@@ -133,7 +136,8 @@ end
|
|
133
136
|
|
134
137
|
rand = Random.new
|
135
138
|
LOREM.each_with_index do |title, index|
|
136
|
-
m = Movie.create!(title: title, studio: studios[index % studios.length],
|
139
|
+
m = Movie.create!(title: title, studio: studios[index % studios.length],
|
140
|
+
price: rand.rand(20.0), year: (index + 1975))
|
137
141
|
3.times do
|
138
142
|
actor = actors[rand(actors.length)]
|
139
143
|
unless m.actors.include? actor
|
data/test/smoke_test.rb
CHANGED
@@ -23,6 +23,10 @@ class MovieSearch < FortyFacets::FacetSearch
|
|
23
23
|
facet [:studio, :country], name: 'Country'
|
24
24
|
facet [:studio, :status], name: 'Studio status'
|
25
25
|
facet [:studio, :producers], name: 'Producers'
|
26
|
+
sql_facet({ classic: "year <= 1980", non_classic: "year > 1980" },
|
27
|
+
{ name: "Classic", path: :classic })
|
28
|
+
sql_facet({ classic: "year <= 1980", non_classic: "year > 1980" },
|
29
|
+
{ name: "Classic" })
|
26
30
|
text [:studio, :description], name: 'Studio Description'
|
27
31
|
end
|
28
32
|
|
@@ -33,6 +37,50 @@ class SmokeTest < Minitest::Test
|
|
33
37
|
assert_equal Movie.all.size, search.result.size
|
34
38
|
end
|
35
39
|
|
40
|
+
def test_scope_filter
|
41
|
+
search = MovieSearch.new("search" => {})
|
42
|
+
assert_equal 40, search.result.size
|
43
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:classic, 6, false)
|
44
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, false)
|
45
|
+
|
46
|
+
search = MovieSearch.new("search" => { "classic" => "classic" })
|
47
|
+
assert_equal 6, search.result.size
|
48
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:classic, 6, true)
|
49
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, false)
|
50
|
+
|
51
|
+
search = MovieSearch.new("search" => { "classic" => "non_classic" })
|
52
|
+
assert_equal 34, search.result.size
|
53
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:classic, 6, false)
|
54
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, true)
|
55
|
+
|
56
|
+
search = MovieSearch.new("search" => { "classic" => ["non_classic", "classic"] })
|
57
|
+
assert_equal 40, search.result.size
|
58
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:classic, 6, true)
|
59
|
+
assert search.filter(:classic).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, true)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_scope_filter_without_path
|
63
|
+
search = MovieSearch.new("search" => {})
|
64
|
+
assert_equal 40, search.result.size
|
65
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:classic, 6, false)
|
66
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, false)
|
67
|
+
|
68
|
+
search = MovieSearch.new("search" => { "classic-non_classic" => "classic" })
|
69
|
+
assert_equal 6, search.result.size
|
70
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:classic, 6, true)
|
71
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, false)
|
72
|
+
|
73
|
+
search = MovieSearch.new("search" => { "classic-non_classic" => "non_classic" })
|
74
|
+
assert_equal 34, search.result.size
|
75
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:classic, 6, false)
|
76
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, true)
|
77
|
+
|
78
|
+
search = MovieSearch.new("search" => { "classic-non_classic" => ["non_classic", "classic"] })
|
79
|
+
assert_equal 40, search.result.size
|
80
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:classic, 6, true)
|
81
|
+
assert search.filter([:classic, :non_classic]).facet.include? FortyFacets::FacetValue.new(:non_classic, 34, true)
|
82
|
+
end
|
83
|
+
|
36
84
|
def test_text_filter
|
37
85
|
search = MovieSearch.new({'search' => { 'title' => 'ipsum' }})
|
38
86
|
assert_equal 1, search.result.size
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forty_facets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Axel Tetzlaff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -117,6 +117,7 @@ files:
|
|
117
117
|
- lib/forty_facets/filter.rb
|
118
118
|
- lib/forty_facets/filter/facet_filter_definition.rb
|
119
119
|
- lib/forty_facets/filter/range_filter_definition.rb
|
120
|
+
- lib/forty_facets/filter/sql_facet_filter_definition.rb
|
120
121
|
- lib/forty_facets/filter/text_filter_definition.rb
|
121
122
|
- lib/forty_facets/filter_definition.rb
|
122
123
|
- lib/forty_facets/order.rb
|