clickhouse 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +172 -0
- data/Rakefile +15 -0
- data/VERSION +1 -0
- data/clickhouse.gemspec +27 -0
- data/lib/clickhouse.rb +42 -0
- data/lib/clickhouse/connection.rb +23 -0
- data/lib/clickhouse/connection/client.rb +65 -0
- data/lib/clickhouse/connection/logger.rb +12 -0
- data/lib/clickhouse/connection/query.rb +160 -0
- data/lib/clickhouse/connection/query/result_row.rb +18 -0
- data/lib/clickhouse/connection/query/result_set.rb +101 -0
- data/lib/clickhouse/connection/query/table.rb +50 -0
- data/lib/clickhouse/error.rb +18 -0
- data/lib/clickhouse/version.rb +7 -0
- data/script/console +58 -0
- data/test/test_helper.rb +15 -0
- data/test/test_helper/coverage.rb +16 -0
- data/test/test_helper/minitest.rb +13 -0
- data/test/test_helper/simple_connection.rb +12 -0
- data/test/unit/connection/query/test_result_row.rb +36 -0
- data/test/unit/connection/query/test_result_set.rb +196 -0
- data/test/unit/connection/query/test_table.rb +39 -0
- data/test/unit/connection/test_client.rb +131 -0
- data/test/unit/connection/test_logger.rb +35 -0
- data/test/unit/connection/test_query.rb +391 -0
- data/test/unit/test_clickhouse.rb +91 -0
- data/test/unit/test_connection.rb +44 -0
- metadata +199 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative "../../../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
module Connection
|
5
|
+
module Query
|
6
|
+
class TestTable < MiniTest::Test
|
7
|
+
|
8
|
+
describe Clickhouse::Connection::Query::Table do
|
9
|
+
it "generates a 'CREATE TABLE' statement" do
|
10
|
+
table = Clickhouse::Connection::Query::Table.new("logs_test") do |t|
|
11
|
+
t.uint8 :id
|
12
|
+
t.float32 :price
|
13
|
+
t.string :name
|
14
|
+
t.date :date
|
15
|
+
t.date_time :time
|
16
|
+
t.fixed_string :hex_id, 8
|
17
|
+
t.engine "MergeTree(date, 8192)"
|
18
|
+
end
|
19
|
+
|
20
|
+
sql = <<-SQL
|
21
|
+
CREATE TABLE logs_test (
|
22
|
+
id UInt8,
|
23
|
+
price Float32,
|
24
|
+
name String,
|
25
|
+
date Date,
|
26
|
+
time DateTime,
|
27
|
+
hex_id FixedString(8)
|
28
|
+
)
|
29
|
+
ENGINE = MergeTree(date, 8192)
|
30
|
+
SQL
|
31
|
+
|
32
|
+
assert_equal sql.strip, table.to_sql.strip
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
module Connection
|
5
|
+
class TestClient < MiniTest::Test
|
6
|
+
|
7
|
+
class Connection < SimpleConnection
|
8
|
+
include Clickhouse::Connection::Client
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Clickhouse::Connection::Client do
|
12
|
+
before do
|
13
|
+
@connection = Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#connect!" do
|
17
|
+
describe "when failed to connect" do
|
18
|
+
it "returns true" do
|
19
|
+
Faraday::Connection.any_instance.expects(:get).raises(Faraday::ConnectionFailed.new("Failed to connect"))
|
20
|
+
assert_raises Clickhouse::ConnectionError do
|
21
|
+
@connection.connect!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when receiving 200" do
|
27
|
+
it "returns true" do
|
28
|
+
Faraday::Connection.any_instance.expects(:get).returns(stub(:status => 200))
|
29
|
+
assert_equal true, @connection.connect!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "when receiving 500" do
|
34
|
+
it "raises a Clickhouse::ConnectionError" do
|
35
|
+
Faraday::Connection.any_instance.expects(:get).returns(stub(:status => 500))
|
36
|
+
assert_raises Clickhouse::ConnectionError do
|
37
|
+
@connection.connect!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "when already connected" do
|
43
|
+
it "returns nil" do
|
44
|
+
@connection.instance_variable_set :@client, mock
|
45
|
+
assert_nil @connection.connect!
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#connected?" do
|
51
|
+
it "returns whether it has an connected socket" do
|
52
|
+
assert_equal false, @connection.connected?
|
53
|
+
@connection.instance_variable_set :@client, mock
|
54
|
+
assert_equal true, @connection.connected?
|
55
|
+
@connection.instance_variable_set :@client, nil
|
56
|
+
assert_equal false, @connection.connected?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#get" do
|
61
|
+
it "sends a GET request the server" do
|
62
|
+
@connection.instance_variable_set :@client, (client = mock)
|
63
|
+
client.expects(:get).with("/?query=foo", nil).returns(stub(:status => 200, :body => ""))
|
64
|
+
@connection.stubs(:log)
|
65
|
+
@connection.get(:foo)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#post" do
|
70
|
+
it "sends a POST request the server" do
|
71
|
+
@connection.instance_variable_set :@client, (client = mock)
|
72
|
+
client.expects(:post).with("/?query=foo", "body").returns(stub(:status => 200, :body => ""))
|
73
|
+
@connection.stubs(:log)
|
74
|
+
@connection.post(:foo, "body")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#request" do
|
79
|
+
before do
|
80
|
+
@connection.expects(:log)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "connects to the server first" do
|
84
|
+
@connection.instance_variable_set :@client, (client = mock)
|
85
|
+
@connection.expects(:connect!)
|
86
|
+
client.stubs(:get).returns(stub(:status => 200, :body => ""))
|
87
|
+
@connection.send :request, :get, "/", "query"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "queries the server returning the response" do
|
91
|
+
@connection.instance_variable_set :@client, (client = mock)
|
92
|
+
client.expects(:get).with("/?query=SELECT+1", nil).returns(response = stub(:status => 200, :body => ""))
|
93
|
+
assert_equal response, @connection.send(:request, :get, "SELECT 1")
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "when not receiving status 200" do
|
97
|
+
it "raises a Clickhouse::QueryError" do
|
98
|
+
@connection.instance_variable_set :@client, (client = mock)
|
99
|
+
client.expects(:get).with("/?query=SELECT+1", nil).returns(stub(:status => 500, :body => ""))
|
100
|
+
assert_raises Clickhouse::QueryError do
|
101
|
+
@connection.send(:request, :get, "SELECT 1")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "configuration" do
|
108
|
+
describe "database" do
|
109
|
+
it "includes the database in the querystring" do
|
110
|
+
@connection.expects(:log)
|
111
|
+
@connection.instance_variable_get(:@config)[:database] = "system"
|
112
|
+
@connection.instance_variable_set(:@client, (client = mock))
|
113
|
+
client.expects(:get).with("/?database=system&query=SELECT+1", nil).returns(response = stub(:status => 200, :body => ""))
|
114
|
+
assert_equal response, @connection.send(:request, :get, "SELECT 1")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "authentication" do
|
119
|
+
it "includes the credentials in the request headers" do
|
120
|
+
connection = Clickhouse::Connection.new :password => "awesomepassword"
|
121
|
+
connection.expects(:ping!)
|
122
|
+
connection.connect!
|
123
|
+
assert_equal "Basic ZGVmYXVsdDphd2Vzb21lcGFzc3dvcmQ=", connection.send(:client).headers["Authorization"].force_encoding("UTF-8")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
module Connection
|
5
|
+
class TestLogger < MiniTest::Test
|
6
|
+
|
7
|
+
class Connection < SimpleConnection
|
8
|
+
include Clickhouse::Connection::Logger
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Clickhouse::Connection::Logger do
|
12
|
+
before do
|
13
|
+
@connection = Connection.new
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#log" do
|
17
|
+
describe "when having specified a logger" do
|
18
|
+
it "delegates to logger" do
|
19
|
+
(logger = mock).expects(:info, "Hello world!")
|
20
|
+
Clickhouse.expects(:logger).returns(logger).twice
|
21
|
+
@connection.send(:log, :info, "Hello world!")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "when not having specified a logger" do
|
26
|
+
it "does nothing" do
|
27
|
+
assert_nil @connection.send(:log, :info, "Boo!")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,391 @@
|
|
1
|
+
require_relative "../../test_helper"
|
2
|
+
|
3
|
+
module Unit
|
4
|
+
module Connection
|
5
|
+
class TestQuery < MiniTest::Test
|
6
|
+
|
7
|
+
class Connection < SimpleConnection
|
8
|
+
include Clickhouse::Connection::Query
|
9
|
+
include Clickhouse::Connection::Logger
|
10
|
+
end
|
11
|
+
|
12
|
+
describe Clickhouse::Connection::Query do
|
13
|
+
before do
|
14
|
+
@connection = Connection.new
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#execute" do
|
18
|
+
it "sends a POST request" do
|
19
|
+
@connection.expects(:post).with("sql", nil).returns(stub(:status => 200, :body => ""))
|
20
|
+
assert_equal true, @connection.execute("sql")
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "when server returns a non-empty body" do
|
24
|
+
it "returns the body of the response" do
|
25
|
+
@connection.expects(:post).with("sql", "body").returns(stub(:status => 200, :body => "Ok."))
|
26
|
+
assert_equal "Ok.", @connection.execute("sql", "body")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#query" do
|
32
|
+
it "sends a GET request requesting a TSV response including names and types" do
|
33
|
+
@connection.expects(:get).with("sql FORMAT TabSeparatedWithNamesAndTypes").returns(stub(:status => 200, :body => ""))
|
34
|
+
assert_equal [], @connection.query("sql").to_a
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#databases" do
|
39
|
+
it "sends a 'SHOW DATABASES' query" do
|
40
|
+
@connection.expects(:get).with("SHOW DATABASES FORMAT TabSeparatedWithNamesAndTypes").returns(stub(:status => 200, :body => ""))
|
41
|
+
@connection.databases
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#tables" do
|
46
|
+
it "sends a 'SHOW TABLES' query" do
|
47
|
+
@connection.expects(:get).with("SHOW TABLES FORMAT TabSeparatedWithNamesAndTypes").returns(stub(:status => 200, :body => ""))
|
48
|
+
@connection.tables
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#create_table" do
|
53
|
+
it "sends a 'CREATE TABLE' query" do
|
54
|
+
sql = <<-SQL
|
55
|
+
CREATE TABLE logs_test (
|
56
|
+
id UInt8,
|
57
|
+
price Float32,
|
58
|
+
name String,
|
59
|
+
date Date,
|
60
|
+
time DateTime,
|
61
|
+
hex_id FixedString(8)
|
62
|
+
)
|
63
|
+
ENGINE = MergeTree(date, 8192)
|
64
|
+
SQL
|
65
|
+
@connection.expects(:post).with(sql.strip, nil).returns(stub(:status => 200, :body => ""))
|
66
|
+
@connection.create_table("logs_test") do |t|
|
67
|
+
t.uint8 :id
|
68
|
+
t.float32 :price
|
69
|
+
t.string :name
|
70
|
+
t.date :date
|
71
|
+
t.date_time :time
|
72
|
+
t.fixed_string :hex_id, 8
|
73
|
+
t.engine "MergeTree(date, 8192)"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#describe_table" do
|
79
|
+
it "sends a 'DESCRIBE TABLE <name>' query" do
|
80
|
+
@connection.expects(:get).with("DESCRIBE TABLE logs FORMAT TabSeparatedWithNamesAndTypes").returns(stub(:status => 200, :body => ""))
|
81
|
+
@connection.describe_table("logs")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#rename_table" do
|
86
|
+
describe "when passing an array with an even number of names" do
|
87
|
+
it "sends a POST request containing a RENAME TABLE statement" do
|
88
|
+
@connection.expects(:post).with("RENAME TABLE foo TO bar, baz TO qux", nil).returns(stub(:status => 200, :body => "")).twice
|
89
|
+
assert_equal true, @connection.rename_table("foo", "bar", "baz", "qux")
|
90
|
+
assert_equal true, @connection.rename_table(["foo", "bar"], ["baz", "qux"])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "when passing an array with an odd number of names" do
|
95
|
+
it "raises an Clickhouse::InvalidQueryError" do
|
96
|
+
assert_raises Clickhouse::InvalidQueryError do
|
97
|
+
@connection.rename_table "foo"
|
98
|
+
end
|
99
|
+
assert_raises Clickhouse::InvalidQueryError do
|
100
|
+
@connection.rename_table ["foo"]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "when passing a hash" do
|
106
|
+
it "sends a POST request containing a RENAME TABLE statement" do
|
107
|
+
@connection.expects(:post).with("RENAME TABLE foo TO bar, baz TO qux", nil).returns(stub(:status => 200, :body => ""))
|
108
|
+
assert_equal true, @connection.rename_table(:foo => "bar", :baz => "qux")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#drop_table" do
|
114
|
+
it "sends a POST request containing a 'DROP TABLE' statement" do
|
115
|
+
@connection.expects(:post).with("DROP TABLE logs", nil).returns(stub(:status => 200, :body => ""))
|
116
|
+
assert_equal true, @connection.drop_table("logs")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#insert_rows" do
|
121
|
+
before do
|
122
|
+
@csv = <<-CSV
|
123
|
+
id,first_name,last_name
|
124
|
+
12345,Paul,Engel
|
125
|
+
67890,Bruce,Wayne
|
126
|
+
CSV
|
127
|
+
@csv.gsub!(/^\s+/, "")
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "when using hashes" do
|
131
|
+
it "sends a POST request containing a 'INSERT INTO' statement using CSV" do
|
132
|
+
@connection.expects(:post).with("INSERT INTO logs FORMAT CSVWithNames", @csv).returns(stub(:status => 200, :body => ""))
|
133
|
+
assert_equal true, @connection.insert_rows("logs") { |rows|
|
134
|
+
rows << {:id => 12345, :first_name => "Paul", :last_name => "Engel"}
|
135
|
+
rows << {:id => 67890, :first_name => "Bruce", :last_name => "Wayne"}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "when using arrays" do
|
141
|
+
it "sends a POST request containing a 'INSERT INTO' statement using CSV" do
|
142
|
+
@connection.expects(:post).with("INSERT INTO logs FORMAT CSVWithNames", @csv).returns(stub(:status => 200, :body => ""))
|
143
|
+
assert_equal true, @connection.insert_rows("logs", :names => %w(id first_name last_name)) { |rows|
|
144
|
+
rows << [12345, "Paul", "Engel"]
|
145
|
+
rows << [67890, "Bruce", "Wayne"]
|
146
|
+
}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "#select_rows" do
|
152
|
+
it "sends a GET request and parses the result set" do
|
153
|
+
body = <<-TSV
|
154
|
+
year\tname
|
155
|
+
UInt16\tString
|
156
|
+
1982\tPaul
|
157
|
+
1947\tAnna
|
158
|
+
TSV
|
159
|
+
|
160
|
+
@connection.expects(:to_select_query).with(options = {:from => "logs"})
|
161
|
+
@connection.expects(:get).returns(stub(:body => body.gsub(/^\s+/, "")))
|
162
|
+
|
163
|
+
assert_equal [
|
164
|
+
[1982, "Paul"],
|
165
|
+
[1947, "Anna"]
|
166
|
+
], @connection.select_rows(options).to_a
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "#select_row" do
|
171
|
+
it "returns an empty array" do
|
172
|
+
@connection.expects(:select_rows).returns([["Paul", "Engel"], ["Bruce", "Wayne"]])
|
173
|
+
assert_equal ["Paul", "Engel"], @connection.select_row({})
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "#select_values" do
|
178
|
+
describe "when empty result set" do
|
179
|
+
it "returns an empty array" do
|
180
|
+
@connection.expects(:to_select_query)
|
181
|
+
@connection.expects(:get).returns(stub(:body => ""))
|
182
|
+
assert_equal [], @connection.select_values({})
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "when getting data" do
|
187
|
+
it "returns every first value of every row" do
|
188
|
+
body = <<-TSV
|
189
|
+
year\tname
|
190
|
+
UInt16\tString
|
191
|
+
1982\tPaul
|
192
|
+
1947\tAnna
|
193
|
+
TSV
|
194
|
+
|
195
|
+
@connection.expects(:to_select_query)
|
196
|
+
@connection.expects(:get).returns(stub(:body => body.gsub(/^\s+/, "")))
|
197
|
+
assert_equal [
|
198
|
+
1982,
|
199
|
+
1947
|
200
|
+
], @connection.select_values({})
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "#select_value" do
|
206
|
+
describe "when empty result set" do
|
207
|
+
it "returns nil" do
|
208
|
+
@connection.expects(:select_values).with(options = {:foo => "bar"}).returns([])
|
209
|
+
assert_nil @connection.select_value(options)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "when getting data" do
|
214
|
+
it "returns the first value of the first row" do
|
215
|
+
@connection.expects(:select_values).with(options = {:foo => "bar"}).returns([1982])
|
216
|
+
assert_equal 1982, @connection.select_value(options)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "#count" do
|
222
|
+
it "returns the first value of the first row" do
|
223
|
+
@connection.expects(:select_value).with(:select => "COUNT(*)", :from => "logs").returns(1982)
|
224
|
+
assert_equal 1982, @connection.count(:from => "logs")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "#to_select_query" do
|
229
|
+
describe "when passing :from option" do
|
230
|
+
it "generates a simple 'SELECT * FROM <table>' query" do
|
231
|
+
query = <<-SQL
|
232
|
+
SELECT *
|
233
|
+
FROM logs
|
234
|
+
SQL
|
235
|
+
options = {
|
236
|
+
:from => "logs"
|
237
|
+
}
|
238
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "when passing :from and :select option" do
|
243
|
+
describe "when passing a single column" do
|
244
|
+
it "respects the single column in the SELECT statement" do
|
245
|
+
query = <<-SQL
|
246
|
+
SELECT MIN(date)
|
247
|
+
FROM logs
|
248
|
+
SQL
|
249
|
+
options = {
|
250
|
+
:select => "MIN(date)",
|
251
|
+
:from => "logs"
|
252
|
+
}
|
253
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe "when passing multiple columns" do
|
258
|
+
it "only includes the passed columns in the SELECT statement" do
|
259
|
+
query = <<-SQL
|
260
|
+
SELECT MIN(date), MAX(date)
|
261
|
+
FROM logs
|
262
|
+
SQL
|
263
|
+
options = {
|
264
|
+
:select => ["MIN(date)", "MAX(date)"],
|
265
|
+
:from => "logs"
|
266
|
+
}
|
267
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "when filtering on value is empty" do
|
272
|
+
it "uses the empty() function in the WHERE statement" do
|
273
|
+
query = <<-SQL
|
274
|
+
SELECT *
|
275
|
+
FROM logs
|
276
|
+
WHERE empty(parent_id)
|
277
|
+
SQL
|
278
|
+
options = {
|
279
|
+
:from => "logs",
|
280
|
+
:where => {
|
281
|
+
:parent_id => :empty
|
282
|
+
}
|
283
|
+
}
|
284
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "when filtering on value is within a certain range" do
|
289
|
+
it "includes the range in the WHERE statement" do
|
290
|
+
query = <<-SQL
|
291
|
+
SELECT *
|
292
|
+
FROM logs
|
293
|
+
WHERE code >= 6 AND code <= 10
|
294
|
+
SQL
|
295
|
+
options = {
|
296
|
+
:from => "logs",
|
297
|
+
:where => {
|
298
|
+
:code => 6..10
|
299
|
+
}
|
300
|
+
}
|
301
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe "when filtering on value in array" do
|
306
|
+
it "uses an IN operator in the WHERE statement" do
|
307
|
+
query = <<-SQL
|
308
|
+
SELECT *
|
309
|
+
FROM logs
|
310
|
+
WHERE code IN (6, 7, 8, 9, 10)
|
311
|
+
SQL
|
312
|
+
options = {
|
313
|
+
:from => "logs",
|
314
|
+
:where => {
|
315
|
+
:code => [6, 7, 8, 9, 10]
|
316
|
+
}
|
317
|
+
}
|
318
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "when filtering using backticks" do
|
323
|
+
it "uses the specified SQL as is" do
|
324
|
+
query = <<-SQL
|
325
|
+
SELECT *
|
326
|
+
FROM logs
|
327
|
+
WHERE id != 'cb5a67d2932911e6'
|
328
|
+
SQL
|
329
|
+
options = {
|
330
|
+
:from => "logs",
|
331
|
+
:where => {
|
332
|
+
:id => "`!= 'cb5a67d2932911e6'`"
|
333
|
+
}
|
334
|
+
}
|
335
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
describe "when filtering on a string" do
|
340
|
+
it "uses a single quoted string" do
|
341
|
+
query = <<-SQL
|
342
|
+
SELECT *
|
343
|
+
FROM logs
|
344
|
+
WHERE id = 'cb5a67d2932911e6'
|
345
|
+
SQL
|
346
|
+
options = {
|
347
|
+
:from => "logs",
|
348
|
+
:where => {
|
349
|
+
:id => "cb5a67d2932911e6"
|
350
|
+
}
|
351
|
+
}
|
352
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
describe "when using all options" do
|
357
|
+
it "generates the complex query" do
|
358
|
+
query = <<-SQL
|
359
|
+
SELECT date, COUNT(id), groupUniqArray(severity), SUM(clicks)
|
360
|
+
FROM logs
|
361
|
+
WHERE date >= '2016-08-01' AND hidden = 0
|
362
|
+
GROUP BY date
|
363
|
+
HAVING MIN(severity) = 2
|
364
|
+
ORDER BY MIN(time) DESC
|
365
|
+
LIMIT 120, 60
|
366
|
+
SQL
|
367
|
+
options = {
|
368
|
+
:select => ["date", "COUNT(id)", "groupUniqArray(severity)", "SUM(clicks)"],
|
369
|
+
:from => "logs",
|
370
|
+
:where => {
|
371
|
+
:date => "`>= '2016-08-01'`",
|
372
|
+
:hidden => 0
|
373
|
+
},
|
374
|
+
:group => "date",
|
375
|
+
:having => {
|
376
|
+
"MIN(severity)" => 2
|
377
|
+
},
|
378
|
+
:order => "MIN(time) DESC",
|
379
|
+
:limit => 60,
|
380
|
+
:offset => 120
|
381
|
+
}
|
382
|
+
assert_query(query, @connection.send(:to_select_query, options))
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|