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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6cb5a21b306e4a1d4ba2ed3f56a32bccede9d3e
4
- data.tar.gz: db352cb8caf7b6204b5af04cae89ade3bb3225a3
3
+ metadata.gz: 5d13acaecbe1b4f13f6b9956f2e75cf69cfaff23
4
+ data.tar.gz: acdef611442f0a968b0b9810c962b25864c0b406
5
5
  SHA512:
6
- metadata.gz: 2f34769acd4326c2d965fee9e69587af995d1764e00318531e8d36fab9020f520aaa4cb57d5950a95938a895ac3359a4800cdae089673c59f5c280f1d16a4611
7
- data.tar.gz: cbcafc9311ea4f8384f57065324c104d0948bc8f95ad0e5108a4479d319e603e2501a8cc25b89c00057fbdd0777585b6b5621e43ed1695b07091e6faa27dc1b5
6
+ metadata.gz: a6f4cc4380eea63cee183a0baff9b606e40e94cdc6522e5e16e33e44acb161987d6001ebf743fa6a7f054c4ed8cc034edd8494893a4c9736be58376efbd2ad7d
7
+ data.tar.gz: 950a18e1686c18591e474900353f738c78cc5f568c830dd41f43b231905eebdfe3bc415fd1662d710e9ec1072e4bba3ab050886f239a20aa35e8c237f7db75e0
@@ -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
- hosts.each_slice(SQLITE_LIMIT_COMPOUND_SELECT) do |hosts|
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
- result = args.each_slice(SQLITE_LIMIT_COMPOUND_SELECT).flat_map { |args|
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
@@ -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
@@ -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
- if options.key?(:index)
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
- stdin = IO.popen("cat #{Shellwords.shellescape(options[:infile])}")
167
- else
168
- stdin = :close
169
- end
170
- IO.popen(cmdline, in: stdin) do |io|
171
- io.each_with_index do |s, i|
172
- if output
173
- if identifier
174
- if color
175
- STDOUT.write("\e[0;#{color}m")
176
- end
177
- STDOUT.write(identifier)
178
- STDOUT.write(":")
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
@@ -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(SQLITE_LIMIT_COMPOUND_SELECT).flat_map { |tags|
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(SQLITE_LIMIT_COMPOUND_SELECT / 2).flat_map { |tags|
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
- (min / (SQLITE_LIMIT_COMPOUND_SELECT - 2)).upto(max / (SQLITE_LIMIT_COMPOUND_SELECT - 2)).flat_map { |i|
50
- range = ((SQLITE_LIMIT_COMPOUND_SELECT - 2) * i)...((SQLITE_LIMIT_COMPOUND_SELECT - 2) * (i + 1))
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 and expression.op == :NOT
94
- expression.expression
95
- else
96
- case expression
97
- when QueryExpressionNode
98
- q = expression.query
99
- v = expression.values
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
- (min / ((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2)).upto(max / ((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2)).flat_map { |i|
159
- range = (((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2) * i)...(((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2) * (i + 1))
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
- (min / ((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2)).upto(max / ((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2)).flat_map { |i|
186
- range = (((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2) * i)...(((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 2) * (i + 1))
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
- (min / ((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 4)).upto(max / ((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 4)).flat_map { |i|
213
- range = (((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 4) * i)...(((SQLITE_LIMIT_COMPOUND_SELECT - 2) / 4) * (i + 1))
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
- if lq and rq and lv.length + rv.length <= SQLITE_LIMIT_COMPOUND_SELECT
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
- if SQLITE_LIMIT_COMPOUND_SELECT < expressions.length
339
- raise(ArgumentError.new("expressions limit exceeded: #{expressions.length} for #{SQLITE_LIMIT_COMPOUND_SELECT}"))
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
- expressions.each_slice(SQLITE_LIMIT_COMPOUND_SELECT / condition_length).flat_map { |expressions|
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
  }
@@ -1,3 +1,3 @@
1
1
  module Hotdog
2
- VERSION = "0.25.0"
2
+ VERSION = "0.26.0"
3
3
  end
@@ -5,7 +5,7 @@ require "hotdog/commands/search"
5
5
  require "parslet"
6
6
 
7
7
  describe "unary expression" do
8
- it "should be everything" do
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 be nothing" do
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.25.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-22 00:00:00.000000000 Z
11
+ date: 2017-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler