search_cop 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -25,6 +25,7 @@ gemfile:
25
25
  - gemfiles/3.2.gemfile
26
26
  - gemfiles/4.0.gemfile
27
27
  - gemfiles/4.1.gemfile
28
+ - gemfiles/4.2.gemfile
28
29
 
29
30
  install:
30
31
  - "travis_retry bundle install"
data/Appraisals CHANGED
@@ -12,3 +12,9 @@ appraise "4.1" do
12
12
  gem "activerecord", "~> 4.1.0.beta"
13
13
  gem "search_cop", :path => "../"
14
14
  end
15
+
16
+ appraise "4.2" do
17
+ gem "activerecord", "~> 4.2.0.beta"
18
+ gem "search_cop", :path => "../"
19
+ end
20
+
data/README.md CHANGED
@@ -97,7 +97,7 @@ end
97
97
 
98
98
  ## How does it work
99
99
 
100
- SearchCop parses the query and maps it to an SQL Query using Arel.
100
+ SearchCop parses the query and maps it to an SQL Query in a database agnostic way.
101
101
  Thus, SearchCop is not bound to a specific RDBMS.
102
102
 
103
103
  ```ruby
@@ -0,0 +1,26 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.2.0.beta"
6
+ gem "search_cop", :path => "../"
7
+
8
+ platforms :jruby do
9
+ gem "activerecord-jdbcmysql-adapter"
10
+ gem "activerecord-jdbcsqlite3-adapter"
11
+ gem "activerecord-jdbcpostgresql-adapter"
12
+ end
13
+
14
+ platforms :ruby do
15
+ gem "sqlite3"
16
+ gem "mysql2"
17
+ gem "pg"
18
+ end
19
+
20
+ platforms :rbx do
21
+ gem "racc"
22
+ gem "rubysl", "~> 2.0"
23
+ gem "psych"
24
+ end
25
+
26
+ gemspec :path => "../"
@@ -9,7 +9,7 @@ module SearchCop
9
9
 
10
10
  arel = SearchCop::Parser.parse(query, query_info).optimize!
11
11
 
12
- self.sql = model.connection.visitor.accept(arel)
12
+ self.sql = SearchCop::Visitors::Visitor.new(model.connection).visit(arel)
13
13
  end
14
14
 
15
15
  def associations
@@ -29,7 +29,7 @@ module SearchCop
29
29
  def attributes(*args)
30
30
  args.each do |arg|
31
31
  attributes_hash arg.is_a?(Hash) ? arg : { arg => arg }
32
- end
32
+ end
33
33
  end
34
34
 
35
35
  def options(key, options = {})
@@ -54,8 +54,8 @@ module SearchCop
54
54
  table, attribute = column.to_s =~ /\./ ? column.to_s.split(".") : [model.name.tableize, column]
55
55
 
56
56
  "#{table}.#{attribute}"
57
- end
58
- end
57
+ end
58
+ end
59
59
  end
60
60
  end
61
61
  end
@@ -1,3 +1,3 @@
1
1
  module SearchCop
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -0,0 +1,43 @@
1
+
2
+ module SearchCop
3
+ module Visitors
4
+ module Mysql
5
+ class FulltextQuery < Visitor
6
+ def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(node)
7
+ node.right.split(/[\s+'"<>()~-]+/).collect { |word| "-#{word}" }.join(" ")
8
+ end
9
+
10
+ def visit_SearchCopGrammar_Nodes_MatchesFulltext(node)
11
+ words = node.right.split(/[\s+'"<>()~-]+/)
12
+
13
+ words.size > 1 ? "\"#{words.join " "}\"" : words.first
14
+ end
15
+
16
+ def visit_SearchCopGrammar_Nodes_And_Fulltext(node)
17
+ res = node.nodes.collect do |node|
18
+ if node.is_a?(SearchCopGrammar::Nodes::MatchesFulltextNot)
19
+ visit node
20
+ else
21
+ node.nodes.size > 1 ? "+(#{visit node})" : "+#{visit node}"
22
+ end
23
+ end
24
+
25
+ res.join " "
26
+ end
27
+
28
+ def visit_SearchCopGrammar_Nodes_Or_Fulltext(node)
29
+ node.nodes.collect { |node| "(#{visit node})" }.join(" ")
30
+ end
31
+ end
32
+
33
+ def visit_SearchCopGrammar_Attributes_Collection(node)
34
+ node.attributes.collect { |attribute| visit attribute }.join(", ")
35
+ end
36
+
37
+ def visit_SearchCopGrammar_Nodes_FulltextExpression(node)
38
+ "MATCH(#{visit node.collection}) AGAINST(#{visit FulltextQuery.new(connection).visit(node.node)} IN BOOLEAN MODE)"
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,39 @@
1
+
2
+ module SearchCop
3
+ module Visitors
4
+ module Postgres
5
+ class FulltextQuery < Visitor
6
+ def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(node)
7
+ "!'#{node.right.gsub /[\s&|!:'"]+/, " "}'"
8
+ end
9
+
10
+ def visit_SearchCopGrammar_Nodes_MatchesFulltext(node)
11
+ "'#{node.right.gsub /[\s&|!:'"]+/, " "}'"
12
+ end
13
+
14
+ def visit_SearchCopGrammar_Nodes_And_Fulltext(node)
15
+ node.nodes.collect { |node| "(#{visit node})" }.join(" & ")
16
+ end
17
+
18
+ def visit_SearchCopGrammar_Nodes_Or_Fulltext(node)
19
+ node.nodes.collect { |node| "(#{visit node})" }.join(" | ")
20
+ end
21
+ end
22
+
23
+ def visit_SearchCopGrammar_Nodes_Matches(node)
24
+ "#{visit node.left} ILIKE #{visit node.right}"
25
+ end
26
+
27
+ def visit_SearchCopGrammar_Attributes_Collection(node)
28
+ node.attributes.collect { |attribute| visit attribute }.join(" || ' ' || ")
29
+ end
30
+
31
+ def visit_SearchCopGrammar_Nodes_FulltextExpression(node)
32
+ dictionary = node.collection.options[:dictionary] || "simple"
33
+
34
+ "to_tsvector(#{visit dictionary}, #{visit node.collection}) @@ to_tsquery(#{visit dictionary}, #{visit FulltextQuery.new(connection).visit(node.node)})"
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,96 @@
1
+
2
+ module SearchCop
3
+ module Visitors
4
+ class Visitor
5
+ attr_accessor :connection
6
+
7
+ def initialize(connection)
8
+ @connection = connection
9
+
10
+ extend(SearchCop::Visitors::Mysql) if @connection.class.name =~ /mysql/i
11
+ extend(SearchCop::Visitors::Postgres) if @connection.class.name =~ /postgres/i
12
+ end
13
+
14
+ def visit(visit_node = node)
15
+ send "visit_#{visit_node.class.name.gsub /::/, "_"}", visit_node
16
+ end
17
+
18
+ def visit_SearchCopGrammar_Nodes_And(node)
19
+ "(#{node.nodes.collect { |n| visit n }.join(" AND ")})"
20
+ end
21
+
22
+ def visit_SearchCopGrammar_Nodes_Or(node)
23
+ "(#{node.nodes.collect { |n| visit n }.join(" OR ")})"
24
+ end
25
+
26
+ def visit_SearchCopGrammar_Nodes_GreaterThan(node)
27
+ "#{visit node.left} > #{visit node.right}"
28
+ end
29
+
30
+ def visit_SearchCopGrammar_Nodes_GreaterThanOrEqual(node)
31
+ "#{visit node.left} >= #{visit node.right}"
32
+ end
33
+
34
+ def visit_SearchCopGrammar_Nodes_LessThan(node)
35
+ "#{visit node.left} < #{visit node.right}"
36
+ end
37
+
38
+ def visit_SearchCopGrammar_Nodes_LessThanOrEqual(node)
39
+ "#{visit node.left} <= #{visit node.right}"
40
+ end
41
+
42
+ def visit_SearchCopGrammar_Nodes_Equality(node)
43
+ "#{visit node.left} = #{visit node.right}"
44
+ end
45
+
46
+ def visit_SearchCopGrammar_Nodes_NotEqual(node)
47
+ "#{visit node.left} != #{visit node.right}"
48
+ end
49
+
50
+ def visit_SearchCopGrammar_Nodes_Matches(node)
51
+ "#{visit node.left} LIKE #{visit node.right}"
52
+ end
53
+
54
+ def visit_SearchCopGrammar_Nodes_Not(node)
55
+ "NOT (#{visit node.object})"
56
+ end
57
+
58
+ def quote_table_name(name)
59
+ connection.quote_table_name name
60
+ end
61
+
62
+ def quote_column_name(name)
63
+ connection.quote_column_name name
64
+ end
65
+
66
+ def visit_attribute(attribute)
67
+ "#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}"
68
+ end
69
+
70
+ alias :visit_SearchCopGrammar_Attributes_String :visit_attribute
71
+ alias :visit_SearchCopGrammar_Attributes_Text :visit_attribute
72
+ alias :visit_SearchCopGrammar_Attributes_Float :visit_attribute
73
+ alias :visit_SearchCopGrammar_Attributes_Integer :visit_attribute
74
+ alias :visit_SearchCopGrammar_Attributes_Decimal :visit_attribute
75
+ alias :visit_SearchCopGrammar_Attributes_Datetime :visit_attribute
76
+ alias :visit_SearchCopGrammar_Attributes_Timestamp :visit_attribute
77
+ alias :visit_SearchCopGrammar_Attributes_Date :visit_attribute
78
+ alias :visit_SearchCopGrammar_Attributes_Time :visit_attribute
79
+ alias :visit_SearchCopGrammar_Attributes_Boolean :visit_attribute
80
+
81
+ def quote(value)
82
+ connection.quote value
83
+ end
84
+
85
+ alias :visit_TrueClass :quote
86
+ alias :visit_FalseClass :quote
87
+ alias :visit_String :quote
88
+ alias :visit_Time :quote
89
+ alias :visit_Date :quote
90
+ alias :visit_Float :quote
91
+ alias :visit_Fixnum :quote
92
+ alias :visit_Symbol :quote
93
+ end
94
+ end
95
+ end
96
+
@@ -0,0 +1,5 @@
1
+
2
+ require "search_cop/visitors/visitor"
3
+ require "search_cop/visitors/mysql"
4
+ require "search_cop/visitors/postgres"
5
+
data/lib/search_cop.rb CHANGED
@@ -1,11 +1,11 @@
1
1
 
2
2
  require "search_cop/version"
3
- require "search_cop/arel"
4
3
  require "search_cop/search_scope"
5
4
  require "search_cop/query_info"
6
5
  require "search_cop/query_builder"
7
6
  require "search_cop/grammar_parser"
8
7
  require "search_cop/hash_parser"
8
+ require "search_cop/visitors"
9
9
 
10
10
  module SearchCop
11
11
  class SpecificationError < StandardError; end
@@ -82,16 +82,18 @@ module SearchCopGrammar
82
82
 
83
83
  raise(SearchCop::UnknownAttribute, "Unknown attribute #{attribute_definition}") unless klass.columns_hash[column]
84
84
 
85
- Attributes.const_get(klass.columns_hash[column].type.to_s.classify).new(klass.arel_table.alias(alias_for(table))[column], klass, options)
85
+ Attributes.const_get(klass.columns_hash[column].type.to_s.classify).new(klass, alias_for(table), column, options)
86
86
  end
87
87
  end
88
88
 
89
89
  class Base
90
- attr_reader :attribute, :options
90
+ attr_reader :attribute, :table_alias, :column_name, :options
91
91
 
92
- def initialize(attribute, klass, options = {})
93
- @attribute = attribute
92
+ def initialize(klass, table_alias, column_name, options = {})
93
+ @attribute = klass.arel_table.alias(table_alias)[column_name]
94
94
  @klass = klass
95
+ @table_alias = table_alias
96
+ @column_name = column_name
95
97
  @options = (options || {})
96
98
  end
97
99
 
@@ -115,16 +117,16 @@ module SearchCopGrammar
115
117
  define_method method do |value|
116
118
  raise(SearchCop::IncompatibleDatatype, "Incompatible datatype for #{value}") unless compatible?(value)
117
119
 
118
- SearchCopGrammar::Nodes.const_get(class_name).new(@attribute, map(value))
120
+ SearchCopGrammar::Nodes.const_get(class_name).new(self, map(value))
119
121
  end
120
122
  end
121
123
 
122
124
  def method_missing(name, *args, &block)
123
- @attribute.send name, *args, &block
125
+ @attribute.send(name, *args, &block)
124
126
  end
125
127
 
126
128
  def respond_to?(*args)
127
- @attribute.respond_to? *args
129
+ super(*args) || @attribute.respond_to?(*args)
128
130
  end
129
131
  end
130
132
 
@@ -154,9 +156,18 @@ module SearchCopGrammar
154
156
 
155
157
  false
156
158
  end
159
+
160
+ def map(value)
161
+ value.to_f
162
+ end
163
+ end
164
+
165
+ class Integer < Float
166
+ def map(value)
167
+ value.to_i
168
+ end
157
169
  end
158
170
 
159
- class Integer < Float; end
160
171
  class Decimal < Float; end
161
172
 
162
173
  class Datetime < WithoutMatches
@@ -159,7 +159,7 @@ module SearchCopGrammar
159
159
  def initialize(collection, *nodes)
160
160
  @collection = collection
161
161
 
162
- super *nodes
162
+ super(*nodes)
163
163
  end
164
164
 
165
165
  def fulltext?
@@ -21,7 +21,7 @@ grammar SearchCopGrammar
21
21
  end
22
22
 
23
23
  rule parentheses_expression
24
- '(' complex_expression ')' <ParenthesesExpression>
24
+ '(' complex_expression ')' <ParenthesesExpression>
25
25
  end
26
26
 
27
27
  rule not_expression
data/test/test_helper.rb CHANGED
@@ -146,5 +146,17 @@ class SearchCop::TestCase
146
146
  def assert_not_nil(value)
147
147
  assert value
148
148
  end
149
+
150
+ def quote_table_name(name)
151
+ ActiveRecord::Base.connection.quote_table_name name
152
+ end
153
+
154
+ def quote_column_name(name)
155
+ ActiveRecord::Base.connection.quote_column_name name
156
+ end
157
+
158
+ def quote(object)
159
+ ActiveRecord::Base.connection.quote object
160
+ end
149
161
  end
150
162
 
@@ -0,0 +1,101 @@
1
+
2
+ require File.expand_path("../test_helper", __FILE__)
3
+
4
+ class VisitorTest < SearchCop::TestCase
5
+ def test_and
6
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gt(0).and(SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lt(2))
7
+
8
+ assert_equal "(#{quote_table_name "products"}.#{quote_column_name "stock"} > 0 AND #{quote_table_name "products"}.#{quote_column_name "stock"} < 2)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
9
+ end
10
+
11
+ def test_or
12
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gt(0).or(SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lt(2))
13
+
14
+ assert_equal "(#{quote_table_name "products"}.#{quote_column_name "stock"} > 0 OR #{quote_table_name "products"}.#{quote_column_name "stock"} < 2)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
15
+ end
16
+
17
+ def test_greater_than
18
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gt(1)
19
+
20
+ assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} > 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
21
+ end
22
+
23
+ def test_greater_than_or_equal
24
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gteq(1)
25
+
26
+ assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} >= 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
27
+ end
28
+
29
+ def test_less_than
30
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lt(1)
31
+
32
+ assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} < 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
33
+ end
34
+
35
+ def test_less_than_or_equal
36
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lteq(1)
37
+
38
+ assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} <= 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
39
+ end
40
+
41
+ def test_equality
42
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").eq(1)
43
+
44
+ assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} = 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
45
+ end
46
+
47
+ def test_not_equal
48
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").not_eq(1)
49
+
50
+ assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} != 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
51
+ end
52
+
53
+ def test_matches
54
+ node = SearchCopGrammar::Attributes::String.new(Product, "products", "notice").matches("Notice")
55
+
56
+ assert_equal("#{quote_table_name "products"}.#{quote_column_name "notice"} LIKE #{quote "%Notice%"}", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] != "postgres"
57
+ assert_equal("#{quote_table_name "products"}.#{quote_column_name "notice"} ILIKE #{quote "%Notice%"}", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
58
+ end
59
+
60
+ def test_not
61
+ node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").eq(1).not
62
+
63
+ assert_equal "NOT (#{quote_table_name "products"}.#{quote_column_name "stock"} = 1)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
64
+ end
65
+
66
+ def test_attribute
67
+ # Already tested
68
+ end
69
+
70
+ def test_quote
71
+ assert_equal quote("Test"), SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit("Test")
72
+ end
73
+
74
+ def test_fulltext
75
+ node = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query").optimize!
76
+
77
+ assert_equal("MATCH(`products`.`title`) AGAINST('Query' IN BOOLEAN MODE)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "mysql"
78
+ assert_equal("to_tsvector('english', \"products\".\"title\") @@ to_tsquery('english', '''Query''')", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
79
+ end
80
+
81
+ def test_fulltext_and
82
+ query1 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query1")
83
+ query2 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query2")
84
+
85
+ node = query1.and(query2).optimize!
86
+
87
+ assert_equal("(MATCH(`products`.`title`) AGAINST('+Query1 +Query2' IN BOOLEAN MODE))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "mysql"
88
+ assert_equal("(to_tsvector('english', \"products\".\"title\") @@ to_tsquery('english', '(''Query1'') & (''Query2'')'))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
89
+ end
90
+
91
+ def test_fulltext_or
92
+ query1 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query1")
93
+ query2 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query2")
94
+
95
+ node = query1.or(query2).optimize!
96
+
97
+ assert_equal("(MATCH(`products`.`title`) AGAINST('(Query1) (Query2)' IN BOOLEAN MODE))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "mysql"
98
+ assert_equal("(to_tsvector('english', \"products\".\"title\") @@ to_tsquery('english', '(''Query1'') | (''Query2'')'))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
99
+ end
100
+ end
101
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: search_cop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-16 00:00:00.000000000 Z
12
+ date: 2014-12-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: treetop
@@ -142,15 +142,18 @@ files:
142
142
  - gemfiles/3.2.gemfile
143
143
  - gemfiles/4.0.gemfile
144
144
  - gemfiles/4.1.gemfile
145
+ - gemfiles/4.2.gemfile
145
146
  - lib/search_cop.rb
146
- - lib/search_cop/arel.rb
147
- - lib/search_cop/arel/visitors.rb
148
147
  - lib/search_cop/grammar_parser.rb
149
148
  - lib/search_cop/hash_parser.rb
150
149
  - lib/search_cop/query_builder.rb
151
150
  - lib/search_cop/query_info.rb
152
151
  - lib/search_cop/search_scope.rb
153
152
  - lib/search_cop/version.rb
153
+ - lib/search_cop/visitors.rb
154
+ - lib/search_cop/visitors/mysql.rb
155
+ - lib/search_cop/visitors/postgres.rb
156
+ - lib/search_cop/visitors/visitor.rb
154
157
  - lib/search_cop_grammar.rb
155
158
  - lib/search_cop_grammar.treetop
156
159
  - lib/search_cop_grammar/attributes.rb
@@ -172,6 +175,7 @@ files:
172
175
  - test/search_cop_test.rb
173
176
  - test/string_test.rb
174
177
  - test/test_helper.rb
178
+ - test/visitor_test.rb
175
179
  homepage: https://github.com/mrkamel/search_cop
176
180
  licenses:
177
181
  - MIT
@@ -215,3 +219,4 @@ test_files:
215
219
  - test/search_cop_test.rb
216
220
  - test/string_test.rb
217
221
  - test/test_helper.rb
222
+ - test/visitor_test.rb
@@ -1,223 +0,0 @@
1
-
2
- module SearchCop
3
- module Arel
4
- module Visitors
5
- module ToSql
6
- if ::Arel::VERSION >= "4.0.1"
7
- def visit_SearchCopGrammar_Nodes_And(o, a)
8
- visit ::Arel::Nodes::Grouping.new(o.nodes.inject { |res, cur| ::Arel::Nodes::And.new [res, cur] }), a
9
- end
10
-
11
- def visit_SearchCopGrammar_Nodes_Or(o, a)
12
- visit ::Arel::Nodes::Grouping.new(o.nodes.inject { |res, cur| ::Arel::Nodes::Or.new res, cur }), a
13
- end
14
-
15
- def visit_SearchCopGrammar_Nodes_Equality(o, a)
16
- visit ::Arel::Nodes::Equality.new(o.left, o.right), a
17
- end
18
-
19
- def visit_SearchCopGrammar_Nodes_NotEqual(o, a)
20
- visit ::Arel::Nodes::NotEqual.new(o.left, o.right), a
21
- end
22
-
23
- def visit_SearchCopGrammar_Nodes_LessThan(o, a)
24
- visit ::Arel::Nodes::LessThan.new(o.left, o.right), a
25
- end
26
-
27
- def visit_SearchCopGrammar_Nodes_LessThanOrEqual(o, a)
28
- visit ::Arel::Nodes::LessThanOrEqual.new(o.left, o.right), a
29
- end
30
-
31
- def visit_SearchCopGrammar_Nodes_GreaterThan(o, a)
32
- visit ::Arel::Nodes::GreaterThan.new(o.left, o.right), a
33
- end
34
-
35
- def visit_SearchCopGrammar_Nodes_GreaterThanOrEqual(o, a)
36
- visit ::Arel::Nodes::GreaterThanOrEqual.new(o.left, o.right), a
37
- end
38
-
39
- def visit_SearchCopGrammar_Nodes_Not(o, a)
40
- visit ::Arel::Nodes::Not.new(o.object), a
41
- end
42
-
43
- def visit_SearchCopGrammar_Nodes_Matches(o, a)
44
- visit ::Arel::Nodes::Matches.new(o.left, o.right), a
45
- end
46
- else
47
- def visit_SearchCopGrammar_Nodes_And(o)
48
- visit ::Arel::Nodes::Grouping.new(o.nodes.inject { |res, cur| ::Arel::Nodes::And.new [res, cur] })
49
- end
50
-
51
- def visit_SearchCopGrammar_Nodes_Or(o)
52
- visit ::Arel::Nodes::Grouping.new(o.nodes.inject { |res, cur| ::Arel::Nodes::Or.new res, cur })
53
- end
54
-
55
- def visit_SearchCopGrammar_Nodes_Equality(o)
56
- visit ::Arel::Nodes::Equality.new(o.left, o.right)
57
- end
58
-
59
- def visit_SearchCopGrammar_Nodes_NotEqual(o)
60
- visit ::Arel::Nodes::NotEqual.new(o.left, o.right)
61
- end
62
-
63
- def visit_SearchCopGrammar_Nodes_LessThan(o)
64
- visit ::Arel::Nodes::LessThan.new(o.left, o.right)
65
- end
66
-
67
- def visit_SearchCopGrammar_Nodes_LessThanOrEqual(o)
68
- visit ::Arel::Nodes::LessThanOrEqual.new(o.left, o.right)
69
- end
70
-
71
- def visit_SearchCopGrammar_Nodes_GreaterThan(o)
72
- visit ::Arel::Nodes::GreaterThan.new(o.left, o.right)
73
- end
74
-
75
- def visit_SearchCopGrammar_Nodes_GreaterThanOrEqual(o)
76
- visit ::Arel::Nodes::GreaterThanOrEqual.new(o.left, o.right)
77
- end
78
-
79
- def visit_SearchCopGrammar_Nodes_Not(o)
80
- visit ::Arel::Nodes::Not.new(o.object)
81
- end
82
-
83
- def visit_SearchCopGrammar_Nodes_Matches(o)
84
- visit ::Arel::Nodes::Matches.new(o.left, o.right)
85
- end
86
- end
87
- end
88
-
89
- module MySQL
90
- if ::Arel::VERSION >= "4.0.1"
91
- def visit_SearchCopGrammar_Attributes_Collection(o, a)
92
- o.attributes.collect { |attribute| visit attribute.attribute, a }.join(", ")
93
- end
94
-
95
- def visit_SearchCopGrammar_Nodes_FulltextExpression(o, a)
96
- "MATCH(#{visit o.collection, a}) AGAINST(#{visit visit(o.node, a), a} IN BOOLEAN MODE)"
97
- end
98
-
99
- def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(o, a)
100
- o.right.split(/[\s+'"<>()~-]+/).collect { |word| "-#{word}" }.join(" ")
101
- end
102
-
103
- def visit_SearchCopGrammar_Nodes_MatchesFulltext(o, a)
104
- words = o.right.split(/[\s+'"<>()~-]+/)
105
-
106
- words.size > 1 ? "\"#{words.join " "}\"" : words.first
107
- end
108
-
109
- def visit_SearchCopGrammar_Nodes_And_Fulltext(o, a)
110
- res = o.nodes.collect do |node|
111
- if node.is_a?(SearchCopGrammar::Nodes::MatchesFulltextNot)
112
- visit node, a
113
- else
114
- node.nodes.size > 1 ? "+(#{visit node, a})" : "+#{visit node, a}"
115
- end
116
- end
117
-
118
- res.join " "
119
- end
120
-
121
- def visit_SearchCopGrammar_Nodes_Or_Fulltext(o, a)
122
- o.nodes.collect { |node| "(#{visit node, a})" }.join(" ")
123
- end
124
- else
125
- def visit_SearchCopGrammar_Attributes_Collection(o)
126
- o.attributes.collect { |attribute| visit attribute.attribute }.join(", ")
127
- end
128
-
129
- def visit_SearchCopGrammar_Nodes_FulltextExpression(o)
130
- "MATCH(#{visit o.collection}) AGAINST(#{visit visit(o.node)} IN BOOLEAN MODE)"
131
- end
132
-
133
- def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(o)
134
- o.right.split(/[\s+'"<>()~-]+/).collect { |word| "-#{word}" }.join(" ")
135
- end
136
-
137
- def visit_SearchCopGrammar_Nodes_MatchesFulltext(o)
138
- words = o.right.split(/[\s+'"<>()~-]+/)
139
-
140
- words.size > 1 ? "\"#{words.join " "}\"" : words.first
141
- end
142
-
143
- def visit_SearchCopGrammar_Nodes_And_Fulltext(o)
144
- res = o.nodes.collect do |node|
145
- if node.is_a?(SearchCopGrammar::Nodes::MatchesFulltextNot)
146
- visit node
147
- else
148
- node.nodes.size > 1 ? "+(#{visit node})" : "+#{visit node}"
149
- end
150
- end
151
-
152
- res.join " "
153
- end
154
-
155
- def visit_SearchCopGrammar_Nodes_Or_Fulltext(o)
156
- o.nodes.collect { |node| "(#{visit node})" }.join(" ")
157
- end
158
- end
159
- end
160
-
161
- module PostgreSQL
162
- if ::Arel::VERSION >= "4.0.1"
163
- def visit_SearchCopGrammar_Attributes_Collection(o, a)
164
- o.attributes.collect { |attribute| visit attribute.attribute, a }.join(" || ' ' || ")
165
- end
166
-
167
- def visit_SearchCopGrammar_Nodes_FulltextExpression(o, a)
168
- dictionary = o.collection.options[:dictionary] || "simple"
169
-
170
- "to_tsvector(#{visit dictionary, a}, #{visit o.collection, a}) @@ to_tsquery(#{visit dictionary, a}, #{visit visit(o.node, a), a})"
171
- end
172
-
173
- def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(o, a)
174
- "!'#{o.right}'"
175
- end
176
-
177
- def visit_SearchCopGrammar_Nodes_MatchesFulltext(o, a)
178
- "'#{o.right.gsub /[\s&|!:'"]+/, " "}'"
179
- end
180
-
181
- def visit_SearchCopGrammar_Nodes_And_Fulltext(o, a)
182
- o.nodes.collect { |node| "(#{visit node, a})" }.join(" & ")
183
- end
184
-
185
- def visit_SearchCopGrammar_Nodes_Or_Fulltext(o, a)
186
- o.nodes.collect { |node| "(#{visit node, a})" }.join(" | ")
187
- end
188
- else
189
- def visit_SearchCopGrammar_Attributes_Collection(o)
190
- o.attributes.collect { |attribute| visit attribute.attribute }.join(" || ' ' || ")
191
- end
192
-
193
- def visit_SearchCopGrammar_Nodes_FulltextExpression(o)
194
- dictionary = o.collection.options[:dictionary] || "simple"
195
-
196
- "to_tsvector(#{visit dictionary.to_sym}, #{visit o.collection}) @@ to_tsquery(#{visit dictionary.to_sym}, #{visit visit(o.node)})" # to_sym fixes a 3.2 + postgres bug
197
- end
198
-
199
- def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(o)
200
- "!'#{o.right}'"
201
- end
202
-
203
- def visit_SearchCopGrammar_Nodes_MatchesFulltext(o)
204
- "'#{o.right.gsub /[\s&|!:'"]+/, " "}'"
205
- end
206
-
207
- def visit_SearchCopGrammar_Nodes_And_Fulltext(o)
208
- o.nodes.collect { |node| "(#{visit node})" }.join(" & ")
209
- end
210
-
211
- def visit_SearchCopGrammar_Nodes_Or_Fulltext(o)
212
- o.nodes.collect { |node| "(#{visit node})" }.join(" | ")
213
- end
214
- end
215
- end
216
- end
217
- end
218
- end
219
-
220
- Arel::Visitors::PostgreSQL.send :include, SearchCop::Arel::Visitors::PostgreSQL
221
- Arel::Visitors::MySQL.send :include, SearchCop::Arel::Visitors::MySQL
222
- Arel::Visitors::ToSql.send :include, SearchCop::Arel::Visitors::ToSql
223
-
@@ -1,4 +0,0 @@
1
-
2
- require "arel"
3
- require "search_cop/arel/visitors"
4
-