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: 8c1b899c749aee5b7a81173484fb0fa69eaffd2ab96a26cc3bff7fb7293c5058
4
- data.tar.gz: 95c7404d1176cbfb7db75b07323c2e51c13d449c7dc111f53db15db04982d5cf
3
+ metadata.gz: e1d615f992c4521f18821e9b3ee2d96fb800095abeadf549f59b8c24fb6419b6
4
+ data.tar.gz: df4378e2ab56dc1ee3299582f8a9aed11d4d64d5dd1d3d6d38a0d208a0d48f1f
5
5
  SHA512:
6
- metadata.gz: bbcf93763eceef8ce66e809603557bf8a21273c41167fdbac2ab080138af2341dd1e98fb79aa66294e8d6bca32af163b88b38f888d80c929f73f0ec9b5aec3dd
7
- data.tar.gz: c748c0a6c709c665c1028a46072c6536966d07f6d4e665ca55058e28d11f82253fdc94b3d5d78f594e0b3df2c65d55eff4e33ae865d34abc319e4e788a3d76c0
6
+ metadata.gz: 5707ed405d3f6133a6437821b5df18a076b67c299334a226639d8d9e62486f3f385a50907a2bcc57c63a86280125745f3a00975b880086539df899b1106a5acb
7
+ data.tar.gz: 312e172cc413d7f0d2efb127fd7858454b383b6eed72d1102a416f8d408eefaa831247caf5b27c67ae4959b7ac50871ccf5b05d6eb4abaa6cc6dea40d61425c7
@@ -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
- op = 'RLIKE BINARY'
46
- val = "'#{build_quoted_regex(val)}'"
47
- elsif type == :str
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} = #{false_val}) OR (#{field} IS NULL))"
19
+ return "NOT ((#{field} = 0) OR (#{field} IS NULL))"
22
20
  end
23
- return "((#{field} = #{false_val}) OR (#{field} IS NULL))"
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.11.3
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-03-04 00:00:00.000000000 Z
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.6
64
+ rubygems_version: 3.0.8
64
65
  signing_key:
65
66
  specification_version: 4
66
67
  summary: Let users query collections with ease.