hotdog 0.25.0 → 0.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hotdog/commands/down.rb +2 -1
- data/lib/hotdog/commands/hosts.rb +2 -1
- data/lib/hotdog/commands/pssh.rb +3 -1
- data/lib/hotdog/commands/ssh.rb +58 -24
- data/lib/hotdog/commands/tags.rb +3 -2
- data/lib/hotdog/expression/semantics.rb +61 -33
- data/lib/hotdog/version.rb +1 -1
- data/spec/optimizer/unary_expression_spec.rb +307 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d13acaecbe1b4f13f6b9956f2e75cf69cfaff23
|
4
|
+
data.tar.gz: acdef611442f0a968b0b9810c962b25864c0b406
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6f4cc4380eea63cee183a0baff9b606e40e94cdc6522e5e16e33e44acb161987d6001ebf743fa6a7f054c4ed8cc034edd8494893a4c9736be58376efbd2ad7d
|
7
|
+
data.tar.gz: 950a18e1686c18591e474900353f738c78cc5f568c830dd41f43b231905eebdfe3bc415fd1662d710e9ec1072e4bba3ab050886f239a20aa35e8c237f7db75e0
|
data/lib/hotdog/commands/down.rb
CHANGED
@@ -39,7 +39,8 @@ module Hotdog
|
|
39
39
|
with_retry(error_handler: ->(error) { reload }) do
|
40
40
|
if open_db
|
41
41
|
@db.transaction do
|
42
|
-
|
42
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
43
|
+
hosts.each_slice(sqlite_limit_compound_select) do |hosts|
|
43
44
|
execute_db(@db, "DELETE FROM hosts_tags WHERE host_id IN ( SELECT id FROM hosts WHERE name IN (%s) );" % hosts.map { "?" }.join(", "), hosts)
|
44
45
|
execute_db(@db, "DELETE FROM hosts WHERE name IN (%s);" % hosts.map { "?" }.join(", "), hosts)
|
45
46
|
end
|
@@ -13,7 +13,8 @@ module Hotdog
|
|
13
13
|
execute("SELECT id FROM hosts WHERE LOWER(name) GLOB LOWER(?);", [host_name]).to_a.reduce(:+) || []
|
14
14
|
}
|
15
15
|
else
|
16
|
-
|
16
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
17
|
+
result = args.each_slice(sqlite_limit_compound_select).flat_map { |args|
|
17
18
|
execute("SELECT id FROM hosts WHERE name IN (%s);" % args.map { "?" }.join(", "), args).to_a.reduce(:+) || []
|
18
19
|
}
|
19
20
|
end
|
data/lib/hotdog/commands/pssh.rb
CHANGED
@@ -5,6 +5,7 @@ require "parallel"
|
|
5
5
|
require "parslet"
|
6
6
|
require "shellwords"
|
7
7
|
require "tempfile"
|
8
|
+
require "thread"
|
8
9
|
require "hotdog/commands/ssh"
|
9
10
|
|
10
11
|
module Hotdog
|
@@ -43,9 +44,10 @@ module Hotdog
|
|
43
44
|
true
|
44
45
|
}
|
45
46
|
else
|
47
|
+
output_lock = Mutex.new
|
46
48
|
stats = Parallel.map(hosts_cmdlines.each_with_index.to_a, in_threads: parallelism(hosts)) { |(host, cmdline), i|
|
47
49
|
identifier = options[:show_identifier] ? host : nil
|
48
|
-
success = exec_command(identifier, cmdline, index: i, output: true, infile: (infile ? infile.path : nil))
|
50
|
+
success = exec_command(identifier, cmdline, index: i, output: true, infile: (infile ? infile.path : nil), output_lock: output_lock)
|
49
51
|
if !success && options[:stop_on_error]
|
50
52
|
raise StopException.new
|
51
53
|
end
|
data/lib/hotdog/commands/ssh.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "json"
|
4
4
|
require "parslet"
|
5
5
|
require "shellwords"
|
6
|
+
require "thread"
|
6
7
|
require "hotdog/commands/search"
|
7
8
|
|
8
9
|
module Hotdog
|
@@ -152,42 +153,75 @@ module Hotdog
|
|
152
153
|
|
153
154
|
def exec_command(identifier, cmdline, options={})
|
154
155
|
output = options.fetch(:output, true)
|
156
|
+
output_lock = options[:output_lock] || Mutex.new
|
155
157
|
logger.debug("execute: #{cmdline}")
|
156
158
|
if use_color?
|
157
|
-
|
158
|
-
color = 31 + (options[:index] % 6)
|
159
|
-
else
|
160
|
-
color = 36
|
161
|
-
end
|
159
|
+
color = color_code(options[:index])
|
162
160
|
else
|
163
161
|
color = nil
|
164
162
|
end
|
165
163
|
if options[:infile]
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
STDOUT.write(i.to_s)
|
180
|
-
STDOUT.write(":")
|
181
|
-
if color
|
182
|
-
STDOUT.write("\e[0m")
|
183
|
-
end
|
164
|
+
cmdline = "cat #{Shellwords.shellescape(options[:infile])} | #{cmdline}"
|
165
|
+
end
|
166
|
+
cmderr, child_cmderr = IO.pipe
|
167
|
+
IO.popen(cmdline, in: :close, err: child_cmderr) do |cmdout|
|
168
|
+
i = 0
|
169
|
+
each_readable([cmderr, cmdout]) do |readable|
|
170
|
+
raw = readable.readline
|
171
|
+
output_lock.synchronize do
|
172
|
+
if readable == cmdout
|
173
|
+
STDOUT.puts(prettify_output(raw, i, color, identifier))
|
174
|
+
i += 1
|
175
|
+
else
|
176
|
+
STDERR.puts(raw)
|
184
177
|
end
|
185
|
-
STDOUT.puts(s)
|
186
178
|
end
|
187
179
|
end
|
188
180
|
end
|
189
181
|
$?.success? # $? is thread-local variable
|
190
182
|
end
|
183
|
+
|
184
|
+
private
|
185
|
+
def each_readable(read_list, timeout=1)
|
186
|
+
loop do
|
187
|
+
# we cannot look until IO#eof? since it will block for pipes
|
188
|
+
# http://ruby-doc.org/core-2.4.0/IO.html#method-i-eof-3F
|
189
|
+
rs = Array(IO.select(read_list, [], [], timeout)).first
|
190
|
+
if r = Array(rs).first
|
191
|
+
begin
|
192
|
+
yield r
|
193
|
+
rescue EOFError => error
|
194
|
+
break
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def color_code(index)
|
201
|
+
if index
|
202
|
+
color = 31 + (index % 6)
|
203
|
+
else
|
204
|
+
color = 36
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def prettify_output(raw, i, color, identifier)
|
209
|
+
buf = []
|
210
|
+
if identifier
|
211
|
+
if color
|
212
|
+
buf << ("\e[0;#{color}m")
|
213
|
+
end
|
214
|
+
buf << identifier
|
215
|
+
buf << ":"
|
216
|
+
buf << i.to_s
|
217
|
+
buf << ":"
|
218
|
+
if color
|
219
|
+
buf << "\e[0m"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
buf << raw
|
223
|
+
buf.join
|
224
|
+
end
|
191
225
|
end
|
192
226
|
|
193
227
|
class SingularSshAlike < SshAlike
|
data/lib/hotdog/commands/tags.rb
CHANGED
@@ -9,14 +9,15 @@ module Hotdog
|
|
9
9
|
show_tags(result)
|
10
10
|
else
|
11
11
|
tags = args.map { |tag| split_tag(tag) }
|
12
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
12
13
|
if tags.all? { |_tagname, tagvalue| tagvalue.empty? }
|
13
|
-
result = tags.each_slice(
|
14
|
+
result = tags.each_slice(sqlite_limit_compound_select).flat_map { |tags|
|
14
15
|
q = "SELECT value FROM tags " \
|
15
16
|
"WHERE %s;" % tags.map { |tagname, _tagvalue| glob?(tagname) ? "LOWER(name) GLOB LOWER(?)" : "name = ?" }.join(" OR ")
|
16
17
|
execute(q, tags.map { |tagname, _tagvalue| tagname }).map { |value| [value] }
|
17
18
|
}
|
18
19
|
else
|
19
|
-
result = tags.each_slice(
|
20
|
+
result = tags.each_slice(sqlite_limit_compound_select / 2).flat_map { |tags|
|
20
21
|
q = "SELECT value FROM tags " \
|
21
22
|
"WHERE %s;" % tags.map { |tagname, tagvalue| (glob?(tagname) or glob?(tagvalue)) ? "( LOWER(name) GLOB LOWER(?) AND LOWER(value) GLOB LOWER(?) )" : "( name = ? AND value = ? )" }.join(" OR ")
|
22
23
|
execute(q, tags).map { |value| [value] }
|
@@ -25,6 +25,8 @@ module Hotdog
|
|
25
25
|
|
26
26
|
def initialize(op, expression)
|
27
27
|
case (op || "not").to_s
|
28
|
+
when "NOOP", "noop"
|
29
|
+
@op = :NOOP
|
28
30
|
when "!", "~", "NOT", "not"
|
29
31
|
@op = :NOT
|
30
32
|
else
|
@@ -35,6 +37,8 @@ module Hotdog
|
|
35
37
|
|
36
38
|
def evaluate(environment, options={})
|
37
39
|
case @op
|
40
|
+
when :NOOP
|
41
|
+
@expression.evaluate(environment, options)
|
38
42
|
when :NOT
|
39
43
|
values = @expression.evaluate(environment, options).tap do |values|
|
40
44
|
environment.logger.debug("expr: #{values.length} value(s)")
|
@@ -46,8 +50,9 @@ module Hotdog
|
|
46
50
|
else
|
47
51
|
# workaround for "too many terms in compound SELECT"
|
48
52
|
min, max = environment.execute("SELECT MIN(id), MAX(id) FROM hosts LIMIT 1;").first.to_a
|
49
|
-
|
50
|
-
|
53
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
54
|
+
(min / (sqlite_limit_compound_select - 2)).upto(max / (sqlite_limit_compound_select - 2)).flat_map { |i|
|
55
|
+
range = ((sqlite_limit_compound_select - 2) * i)...((sqlite_limit_compound_select - 2) * (i + 1))
|
51
56
|
selected = values.select { |n| range === n }
|
52
57
|
q = "SELECT id FROM hosts " \
|
53
58
|
"WHERE ? <= id AND id < ? AND id NOT IN (%s);"
|
@@ -62,8 +67,9 @@ module Hotdog
|
|
62
67
|
end
|
63
68
|
|
64
69
|
def optimize(options={})
|
65
|
-
@expression = @expression.optimize(options)
|
66
70
|
case op
|
71
|
+
when :NOOP
|
72
|
+
optimize1(options)
|
67
73
|
when :NOT
|
68
74
|
case expression
|
69
75
|
when EverythingNode
|
@@ -74,6 +80,7 @@ module Hotdog
|
|
74
80
|
optimize1(options)
|
75
81
|
end
|
76
82
|
else
|
83
|
+
@expression = expression.optimize(options)
|
77
84
|
self
|
78
85
|
end
|
79
86
|
end
|
@@ -89,30 +96,45 @@ module Hotdog
|
|
89
96
|
private
|
90
97
|
def optimize1(options={})
|
91
98
|
case op
|
99
|
+
when :NOOP
|
100
|
+
expression.optimize(options)
|
92
101
|
when :NOT
|
93
|
-
if UnaryExpressionNode === expression
|
94
|
-
expression.
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
if q and v.length <= SQLITE_LIMIT_COMPOUND_SELECT
|
101
|
-
QueryExpressionNode.new("SELECT id AS host_id FROM hosts EXCEPT #{q.sub(/\s*;\s*\z/, "")};", v)
|
102
|
-
else
|
103
|
-
self
|
104
|
-
end
|
105
|
-
when TagExpressionNode
|
106
|
-
q = expression.maybe_query(options)
|
107
|
-
v = expression.condition_values(options)
|
108
|
-
if q and v.length <= SQLITE_LIMIT_COMPOUND_SELECT
|
109
|
-
QueryExpressionNode.new("SELECT id AS host_id FROM hosts EXCEPT #{q.sub(/\s*;\s*\z/, "")};", v)
|
110
|
-
else
|
111
|
-
self
|
112
|
-
end
|
102
|
+
if UnaryExpressionNode === expression
|
103
|
+
case expression.op
|
104
|
+
when :NOOP
|
105
|
+
@expression = expression.optimize(options)
|
106
|
+
optimize2(options)
|
107
|
+
when :NOT
|
108
|
+
expression.expression.optimize(options)
|
113
109
|
else
|
114
110
|
self
|
115
111
|
end
|
112
|
+
else
|
113
|
+
optimize2(options)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
self
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def optimize2(options={})
|
121
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
122
|
+
case expression
|
123
|
+
when QueryExpressionNode
|
124
|
+
q = expression.query
|
125
|
+
v = expression.values
|
126
|
+
if q and v.length <= sqlite_limit_compound_select
|
127
|
+
QueryExpressionNode.new("SELECT id AS host_id FROM hosts EXCEPT #{q.sub(/\s*;\s*\z/, "")};", v)
|
128
|
+
else
|
129
|
+
self
|
130
|
+
end
|
131
|
+
when TagExpressionNode
|
132
|
+
q = expression.maybe_query(options)
|
133
|
+
v = expression.condition_values(options)
|
134
|
+
if q and v.length <= sqlite_limit_compound_select
|
135
|
+
QueryExpressionNode.new("SELECT id AS host_id FROM hosts EXCEPT #{q.sub(/\s*;\s*\z/, "")};", v)
|
136
|
+
else
|
137
|
+
self
|
116
138
|
end
|
117
139
|
else
|
118
140
|
self
|
@@ -155,8 +177,9 @@ module Hotdog
|
|
155
177
|
else
|
156
178
|
# workaround for "too many terms in compound SELECT"
|
157
179
|
min, max = environment.execute("SELECT MIN(id), MAX(id) FROM hosts LIMIT 1;").first.to_a
|
158
|
-
|
159
|
-
|
180
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
181
|
+
(min / ((sqlite_limit_compound_select - 2) / 2)).upto(max / ((sqlite_limit_compound_select - 2) / 2)).flat_map { |i|
|
182
|
+
range = (((sqlite_limit_compound_select - 2) / 2) * i)...(((sqlite_limit_compound_select - 2) / 2) * (i + 1))
|
160
183
|
left_selected = left_values.select { |n| range === n }
|
161
184
|
right_selected = right_values.select { |n| range === n }
|
162
185
|
q = "SELECT id FROM hosts " \
|
@@ -182,8 +205,9 @@ module Hotdog
|
|
182
205
|
else
|
183
206
|
# workaround for "too many terms in compound SELECT"
|
184
207
|
min, max = environment.execute("SELECT MIN(id), MAX(id) FROM hosts LIMIT 1;").first.to_a
|
185
|
-
|
186
|
-
|
208
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
209
|
+
(min / ((sqlite_limit_compound_select - 2) / 2)).upto(max / ((sqlite_limit_compound_select - 2) / 2)).flat_map { |i|
|
210
|
+
range = (((sqlite_limit_compound_select - 2) / 2) * i)...(((sqlite_limit_compound_select - 2) / 2) * (i + 1))
|
187
211
|
left_selected = left_values.select { |n| range === n }
|
188
212
|
right_selected = right_values.select { |n| range === n }
|
189
213
|
q = "SELECT id FROM hosts " \
|
@@ -209,8 +233,9 @@ module Hotdog
|
|
209
233
|
else
|
210
234
|
# workaround for "too many terms in compound SELECT"
|
211
235
|
min, max = environment.execute("SELECT MIN(id), MAX(id) FROM hosts LIMIT 1;").first.to_a
|
212
|
-
|
213
|
-
|
236
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
237
|
+
(min / ((sqlite_limit_compound_select - 2) / 4)).upto(max / ((sqlite_limit_compound_select - 2) / 4)).flat_map { |i|
|
238
|
+
range = (((sqlite_limit_compound_select - 2) / 4) * i)...(((sqlite_limit_compound_select - 2) / 4) * (i + 1))
|
214
239
|
left_selected = left_values.select { |n| range === n }
|
215
240
|
right_selected = right_values.select { |n| range === n }
|
216
241
|
q = "SELECT id FROM hosts " \
|
@@ -300,7 +325,8 @@ module Hotdog
|
|
300
325
|
lv = left.condition_values(options)
|
301
326
|
rq = right.maybe_query(options)
|
302
327
|
rv = right.condition_values(options)
|
303
|
-
|
328
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
329
|
+
if lq and rq and lv.length + rv.length <= sqlite_limit_compound_select
|
304
330
|
case op
|
305
331
|
when :AND
|
306
332
|
q = "#{lq.sub(/\s*;\s*\z/, "")} INTERSECT #{rq.sub(/\s*;\s*\z/, "")};"
|
@@ -335,8 +361,9 @@ module Hotdog
|
|
335
361
|
else
|
336
362
|
raise(SyntaxError.new("unknown multinary operator: #{op.inspect}"))
|
337
363
|
end
|
338
|
-
|
339
|
-
|
364
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
365
|
+
if sqlite_limit_compound_select < expressions.length
|
366
|
+
raise(ArgumentError.new("expressions limit exceeded: #{expressions.length} for #{sqlite_limit_compound_select}"))
|
340
367
|
end
|
341
368
|
@expressions = expressions
|
342
369
|
@fallback = options[:fallback]
|
@@ -358,7 +385,8 @@ module Hotdog
|
|
358
385
|
query_without_condition = expressions.first.maybe_query_without_condition(options)
|
359
386
|
if query_without_condition
|
360
387
|
condition_length = expressions.map { |expression| expression.condition_values(options).length }.max
|
361
|
-
|
388
|
+
sqlite_limit_compound_select = options[:sqlite_limit_compound_select] || SQLITE_LIMIT_COMPOUND_SELECT
|
389
|
+
expressions.each_slice(sqlite_limit_compound_select / condition_length).flat_map { |expressions|
|
362
390
|
q = query_without_condition.sub(/\s*;\s*\z/, " WHERE #{expressions.map { |expression| "( %s )" % expression.condition(options) }.join(" OR ")};")
|
363
391
|
environment.execute(q, expressions.flat_map { |expression| expression.condition_values(options) }).map { |row| row.first }
|
364
392
|
}
|
data/lib/hotdog/version.rb
CHANGED
@@ -5,7 +5,7 @@ require "hotdog/commands/search"
|
|
5
5
|
require "parslet"
|
6
6
|
|
7
7
|
describe "unary expression" do
|
8
|
-
it "should
|
8
|
+
it "NOT nothing should return everything" do
|
9
9
|
expr = Hotdog::Expression::UnaryExpressionNode.new("NOT", Hotdog::Expression::NothingNode.new())
|
10
10
|
expect(expr.optimize.dump).to eq({
|
11
11
|
query: "SELECT id AS host_id FROM hosts;",
|
@@ -13,11 +13,316 @@ describe "unary expression" do
|
|
13
13
|
})
|
14
14
|
end
|
15
15
|
|
16
|
-
it "should
|
16
|
+
it "NOT everything should return nothing" do
|
17
17
|
expr = Hotdog::Expression::UnaryExpressionNode.new("NOT", Hotdog::Expression::EverythingNode.new())
|
18
18
|
expect(expr.optimize.dump).to eq({
|
19
19
|
query: "SELECT NULL AS host_id WHERE host_id NOT NULL;",
|
20
20
|
values: [],
|
21
21
|
})
|
22
22
|
end
|
23
|
+
|
24
|
+
it "NOT NOT nothing should return nothing" do
|
25
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
26
|
+
"NOT",
|
27
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
28
|
+
"NOT",
|
29
|
+
Hotdog::Expression::NothingNode.new(),
|
30
|
+
),
|
31
|
+
)
|
32
|
+
expect(expr.optimize.dump).to eq({
|
33
|
+
query: "SELECT NULL AS host_id WHERE host_id NOT NULL;",
|
34
|
+
values: [],
|
35
|
+
})
|
36
|
+
end
|
37
|
+
|
38
|
+
it "NOT NOT everything should return everything" do
|
39
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
40
|
+
"NOT",
|
41
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
42
|
+
"NOT",
|
43
|
+
Hotdog::Expression::EverythingNode.new(),
|
44
|
+
),
|
45
|
+
)
|
46
|
+
expect(expr.optimize.dump).to eq({
|
47
|
+
query: "SELECT id AS host_id FROM hosts;",
|
48
|
+
values: [],
|
49
|
+
})
|
50
|
+
end
|
51
|
+
|
52
|
+
it "NOT NOT NOT nothing should return everything" do
|
53
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
54
|
+
"NOT",
|
55
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
56
|
+
"NOT",
|
57
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
58
|
+
"NOT",
|
59
|
+
Hotdog::Expression::NothingNode.new(),
|
60
|
+
),
|
61
|
+
),
|
62
|
+
)
|
63
|
+
expect(expr.optimize.dump).to eq({
|
64
|
+
query: "SELECT id AS host_id FROM hosts;",
|
65
|
+
values: [],
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
it "NOT NOT NOT everything should return nothing" do
|
70
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
71
|
+
"NOT",
|
72
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
73
|
+
"NOT",
|
74
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
75
|
+
"NOT",
|
76
|
+
Hotdog::Expression::EverythingNode.new(),
|
77
|
+
),
|
78
|
+
),
|
79
|
+
)
|
80
|
+
expect(expr.optimize.dump).to eq({
|
81
|
+
query: "SELECT NULL AS host_id WHERE host_id NOT NULL;",
|
82
|
+
values: [],
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
it "NOT host should return everything except the host" do
|
87
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
88
|
+
"NOT",
|
89
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
90
|
+
)
|
91
|
+
expect(expr.optimize.dump).to eq({
|
92
|
+
query: "SELECT id AS host_id FROM hosts EXCEPT SELECT hosts.id AS host_id FROM hosts WHERE hosts.name = ?;",
|
93
|
+
values: ["foo"],
|
94
|
+
})
|
95
|
+
end
|
96
|
+
|
97
|
+
it "NOT NOT host should return the host" do
|
98
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
99
|
+
"NOT",
|
100
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
101
|
+
"NOT",
|
102
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
103
|
+
),
|
104
|
+
)
|
105
|
+
expect(expr.optimize.dump).to eq({
|
106
|
+
tagname: "host",
|
107
|
+
separator: ":",
|
108
|
+
tagvalue: "foo",
|
109
|
+
fallback: {
|
110
|
+
query: [
|
111
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
112
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
113
|
+
].join(" "),
|
114
|
+
values: ["*foo*"],
|
115
|
+
},
|
116
|
+
})
|
117
|
+
end
|
118
|
+
|
119
|
+
it "NOT NOT NOT host should return everything except the host" do
|
120
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
121
|
+
"NOT",
|
122
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
123
|
+
"NOT",
|
124
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
125
|
+
"NOT",
|
126
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
127
|
+
),
|
128
|
+
),
|
129
|
+
)
|
130
|
+
expect(expr.optimize.dump).to eq({
|
131
|
+
query: "SELECT id AS host_id FROM hosts EXCEPT SELECT hosts.id AS host_id FROM hosts WHERE hosts.name = ?;",
|
132
|
+
values: ["foo"],
|
133
|
+
})
|
134
|
+
end
|
135
|
+
|
136
|
+
it "NOOP host should return the host" do
|
137
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
138
|
+
"NOOP",
|
139
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
140
|
+
)
|
141
|
+
expect(expr.optimize.dump).to eq({
|
142
|
+
tagname: "host",
|
143
|
+
separator: ":",
|
144
|
+
tagvalue: "foo",
|
145
|
+
fallback: {
|
146
|
+
query: [
|
147
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
148
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
149
|
+
].join(" "),
|
150
|
+
values: ["*foo*"],
|
151
|
+
},
|
152
|
+
})
|
153
|
+
end
|
154
|
+
|
155
|
+
it "NOOP NOOP host should return the host" do
|
156
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
157
|
+
"NOOP",
|
158
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
159
|
+
"NOOP",
|
160
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
161
|
+
),
|
162
|
+
)
|
163
|
+
expect(expr.optimize.dump).to eq({
|
164
|
+
tagname: "host",
|
165
|
+
separator: ":",
|
166
|
+
tagvalue: "foo",
|
167
|
+
fallback: {
|
168
|
+
query: [
|
169
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
170
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
171
|
+
].join(" "),
|
172
|
+
values: ["*foo*"],
|
173
|
+
},
|
174
|
+
})
|
175
|
+
end
|
176
|
+
|
177
|
+
it "NOOP NOOP NOOP host should return the host" do
|
178
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
179
|
+
"NOOP",
|
180
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
181
|
+
"NOOP",
|
182
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
183
|
+
"NOOP",
|
184
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
185
|
+
),
|
186
|
+
),
|
187
|
+
)
|
188
|
+
expect(expr.optimize.dump).to eq({
|
189
|
+
tagname: "host",
|
190
|
+
separator: ":",
|
191
|
+
tagvalue: "foo",
|
192
|
+
fallback: {
|
193
|
+
query: [
|
194
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
195
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
196
|
+
].join(" "),
|
197
|
+
values: ["*foo*"],
|
198
|
+
},
|
199
|
+
})
|
200
|
+
end
|
201
|
+
|
202
|
+
it "NOT NOOP NOOP host should return everything except the host" do
|
203
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
204
|
+
"NOT",
|
205
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
206
|
+
"NOOP",
|
207
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
208
|
+
"NOOP",
|
209
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
210
|
+
),
|
211
|
+
),
|
212
|
+
)
|
213
|
+
expect(expr.optimize.dump).to eq({
|
214
|
+
query: "SELECT id AS host_id FROM hosts EXCEPT SELECT hosts.id AS host_id FROM hosts WHERE hosts.name = ?;",
|
215
|
+
values: ["foo"],
|
216
|
+
})
|
217
|
+
end
|
218
|
+
|
219
|
+
it "NOOP NOT NOOP host should return everything except the host" do
|
220
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
221
|
+
"NOOP",
|
222
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
223
|
+
"NOT",
|
224
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
225
|
+
"NOOP",
|
226
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
227
|
+
),
|
228
|
+
),
|
229
|
+
)
|
230
|
+
expect(expr.optimize.dump).to eq({
|
231
|
+
query: "SELECT id AS host_id FROM hosts EXCEPT SELECT hosts.id AS host_id FROM hosts WHERE hosts.name = ?;",
|
232
|
+
values: ["foo"],
|
233
|
+
})
|
234
|
+
end
|
235
|
+
|
236
|
+
it "NOOP NOOP NOT host should return everything except the host" do
|
237
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
238
|
+
"NOOP",
|
239
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
240
|
+
"NOOP",
|
241
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
242
|
+
"NOT",
|
243
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
244
|
+
),
|
245
|
+
),
|
246
|
+
)
|
247
|
+
expect(expr.optimize.dump).to eq({
|
248
|
+
query: "SELECT id AS host_id FROM hosts EXCEPT SELECT hosts.id AS host_id FROM hosts WHERE hosts.name = ?;",
|
249
|
+
values: ["foo"],
|
250
|
+
})
|
251
|
+
end
|
252
|
+
|
253
|
+
it "NOOP NOT NOT host should return everything except the host" do
|
254
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
255
|
+
"NOT",
|
256
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
257
|
+
"NOT",
|
258
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
259
|
+
"NOOP",
|
260
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
261
|
+
),
|
262
|
+
),
|
263
|
+
)
|
264
|
+
expect(expr.optimize.dump).to eq({
|
265
|
+
tagname: "host",
|
266
|
+
separator: ":",
|
267
|
+
tagvalue: "foo",
|
268
|
+
fallback: {
|
269
|
+
query: [
|
270
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
271
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
272
|
+
].join(" "),
|
273
|
+
values: ["*foo*"],
|
274
|
+
},
|
275
|
+
})
|
276
|
+
end
|
277
|
+
|
278
|
+
it "NOT NOOP NOT host should return everything except the host" do
|
279
|
+
pending("optimization of 2+ depth unary expression is not yet supported")
|
280
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
281
|
+
"NOT",
|
282
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
283
|
+
"NOOP",
|
284
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
285
|
+
"NOT",
|
286
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
287
|
+
),
|
288
|
+
),
|
289
|
+
)
|
290
|
+
expect(expr.optimize.dump).to eq({
|
291
|
+
tagname: "host",
|
292
|
+
separator: ":",
|
293
|
+
tagvalue: "foo",
|
294
|
+
fallback: {
|
295
|
+
query: [
|
296
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
297
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
298
|
+
].join(" "),
|
299
|
+
values: ["*foo*"],
|
300
|
+
},
|
301
|
+
})
|
302
|
+
end
|
303
|
+
|
304
|
+
it "NOT NOT NOOP host should return everything except the host" do
|
305
|
+
expr = Hotdog::Expression::UnaryExpressionNode.new(
|
306
|
+
"NOT",
|
307
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
308
|
+
"NOT",
|
309
|
+
Hotdog::Expression::UnaryExpressionNode.new(
|
310
|
+
"NOOP",
|
311
|
+
Hotdog::Expression::StringHostNode.new("foo", ":"),
|
312
|
+
),
|
313
|
+
),
|
314
|
+
)
|
315
|
+
expect(expr.optimize.dump).to eq({
|
316
|
+
tagname: "host",
|
317
|
+
separator: ":",
|
318
|
+
tagvalue: "foo",
|
319
|
+
fallback: {
|
320
|
+
query: [
|
321
|
+
"SELECT hosts.id AS host_id FROM hosts",
|
322
|
+
"WHERE LOWER(hosts.name) GLOB LOWER(?);",
|
323
|
+
].join(" "),
|
324
|
+
values: ["*foo*"],
|
325
|
+
},
|
326
|
+
})
|
327
|
+
end
|
23
328
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotdog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.26.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yamashita Yuu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|