command_search 0.11.0 → 0.11.1

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: 6ab70b519f399ddeeba1a8862085f8017d327b60a2cbfddaa4682363e56d2f38
4
- data.tar.gz: 204fc638f22b3ffddef67f3065c551885c9b116b4fcadffb118f52d4d7ccffb2
3
+ metadata.gz: 647f1b1fa534c1187bd63333ae986e357fb122a777e9f56d9af2d7d6f34ee6c8
4
+ data.tar.gz: d070864c2e1bba273a8fa837b20c7732efcbb5768149046cf2e68ee666e6f0b3
5
5
  SHA512:
6
- metadata.gz: 15beca3aa277baf873b57ff539b46c7dc966e357801ed69ed3818b17d89e021a6ead6bc233e119fd227bfc62615e2e0078e954cd92b9a32b216e3414cf6313e4
7
- data.tar.gz: 34da12042bd8b24d8b83bdceb08454a8ec72517cd3cfca155072cc286d0b54c683bfa16fc65f8f579759ea1a8279576c989fbd7599fdd818e0a0d45b2a7cd646
6
+ metadata.gz: 3b37775511b9cb93c556c9ce766bc76b3df6f15fb8a2671c814fa0809d32c96a5ffff0371cce4f9fb53dd9de0123f477c233611be04280883c811635a0775208
7
+ data.tar.gz: e9a636dd33c9e53211e381a00e6af3cf2aa0901fdd5e6a12079053285465eb8b4775206f48b295146b2a2e08e4e440b3888e8bff0c1bd8270edff520ad00e0b5
@@ -7,6 +7,7 @@ load(__dir__ + '/command_search/optimizer.rb')
7
7
  load(__dir__ + '/command_search/backends/memory.rb')
8
8
  load(__dir__ + '/command_search/backends/mongoer.rb')
9
9
  load(__dir__ + '/command_search/backends/postgres.rb')
10
+ load(__dir__ + '/command_search/backends/sqlite.rb')
10
11
 
11
12
  class Boolean; end
12
13
 
@@ -24,6 +25,10 @@ module CommandSearch
24
25
  Normalizer.normalize!(ast, fields, false)
25
26
  return Postgres.build_query(ast)
26
27
  end
28
+ if type == :sqlite
29
+ Normalizer.normalize!(ast, fields, false)
30
+ return Sqlite.build_query(ast)
31
+ end
27
32
  Normalizer.normalize!(ast, fields)
28
33
  return Mongoer.build_query(ast) if type == :mongo
29
34
  ast
@@ -38,6 +43,10 @@ module CommandSearch
38
43
  ast = CommandSearch.build(:postgres, query, options)
39
44
  return source.where(ast)
40
45
  end
46
+ if source.respond_to?(:sqlite3_connection)
47
+ ast = CommandSearch.build(:sqlite, query, options)
48
+ return source.where(ast)
49
+ end
41
50
  ast = CommandSearch.build(:other, query, options)
42
51
  source.select { |x| CommandSearch::Memory.check(x, ast) }
43
52
  end
@@ -4,16 +4,15 @@ module CommandSearch
4
4
 
5
5
  def quote_string(str)
6
6
  # activerecord/lib/active_record/connection_adapters/abstract/quoting.rb:62
7
- str.gsub!('\\', '\&\&')
8
- str.gsub!("'", "''")
9
- Regexp.escape(str)
7
+ str.gsub('\\', '\&\&').gsub("'", "''")
10
8
  end
11
9
 
12
10
  def build_quoted_regex(input)
13
11
  str = quote_string(input)
12
+ str = Regexp.escape(str)
14
13
  if str[/(^\W)|(\W$)/]
15
- head_border = '(^|\s|[^:+\w])'
16
- tail_border = '($|\s|[^:+\w])'
14
+ head_border = '(^|[^:+\w])'
15
+ tail_border = '($|[^:+\w])'
17
16
  return head_border + str + tail_border
18
17
  end
19
18
  '\m' + str + '\y'
@@ -36,14 +35,23 @@ module CommandSearch
36
35
  end
37
36
  if type == Time
38
37
  return '0 = 1' unless val
39
- return "(#{field} >= '#{val[0]}') AND (#{field} < '#{val[1]}') AND (#{field} IS NOT NULL)"
38
+ return "
39
+ (
40
+ (#{field} >= '#{val[0]}') AND
41
+ (#{field} < '#{val[1]}') AND
42
+ (#{field} IS NOT NULL)
43
+ )
44
+ "
40
45
  end
41
46
  if type == :quote
42
47
  op = '~'
43
48
  val = "'#{build_quoted_regex(val)}'"
44
49
  elsif type == :str
45
- op = '~*'
46
- val = "'#{quote_string(val)}'"
50
+ op = '~~*'
51
+ val = quote_string(val)
52
+ val.gsub!('%', '\%')
53
+ val.gsub!('_', '\_')
54
+ val = "'%#{val}%'"
47
55
  elsif type == :number
48
56
  op = '='
49
57
  end
@@ -58,7 +66,13 @@ module CommandSearch
58
66
  type = search_node[:type]
59
67
  op = node[:nest_op]
60
68
  if node[:compare_across_fields]
61
- "(#{field} #{op} #{val}) AND (#{field} IS NOT NULL) AND (#{val} IS NOT NULL)"
69
+ "
70
+ (
71
+ (#{field} #{op} #{val}) AND
72
+ (#{field} IS NOT NULL) AND
73
+ (#{val} IS NOT NULL)
74
+ )
75
+ "
62
76
  elsif type == Time && val
63
77
  "(#{field} #{op} '#{val}') AND (#{field} IS NOT NULL)"
64
78
  elsif val.is_a?(Numeric) || val == val.to_i.to_s || val == val.to_f.to_s
@@ -0,0 +1,111 @@
1
+ module CommandSearch
2
+ module Sqlite
3
+ module_function
4
+
5
+ def quote_string(str)
6
+ # activerecord/lib/active_record/connection_adapters/abstract/quoting.rb:62
7
+ str.gsub('\\', '\&\&').gsub("'", "''")
8
+ end
9
+
10
+ def command_search(node)
11
+ field_node = node[:value].first
12
+ field = field_node[:value]
13
+ search_node = node[:value].last
14
+ val = search_node[:value]
15
+ type = search_node[:type]
16
+ return '0 = 1' if field == '__CommandSearch_dummy_key__'
17
+ if type == Boolean || type == :existence
18
+ false_val = 'false'
19
+ false_val = 0 if field_node[:field_type] == Numeric
20
+ if val
21
+ return "NOT ((#{field} = #{false_val}) OR (#{field} IS NULL))"
22
+ end
23
+ return "((#{field} = #{false_val}) OR (#{field} IS NULL))"
24
+ end
25
+ if type == Time
26
+ return '0 = 1' unless val
27
+ return "
28
+ (
29
+ (#{field} > '#{val[0] - 1}') AND
30
+ (#{field} <= '#{val[1] - 1}') AND
31
+ (#{field} IS NOT NULL)
32
+ )
33
+ "
34
+ end
35
+ if type == :quote
36
+ val = quote_string(val)
37
+ val.gsub!('[', '[[]')
38
+ val.gsub!('*', '[*]')
39
+ val.gsub!('?', '[?]')
40
+ border = '[ .,()?"\'\']'
41
+ return "
42
+ (
43
+ (#{field} IS NOT NULL) AND
44
+ (
45
+ (#{field} GLOB '#{val}') OR
46
+ (#{field} GLOB '*#{border}#{val}#{border}*') OR
47
+ (#{field} GLOB '*#{border}#{val}') OR
48
+ (#{field} GLOB '#{val}#{border}*')
49
+ )
50
+ )
51
+ "
52
+ elsif type == :str
53
+ op = 'LIKE'
54
+ val = quote_string(val)
55
+ val.gsub!('%', '\%')
56
+ val.gsub!('_', '\_')
57
+ val = "'%#{val}%' ESCAPE '\\'"
58
+ elsif type == :number
59
+ op = '='
60
+ end
61
+ "((#{field} #{op} #{val}) AND (#{field} IS NOT NULL))"
62
+ end
63
+
64
+ def compare_search(node)
65
+ field_node = node[:value].first
66
+ field = field_node[:value]
67
+ search_node = node[:value].last
68
+ val = search_node[:value]
69
+ type = search_node[:type]
70
+ op = node[:nest_op]
71
+ if node[:compare_across_fields]
72
+ "
73
+ (
74
+ (#{field} #{op} #{val}) AND
75
+ (#{field} IS NOT NULL) AND
76
+ (#{val} IS NOT NULL)
77
+ )
78
+ "
79
+ elsif type == Time && val
80
+ "(#{field} #{op} '#{val}') AND (#{field} IS NOT NULL)"
81
+ elsif val.is_a?(Numeric) || val == val.to_i.to_s || val == val.to_f.to_s
82
+ "(#{field} #{op} #{val}) AND (#{field} IS NOT NULL)"
83
+ else
84
+ '0 = 1'
85
+ end
86
+ end
87
+
88
+ def build_query(ast)
89
+ out = []
90
+ ast = [ast] unless ast.is_a?(Array)
91
+ ast.each do |node|
92
+ type = node[:type]
93
+ if type == :colon
94
+ out.push(command_search(node))
95
+ elsif type == :compare
96
+ out.push(compare_search(node))
97
+ elsif type == :and
98
+ out.push(build_query(node[:value]))
99
+ elsif type == :or
100
+ clauses = node[:value].map { |x| build_query(x) }
101
+ clause = clauses.join(' OR ')
102
+ out.push("(#{clause})")
103
+ elsif type == :not
104
+ clause = build_query(node[:value])
105
+ out.push("NOT (#{clause})")
106
+ end
107
+ end
108
+ out.join(' AND ')
109
+ end
110
+ end
111
+ end
@@ -53,8 +53,8 @@ module CommandSearch
53
53
  str = Regexp.escape(raw)
54
54
  return node[:value] = /#{str}/i unless type == :quote
55
55
  return node[:value] = /\b#{str}\b/ unless raw[/(\A\W)|(\W\Z)/]
56
- border_a = '(^|\s|[^:+\w])'
57
- border_b = '($|\s|[^:+\w])'
56
+ border_a = '(^|[^:+\w])'
57
+ border_b = '($|[^:+\w])'
58
58
  node[:value] = Regexp.new(border_a + str + border_b)
59
59
  end
60
60
 
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.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - zumbalogy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-14 00:00:00.000000000 Z
11
+ date: 2019-12-18 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/postgres.rb
38
+ - lib/command_search/backends/sqlite.rb
38
39
  - lib/command_search/lexer.rb
39
40
  - lib/command_search/normalizer.rb
40
41
  - lib/command_search/optimizer.rb