command_search 0.11.3 → 0.12.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
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.
|