clickhouse 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +8 -0
- data/VERSION +1 -1
- data/lib/clickhouse/connection/query.rb +20 -19
- data/lib/clickhouse/connection/query/result_row.rb +21 -3
- data/lib/clickhouse/connection/query/result_set.rb +3 -3
- data/lib/clickhouse/version.rb +1 -1
- data/test/unit/connection/query/test_result_set.rb +3 -3
- data/test/unit/connection/test_query.rb +35 -18
- 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: 382f431988af06b9879728821c0c002676cb930d
|
4
|
+
data.tar.gz: 7fc6c4674ef83c45989bd8d3759ad85629beecee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83868f46b3dbbd9e977c6ac14a4badf252f9cc213cfbab9545a777ff241003357bd90241bbea1cedd58871457e0a4c43598385839a827e1815a897848bc5bcab
|
7
|
+
data.tar.gz: 39d8d2ab4a094e5e5f7b3d269d40d6fad75619fd97a3bee5c04b7bd766eff2096398a5c798fad6cf29d6ee0bafbe33d908cd7068e5c0a98e68c37a051d9a79f5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## Clickhouse CHANGELOG
|
2
2
|
|
3
|
+
### Version 0.1.1 (October 19, 2016)
|
4
|
+
|
5
|
+
* Using the JSONCompact format as query output which does not brake when having a JSON string within the data
|
6
|
+
* Ensuring that Clickhouse::Connection::Query#count return an integer
|
7
|
+
* Made Clickhouse::Connection::Query#to_select_query public
|
8
|
+
* Being able to pass strings as :where or :having option
|
9
|
+
* Being able to symbolize the row to hash parsing
|
10
|
+
|
3
11
|
### Version 0.1.0 (October 18, 2016)
|
4
12
|
|
5
13
|
* Initial release
|
data/README.md
CHANGED
@@ -17,6 +17,14 @@ Well, the developers of Clickhouse themselves [discourage](https://github.com/ya
|
|
17
17
|
> TCP transport is more specific, we don't want to expose details.
|
18
18
|
Despite we have full compatibility of protocol of different versions of client and server, we want to keep the ability to "break" it for very old clients. And that protocol is not too clean to make a specification.
|
19
19
|
|
20
|
+
### Why use the JSONCompact format and not the native format?
|
21
|
+
|
22
|
+
Despite of it being the most efficient format, using the native format is also [discouraged] by the Clickhouse developers.
|
23
|
+
|
24
|
+
> The most efficient format. Data is written and read by blocks in binary format. For each block, the number of rows, number of columns, column names and types, and parts of columns in this block are recorded one after another. In other words, this format is "columnar" - it doesn't convert columns to rows. This is the format used in the native interface for interaction between servers, for using the command-line client, and for C++ clients.
|
25
|
+
>
|
26
|
+
> You can use this format to quickly generate dumps that can only be read by the ClickHouse DBMS. It doesn't make sense to work with this format yourself.
|
27
|
+
|
20
28
|
## Installation
|
21
29
|
|
22
30
|
Run the following command to install `Clickhouse`:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -13,7 +13,7 @@ module Clickhouse
|
|
13
13
|
|
14
14
|
def query(query)
|
15
15
|
query = query.to_s.gsub(/(;|\bFORMAT \w+)/i, "").strip
|
16
|
-
query += " FORMAT
|
16
|
+
query += " FORMAT JSONCompact"
|
17
17
|
parse_response get(query).body.to_s
|
18
18
|
end
|
19
19
|
|
@@ -70,7 +70,20 @@ module Clickhouse
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def count(options)
|
73
|
-
|
73
|
+
options = options.merge(:select => "COUNT(*)")
|
74
|
+
select_value(options).to_i
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_select_query(options)
|
78
|
+
to_select_options(options).collect do |(key, value)|
|
79
|
+
next if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
80
|
+
|
81
|
+
statement = [key.to_s.upcase]
|
82
|
+
statement << "BY" if %W(GROUP ORDER).include?(statement[0])
|
83
|
+
statement << to_segment(key, value)
|
84
|
+
statement.join(" ")
|
85
|
+
|
86
|
+
end.compact.join("\n").force_encoding("UTF-8")
|
74
87
|
end
|
75
88
|
|
76
89
|
private
|
@@ -111,7 +124,7 @@ module Clickhouse
|
|
111
124
|
when :select
|
112
125
|
[value].flatten.join(", ")
|
113
126
|
when :where, :having
|
114
|
-
to_condition_statements(value)
|
127
|
+
value.is_a?(Hash) ? to_condition_statements(value) : value
|
115
128
|
else
|
116
129
|
value
|
117
130
|
end
|
@@ -136,23 +149,11 @@ module Clickhouse
|
|
136
149
|
end.flatten.join(" AND ")
|
137
150
|
end
|
138
151
|
|
139
|
-
def to_select_query(options)
|
140
|
-
to_select_options(options).collect do |(key, value)|
|
141
|
-
next if value.nil? && (!value.respond_to?(:empty?) || value.empty?)
|
142
|
-
|
143
|
-
statement = [key.to_s.upcase]
|
144
|
-
statement << "BY" if %W(GROUP ORDER).include?(statement[0])
|
145
|
-
statement << to_segment(key, value)
|
146
|
-
statement.join(" ")
|
147
|
-
|
148
|
-
end.compact.join("\n").force_encoding("UTF-8")
|
149
|
-
end
|
150
|
-
|
151
152
|
def parse_response(response)
|
152
|
-
|
153
|
-
names =
|
154
|
-
types =
|
155
|
-
ResultSet.new
|
153
|
+
data = JSON.parse response
|
154
|
+
names = data["meta"].collect{|column| column["name"]}
|
155
|
+
types = data["meta"].collect{|column| column["type"]}
|
156
|
+
ResultSet.new data["data"], names, types
|
156
157
|
end
|
157
158
|
|
158
159
|
end
|
@@ -5,11 +5,29 @@ module Clickhouse
|
|
5
5
|
|
6
6
|
def initialize(values = [], keys = nil)
|
7
7
|
super values
|
8
|
-
@keys = keys
|
8
|
+
@keys = normalize_keys(keys)
|
9
9
|
end
|
10
10
|
|
11
|
-
def to_hash
|
12
|
-
@hash ||=
|
11
|
+
def to_hash(symbolize = false)
|
12
|
+
@hash ||= begin
|
13
|
+
keys = symbolize ? @keys.collect(&:to_sym) : @keys
|
14
|
+
Hash[keys.zip(self)]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def normalize_keys(keys)
|
21
|
+
if keys
|
22
|
+
keys.collect do |key|
|
23
|
+
key.match(/^any\(([^\)]+)\)$/)
|
24
|
+
$1 || key
|
25
|
+
end
|
26
|
+
else
|
27
|
+
(0..(size - 1)).collect do |index|
|
28
|
+
"column#{index}"
|
29
|
+
end
|
30
|
+
end
|
13
31
|
end
|
14
32
|
|
15
33
|
end
|
@@ -31,8 +31,8 @@ module Clickhouse
|
|
31
31
|
!empty?
|
32
32
|
end
|
33
33
|
|
34
|
-
def to_hashes
|
35
|
-
collect(
|
34
|
+
def to_hashes(symbolize = false)
|
35
|
+
collect{|row| row.to_hash(symbolize)}
|
36
36
|
end
|
37
37
|
|
38
38
|
private
|
@@ -92,7 +92,7 @@ module Clickhouse
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def parse_array_value(value)
|
95
|
-
|
95
|
+
value
|
96
96
|
end
|
97
97
|
|
98
98
|
end
|
data/lib/clickhouse/version.rb
CHANGED
@@ -17,7 +17,7 @@ module Unit
|
|
17
17
|
"d91d1c90\u0000\u0000\u0000",
|
18
18
|
"2016-03-20",
|
19
19
|
"2016-03-20 23:49:11",
|
20
|
-
|
20
|
+
[4, 2, 5, 7]
|
21
21
|
], [
|
22
22
|
"12948140",
|
23
23
|
"9320.11",
|
@@ -25,7 +25,7 @@ module Unit
|
|
25
25
|
"d91d217c\u0000\u0000",
|
26
26
|
"2016-03-20",
|
27
27
|
"2016-03-20 23:58:34",
|
28
|
-
|
28
|
+
[6, 2, 9, 8, 1]
|
29
29
|
], [
|
30
30
|
"319384",
|
31
31
|
"101.02",
|
@@ -33,7 +33,7 @@ module Unit
|
|
33
33
|
"d91d2294\u0000\u0000\u0000",
|
34
34
|
"2016-03-20",
|
35
35
|
"2016-03-20 22:55:39",
|
36
|
-
|
36
|
+
[3, 1, 2]
|
37
37
|
]
|
38
38
|
],
|
39
39
|
%w(
|
@@ -30,21 +30,24 @@ module Unit
|
|
30
30
|
|
31
31
|
describe "#query" do
|
32
32
|
it "sends a GET request requesting a TSV response including names and types" do
|
33
|
-
@connection.expects(:get).with("sql FORMAT
|
33
|
+
@connection.expects(:get).with("sql FORMAT JSONCompact").returns(stub(:status => 200, :body => ""))
|
34
|
+
@connection.stubs(:parse_response)
|
34
35
|
assert_equal [], @connection.query("sql").to_a
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
describe "#databases" do
|
39
40
|
it "sends a 'SHOW DATABASES' query" do
|
40
|
-
@connection.expects(:get).with("SHOW DATABASES FORMAT
|
41
|
+
@connection.expects(:get).with("SHOW DATABASES FORMAT JSONCompact").returns(stub(:status => 200, :body => "{}"))
|
42
|
+
@connection.stubs(:parse_response).returns([])
|
41
43
|
@connection.databases
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
47
|
describe "#tables" do
|
46
48
|
it "sends a 'SHOW TABLES' query" do
|
47
|
-
@connection.expects(:get).with("SHOW TABLES FORMAT
|
49
|
+
@connection.expects(:get).with("SHOW TABLES FORMAT JSONCompact").returns(stub(:status => 200, :body => "{}"))
|
50
|
+
@connection.stubs(:parse_response).returns([])
|
48
51
|
@connection.tables
|
49
52
|
end
|
50
53
|
end
|
@@ -77,7 +80,8 @@ ENGINE = MergeTree(date, 8192)
|
|
77
80
|
|
78
81
|
describe "#describe_table" do
|
79
82
|
it "sends a 'DESCRIBE TABLE <name>' query" do
|
80
|
-
@connection.expects(:get).with("DESCRIBE TABLE logs FORMAT
|
83
|
+
@connection.expects(:get).with("DESCRIBE TABLE logs FORMAT JSONCompact").returns(stub(:status => 200, :body => ""))
|
84
|
+
@connection.stubs(:parse_response)
|
81
85
|
@connection.describe_table("logs")
|
82
86
|
end
|
83
87
|
end
|
@@ -150,15 +154,21 @@ ENGINE = MergeTree(date, 8192)
|
|
150
154
|
|
151
155
|
describe "#select_rows" do
|
152
156
|
it "sends a GET request and parses the result set" do
|
153
|
-
body = <<-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
157
|
+
body = <<-JAVASCRIPT
|
158
|
+
{
|
159
|
+
"meta": [
|
160
|
+
{"name": "year", "type": "UInt16"},
|
161
|
+
{"name": "name", "type": "String"}
|
162
|
+
],
|
163
|
+
"data": [
|
164
|
+
[1982, "Paul"],
|
165
|
+
[1947, "Anna"]
|
166
|
+
]
|
167
|
+
}
|
168
|
+
JAVASCRIPT
|
159
169
|
|
160
170
|
@connection.expects(:to_select_query).with(options = {:from => "logs"})
|
161
|
-
@connection.expects(:get).returns(stub(:body => body
|
171
|
+
@connection.expects(:get).returns(stub(:body => body))
|
162
172
|
|
163
173
|
assert_equal [
|
164
174
|
[1982, "Paul"],
|
@@ -179,21 +189,28 @@ ENGINE = MergeTree(date, 8192)
|
|
179
189
|
it "returns an empty array" do
|
180
190
|
@connection.expects(:to_select_query)
|
181
191
|
@connection.expects(:get).returns(stub(:body => ""))
|
192
|
+
@connection.stubs(:parse_response).returns([])
|
182
193
|
assert_equal [], @connection.select_values({})
|
183
194
|
end
|
184
195
|
end
|
185
196
|
|
186
197
|
describe "when getting data" do
|
187
198
|
it "returns every first value of every row" do
|
188
|
-
body = <<-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
199
|
+
body = <<-JAVASCRIPT
|
200
|
+
{
|
201
|
+
"meta": [
|
202
|
+
{"name": "year", "type": "UInt16"},
|
203
|
+
{"name": "name", "type": "String"}
|
204
|
+
],
|
205
|
+
"data": [
|
206
|
+
[1982, "Paul"],
|
207
|
+
[1947, "Anna"]
|
208
|
+
]
|
209
|
+
}
|
210
|
+
JAVASCRIPT
|
194
211
|
|
195
212
|
@connection.expects(:to_select_query)
|
196
|
-
@connection.expects(:get).returns(stub(:body => body
|
213
|
+
@connection.expects(:get).returns(stub(:body => body))
|
197
214
|
assert_equal [
|
198
215
|
1982,
|
199
216
|
1947
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clickhouse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Engel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|