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: 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.