search_cop 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +42 -0
  3. data/.rubocop.yml +128 -0
  4. data/CHANGELOG.md +14 -9
  5. data/Gemfile +4 -5
  6. data/README.md +11 -1
  7. data/Rakefile +0 -1
  8. data/docker-compose.yml +8 -1
  9. data/gemfiles/{5.1.gemfile → rails5.gemfile} +2 -2
  10. data/gemfiles/rails6.gemfile +13 -0
  11. data/lib/search_cop.rb +5 -23
  12. data/lib/search_cop/grammar_parser.rb +1 -3
  13. data/lib/search_cop/hash_parser.rb +19 -19
  14. data/lib/search_cop/helpers.rb +15 -0
  15. data/lib/search_cop/query_builder.rb +0 -2
  16. data/lib/search_cop/query_info.rb +0 -2
  17. data/lib/search_cop/search_scope.rb +2 -4
  18. data/lib/search_cop/version.rb +1 -1
  19. data/lib/search_cop/visitors.rb +0 -2
  20. data/lib/search_cop/visitors/mysql.rb +4 -2
  21. data/lib/search_cop/visitors/postgres.rb +5 -3
  22. data/lib/search_cop/visitors/visitor.rb +5 -3
  23. data/lib/search_cop_grammar.rb +1 -3
  24. data/lib/search_cop_grammar/attributes.rb +45 -34
  25. data/lib/search_cop_grammar/nodes.rb +0 -2
  26. data/search_cop.gemspec +8 -8
  27. data/test/and_test.rb +6 -8
  28. data/test/boolean_test.rb +7 -9
  29. data/test/database.yml +2 -1
  30. data/test/date_test.rb +14 -16
  31. data/test/datetime_test.rb +15 -17
  32. data/test/default_operator_test.rb +14 -10
  33. data/test/error_test.rb +2 -4
  34. data/test/float_test.rb +9 -11
  35. data/test/fulltext_test.rb +6 -8
  36. data/test/hash_test.rb +32 -34
  37. data/test/integer_test.rb +9 -11
  38. data/test/not_test.rb +6 -8
  39. data/test/or_test.rb +8 -10
  40. data/test/scope_test.rb +11 -13
  41. data/test/search_cop_test.rb +32 -34
  42. data/test/string_test.rb +67 -19
  43. data/test/test_helper.rb +13 -15
  44. data/test/visitor_test.rb +4 -6
  45. metadata +28 -13
  46. data/.travis.yml +0 -34
  47. data/gemfiles/4.2.gemfile +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf37a33f6c9998a09a09817fe5f14024947a1f83ed63682c066dcf35c385ac57
4
- data.tar.gz: 36df6f6110f2126240702636d93c0ed54322794ff5f558fa6dcb27484c3b2b28
3
+ metadata.gz: 8cb7e91b305057b2ea3df0c96643f8cd2cc726583f2362db9d576ef128826a75
4
+ data.tar.gz: 419ee38ec698795d478f7749486e63b533c9cc497057aa820b5627b343cbdeb4
5
5
  SHA512:
6
- metadata.gz: 4c5233ee11b096ec18e1a53f1e76a6dbb0880a99de9ac41ec836993f317612cf728d81a1332c3f7bfeb42766cb7e28e388061d85cabec8355e7c32e969468761
7
- data.tar.gz: f766262804751519e3566ea80af0358dba148540883d74b5947804e70876ae90555dcb539032f5e59ff1d64fb03b6b10e293e487842b47eeea31246c14a69024
6
+ metadata.gz: 19b765a13b9a21a5b798b60618253729b4a8c1279babe47644d5c030b93b09c87706138ab11cd5bfd9daee757d8d04bff95fc1bc3ce50c5f6f7399aaaabc09d1
7
+ data.tar.gz: a65e72e3d6e5500b986bb312c45dbbd00432419b344765c71387432dd127efd5eb463cd42f71c3e405913a66b8d45201b9d909b9e66da17bf28f11ea3b7aa5c8
@@ -0,0 +1,42 @@
1
+ name: test
2
+ on: [push, pull_request]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ ruby: ["2.5", "2.6", "2.7"]
9
+ rails: ["rails5", "rails6"]
10
+ database: ["sqlite", "postgres", "mysql"]
11
+ services:
12
+ postgres:
13
+ image: postgres
14
+ env:
15
+ POSTGRES_USER: search_cop
16
+ POSTGRES_PASSWORD: secret
17
+ POSTGRES_DB: search_cop
18
+ ports:
19
+ - 5432:5432
20
+ mysql:
21
+ image: mysql
22
+ env:
23
+ MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
24
+ MYSQL_ROOT_PASSWORD: ""
25
+ MYSQL_DATABASE: search_cop
26
+ ports:
27
+ - 3306:3306
28
+ steps:
29
+ - uses: actions/checkout@v1
30
+ - uses: actions/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{ matrix.ruby }}
33
+ - name: test
34
+ env:
35
+ DATABASE: ${{ matrix.database }}
36
+ run: |
37
+ gem install bundler
38
+ bundle config set --local gemfile "gemfiles/${{ matrix.rails }}.gemfile"
39
+ bundle config set --local path "../vendor/bundle"
40
+ bundle install
41
+ bundle exec rake test
42
+ bundle exec rubocop
data/.rubocop.yml ADDED
@@ -0,0 +1,128 @@
1
+ AllCops:
2
+ NewCops: enable
3
+
4
+ Gemspec/RequiredRubyVersion:
5
+ Enabled: false
6
+
7
+ Style/CaseLikeIf:
8
+ Enabled: false
9
+
10
+ Style/RedundantArgument:
11
+ Enabled: false
12
+
13
+ Lint/EmptyBlock:
14
+ Enabled: false
15
+
16
+ Layout/EmptyLineBetweenDefs:
17
+ Enabled: false
18
+
19
+ Style/FrozenStringLiteralComment:
20
+ Enabled: false
21
+
22
+ Lint/RedundantRequireStatement:
23
+ Enabled: false
24
+
25
+ Layout/ArgumentAlignment:
26
+ EnforcedStyle: with_fixed_indentation
27
+
28
+ Layout/FirstArrayElementIndentation:
29
+ EnforcedStyle: consistent
30
+
31
+ Style/PercentLiteralDelimiters:
32
+ Enabled: false
33
+
34
+ Style/SpecialGlobalVars:
35
+ EnforcedStyle: use_english_names
36
+
37
+ Security/Eval:
38
+ Enabled: false
39
+
40
+ Style/WordArray:
41
+ EnforcedStyle: brackets
42
+
43
+ Style/ClassAndModuleChildren:
44
+ Enabled: false
45
+
46
+ Style/TrivialAccessors:
47
+ Enabled: false
48
+
49
+ Style/Alias:
50
+ Enabled: false
51
+
52
+ Style/StringLiteralsInInterpolation:
53
+ EnforcedStyle: double_quotes
54
+
55
+ Metrics/ClassLength:
56
+ Enabled: false
57
+
58
+ Naming/MethodParameterName:
59
+ Enabled: false
60
+
61
+ Style/SymbolArray:
62
+ EnforcedStyle: brackets
63
+
64
+ Layout/RescueEnsureAlignment:
65
+ Enabled: false
66
+
67
+ Layout/LineLength:
68
+ Enabled: false
69
+
70
+ Metrics/MethodLength:
71
+ Enabled: false
72
+
73
+ Metrics/ModuleLength:
74
+ Enabled: false
75
+
76
+ Style/ZeroLengthPredicate:
77
+ Enabled: false
78
+
79
+ Metrics/PerceivedComplexity:
80
+ Enabled: false
81
+
82
+ Metrics/AbcSize:
83
+ Enabled: false
84
+
85
+ Metrics/CyclomaticComplexity:
86
+ Enabled: false
87
+
88
+ Metrics/BlockLength:
89
+ Enabled: false
90
+
91
+ Metrics/BlockNesting:
92
+ Enabled: false
93
+
94
+ Style/NumericPredicate:
95
+ Enabled: false
96
+
97
+ Naming/AccessorMethodName:
98
+ Enabled: false
99
+
100
+ Naming/MemoizedInstanceVariableName:
101
+ Enabled: false
102
+
103
+ Style/StringLiterals:
104
+ EnforcedStyle: double_quotes
105
+
106
+ Style/Documentation:
107
+ Enabled: false
108
+
109
+ Naming/ConstantName:
110
+ Enabled: false
111
+
112
+ Style/MutableConstant:
113
+ Enabled: false
114
+
115
+ Layout/MultilineMethodCallIndentation:
116
+ EnforcedStyle: indented
117
+
118
+ Layout/ParameterAlignment:
119
+ EnforcedStyle: with_fixed_indentation
120
+
121
+ Lint/UnusedMethodArgument:
122
+ Enabled: false
123
+
124
+ Style/IfUnlessModifier:
125
+ Enabled: false
126
+
127
+ Style/RedundantBegin:
128
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -3,13 +3,18 @@
3
3
 
4
4
  Version 1.2.0:
5
5
 
6
+ * Added support for disabling the right wildcard
7
+ * Fixed escaping of wildcard chars (`_`, `%`)
8
+
9
+ Version 1.1.0:
10
+
6
11
  * Adds customizable default operator to concatenate conditions (#49)
7
12
  * Make the postgis adapter use the postgres extensions
8
13
 
9
14
  Version 1.0.9:
10
15
 
11
- * Use [:blank:] instead of \s for space (#46)
12
- * Updated SearchCop::Visitors::Visitor to check the connection's adapter_name when extending. (#47)
16
+ * Use `[:blank:]` instead of `\s` for space (#46)
17
+ * Updated `SearchCop::Visitors::Visitor` to check the connection's `adapter_name` when extending. (#47)
13
18
  * Fix for negative numeric values
14
19
  * allow searching for relative dates, like hours, days, weeks, months or years ago
15
20
 
@@ -19,8 +24,8 @@ Version 1.0.8:
19
24
 
20
25
  Version 1.0.7:
21
26
 
22
- * Bugfix regarding NOT queries in fulltext mode #32
23
- * Safely handle NULL values for match queries
27
+ * Bugfix regarding `NOT` queries in fulltext mode #32
28
+ * Safely handle `NULL` values for match queries
24
29
  * Added coalesce option
25
30
 
26
31
  Version 1.0.6:
@@ -58,7 +63,7 @@ Version 1.0.0:
58
63
 
59
64
  Version 0.0.5:
60
65
 
61
- * Supporting :default => false
66
+ * Supporting `:default => false`
62
67
  * Datetime/Date greater operator fix
63
68
  * Use reflection to find associated models
64
69
  * Providing reflection
@@ -67,16 +72,16 @@ Version 0.0.4:
67
72
 
68
73
  * Fixed date attributes
69
74
  * Fail softly for mixed datatype attributes
70
- * Support custom table, class and alias names via attr_searchable_alias
75
+ * Support custom table, class and alias names via `attr_searchable_alias`
71
76
 
72
77
  Version 0.0.3:
73
78
 
74
- * belongs_to association fixes
79
+ * `belongs_to` association fixes
75
80
 
76
81
  Version 0.0.2:
77
82
 
78
83
  * Arel abstraction layer added
79
- * count() queries resulting in "Cannot visit AttrSearchableGrammar::Nodes..." fixed
84
+ * `count()` queries resulting in "Cannot visit AttrSearchableGrammar::Nodes..." fixed
80
85
  * Better error messages
81
- * Model#unsafe_search added
86
+ * `Model#unsafe_search` added
82
87
 
data/Gemfile CHANGED
@@ -1,11 +1,10 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in search_cop.gemspec
4
4
  gemspec
5
5
 
6
6
  platforms :ruby do
7
- gem 'sqlite3'
8
- gem 'mysql2'
9
- gem 'pg'
7
+ gem "mysql2"
8
+ gem "pg"
9
+ gem "sqlite3"
10
10
  end
11
-
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SearchCop
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/mrkamel/search_cop.png?branch=master)](http://travis-ci.org/mrkamel/search_cop)
3
+ [![Build Status](https://github.com/mrkamel/search_cop/workflows/test/badge.svg?branch=master)](https://github.com/mrkamel/search_cop/actions?query=workflow%3Atest)
4
4
  [![Code Climate](https://codeclimate.com/github/mrkamel/search_cop.png)](https://codeclimate.com/github/mrkamel/search_cop)
5
5
  [![Gem Version](https://badge.fury.io/rb/search_cop.svg)](http://badge.fury.io/rb/search_cop)
6
6
 
@@ -329,6 +329,16 @@ User.search("admin")
329
329
  # ... WHERE users.username LIKE 'admin%'
330
330
  ```
331
331
 
332
+ Similarly, you can disable the right wildcard as well:
333
+
334
+ ```ruby
335
+ search_scope :search do
336
+ attributes :username
337
+
338
+ options :username, right_wildcard: false
339
+ end
340
+ ```
341
+
332
342
  ## Default operator
333
343
 
334
344
  When you define multiple fields on a search scope, SearcCop will use
data/Rakefile CHANGED
@@ -6,4 +6,3 @@ Rake::TestTask.new(:test) do |t|
6
6
  t.pattern = "test/**/*_test.rb"
7
7
  t.verbose = true
8
8
  end
9
-
data/docker-compose.yml CHANGED
@@ -8,4 +8,11 @@ services:
8
8
  - MYSQL_ROOT_PASSWORD=
9
9
  ports:
10
10
  - 3306:3306
11
-
11
+ postgres:
12
+ image: postgres:9.6.6
13
+ environment:
14
+ POSTGRES_DB: search_cop
15
+ POSTGRES_USER: search_cop
16
+ POSTGRES_PASSWORD: secret
17
+ ports:
18
+ - 5432:5432
@@ -5,9 +5,9 @@ source "https://rubygems.org"
5
5
  gem "activerecord", "~> 5.1"
6
6
 
7
7
  platforms :ruby do
8
- gem "sqlite3"
9
8
  gem "mysql2"
10
9
  gem "pg"
10
+ gem "sqlite3"
11
11
  end
12
12
 
13
- gemspec :path => "../"
13
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.0"
6
+
7
+ platforms :ruby do
8
+ gem "mysql2"
9
+ gem "pg"
10
+ gem "sqlite3"
11
+ end
12
+
13
+ gemspec path: "../"
data/lib/search_cop.rb CHANGED
@@ -1,5 +1,5 @@
1
-
2
1
  require "search_cop/version"
2
+ require "search_cop/helpers"
3
3
  require "search_cop/search_scope"
4
4
  require "search_cop/query_info"
5
5
  require "search_cop/query_builder"
@@ -23,7 +23,7 @@ module SearchCop
23
23
  module Parser
24
24
  def self.parse(query, query_info, query_options = {})
25
25
  if query.is_a?(Hash)
26
- SearchCop::HashParser.new(query_info).parse(query)
26
+ SearchCop::HashParser.new(query_info).parse(query, query_options)
27
27
  else
28
28
  SearchCop::GrammarParser.new(query_info).parse(query, query_options)
29
29
  end
@@ -44,8 +44,8 @@ module SearchCop
44
44
  search_scopes[name] = SearchScope.new(name, self)
45
45
  search_scopes[name].instance_exec(&block)
46
46
 
47
- self.send(:define_singleton_method, name) { |query, query_options={}| search_cop query, name, query_options }
48
- self.send(:define_singleton_method, "unsafe_#{name}") { |query, query_options={}| unsafe_search_cop query, name, query_options }
47
+ send(:define_singleton_method, name) { |query, query_options = {}| search_cop(query, name, query_options) }
48
+ send(:define_singleton_method, "unsafe_#{name}") { |query, query_options = {}| unsafe_search_cop(query, name, query_options) }
49
49
  end
50
50
 
51
51
  def search_reflection(scope_name)
@@ -53,7 +53,7 @@ module SearchCop
53
53
  end
54
54
 
55
55
  def search_cop(query, scope_name, query_options)
56
- unsafe_search_cop query, scope_name, query_options
56
+ unsafe_search_cop(query, scope_name, query_options)
57
57
  rescue SearchCop::RuntimeError
58
58
  respond_to?(:none) ? none : where("1 = 0")
59
59
  end
@@ -69,22 +69,4 @@ module SearchCop
69
69
  (scope || self).where(query_builder.sql)
70
70
  end
71
71
  end
72
-
73
- module Helpers
74
- def self.sanitize_default_operator(hash, delete_hash_option=false)
75
- default_operator = :and
76
- if hash.member?(:default_operator)
77
- unless [:and, :or].include?(hash[:default_operator])
78
- raise(SearchCop::UnknownDefaultOperator, "Unknown default operator value #{hash[:default_operator]}")
79
- end
80
-
81
- default_operator = hash[:default_operator]
82
- end
83
-
84
- hash.delete(:default_operator) if delete_hash_option
85
-
86
- default_operator
87
- end
88
- end
89
72
  end
90
-
@@ -1,8 +1,7 @@
1
-
2
1
  require "search_cop_grammar"
3
2
  require "treetop"
4
3
 
5
- Treetop.load File.expand_path("../../search_cop_grammar.treetop", __FILE__)
4
+ Treetop.load File.expand_path("../search_cop_grammar.treetop", __dir__)
6
5
 
7
6
  module SearchCop
8
7
  class GrammarParser
@@ -20,4 +19,3 @@ module SearchCop
20
19
  end
21
20
  end
22
21
  end
23
-
@@ -1,4 +1,3 @@
1
-
2
1
  class SearchCop::HashParser
3
2
  attr_reader :query_info
4
3
 
@@ -6,25 +5,25 @@ class SearchCop::HashParser
6
5
  @query_info = query_info
7
6
  end
8
7
 
9
- def parse(hash)
10
- default_operator = SearchCop::Helpers.sanitize_default_operator(hash, true)
8
+ def parse(hash, query_options = {})
9
+ default_operator = SearchCop::Helpers.sanitize_default_operator(query_options)
11
10
 
12
11
  res = hash.collect do |key, value|
13
12
  case key
14
- when :and
15
- value.collect { |val| parse val }.inject(:and)
16
- when :or
17
- value.collect { |val| parse val }.inject(:or)
18
- when :not
19
- parse(value).not
20
- when :query
21
- SearchCop::Parser.parse value, query_info
22
- else
23
- parse_attribute key, value
13
+ when :and
14
+ value.collect { |val| parse val }.inject(:and)
15
+ when :or
16
+ value.collect { |val| parse val }.inject(:or)
17
+ when :not
18
+ parse(value).not
19
+ when :query
20
+ SearchCop::Parser.parse(value, query_info)
21
+ else
22
+ parse_attribute(key, value)
24
23
  end
25
24
  end
26
25
 
27
- res.inject default_operator
26
+ res.inject(default_operator)
28
27
  end
29
28
 
30
29
  private
@@ -35,14 +34,15 @@ class SearchCop::HashParser
35
34
  if value.is_a?(Hash)
36
35
  raise(SearchCop::ParseError, "Unknown operator #{value.keys.first}") unless collection.valid_operator?(value.keys.first)
37
36
 
38
- if generator = collection.generator_for(value.keys.first)
39
- collection.generator generator, value.values.first
37
+ generator = collection.generator_for(value.keys.first)
38
+
39
+ if generator
40
+ collection.generator(generator, value.values.first)
40
41
  else
41
- collection.send value.keys.first, value.values.first.to_s
42
+ collection.send(value.keys.first, value.values.first.to_s)
42
43
  end
43
44
  else
44
- collection.send :matches, value.to_s
45
+ collection.send(:matches, value.to_s)
45
46
  end
46
47
  end
47
48
  end
48
-