search_cop 1.2.3 → 1.3.0
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.
- 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
|
-
|