command_search 0.11.3 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1d615f992c4521f18821e9b3ee2d96fb800095abeadf549f59b8c24fb6419b6
|
4
|
+
data.tar.gz: df4378e2ab56dc1ee3299582f8a9aed11d4d64d5dd1d3d6d38a0d208a0d48f1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5707ed405d3f6133a6437821b5df18a076b67c299334a226639d8d9e62486f3f385a50907a2bcc57c63a86280125745f3a00975b880086539df899b1106a5acb
|
7
|
+
data.tar.gz: 312e172cc413d7f0d2efb127fd7858454b383b6eed72d1102a416f8d408eefaa831247caf5b27c67ae4959b7ac50871ccf5b05d6eb4abaa6cc6dea40d61425c7
|
data/lib/command_search.rb
CHANGED
@@ -9,6 +9,7 @@ load(__dir__ + '/command_search/backends/mongoer.rb')
|
|
9
9
|
load(__dir__ + '/command_search/backends/postgres.rb')
|
10
10
|
load(__dir__ + '/command_search/backends/sqlite.rb')
|
11
11
|
load(__dir__ + '/command_search/backends/mysql.rb')
|
12
|
+
load(__dir__ + '/command_search/backends/mysql_v5.rb')
|
12
13
|
|
13
14
|
class Boolean; end
|
14
15
|
|
@@ -34,6 +35,10 @@ module CommandSearch
|
|
34
35
|
Normalizer.normalize!(ast, fields, false)
|
35
36
|
return Mysql.build_query(ast)
|
36
37
|
end
|
38
|
+
if type == :mysqlV5
|
39
|
+
Normalizer.normalize!(ast, fields, false)
|
40
|
+
return MysqlV5.build_query(ast)
|
41
|
+
end
|
37
42
|
Normalizer.normalize!(ast, fields)
|
38
43
|
return Mongoer.build_query(ast) if type == :mongo
|
39
44
|
ast
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# NOTE: This module supports does not support MariaDB or eariler Mysql versions than 8.0, due to
|
2
|
+
# changes in how word breaks are handled in regexes.
|
3
|
+
|
1
4
|
module CommandSearch
|
2
5
|
module Mysql
|
3
6
|
module_function
|
@@ -42,16 +45,17 @@ module CommandSearch
|
|
42
45
|
"
|
43
46
|
end
|
44
47
|
if type == :quote
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
val = build_quoted_regex(val)
|
49
|
+
return "(REGEXP_LIKE(#{field}, '#{val}', 'c') AND (#{field} IS NOT NULL))"
|
50
|
+
end
|
51
|
+
if type == :number
|
52
|
+
op = '='
|
53
|
+
else # type == :str
|
48
54
|
op = 'LIKE'
|
49
55
|
val = quote_string(val)
|
50
56
|
val.gsub!('%', '\%')
|
51
57
|
val.gsub!('_', '\_')
|
52
58
|
val = "'%#{val}%'"
|
53
|
-
elsif type == :number
|
54
|
-
op = '='
|
55
59
|
end
|
56
60
|
"((#{field} #{op} #{val}) AND (#{field} IS NOT NULL))"
|
57
61
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# NOTE: This module supports MariaDB and MySql 5 with its distinct word break regex rules.
|
2
|
+
|
3
|
+
module CommandSearch
|
4
|
+
module MysqlV5
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def quote_string(str)
|
8
|
+
# activerecord/lib/active_record/connection_adapters/abstract/quoting.rb:62
|
9
|
+
str.gsub('\\', '\&\&').gsub("'", "''")
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_quoted_regex(str)
|
13
|
+
str = Regexp.escape(str)
|
14
|
+
str = quote_string(str)
|
15
|
+
if str[/(^\W)|(\W$)/]
|
16
|
+
head_border = '(^|[[:<:]]|\\\\()'
|
17
|
+
tail_border = '($|[[:>:]]|\\\\))'
|
18
|
+
return head_border + str + tail_border
|
19
|
+
end
|
20
|
+
'[[:<:]]' + str + '[[:>:]]'
|
21
|
+
end
|
22
|
+
|
23
|
+
def command_search(node)
|
24
|
+
field_node = node[:value].first
|
25
|
+
field = field_node[:value]
|
26
|
+
search_node = node[:value].last
|
27
|
+
val = search_node[:value]
|
28
|
+
type = search_node[:type]
|
29
|
+
return '0 = 1' if field == '__CommandSearch_dummy_key__'
|
30
|
+
if type == Boolean || type == :existence
|
31
|
+
if val
|
32
|
+
return "(NOT ((#{field} IS NULL) OR (#{field} LIKE '0')))"
|
33
|
+
end
|
34
|
+
return "((#{field} IS NULL) OR (#{field} LIKE '0'))"
|
35
|
+
end
|
36
|
+
if type == Time
|
37
|
+
return '0 = 1' unless val
|
38
|
+
return "
|
39
|
+
(
|
40
|
+
(#{field} > '#{val[0] - 1}') AND
|
41
|
+
(#{field} <= '#{val[1] - 1}') AND
|
42
|
+
(#{field} IS NOT NULL)
|
43
|
+
)
|
44
|
+
"
|
45
|
+
end
|
46
|
+
if type == :quote
|
47
|
+
op = 'RLIKE BINARY'
|
48
|
+
val = "'#{build_quoted_regex(val)}'"
|
49
|
+
elsif type == :number
|
50
|
+
op = '='
|
51
|
+
else # type == :str
|
52
|
+
op = 'LIKE'
|
53
|
+
val = quote_string(val)
|
54
|
+
val.gsub!('%', '\%')
|
55
|
+
val.gsub!('_', '\_')
|
56
|
+
val = "'%#{val}%'"
|
57
|
+
end
|
58
|
+
"((#{field} #{op} #{val}) AND (#{field} IS NOT NULL))"
|
59
|
+
end
|
60
|
+
|
61
|
+
def compare_search(node)
|
62
|
+
field_node = node[:value].first
|
63
|
+
field = field_node[:value]
|
64
|
+
search_node = node[:value].last
|
65
|
+
val = search_node[:value]
|
66
|
+
type = search_node[:type]
|
67
|
+
op = node[:nest_op]
|
68
|
+
if node[:compare_across_fields]
|
69
|
+
"
|
70
|
+
(
|
71
|
+
(#{field} #{op} #{val}) AND
|
72
|
+
(#{field} IS NOT NULL) AND
|
73
|
+
(#{val} IS NOT NULL)
|
74
|
+
)
|
75
|
+
"
|
76
|
+
elsif type == Time && val
|
77
|
+
"(#{field} #{op} '#{val}') AND (#{field} IS NOT NULL)"
|
78
|
+
elsif val.is_a?(Numeric) || val == val.to_i.to_s || val == val.to_f.to_s
|
79
|
+
"(#{field} #{op} #{val}) AND (#{field} IS NOT NULL)"
|
80
|
+
else
|
81
|
+
'0 = 1'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_query(ast)
|
86
|
+
out = []
|
87
|
+
ast = [ast] unless ast.is_a?(Array)
|
88
|
+
ast.each do |node|
|
89
|
+
type = node[:type]
|
90
|
+
if type == :colon
|
91
|
+
out.push(command_search(node))
|
92
|
+
elsif type == :compare
|
93
|
+
out.push(compare_search(node))
|
94
|
+
elsif type == :and
|
95
|
+
out.push(build_query(node[:value]))
|
96
|
+
elsif type == :or
|
97
|
+
clauses = node[:value].map { |x| build_query(x) }
|
98
|
+
clause = clauses.join(' OR ')
|
99
|
+
out.push("(#{clause})")
|
100
|
+
elsif type == :not
|
101
|
+
clause = build_query(node[:value])
|
102
|
+
out.push("NOT (#{clause})")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
out.join(' AND ')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -15,12 +15,10 @@ module CommandSearch
|
|
15
15
|
type = search_node[:type]
|
16
16
|
return '0 = 1' if field == '__CommandSearch_dummy_key__'
|
17
17
|
if type == Boolean || type == :existence
|
18
|
-
false_val = 'false'
|
19
|
-
false_val = 0 if field_node[:field_type] == Numeric
|
20
18
|
if val
|
21
|
-
return "NOT ((#{field} =
|
19
|
+
return "NOT ((#{field} = 0) OR (#{field} IS NULL))"
|
22
20
|
end
|
23
|
-
return "((#{field} =
|
21
|
+
return "((#{field} = 0) OR (#{field} IS NULL))"
|
24
22
|
end
|
25
23
|
if type == Time
|
26
24
|
return '0 = 1' unless val
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zumbalogy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chronic
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/command_search/backends/memory.rb
|
36
36
|
- lib/command_search/backends/mongoer.rb
|
37
37
|
- lib/command_search/backends/mysql.rb
|
38
|
+
- lib/command_search/backends/mysql_v5.rb
|
38
39
|
- lib/command_search/backends/postgres.rb
|
39
40
|
- lib/command_search/backends/sqlite.rb
|
40
41
|
- lib/command_search/lexer.rb
|
@@ -60,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
61
|
- !ruby/object:Gem::Version
|
61
62
|
version: '0'
|
62
63
|
requirements: []
|
63
|
-
rubygems_version: 3.0.
|
64
|
+
rubygems_version: 3.0.8
|
64
65
|
signing_key:
|
65
66
|
specification_version: 4
|
66
67
|
summary: Let users query collections with ease.
|