searchgasm 0.9.6 → 0.9.7
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.
- data/CHANGELOG +2 -0
- data/Manifest +34 -21
- data/{README.mdown → README.rdoc} +96 -63
- data/Rakefile +1 -1
- data/examples/README.rdoc +4 -0
- data/lib/searchgasm/active_record/associations.rb +40 -42
- data/lib/searchgasm/active_record/base.rb +75 -61
- data/lib/searchgasm/condition/base.rb +127 -0
- data/lib/searchgasm/condition/begins_with.rb +20 -0
- data/lib/searchgasm/condition/child_of.rb +11 -0
- data/lib/searchgasm/condition/contains.rb +20 -0
- data/lib/searchgasm/condition/descendant_of.rb +24 -0
- data/lib/searchgasm/condition/does_not_equal.rb +28 -0
- data/lib/searchgasm/condition/ends_with.rb +20 -0
- data/lib/searchgasm/condition/equals.rb +20 -0
- data/lib/searchgasm/condition/greater_than.rb +25 -0
- data/lib/searchgasm/condition/greater_than_or_equal_to.rb +20 -0
- data/lib/searchgasm/condition/inclusive_descendant_of.rb +13 -0
- data/lib/searchgasm/condition/keywords.rb +33 -0
- data/lib/searchgasm/condition/less_than.rb +25 -0
- data/lib/searchgasm/condition/less_than_or_equal_to.rb +20 -0
- data/lib/searchgasm/condition/sibling_of.rb +16 -0
- data/lib/searchgasm/condition/tree.rb +16 -0
- data/lib/searchgasm/conditions/base.rb +221 -0
- data/lib/searchgasm/conditions/protection.rb +30 -0
- data/lib/searchgasm/config.rb +137 -0
- data/lib/searchgasm/helpers/form_helper.rb +159 -0
- data/lib/searchgasm/helpers/search_helper.rb +178 -0
- data/lib/searchgasm/helpers/utilities_helper.rb +125 -0
- data/lib/searchgasm/search/base.rb +73 -179
- data/lib/searchgasm/search/conditions.rb +42 -166
- data/lib/searchgasm/search/ordering.rb +149 -0
- data/lib/searchgasm/search/pagination.rb +69 -0
- data/lib/searchgasm/search/protection.rb +61 -0
- data/lib/searchgasm/utilities.rb +30 -0
- data/lib/searchgasm/version.rb +44 -47
- data/lib/searchgasm.rb +57 -21
- data/searchgasm.gemspec +71 -46
- data/test/test_active_record_associations.rb +1 -1
- data/test/test_active_record_base.rb +4 -4
- data/test/test_condition.rb +143 -0
- data/test/{test_searchgasm_conditions.rb → test_conditions_base.rb} +43 -33
- data/test/test_search_base.rb +189 -0
- data/test/test_search_ordering.rb +91 -0
- data/test/test_search_pagination.rb +56 -0
- data/test/test_search_protection.rb +35 -0
- metadata +70 -45
- data/lib/searchgasm/search/condition.rb +0 -105
- data/lib/searchgasm/search/condition_types/begins_with_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/child_of_condition.rb +0 -17
- data/lib/searchgasm/search/condition_types/contains_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/descendant_of_condition.rb +0 -30
- data/lib/searchgasm/search/condition_types/does_not_equal_condition.rb +0 -34
- data/lib/searchgasm/search/condition_types/ends_with_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/equals_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/greater_than_condition.rb +0 -31
- data/lib/searchgasm/search/condition_types/greater_than_or_equal_to_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/inclusive_descendant_of_condition.rb +0 -19
- data/lib/searchgasm/search/condition_types/keywords_condition.rb +0 -39
- data/lib/searchgasm/search/condition_types/less_than_condition.rb +0 -31
- data/lib/searchgasm/search/condition_types/less_than_or_equal_to_condition.rb +0 -26
- data/lib/searchgasm/search/condition_types/sibling_of_condition.rb +0 -22
- data/lib/searchgasm/search/condition_types/tree_condition.rb +0 -20
- data/lib/searchgasm/search/utilities.rb +0 -34
- data/test/test_searchgasm_base.rb +0 -185
- data/test/test_searchgasm_condition_types.rb +0 -143
@@ -1,76 +1,90 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
1
|
+
module Searchgasm
|
2
|
+
module ActiveRecord #:nodoc: all
|
3
|
+
module Base
|
4
|
+
def calculate_with_searchgasm(*args)
|
5
|
+
options = args.extract_options!
|
6
|
+
options = sanitize_options_with_searchgasm(options)
|
7
|
+
args << options
|
8
|
+
calculate_without_searchgasm(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def find_with_searchgasm(*args)
|
12
|
+
options = args.extract_options!
|
13
|
+
options = sanitize_options_with_searchgasm(options)
|
14
|
+
args << options
|
15
|
+
find_without_searchgasm(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def scope_with_searchgasm(method, key = nil)
|
19
|
+
scope = scope_without_searchgasm(method, key)
|
20
|
+
return sanitize_options_with_searchgasm(scope) if key.nil? && method == :find && !scope.blank?
|
21
|
+
scope
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_conditions(values = {}, &block)
|
25
|
+
conditions = searchgasm_conditions
|
26
|
+
conditions.protect = true
|
27
|
+
conditions.conditions = values
|
28
|
+
yield conditions if block_given?
|
29
|
+
conditions
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_conditions!(values = {}, &block)
|
33
|
+
conditions = searchgasm_conditions(values)
|
34
|
+
yield conditions if block_given?
|
35
|
+
conditions
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_search(options = {}, &block)
|
39
|
+
search = searchgasm_searcher
|
40
|
+
search.protect = true
|
41
|
+
search.options = options
|
42
|
+
yield search if block_given?
|
43
|
+
search
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_search!(options = {}, &block)
|
47
|
+
search = searchgasm_searcher(options)
|
48
|
+
yield search if block_given?
|
49
|
+
search
|
50
|
+
end
|
24
51
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
52
|
+
def conditions_protected(*conditions)
|
53
|
+
write_inheritable_attribute(:conditions_protected, Set.new(conditions.map(&:to_s)) + (protected_conditions || []))
|
54
|
+
end
|
55
|
+
|
56
|
+
def protected_conditions
|
57
|
+
read_inheritable_attribute(:conditions_protected)
|
58
|
+
end
|
32
59
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
60
|
+
def conditions_accessible(*conditions)
|
61
|
+
write_inheritable_attribute(:conditions_accessible, Set.new(conditions.map(&:to_s)) + (protected_conditions || []))
|
62
|
+
end
|
63
|
+
|
64
|
+
def accessible_conditions
|
65
|
+
read_inheritable_attribute(:conditions_accessible)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def sanitize_options_with_searchgasm(options = {})
|
70
|
+
return options unless Searchgasm::Search::Base.needed?(self, options)
|
71
|
+
searchgasm_searcher(options).sanitize
|
37
72
|
end
|
38
73
|
|
39
|
-
def
|
40
|
-
|
41
|
-
search.protect = true
|
42
|
-
search.options = options
|
43
|
-
yield search if block_given?
|
44
|
-
search
|
74
|
+
def searchgasm_conditions(options = {})
|
75
|
+
Searchgasm::Conditions::Base.new(self, options)
|
45
76
|
end
|
46
77
|
|
47
|
-
def
|
48
|
-
|
49
|
-
yield search if block_given?
|
50
|
-
search
|
78
|
+
def searchgasm_searcher(options = {})
|
79
|
+
Searchgasm::Search::Base.new(self, options)
|
51
80
|
end
|
52
|
-
|
53
|
-
private
|
54
|
-
def sanitize_options_with_searchgasm(options = {})
|
55
|
-
return options unless BinaryLogic::Searchgasm::Search::Base.needed?(self, options)
|
56
|
-
searchgasm_searcher(options).sanitize
|
57
|
-
end
|
58
|
-
|
59
|
-
def searchgasm_conditions(options = {})
|
60
|
-
BinaryLogic::Searchgasm::Search::Conditions.new(self, options)
|
61
|
-
end
|
62
|
-
|
63
|
-
def searchgasm_searcher(options = {})
|
64
|
-
BinaryLogic::Searchgasm::Search::Base.new(self, options)
|
65
|
-
end
|
66
|
-
end
|
67
81
|
end
|
68
82
|
end
|
69
83
|
end
|
70
84
|
|
71
|
-
ActiveRecord::Base.send(:extend,
|
85
|
+
ActiveRecord::Base.send(:extend, Searchgasm::ActiveRecord::Base)
|
72
86
|
|
73
|
-
module
|
87
|
+
module ActiveRecord #:nodoc: all
|
74
88
|
class Base
|
75
89
|
class << self
|
76
90
|
alias_method_chain :calculate, :searchgasm
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition # :nodoc:
|
3
|
+
# = Conditions condition
|
4
|
+
#
|
5
|
+
# The base class for creating a condition. Your custom conditions should extend this class.
|
6
|
+
# See Searchgasm::Conditions::Base.register_condition on how to write your own condition.
|
7
|
+
class Base
|
8
|
+
include Utilities
|
9
|
+
|
10
|
+
attr_accessor :column, :klass
|
11
|
+
attr_reader :value
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# Name of the condition inferred from the class name
|
15
|
+
def condition_name
|
16
|
+
name.split("::").last.gsub(/Condition$/, "").underscore
|
17
|
+
end
|
18
|
+
|
19
|
+
# I pass you a column you tell me what to call the condition. If you don't want to use this condition for the column
|
20
|
+
# just return nil
|
21
|
+
def name_for_column(column)
|
22
|
+
"#{column.name}_#{condition_name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Alias methods for the column condition.
|
26
|
+
def aliases_for_column(column)
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sane as name_for_column but for the class as a whole. For example the tree methods apply to the class as a whole and not
|
31
|
+
# specific columns. Any condition that applies to columns should probably return nil here.
|
32
|
+
def name_for_klass(klass)
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# Alias methods for the klass condition
|
37
|
+
def aliases_for_klass(klass)
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
|
41
|
+
# A utility method for using in name_for_column. For example the keywords condition only applied to string columns, the great than condition doesnt.
|
42
|
+
def string_column?(column)
|
43
|
+
[:string, :text].include?(column.type)
|
44
|
+
end
|
45
|
+
|
46
|
+
# A utility method for using in name_for_column. For example you wouldn't want a string column to use the greater thann condition, but you would for an integer column.
|
47
|
+
def comparable_column?(column)
|
48
|
+
[:integer, :float, :decimal, :datetime, :timestamp, :time, :date].include?(column.type)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(klass, column = nil)
|
53
|
+
self.klass = klass
|
54
|
+
self.column = column.is_a?(String) ? klass.columns_hash[column] : column
|
55
|
+
end
|
56
|
+
|
57
|
+
# Allows nils to be meaninful values
|
58
|
+
def explicitly_set_value=(value)
|
59
|
+
@explicitly_set_value = value
|
60
|
+
end
|
61
|
+
|
62
|
+
# Need this if someone wants to actually use nil in a meaningful way
|
63
|
+
def explicitly_set_value?
|
64
|
+
@explicitly_set_value == true
|
65
|
+
end
|
66
|
+
|
67
|
+
# In most cases a blank value should be ignored, except for conditions like equals. A blank value is meaningful there, but a blank value for they keyswords condition is not.
|
68
|
+
def ignore_blanks?
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
# A convenience method for the name of the method for that specific column or klass
|
73
|
+
def name
|
74
|
+
column ? self.class.name_for_column(column) : self.class.name_for_klass(klass)
|
75
|
+
end
|
76
|
+
|
77
|
+
# A convenience method for the name of this condition
|
78
|
+
def condition_name
|
79
|
+
self.class.condition_name
|
80
|
+
end
|
81
|
+
|
82
|
+
# Quotes a column name properly for sql.
|
83
|
+
def quote_column_name(column_name)
|
84
|
+
klass.connection.quote_column_name(column_name)
|
85
|
+
end
|
86
|
+
|
87
|
+
# A convenience method for using when writing your sql in to_conditions. This is the proper way to use a column name in a query for most databases
|
88
|
+
def quoted_column_name
|
89
|
+
quote_column_name(column.name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Quotes a table name properly for sql
|
93
|
+
def quote_table_name(table_name)
|
94
|
+
klass.connection.quote_table_name(table_name)
|
95
|
+
end
|
96
|
+
|
97
|
+
# A convenience method for using when writing your sql in to_conditions. This is the proper way to use a table name in a query for most databases
|
98
|
+
def quoted_table_name
|
99
|
+
quote_table_name(klass.table_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
# You should refrain from overwriting this method, it performs various tasks before callign your to_conditions method, allowing you to keep to_conditions simple.
|
103
|
+
def sanitize(alt_value = nil) # :nodoc:
|
104
|
+
return unless explicitly_set_value?
|
105
|
+
v = alt_value || value
|
106
|
+
if v.is_a?(Array) && !["equals", "does_not_equal"].include?(condition_name)
|
107
|
+
merge_conditions(*v.collect { |i| sanitize(i) })
|
108
|
+
else
|
109
|
+
v = v.utc if column && [:time, :timestamp, :datetime].include?(column.type) && klass.time_zone_aware_attributes && !klass.skip_time_zone_conversion_for_attributes.include?(column.name.to_sym)
|
110
|
+
to_conditions(v)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# The value for the condition
|
115
|
+
def value
|
116
|
+
@value.is_a?(String) ? column.type_cast(@value) : @value
|
117
|
+
end
|
118
|
+
|
119
|
+
# Sets the value for the condition, will ignore place if ignore_blanks?
|
120
|
+
def value=(v)
|
121
|
+
return if ignore_blanks? && v.blank?
|
122
|
+
self.explicitly_set_value = true
|
123
|
+
@value = v
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class BeginsWith < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless string_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
["#{column.name}_bw", "#{column.name}_starts_with", "#{column.name}_start"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_conditions(value)
|
16
|
+
["#{quoted_table_name}.#{quoted_column_name} LIKE ?", "#{value}%"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class ChildOf < Tree
|
4
|
+
def to_conditions(value)
|
5
|
+
parent_association = klass.reflect_on_association(:parent)
|
6
|
+
foreign_key_name = (parent_association && parent_association.options[:foreign_key]) || "parent_id"
|
7
|
+
["#{quoted_table_name}.#{quote_column_name(foreign_key_name)} = ?", (value.is_a?(klass) ? value.send(klass.primary_key) : value)]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class Contains < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless string_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
["#{column.name}_like", "#{column.name}_has"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_conditions(value)
|
16
|
+
["#{quoted_table_name}.#{quoted_column_name} LIKE ?", "%#{value}%"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class DescendantOf < Tree
|
4
|
+
def to_conditions(value)
|
5
|
+
# Wish I knew how to do this in SQL
|
6
|
+
root = (value.is_a?(klass) ? value : klass.find(value)) rescue return
|
7
|
+
strs = []
|
8
|
+
subs = []
|
9
|
+
all_children_ids(root).each do |child_id|
|
10
|
+
strs << "#{quoted_table_name}.#{quote_column_name(klass.primary_key)} = ?"
|
11
|
+
subs << child_id
|
12
|
+
end
|
13
|
+
[strs.join(" OR "), *subs]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def all_children_ids(record)
|
18
|
+
ids = record.children.collect { |child| child.send(klass.primary_key) }
|
19
|
+
record.children.each { |child| ids += all_children_ids(child) }
|
20
|
+
ids
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class DoesNotEqual < Base
|
4
|
+
class << self
|
5
|
+
def aliases_for_column(column)
|
6
|
+
["#{column.name}_is_not", "#{column.name}_not"]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def ignore_blanks?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_conditions(value)
|
15
|
+
# Delegate to equals and then change
|
16
|
+
condition = Equals.new(klass, column)
|
17
|
+
condition.value = value
|
18
|
+
|
19
|
+
sql = condition.sanitize
|
20
|
+
sql.gsub!(/ IS /, " IS NOT ")
|
21
|
+
sql.gsub!(/ BETWEEN /, " NOT BETWEEN ")
|
22
|
+
sql.gsub!(/ IN /, " NOT IN ")
|
23
|
+
sql.gsub!(/=/, "!=")
|
24
|
+
sql
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class EndsWith < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless string_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
["#{column.name}_ew", "#{column.name}_ends", "#{column.name}_end"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_conditions(value)
|
16
|
+
["#{quoted_table_name}.#{quoted_column_name} LIKE ?", "%#{value}"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class Equals < Base
|
4
|
+
class << self
|
5
|
+
def aliases_for_column(column)
|
6
|
+
["#{column.name}", "#{column.name}_is"]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def ignore_blanks?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_conditions(value)
|
15
|
+
# Let ActiveRecord handle this
|
16
|
+
klass.send(:sanitize_sql_hash_for_conditions, {column.name => value})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class GreaterThan < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless comparable_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
column_names = [column.name]
|
12
|
+
column_names << column.name.gsub(/_at$/, "") if [:datetime, :timestamp, :time, :date].include?(column.type) && column.name =~ /_at$/
|
13
|
+
|
14
|
+
aliases = []
|
15
|
+
column_names.each { |column_name| aliases += ["#{column_name}_gt", "#{column_name}_after"] }
|
16
|
+
aliases
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_conditions(value)
|
21
|
+
["#{quoted_table_name}.#{quoted_column_name} > ?", value]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class GreaterThanOrEqualTo < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless comparable_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
["#{column.name}_gte", "#{column.name}_at_least"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_conditions(value)
|
16
|
+
["#{quoted_table_name}.#{quoted_column_name} >= ?", value]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class InclusiveDescendantOf < Tree
|
4
|
+
include Searchgasm::Utilities
|
5
|
+
|
6
|
+
def to_conditions(value)
|
7
|
+
condition = DescendantOf.new(klass, column)
|
8
|
+
condition.value = value
|
9
|
+
merge_conditions(["#{quoted_table_name}.#{quote_column_name(klass.primary_key)} = ?", (value.is_a?(klass) ? value.send(klass.primary_key) : value)], condition.sanitize, :any => true)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class Keywords < Base
|
4
|
+
BLACKLISTED_WORDS = ('a'..'z').to_a + ["about", "an", "are", "as", "at", "be", "by", "com", "de", "en", "for", "from", "how", "in", "is", "it", "la", "of", "on", "or", "that", "the", "the", "this", "to", "und", "was", "what", "when", "where", "who", "will", "with", "www"] # from ranks.nl
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def name_for_column(column)
|
8
|
+
return unless string_column?(column)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def aliases_for_column(column)
|
13
|
+
["#{column.name}_kwords", "#{column.name}_kw"]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_conditions(value)
|
18
|
+
strs = []
|
19
|
+
subs = []
|
20
|
+
|
21
|
+
search_parts = value.gsub(/,/, " ").split(/ /).collect { |word| word.downcase.gsub(/[^[:alnum:]]/, ''); }.uniq.select { |word| !BLACKLISTED_WORDS.include?(word.downcase) && !word.blank? }
|
22
|
+
return if search_parts.blank?
|
23
|
+
|
24
|
+
search_parts.each do |search_part|
|
25
|
+
strs << "#{quoted_table_name}.#{quoted_column_name} LIKE ?"
|
26
|
+
subs << "%#{search_part}%"
|
27
|
+
end
|
28
|
+
|
29
|
+
[strs.join(" AND "), *subs]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class LessThan < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless comparable_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
column_names = [column.name]
|
12
|
+
column_names << column.name.gsub(/_at$/, "") if [:datetime, :timestamp, :time, :date].include?(column.type) && column.name =~ /_at$/
|
13
|
+
|
14
|
+
aliases = []
|
15
|
+
column_names.each { |column_name| aliases += ["#{column_name}_lt", "#{column_name}_before"] }
|
16
|
+
aliases
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_conditions(value)
|
21
|
+
["#{quoted_table_name}.#{quoted_column_name} < ?", value]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class LessThanOrEqualTo < Base
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
return unless comparable_column?(column)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def aliases_for_column(column)
|
11
|
+
["#{column.name}_lte", "#{column.name}_at_most"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_conditions(value)
|
16
|
+
["#{quoted_table_name}.#{quoted_column_name} <= ?", value]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class SiblingOf < Tree
|
4
|
+
include Searchgasm::Utilities
|
5
|
+
|
6
|
+
def to_conditions(value)
|
7
|
+
parent_association = klass.reflect_on_association(:parent)
|
8
|
+
foreign_key_name = (parent_association && parent_association.options[:foreign_key]) || "parent_id"
|
9
|
+
parent_id = (value.is_a?(klass) ? value : klass.find(value)).send(foreign_key_name)
|
10
|
+
condition = ChildOf.new(klass, column)
|
11
|
+
condition.value = parent_id
|
12
|
+
merge_conditions(["#{quoted_table_name}.#{quote_column_name(klass.primary_key)} != ?", (value.is_a?(klass) ? value.send(klass.primary_key) : value)], condition.sanitize)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module Condition
|
3
|
+
class Tree < Base # :nodoc:
|
4
|
+
class << self
|
5
|
+
def name_for_column(column)
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def name_for_klass(klass)
|
10
|
+
return unless klass.reflect_on_association(:parent) && klass.reflect_on_association(:children)
|
11
|
+
condition_name
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|