search_cop 1.2.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +6 -0
- data/README.md +26 -1
- data/docker-compose.yml +2 -1
- data/gemfiles/rails5.gemfile +5 -0
- data/gemfiles/rails6.gemfile +5 -0
- data/gemfiles/rails7.gemfile +5 -0
- data/lib/search_cop/version.rb +1 -1
- data/lib/search_cop/visitors/mysql.rb +6 -2
- data/lib/search_cop/visitors/postgres.rb +16 -0
- data/lib/search_cop/visitors/sqlite.rb +13 -0
- data/lib/search_cop/visitors/visitor.rb +3 -1
- data/lib/search_cop/visitors.rb +1 -0
- data/lib/search_cop_grammar/attributes.rb +10 -4
- metadata +7 -108
- data/.github/workflows/test.yml +0 -50
- data/.gitignore +0 -18
- data/search_cop.gemspec +0 -27
- data/test/and_test.rb +0 -25
- data/test/boolean_test.rb +0 -51
- data/test/database.yml +0 -20
- data/test/date_test.rb +0 -107
- data/test/datetime_test.rb +0 -115
- data/test/default_operator_test.rb +0 -51
- data/test/error_test.rb +0 -15
- data/test/float_test.rb +0 -72
- data/test/fulltext_test.rb +0 -25
- data/test/hash_test.rb +0 -105
- data/test/integer_test.rb +0 -65
- data/test/not_test.rb +0 -25
- data/test/or_test.rb +0 -27
- data/test/scope_test.rb +0 -53
- data/test/search_cop_test.rb +0 -166
- data/test/string_test.rb +0 -142
- data/test/test_helper.rb +0 -205
- data/test/visitor_test.rb +0 -108
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1f72257612f45ef71a297f5ae8924fca0d8dad9f3c19e6e0b6e2c96e60f36ac
|
4
|
+
data.tar.gz: 2aa35b3f92c08cd24266d28f4c1e3fe195b627bb478be415ff4669b2344676de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee27a86501f8c3f2588f50b5d78889b8ad6ae9e2d28fcd219617d4839590f61d98c80850f8247da34a5081e12075315d53918a61b3b9636618645d138fd7bd4c
|
7
|
+
data.tar.gz: 046c39f90c8a541d1e000f95772fb5d8eeb2095fc8afe8717b5b95f5672576d988375853525243923852029728d485b3cfd1046f6bd68c9134065738a69f31bf
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
|
2
2
|
# Changelog
|
3
3
|
|
4
|
+
Version 1.3.0:
|
5
|
+
|
6
|
+
* Support json fields for postgres, mysql and sqlite
|
7
|
+
* Support jsonb and hstore fields for postgres
|
8
|
+
* Add support for timestamptz for postgres
|
9
|
+
|
4
10
|
Version 1.2.3:
|
5
11
|
|
6
12
|
* Fix table name for namespaced and inherited models #70 #67
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -103,8 +103,9 @@ Book.search("Harry Potter")
|
|
103
103
|
# ... WHERE (books.title LIKE '%Harry%' OR books.description LIKE '%Harry%' OR ...) AND (books.title LIKE '%Potter%' OR books.description LIKE '%Potter%' ...)
|
104
104
|
|
105
105
|
Book.search("available:yes OR created_at:2014")
|
106
|
-
# ... WHERE books.available = 1 OR (books.created_at >= '2014-01-01 00:00:00' and books.created_at <= '2014-12-31
|
106
|
+
# ... WHERE books.available = 1 OR (books.created_at >= '2014-01-01 00:00:00.00000' and books.created_at <= '2014-12-31 23:59:59.99999')
|
107
107
|
```
|
108
|
+
SearchCop is using ActiveSupport's beginning_of_year and end_of_year methods for the values used in building the SQL query for this case.
|
108
109
|
|
109
110
|
Of course, these `LIKE '%...%'` queries won't achieve optimal performance, but
|
110
111
|
check out the section below on SearchCop's fulltext capabilities to
|
@@ -135,6 +136,30 @@ to prevent SQL injection. While we can never be 100% safe from security issues,
|
|
135
136
|
SearchCop takes security issues seriously. Please report responsibly via
|
136
137
|
security at flakks dot com in case you find any security related issues.
|
137
138
|
|
139
|
+
## json/jsonb/hstore
|
140
|
+
|
141
|
+
SearchCop supports json fields for MySQL, as well as json, jsonb and hstore
|
142
|
+
fields for postgres. Currently, field values are always expected to be strings
|
143
|
+
and no arrays are supported. You can specify json attributes via:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
search_scope :search do
|
147
|
+
attributes user_agent: "context->browser->user_agent"
|
148
|
+
|
149
|
+
# ...
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
where `context` is a json/jsonb column which e.g. contains:
|
154
|
+
|
155
|
+
```json
|
156
|
+
{
|
157
|
+
"browser": {
|
158
|
+
"user_agent": "Firefox ..."
|
159
|
+
}
|
160
|
+
}
|
161
|
+
```
|
162
|
+
|
138
163
|
## Fulltext index capabilities
|
139
164
|
|
140
165
|
By default, i.e. if you don't tell SearchCop about your fulltext indices,
|
data/docker-compose.yml
CHANGED
@@ -6,10 +6,11 @@ services:
|
|
6
6
|
environment:
|
7
7
|
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
8
8
|
- MYSQL_ROOT_PASSWORD=
|
9
|
+
- MYSQL_DATABASE=search_cop
|
9
10
|
ports:
|
10
11
|
- 3306:3306
|
11
12
|
postgres:
|
12
|
-
image:
|
13
|
+
image: styriadigital/postgres_hstore:10
|
13
14
|
environment:
|
14
15
|
POSTGRES_DB: search_cop
|
15
16
|
POSTGRES_USER: search_cop
|
data/gemfiles/rails5.gemfile
CHANGED
data/gemfiles/rails6.gemfile
CHANGED
data/gemfiles/rails7.gemfile
CHANGED
data/lib/search_cop/version.rb
CHANGED
@@ -3,6 +3,10 @@ module SearchCop
|
|
3
3
|
module Mysql
|
4
4
|
# rubocop:disable Naming/MethodName
|
5
5
|
|
6
|
+
def visit_SearchCopGrammar_Attributes_Json(attribute)
|
7
|
+
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->#{quote "$.#{attribute.field_names.join(".")}"}"
|
8
|
+
end
|
9
|
+
|
6
10
|
class FulltextQuery < Visitor
|
7
11
|
def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(node)
|
8
12
|
node.right.split(/[\s+'"<>()~-]+/).collect { |word| "-#{word}" }.join(" ")
|
@@ -38,8 +42,8 @@ module SearchCop
|
|
38
42
|
def visit_SearchCopGrammar_Nodes_FulltextExpression(node)
|
39
43
|
"MATCH(#{visit node.collection}) AGAINST(#{visit FulltextQuery.new(connection).visit(node.node)} IN BOOLEAN MODE)"
|
40
44
|
end
|
41
|
-
end
|
42
45
|
|
43
|
-
|
46
|
+
# rubocop:enable Naming/MethodName
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
@@ -3,6 +3,22 @@ module SearchCop
|
|
3
3
|
module Postgres
|
4
4
|
# rubocop:disable Naming/MethodName
|
5
5
|
|
6
|
+
def visit_SearchCopGrammar_Attributes_Json(attribute)
|
7
|
+
elements = ["#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}", *attribute.field_names.map { |field_name| quote(field_name) }]
|
8
|
+
|
9
|
+
"#{elements[0...-1].join("->")}->>#{elements.last}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit_SearchCopGrammar_Attributes_Jsonb(attribute)
|
13
|
+
elements = ["#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}", *attribute.field_names.map { |field_name| quote(field_name) }]
|
14
|
+
|
15
|
+
"#{elements[0...-1].join("->")}->>#{elements.last}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_SearchCopGrammar_Attributes_Hstore(attribute)
|
19
|
+
"#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}->#{quote attribute.field_names.first}"
|
20
|
+
end
|
21
|
+
|
6
22
|
class FulltextQuery < Visitor
|
7
23
|
def visit_SearchCopGrammar_Nodes_MatchesFulltextNot(node)
|
8
24
|
"!'#{node.right.gsub(/[\s&|!:'"]+/, " ")}'"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SearchCop
|
2
|
+
module Visitors
|
3
|
+
module Sqlite
|
4
|
+
# rubocop:disable Naming/MethodName
|
5
|
+
|
6
|
+
def visit_SearchCopGrammar_Attributes_Json(attribute)
|
7
|
+
"json_extract(#{quote_table_name attribute.table_alias}.#{quote_column_name attribute.column_name}, #{quote "$.#{attribute.field_names.join(".")}"})"
|
8
|
+
end
|
9
|
+
|
10
|
+
# rubocop:enable Naming/MethodName
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -10,10 +10,11 @@ module SearchCop
|
|
10
10
|
|
11
11
|
extend(SearchCop::Visitors::Mysql) if @connection.adapter_name =~ /mysql/i
|
12
12
|
extend(SearchCop::Visitors::Postgres) if @connection.adapter_name =~ /postgres|postgis/i
|
13
|
+
extend(SearchCop::Visitors::Sqlite) if @connection.adapter_name =~ /sqlite/i
|
13
14
|
end
|
14
15
|
|
15
16
|
def visit(visit_node = node)
|
16
|
-
send "visit_#{visit_node.class.name.gsub(
|
17
|
+
send "visit_#{visit_node.class.name.gsub("::", "_")}", visit_node
|
17
18
|
end
|
18
19
|
|
19
20
|
def visit_SearchCopGrammar_Nodes_And(node)
|
@@ -79,6 +80,7 @@ module SearchCop
|
|
79
80
|
alias :visit_SearchCopGrammar_Attributes_Decimal :visit_attribute
|
80
81
|
alias :visit_SearchCopGrammar_Attributes_Datetime :visit_attribute
|
81
82
|
alias :visit_SearchCopGrammar_Attributes_Timestamp :visit_attribute
|
83
|
+
alias :visit_SearchCopGrammar_Attributes_Timestamptz :visit_attribute
|
82
84
|
alias :visit_SearchCopGrammar_Attributes_Date :visit_attribute
|
83
85
|
alias :visit_SearchCopGrammar_Attributes_Time :visit_attribute
|
84
86
|
alias :visit_SearchCopGrammar_Attributes_Boolean :visit_attribute
|
data/lib/search_cop/visitors.rb
CHANGED
@@ -88,12 +88,13 @@ module SearchCopGrammar
|
|
88
88
|
def attribute_for(attribute_definition)
|
89
89
|
query_info.references.push attribute_definition
|
90
90
|
|
91
|
-
table,
|
91
|
+
table, column_with_fields = attribute_definition.split(".")
|
92
|
+
column, *fields = column_with_fields.split("->")
|
92
93
|
klass = klass_for(table)
|
93
94
|
|
94
95
|
raise(SearchCop::UnknownAttribute, "Unknown attribute #{attribute_definition}") unless klass.columns_hash[column]
|
95
96
|
|
96
|
-
Attributes.const_get(klass.columns_hash[column].type.to_s.classify).new(klass, alias_for(table), column, options)
|
97
|
+
Attributes.const_get(klass.columns_hash[column].type.to_s.classify).new(klass, alias_for(table), column, fields, options)
|
97
98
|
end
|
98
99
|
|
99
100
|
def generator_for(name)
|
@@ -110,13 +111,14 @@ module SearchCopGrammar
|
|
110
111
|
end
|
111
112
|
|
112
113
|
class Base
|
113
|
-
attr_reader :attribute, :table_alias, :column_name, :options
|
114
|
+
attr_reader :attribute, :table_alias, :column_name, :field_names, :options
|
114
115
|
|
115
|
-
def initialize(klass, table_alias, column_name, options = {})
|
116
|
+
def initialize(klass, table_alias, column_name, field_names, options = {})
|
116
117
|
@attribute = klass.arel_table.alias(table_alias)[column_name]
|
117
118
|
@klass = klass
|
118
119
|
@table_alias = table_alias
|
119
120
|
@column_name = column_name
|
121
|
+
@field_names = field_names
|
120
122
|
@options = (options || {})
|
121
123
|
end
|
122
124
|
|
@@ -179,6 +181,9 @@ module SearchCopGrammar
|
|
179
181
|
end
|
180
182
|
|
181
183
|
class Text < String; end
|
184
|
+
class Jsonb < String; end
|
185
|
+
class Json < String; end
|
186
|
+
class Hstore < String; end
|
182
187
|
|
183
188
|
class WithoutMatches < Base
|
184
189
|
def matches(value)
|
@@ -255,6 +260,7 @@ module SearchCopGrammar
|
|
255
260
|
end
|
256
261
|
|
257
262
|
class Timestamp < Datetime; end
|
263
|
+
class Timestamptz < Datetime; end
|
258
264
|
|
259
265
|
class Date < Datetime
|
260
266
|
def parse(value)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: search_cop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Vetter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|
@@ -24,90 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: activerecord
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 3.0.0
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 3.0.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: factory_bot
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rake
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rubocop
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
27
|
description: Search engine like fulltext query support for ActiveRecord
|
112
28
|
email:
|
113
29
|
- vetter@flakks.com
|
@@ -115,8 +31,6 @@ executables: []
|
|
115
31
|
extensions: []
|
116
32
|
extra_rdoc_files: []
|
117
33
|
files:
|
118
|
-
- ".github/workflows/test.yml"
|
119
|
-
- ".gitignore"
|
120
34
|
- ".rubocop.yml"
|
121
35
|
- CHANGELOG.md
|
122
36
|
- CONTRIBUTING.md
|
@@ -140,34 +54,19 @@ files:
|
|
140
54
|
- lib/search_cop/visitors.rb
|
141
55
|
- lib/search_cop/visitors/mysql.rb
|
142
56
|
- lib/search_cop/visitors/postgres.rb
|
57
|
+
- lib/search_cop/visitors/sqlite.rb
|
143
58
|
- lib/search_cop/visitors/visitor.rb
|
144
59
|
- lib/search_cop_grammar.rb
|
145
60
|
- lib/search_cop_grammar.treetop
|
146
61
|
- lib/search_cop_grammar/attributes.rb
|
147
62
|
- lib/search_cop_grammar/nodes.rb
|
148
|
-
- search_cop.gemspec
|
149
|
-
- test/and_test.rb
|
150
|
-
- test/boolean_test.rb
|
151
|
-
- test/database.yml
|
152
|
-
- test/date_test.rb
|
153
|
-
- test/datetime_test.rb
|
154
|
-
- test/default_operator_test.rb
|
155
|
-
- test/error_test.rb
|
156
|
-
- test/float_test.rb
|
157
|
-
- test/fulltext_test.rb
|
158
|
-
- test/hash_test.rb
|
159
|
-
- test/integer_test.rb
|
160
|
-
- test/not_test.rb
|
161
|
-
- test/or_test.rb
|
162
|
-
- test/scope_test.rb
|
163
|
-
- test/search_cop_test.rb
|
164
|
-
- test/string_test.rb
|
165
|
-
- test/test_helper.rb
|
166
|
-
- test/visitor_test.rb
|
167
63
|
homepage: https://github.com/mrkamel/search_cop
|
168
64
|
licenses:
|
169
65
|
- MIT
|
170
|
-
metadata:
|
66
|
+
metadata:
|
67
|
+
homepage_uri: https://github.com/mrkamel/search_cop
|
68
|
+
source_code_uri: https://github.com/mrkamel/search_cop
|
69
|
+
changelog_uri: https://github.com/mrkamel/search_cop/blob/master/CHANGELOG.md
|
171
70
|
post_install_message:
|
172
71
|
rdoc_options: []
|
173
72
|
require_paths:
|
data/.github/workflows/test.yml
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
name: test
|
2
|
-
on: [push, pull_request]
|
3
|
-
jobs:
|
4
|
-
build:
|
5
|
-
runs-on: ubuntu-latest
|
6
|
-
strategy:
|
7
|
-
fail-fast: false
|
8
|
-
matrix:
|
9
|
-
ruby: ["2.6", "2.7", "3.0", "3.1"]
|
10
|
-
rails: ["rails5", "rails6", "rails7"]
|
11
|
-
database: ["sqlite", "postgres", "mysql"]
|
12
|
-
exclude:
|
13
|
-
- ruby: "3.0"
|
14
|
-
rails: "rails5"
|
15
|
-
- ruby: "3.1"
|
16
|
-
rails: "rails5"
|
17
|
-
- ruby: "2.6"
|
18
|
-
rails: "rails7"
|
19
|
-
services:
|
20
|
-
postgres:
|
21
|
-
image: postgres
|
22
|
-
env:
|
23
|
-
POSTGRES_USER: search_cop
|
24
|
-
POSTGRES_PASSWORD: secret
|
25
|
-
POSTGRES_DB: search_cop
|
26
|
-
ports:
|
27
|
-
- 5432:5432
|
28
|
-
mysql:
|
29
|
-
image: mysql
|
30
|
-
env:
|
31
|
-
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
|
32
|
-
MYSQL_ROOT_PASSWORD: ""
|
33
|
-
MYSQL_DATABASE: search_cop
|
34
|
-
ports:
|
35
|
-
- 3306:3306
|
36
|
-
steps:
|
37
|
-
- uses: actions/checkout@v1
|
38
|
-
- uses: ruby/setup-ruby@v1
|
39
|
-
with:
|
40
|
-
ruby-version: ${{ matrix.ruby }}
|
41
|
-
- name: test
|
42
|
-
env:
|
43
|
-
DATABASE: ${{ matrix.database }}
|
44
|
-
run: |
|
45
|
-
gem install bundler
|
46
|
-
bundle config set --local gemfile "gemfiles/${{ matrix.rails }}.gemfile"
|
47
|
-
bundle config set --local path "../vendor/bundle"
|
48
|
-
bundle install
|
49
|
-
bundle exec rake test
|
50
|
-
bundle exec rubocop
|
data/.gitignore
DELETED
data/search_cop.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
lib = File.expand_path("lib", __dir__)
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require "search_cop/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "search_cop"
|
7
|
-
spec.version = SearchCop::VERSION
|
8
|
-
spec.authors = ["Benjamin Vetter"]
|
9
|
-
spec.email = ["vetter@flakks.com"]
|
10
|
-
spec.description = "Search engine like fulltext query support for ActiveRecord"
|
11
|
-
spec.summary = "Easily perform complex search engine like fulltext queries on your ActiveRecord models"
|
12
|
-
spec.homepage = "https://github.com/mrkamel/search_cop"
|
13
|
-
spec.license = "MIT"
|
14
|
-
|
15
|
-
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
16
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
-
spec.require_paths = ["lib"]
|
18
|
-
|
19
|
-
spec.add_dependency "treetop"
|
20
|
-
|
21
|
-
spec.add_development_dependency "activerecord", ">= 3.0.0"
|
22
|
-
spec.add_development_dependency "bundler"
|
23
|
-
spec.add_development_dependency "factory_bot"
|
24
|
-
spec.add_development_dependency "minitest"
|
25
|
-
spec.add_development_dependency "rake"
|
26
|
-
spec.add_development_dependency "rubocop"
|
27
|
-
end
|
data/test/and_test.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require File.expand_path("test_helper", __dir__)
|
2
|
-
|
3
|
-
class AndTest < SearchCop::TestCase
|
4
|
-
def test_and_string
|
5
|
-
expected = create(:product, title: "expected title", description: "Description")
|
6
|
-
rejected = create(:product, title: "Rejected title", description: "Description")
|
7
|
-
|
8
|
-
results = Product.search("title: 'Expected title' description: Description")
|
9
|
-
|
10
|
-
assert_includes results, expected
|
11
|
-
refute_includes results, rejected
|
12
|
-
|
13
|
-
assert_equal results, Product.search("title: 'Expected title' AND description: Description")
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_and_hash
|
17
|
-
expected = create(:product, title: "Expected title", description: "Description")
|
18
|
-
rejected = create(:product, title: "Rejected title", description: "Description")
|
19
|
-
|
20
|
-
results = Product.search(and: [{ title: "Expected title" }, { description: "Description" }])
|
21
|
-
|
22
|
-
assert_includes results, expected
|
23
|
-
refute_includes results, rejected
|
24
|
-
end
|
25
|
-
end
|
data/test/boolean_test.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require File.expand_path("test_helper", __dir__)
|
2
|
-
|
3
|
-
class BooleanTest < SearchCop::TestCase
|
4
|
-
def test_mapping
|
5
|
-
product = create(:product, available: true)
|
6
|
-
|
7
|
-
assert_includes Product.search("available: 1"), product
|
8
|
-
assert_includes Product.search("available: true"), product
|
9
|
-
assert_includes Product.search("available: yes"), product
|
10
|
-
|
11
|
-
product = create(:product, available: false)
|
12
|
-
|
13
|
-
assert_includes Product.search("available: 0"), product
|
14
|
-
assert_includes Product.search("available: false"), product
|
15
|
-
assert_includes Product.search("available: no"), product
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_anywhere
|
19
|
-
product = create(:product, available: true)
|
20
|
-
|
21
|
-
assert_includes Product.search("true"), product
|
22
|
-
refute_includes Product.search("false"), product
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_includes
|
26
|
-
product = create(:product, available: true)
|
27
|
-
|
28
|
-
assert_includes Product.search("available: true"), product
|
29
|
-
refute_includes Product.search("available: false"), product
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_equals
|
33
|
-
product = create(:product, available: true)
|
34
|
-
|
35
|
-
assert_includes Product.search("available = true"), product
|
36
|
-
refute_includes Product.search("available = false"), product
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_equals_not
|
40
|
-
product = create(:product, available: false)
|
41
|
-
|
42
|
-
assert_includes Product.search("available != true"), product
|
43
|
-
refute_includes Product.search("available != false"), product
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_incompatible_datatype
|
47
|
-
assert_raises SearchCop::IncompatibleDatatype do
|
48
|
-
Product.unsafe_search "available: Value"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
data/test/database.yml
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
|
2
|
-
sqlite:
|
3
|
-
adapter: sqlite3
|
4
|
-
database: ":memory:"
|
5
|
-
|
6
|
-
mysql:
|
7
|
-
adapter: mysql2
|
8
|
-
database: search_cop
|
9
|
-
host: 127.0.0.1
|
10
|
-
username: root
|
11
|
-
encoding: utf8
|
12
|
-
|
13
|
-
postgres:
|
14
|
-
host: 127.0.0.1
|
15
|
-
adapter: postgresql
|
16
|
-
database: search_cop
|
17
|
-
username: search_cop
|
18
|
-
password: secret
|
19
|
-
encoding: utf8
|
20
|
-
|