command_search 0.8.1 → 0.8.2
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 +5 -5
- data/lib/command_search/command_dealiaser.rb +7 -3
- data/lib/command_search/mongoer.rb +43 -60
- data/lib/command_search/parser.rb +30 -28
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 15ffe763615f2dbf119a8960fb91405376f2d2e30b3f43f594c6b3c7730ce96c
|
4
|
+
data.tar.gz: afe8f45ba3199a987b5ee2abbb7429fc13d89658d8dd0c48af74c19d3f4634ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b10c60d4c3cca7daea2f1d14b3fc87afbdaf79922f1fc2f6fb4b33b97af8983c61ce0140e5ec1234749bd1b738fe6f34b9f6932db7f7f5ec7b95492ad863e3b
|
7
|
+
data.tar.gz: ad4acd1ceeafa32f0982a9c076724b3b933177653e997f2d8a5c9635f61d3f17980e47285c32b375a1ec0a28765dd5eaf00f01c5a160d8cd7e9cc1f1c3cc04f2
|
@@ -15,9 +15,13 @@ module CommandSearch
|
|
15
15
|
|
16
16
|
def unnest_unaliased(node, aliases)
|
17
17
|
type = node[:nest_type]
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
if type == :colon
|
19
|
+
val = node[:value][0][:value].to_sym
|
20
|
+
return node if aliases[val]
|
21
|
+
elsif type == :compare
|
22
|
+
return node if node[:value].any? { |child| aliases[child[:value].to_sym] }
|
23
|
+
end
|
24
|
+
values = node[:value].map { |x| x[:value] }
|
21
25
|
str_values = values.join(node[:nest_op])
|
22
26
|
{ type: :str, value: str_values }
|
23
27
|
end
|
@@ -5,28 +5,27 @@ module CommandSearch
|
|
5
5
|
module_function
|
6
6
|
|
7
7
|
def numeric_field?(field, command_types)
|
8
|
-
|
9
|
-
if
|
10
|
-
type = (
|
11
|
-
else
|
12
|
-
type = raw_type
|
8
|
+
type = command_types[field.to_sym]
|
9
|
+
if type.is_a?(Array)
|
10
|
+
type = (type - [:allow_existence_boolean]).first
|
13
11
|
end
|
14
12
|
[Numeric, Integer].include?(type)
|
15
13
|
end
|
16
14
|
|
15
|
+
def build_str_regex(raw, type)
|
16
|
+
str = Regexp.escape(raw)
|
17
|
+
return /#{str}/i unless type == :quoted_str
|
18
|
+
return '' if raw == ''
|
19
|
+
return /\b#{str}\b/ unless raw[/(^\W)|(\W$)/]
|
20
|
+
border_a = '(^|\s|[^:+\w])'
|
21
|
+
border_b = '($|\s|[^:+\w])'
|
22
|
+
Regexp.new(border_a + str + border_b)
|
23
|
+
end
|
24
|
+
|
17
25
|
def build_search(ast_node, fields, command_types)
|
18
26
|
str = ast_node[:value] || ''
|
19
27
|
fields = [fields] unless fields.is_a?(Array)
|
20
|
-
|
21
|
-
regex = /\b#{Regexp.escape(str)}\b/
|
22
|
-
if str[/(^\W)|(\W$)/]
|
23
|
-
head_border = '(?<=^|[^:+\w])'
|
24
|
-
tail_border = '(?=$|[^:+\w])'
|
25
|
-
regex = Regexp.new(head_border + Regexp.escape(str) + tail_border)
|
26
|
-
end
|
27
|
-
else
|
28
|
-
regex = /#{Regexp.escape(str)}/i
|
29
|
-
end
|
28
|
+
regex = build_str_regex(str, ast_node[:type])
|
30
29
|
|
31
30
|
forms = fields.map do |field|
|
32
31
|
if numeric_field?(field, command_types)
|
@@ -39,12 +38,29 @@ module CommandSearch
|
|
39
38
|
{ '$or' => forms }
|
40
39
|
end
|
41
40
|
|
42
|
-
def is_bool_str?(str)
|
43
|
-
str[/\Atrue\Z|\Afalse\Z/i]
|
41
|
+
def is_bool_str?(str, search_type)
|
42
|
+
search_type != :quoted_str && str[/\Atrue\Z|\Afalse\Z/i]
|
44
43
|
end
|
45
44
|
|
46
45
|
def make_boolean(str)
|
47
|
-
str[
|
46
|
+
str[0] == 't'
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_time_command(key, val)
|
50
|
+
time_str = val.tr('_.-', ' ')
|
51
|
+
if time_str == time_str.to_i.to_s
|
52
|
+
date_a = Time.new(time_str)
|
53
|
+
date_b = Time.new(time_str.to_i + 1).yesterday
|
54
|
+
else
|
55
|
+
date = Chronic.parse(time_str, guess: nil) || Chronic.parse(val, guess: nil)
|
56
|
+
return [{ CommandSeachDummyDate: true }, { CommandSeachDummyDate: false }] unless date
|
57
|
+
date_a = date.begin
|
58
|
+
date_b = date.end
|
59
|
+
end
|
60
|
+
[
|
61
|
+
{ key => { '$gte' => date_a } },
|
62
|
+
{ key => { '$lte' => date_b } }
|
63
|
+
]
|
48
64
|
end
|
49
65
|
|
50
66
|
def build_command(ast_node, command_types)
|
@@ -57,11 +73,11 @@ module CommandSearch
|
|
57
73
|
search_type = search_node[:type]
|
58
74
|
|
59
75
|
if raw_type.is_a?(Array)
|
60
|
-
is_bool = raw_type.include?(:allow_existence_boolean) && is_bool_str?(raw_val) && search_type != :quoted_str
|
61
76
|
type = (raw_type - [:allow_existence_boolean]).first
|
77
|
+
is_bool = raw_type.include?(:allow_existence_boolean) && is_bool_str?(raw_val, search_type)
|
62
78
|
else
|
63
|
-
is_bool = false
|
64
79
|
type = raw_type
|
80
|
+
is_bool = false
|
65
81
|
end
|
66
82
|
|
67
83
|
if type == Boolean
|
@@ -84,40 +100,11 @@ module CommandSearch
|
|
84
100
|
val = { '$exists' => false }
|
85
101
|
end
|
86
102
|
elsif type == String
|
87
|
-
|
88
|
-
val = /\b#{Regexp.escape(raw_val)}\b/
|
89
|
-
val = '' if raw_val == ''
|
90
|
-
if raw_val[/(^\W)|(\W$)/]
|
91
|
-
head_border = '(?<=^|[^:+\w])'
|
92
|
-
tail_border = '(?=$|[^:+\w])'
|
93
|
-
val = Regexp.new(head_border + Regexp.escape(raw_val) + tail_border)
|
94
|
-
end
|
95
|
-
else
|
96
|
-
val = /#{Regexp.escape(raw_val)}/i
|
97
|
-
end
|
103
|
+
val = build_str_regex(raw_val, search_type)
|
98
104
|
elsif [Numeric, Integer].include?(type)
|
99
|
-
|
100
|
-
val = raw_val.to_i
|
101
|
-
elsif raw_val.to_f != 0 || raw_val[/\A[\.0]*0\Z/]
|
102
|
-
val = raw_val.to_f
|
103
|
-
else
|
104
|
-
val = raw_val
|
105
|
-
end
|
105
|
+
val = raw_val
|
106
106
|
elsif [Date, Time, DateTime].include?(type)
|
107
|
-
|
108
|
-
if time_str == time_str.to_i.to_s
|
109
|
-
date_begin = Time.new(time_str)
|
110
|
-
date_end = Time.new(time_str.to_i + 1).yesterday
|
111
|
-
else
|
112
|
-
date = Chronic.parse(time_str, guess: nil) || Chronic.parse(raw_val, guess: nil)
|
113
|
-
date_begin = date.begin
|
114
|
-
date_end = date.end
|
115
|
-
end
|
116
|
-
val = [
|
117
|
-
{ key => { '$gte' => date_begin } },
|
118
|
-
{ key => { '$lte' => date_end } }
|
119
|
-
]
|
120
|
-
key = '$and'
|
107
|
+
return build_time_command(key, raw_val)
|
121
108
|
end
|
122
109
|
{ key => val }
|
123
110
|
end
|
@@ -151,7 +138,7 @@ module CommandSearch
|
|
151
138
|
raw_type = command_types[key.to_sym]
|
152
139
|
|
153
140
|
if raw_type.is_a?(Array)
|
154
|
-
type = (raw_type - [:
|
141
|
+
type = (raw_type - [:allow_existence_boolean]).first
|
155
142
|
else
|
156
143
|
type = raw_type
|
157
144
|
end
|
@@ -161,12 +148,6 @@ module CommandSearch
|
|
161
148
|
key = '$' + key
|
162
149
|
val = [key, val]
|
163
150
|
key = '$expr'
|
164
|
-
elsif [Numeric, Integer].include?(type)
|
165
|
-
if val == val.to_i.to_s
|
166
|
-
val = val.to_i
|
167
|
-
else
|
168
|
-
val = val.to_f
|
169
|
-
end
|
170
151
|
elsif [Date, Time, DateTime].include?(type)
|
171
152
|
# foo < day | day.start
|
172
153
|
# foo <= day | day.end
|
@@ -187,6 +168,8 @@ module CommandSearch
|
|
187
168
|
date = Chronic.parse(time_str, guess: nil) || Chronic.parse(val, guess: nil)
|
188
169
|
end
|
189
170
|
|
171
|
+
date = date || []
|
172
|
+
|
190
173
|
if date_pick == :start
|
191
174
|
val = date.first
|
192
175
|
elsif date_pick == :end
|
@@ -233,7 +216,7 @@ module CommandSearch
|
|
233
216
|
end
|
234
217
|
end
|
235
218
|
|
236
|
-
def build_query(ast, fields, command_types
|
219
|
+
def build_query(ast, fields, command_types)
|
237
220
|
out = ast
|
238
221
|
build_searches!(out, fields, command_types)
|
239
222
|
build_tree!(out)
|
@@ -2,40 +2,42 @@ module CommandSearch
|
|
2
2
|
module Parser
|
3
3
|
module_function
|
4
4
|
|
5
|
-
def parens_rindex(input)
|
6
|
-
open_i = input.rindex { |x| x[:value] == '(' && x[:type] == :paren }
|
7
|
-
return unless open_i
|
8
|
-
close_offset = input.drop(open_i).index { |x| x[:value] == ')' && x[:type] == :paren }
|
9
|
-
return unless close_offset
|
10
|
-
[open_i, close_offset + open_i]
|
11
|
-
end
|
12
|
-
|
13
5
|
def group_parens!(input)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
i = 0
|
7
|
+
opening_idxs = []
|
8
|
+
while i < input.length
|
9
|
+
next i += 1 unless input[i][:type] == :paren
|
10
|
+
if input[i][:value] == '('
|
11
|
+
opening_idxs.push(i)
|
12
|
+
elsif opening = opening_idxs.pop()
|
13
|
+
val = input[(opening + 1)..(i - 1)]
|
14
|
+
input[opening..i] = { type: :nest, nest_type: :paren, value: val }
|
15
|
+
i -= (val.length + 1)
|
16
|
+
end
|
17
|
+
i += 1
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
def cluster!(type, input, cluster_type = :binary)
|
22
22
|
binary = (cluster_type == :binary)
|
23
|
-
input.
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
23
|
+
i = input.length - 1
|
24
|
+
while i >= 0
|
25
|
+
if input[i][:type] == type
|
26
|
+
val = [input[i + 1]]
|
27
|
+
val.compact!
|
28
|
+
val.unshift(input[i - 1]) if binary && i > 0
|
29
|
+
front_offset = 0
|
30
|
+
front_offset = 1 if binary && i > 0
|
31
|
+
input[(i - front_offset)..(i + 1)] = {
|
32
|
+
type: :nest,
|
33
|
+
nest_type: type,
|
34
|
+
nest_op: input[i][:value],
|
35
|
+
value: val
|
36
|
+
}
|
37
|
+
i -= 1 if binary
|
38
|
+
end
|
39
|
+
cluster!(type, input[i][:value], cluster_type) if input[i][:type] == :nest
|
40
|
+
i -= 1
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
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.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zumbalogy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chronic
|
@@ -57,8 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
57
|
- !ruby/object:Gem::Version
|
58
58
|
version: '0'
|
59
59
|
requirements: []
|
60
|
-
|
61
|
-
rubygems_version: 2.6.11
|
60
|
+
rubygems_version: 3.0.4
|
62
61
|
signing_key:
|
63
62
|
specification_version: 4
|
64
63
|
summary: Let users query collections with ease.
|