clickhouse 0.1.4 → 0.1.8
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 +4 -4
- data/.codeclimate.yml +22 -0
- data/.travis.yml +0 -2
- data/CHANGELOG.md +21 -0
- data/README.md +28 -1
- data/VERSION +1 -1
- data/bin/clickhouse +9 -0
- data/clickhouse.gemspec +7 -2
- data/lib/clickhouse.rb +7 -2
- data/lib/clickhouse/cli.rb +55 -0
- data/lib/clickhouse/cli/client.rb +149 -0
- data/lib/clickhouse/cli/console.rb +73 -0
- data/lib/clickhouse/cli/server.rb +36 -0
- data/lib/clickhouse/cli/server/assets/css/clickhouse.css +177 -0
- data/lib/clickhouse/cli/server/assets/css/codemirror.css +341 -0
- data/lib/clickhouse/cli/server/assets/css/datatables.css +1 -0
- data/lib/clickhouse/cli/server/assets/css/normalize.css +427 -0
- data/lib/clickhouse/cli/server/assets/css/skeleton.css +418 -0
- data/lib/clickhouse/cli/server/assets/js/clickhouse.js +188 -0
- data/lib/clickhouse/cli/server/assets/js/codemirror.js +9096 -0
- data/lib/clickhouse/cli/server/assets/js/datatables.js +166 -0
- data/lib/clickhouse/cli/server/assets/js/disableswipeback.js +97 -0
- data/lib/clickhouse/cli/server/assets/js/jquery.js +11015 -0
- data/lib/clickhouse/cli/server/assets/js/sql.js +232 -0
- data/lib/clickhouse/cli/server/views/index.erb +46 -0
- data/lib/clickhouse/cluster.rb +2 -1
- data/lib/clickhouse/connection.rb +2 -2
- data/lib/clickhouse/connection/client.rb +79 -10
- data/lib/clickhouse/connection/query.rb +7 -8
- data/lib/clickhouse/connection/query/result_set.rb +2 -0
- data/lib/clickhouse/utils.rb +23 -0
- data/lib/clickhouse/version.rb +1 -1
- data/test/unit/connection/test_client.rb +75 -10
- data/test/unit/connection/test_cluster.rb +1 -1
- data/test/unit/connection/test_logger.rb +3 -3
- data/test/unit/connection/test_query.rb +25 -23
- data/test/unit/test_utils.rb +39 -0
- metadata +86 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acc4fd253999310d9bfa4038d1dddeddf60e9108
|
4
|
+
data.tar.gz: c03da9aecb9d94b1fffbc190df88a57c6ac49979
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93016aef4dd65ceb1c60a61c857a0f3bd2452e3476760f283d1c8374ed9b402d410e1e6d8e7c09216dc257adf8ba2d1cec4db7eadb9b9b8d283b3ea8b137606c
|
7
|
+
data.tar.gz: 248da8918613ba751cdf80db2667e8cb3b3a83f64b7e6973da57dfb80cfa76eb40647af4db0442aeec7984647f6a187c9857350418ee03313f6d5ea7ed1ece5f
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
engines:
|
3
|
+
csslint:
|
4
|
+
enabled: false
|
5
|
+
duplication:
|
6
|
+
enabled: true
|
7
|
+
config:
|
8
|
+
languages:
|
9
|
+
- ruby
|
10
|
+
eslint:
|
11
|
+
enabled: true
|
12
|
+
fixme:
|
13
|
+
enabled: true
|
14
|
+
rubocop:
|
15
|
+
enabled: true
|
16
|
+
ratings:
|
17
|
+
paths:
|
18
|
+
- "**.rb"
|
19
|
+
exclude_paths:
|
20
|
+
- lib/clickhouse/cli/
|
21
|
+
- script/
|
22
|
+
- test/
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
## Clickhouse CHANGELOG
|
2
2
|
|
3
|
+
### Version 0.1.8 (November 6, 2016)
|
4
|
+
|
5
|
+
* Fixed loading URLs in GUI
|
6
|
+
|
7
|
+
### Version 0.1.7 (November 6, 2016) [YANKED]
|
8
|
+
|
9
|
+
* Corrected interpolating nested patterns
|
10
|
+
* Only upcasing whole (preserved) words
|
11
|
+
|
12
|
+
### Version 0.1.6 (November 5, 2016) [YANKED]
|
13
|
+
|
14
|
+
* Improved clickhouse console and server
|
15
|
+
* Using Bundler >= 1.13.4
|
16
|
+
* Changed cluster timeout to 5 seconds
|
17
|
+
|
18
|
+
### Version 0.1.5 (November 4, 2016) [YANKED]
|
19
|
+
|
20
|
+
* Added command line interface `clickhouse c`
|
21
|
+
* Being able to start a Sinatra based Clickhouse client using `clickhouse s`
|
22
|
+
* Using :debug to log queries
|
23
|
+
|
3
24
|
### Version 0.1.4 (October 25, 2016)
|
4
25
|
|
5
26
|
* Ensured that Clickhouse does not modify the passed cluster config
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Clickhouse [](https://travis-ci.org/archan937/clickhouse) [](https://codeclimate.com/github/archan937/clickhouse) [](https://codeclimate.com/github/archan937/clickhouse/coverage) [](https://rubygems.org/gems/clickhouse) [](https://rubygems.org/gems/clickhouse)
|
2
2
|
|
3
|
-
A Ruby database driver for ClickHouse.
|
3
|
+
A Ruby database driver for ClickHouse (also Clickhouse CLI and web GUI included).
|
4
4
|
|
5
5
|
## Introduction
|
6
6
|
|
@@ -179,6 +179,33 @@ If all the connections failed, it will just return `nil`.
|
|
179
179
|
|
180
180
|
To see what more the `Clickhouse` gem has to offer, please take a look at the unit tests ( [test/unit/connection/test_query.rb](https://github.com/archan937/clickhouse/blob/master/test/unit/connection/test_query.rb) for instance).
|
181
181
|
|
182
|
+
## Using the Sinatra-based browser GUI and Pry-based CLI
|
183
|
+
|
184
|
+
As of `Clickhouse v0.1.7`, the gem is provided with both a Sinatra-based GUI and a Pry-based CLI. Starting either of them is very easy:
|
185
|
+
|
186
|
+
* `clickhouse s localhost:8123` - (the `s` stands for server as we know from `rails s`)
|
187
|
+
* `clickhouse c localhost:8123` - (the `c` stands for console as we know from `rails c`)
|
188
|
+
|
189
|
+
Multiple connections should be passed comma separated:
|
190
|
+
|
191
|
+
`clickhouse s https://myserver.com:8123,https://myserver.com:8124`
|
192
|
+
|
193
|
+
Use `clickhouse help` to:
|
194
|
+
|
195
|
+
```
|
196
|
+
$ clickhouse help server
|
197
|
+
Usage:
|
198
|
+
clickhouse server [HOSTS]
|
199
|
+
|
200
|
+
Options:
|
201
|
+
-p, [--port=N]
|
202
|
+
# Default: 1982
|
203
|
+
-u, [--username=USERNAME]
|
204
|
+
-P, [--password=PASSWORD]
|
205
|
+
|
206
|
+
Start a Sinatra server as ClickHouse client (HOSTS should be comma separated URIs)
|
207
|
+
```
|
208
|
+
|
182
209
|
## Using the console
|
183
210
|
|
184
211
|
As you probably already noticed, the `Clickhouse` repo is provided with a `script/console` file which you can use for development / testing purposes. Please note that you need to have a ClickHouse server running.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.8
|
data/bin/clickhouse
ADDED
data/clickhouse.gemspec
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path("../lib/clickhouse/version", __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Paul Engel"]
|
6
6
|
gem.email = ["pm_engel@icloud.com"]
|
7
|
-
gem.summary = %q{A Ruby database driver for ClickHouse}
|
8
|
-
gem.description = %q{A Ruby database driver for ClickHouse}
|
7
|
+
gem.summary = %q{A Ruby database driver for ClickHouse (also Clickhouse CLI and web GUI included)}
|
8
|
+
gem.description = %q{A Ruby database driver for ClickHouse (also Clickhouse CLI and web GUI included)}
|
9
9
|
gem.homepage = "https://github.com/archan937/clickhouse"
|
10
10
|
|
11
11
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
@@ -14,9 +14,14 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "clickhouse"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Clickhouse::VERSION
|
17
|
+
gem.licenses = ["MIT"]
|
17
18
|
|
19
|
+
gem.add_dependency "bundler", ">= 1.13.4"
|
18
20
|
gem.add_dependency "faraday"
|
19
21
|
gem.add_dependency "pond"
|
22
|
+
gem.add_dependency "activesupport", ">= 4.1.8"
|
23
|
+
gem.add_dependency "thor"
|
24
|
+
gem.add_dependency "launchy"
|
20
25
|
|
21
26
|
gem.add_development_dependency "rake"
|
22
27
|
gem.add_development_dependency "pry"
|
data/lib/clickhouse.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
require "uri"
|
2
2
|
require "forwardable"
|
3
3
|
require "csv"
|
4
|
+
require "json"
|
4
5
|
|
5
6
|
require "faraday"
|
6
7
|
require "pond"
|
8
|
+
require "active_support/dependencies/autoload"
|
9
|
+
require "active_support/number_helper"
|
10
|
+
require "active_support/core_ext/string/inflections"
|
7
11
|
|
8
12
|
require "clickhouse/cluster"
|
9
13
|
require "clickhouse/connection"
|
14
|
+
require "clickhouse/utils"
|
10
15
|
require "clickhouse/error"
|
11
16
|
require "clickhouse/version"
|
12
17
|
|
@@ -37,12 +42,12 @@ module Clickhouse
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
|
-
def self.connect!(config)
|
45
|
+
def self.connect!(config = {})
|
41
46
|
@connection = connect(config)
|
42
47
|
@connection.connect!
|
43
48
|
end
|
44
49
|
|
45
|
-
def self.connect(config)
|
50
|
+
def self.connect(config = {})
|
46
51
|
klass = (config[:urls] || config["urls"]) ? Cluster : Connection
|
47
52
|
klass.new(config)
|
48
53
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "launchy"
|
3
|
+
require "clickhouse"
|
4
|
+
|
5
|
+
module Clickhouse
|
6
|
+
class CLI < Thor
|
7
|
+
|
8
|
+
DEPENDENCIES = {:server => "sinatra"}
|
9
|
+
DEFAULT_URLS = "http://localhost:8123"
|
10
|
+
|
11
|
+
desc "server [HOSTS]", "Start a Sinatra server as ClickHouse client (HOSTS should be comma separated URIs)"
|
12
|
+
method_options [:port, "-p"] => 1982, [:username, "-u"] => :string, [:password, "-P"] => :string
|
13
|
+
def server(urls = DEFAULT_URLS)
|
14
|
+
run! :server, urls, options do
|
15
|
+
Launchy.open "http://localhost:#{options[:port]}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "console [HOSTS]", "Start a Pry console as ClickHouse client (HOSTS should be comma separated URIs)"
|
20
|
+
method_options [:username, "-u"] => :string, [:password, "-P"] => :string
|
21
|
+
def console(urls = DEFAULT_URLS)
|
22
|
+
run! :console, urls, options
|
23
|
+
end
|
24
|
+
|
25
|
+
map "s" => :server
|
26
|
+
map "c" => :console
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def run!(const, urls, options, &block)
|
31
|
+
require! DEPENDENCIES[const]
|
32
|
+
require_relative "cli/client"
|
33
|
+
require_relative "cli/#{const}"
|
34
|
+
connect! urls, options
|
35
|
+
self.class.const_get(const.to_s.capitalize).run!(:port => options["port"], &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def require!(name)
|
39
|
+
require(name) if name
|
40
|
+
rescue LoadError
|
41
|
+
puts "fatal: #{name.capitalize} not available. Please run `gem install #{name}` first."
|
42
|
+
exit!
|
43
|
+
end
|
44
|
+
|
45
|
+
def connect!(urls, options)
|
46
|
+
config = options.merge(:urls => urls.split(",")).inject({}){|h, (k, v)| h[k.to_sym] = v; h}
|
47
|
+
Clickhouse.establish_connection config
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_missing(method, *_args)
|
51
|
+
raise Error, "Unrecognized command \"#{method}\". Please consult `clickhouse help`."
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Clickhouse
|
2
|
+
class CLI < Thor
|
3
|
+
module Client
|
4
|
+
|
5
|
+
HISTORY_FILE = "#{ENV["HOME"]}/.clickhouse_history"
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
extended(base)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.extended(base)
|
12
|
+
Clickhouse.logger = self
|
13
|
+
load_history
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.debug(message = nil)
|
17
|
+
@log = message.split("\n").detect{|line| line.include?("36m")}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.log
|
21
|
+
@log
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.load_history
|
25
|
+
File.readlines(HISTORY_FILE).each do |line|
|
26
|
+
Readline::HISTORY.push line.gsub(";;", "\n").strip
|
27
|
+
end if File.exists?(HISTORY_FILE)
|
28
|
+
end
|
29
|
+
|
30
|
+
def alter_history(sql, current = true)
|
31
|
+
(Readline::HISTORY.to_a.count{|line| line[-1] != ";"} + (current ? 1 : 0)).times do
|
32
|
+
Readline::HISTORY.pop
|
33
|
+
end
|
34
|
+
unless Readline::HISTORY.to_a[-1] == sql
|
35
|
+
Readline::HISTORY.push(sql)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def dump_history
|
40
|
+
File.open(HISTORY_FILE, "w+") do |file|
|
41
|
+
Readline::HISTORY.each do |line|
|
42
|
+
file.puts line.strip.gsub("\n", ";;")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def prettify(sql)
|
48
|
+
sql, replaced = numerize_patterns(sql)
|
49
|
+
|
50
|
+
preserved_words = %w(
|
51
|
+
USE
|
52
|
+
SHOW
|
53
|
+
DATABASES
|
54
|
+
TABLES
|
55
|
+
PROCESSLIST
|
56
|
+
INSERT
|
57
|
+
INTO
|
58
|
+
FORMAT
|
59
|
+
SELECT
|
60
|
+
COUNT
|
61
|
+
DISTINCT
|
62
|
+
SAMPLE
|
63
|
+
AS
|
64
|
+
FROM
|
65
|
+
JOIN
|
66
|
+
UNION
|
67
|
+
ALL
|
68
|
+
PREWHERE
|
69
|
+
WHERE
|
70
|
+
AND
|
71
|
+
OR
|
72
|
+
NOT
|
73
|
+
IN
|
74
|
+
GROUP
|
75
|
+
BY
|
76
|
+
HAVING
|
77
|
+
ORDER
|
78
|
+
LIMIT
|
79
|
+
CREATE
|
80
|
+
DESCRIBE
|
81
|
+
ALTER
|
82
|
+
RENAME
|
83
|
+
DROP
|
84
|
+
DETACH
|
85
|
+
ATTACH
|
86
|
+
TABLE
|
87
|
+
VIEW
|
88
|
+
PARTITION
|
89
|
+
EXISTS
|
90
|
+
SET
|
91
|
+
OPTIMIZE
|
92
|
+
WITH
|
93
|
+
TOTALS
|
94
|
+
).sort{|a, b| [b.size, a] <=> [a.size, b]}
|
95
|
+
|
96
|
+
sql.gsub!(/(\b)(#{preserved_words.join("|")})(\b)/i) do
|
97
|
+
"#{$1}#{$2.upcase}#{$3}"
|
98
|
+
end
|
99
|
+
|
100
|
+
interpolate_patterns(sql, replaced)
|
101
|
+
end
|
102
|
+
|
103
|
+
def numerize_patterns(sql, replaced = [])
|
104
|
+
sql = sql.gsub(/(["'])(?:(?=(\\?))\2.)*?\1/) do |match|
|
105
|
+
replaced << match
|
106
|
+
"${#{replaced.size - 1}}"
|
107
|
+
end
|
108
|
+
|
109
|
+
parenthesized = false
|
110
|
+
|
111
|
+
sql = sql.gsub(/\([^\(\)]*?\)/) do |match|
|
112
|
+
parenthesized = true
|
113
|
+
replaced << match
|
114
|
+
"%{#{replaced.size - 1}}"
|
115
|
+
end
|
116
|
+
|
117
|
+
parenthesized ? numerize_patterns(sql, replaced) : [sql, replaced]
|
118
|
+
end
|
119
|
+
|
120
|
+
def interpolate_patterns(sql, replaced)
|
121
|
+
matched = false
|
122
|
+
|
123
|
+
sql = sql.gsub(/(\$|%)\{(\d+)\}/) do |match|
|
124
|
+
matched = true
|
125
|
+
replaced[$2.to_i]
|
126
|
+
end
|
127
|
+
|
128
|
+
matched ? interpolate_patterns(sql, replaced) : sql
|
129
|
+
end
|
130
|
+
|
131
|
+
def execute(sql, &block)
|
132
|
+
if sql[-1] == ";"
|
133
|
+
dump_history
|
134
|
+
method = sql.match(/^(SELECT|SHOW|DESCRIBE)/i) ? :query : :execute
|
135
|
+
result = Clickhouse.connection.send(method, sql[0..-2])
|
136
|
+
|
137
|
+
if block_given?
|
138
|
+
block.call(result, Client.log)
|
139
|
+
else
|
140
|
+
process_result(result, Client.log)
|
141
|
+
end
|
142
|
+
else
|
143
|
+
sql
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "readline"
|
2
|
+
|
3
|
+
module Clickhouse
|
4
|
+
class CLI < Thor
|
5
|
+
module Console
|
6
|
+
extend self
|
7
|
+
extend Client
|
8
|
+
|
9
|
+
CLR = "\r\e[A\e[K"
|
10
|
+
|
11
|
+
def run!(options = {})
|
12
|
+
readline
|
13
|
+
end
|
14
|
+
|
15
|
+
# private
|
16
|
+
|
17
|
+
def readline(buffer = nil)
|
18
|
+
prompt = buffer ? ":-] " : ":) "
|
19
|
+
line = Readline.readline(prompt, true)
|
20
|
+
|
21
|
+
exit! unless line && !%w(exit quit).include?(line = line.strip)
|
22
|
+
|
23
|
+
line = prettify(line)
|
24
|
+
sql = [buffer, line].compact.join("\n").gsub(/\s+;$/, ";")
|
25
|
+
|
26
|
+
puts "#{CLR}#{prompt}#{line}"
|
27
|
+
alter_history(sql)
|
28
|
+
|
29
|
+
buffer = begin
|
30
|
+
execute(sql)
|
31
|
+
rescue Clickhouse::Error => e
|
32
|
+
puts "ERROR: #{e.message}"
|
33
|
+
end
|
34
|
+
|
35
|
+
readline buffer
|
36
|
+
end
|
37
|
+
|
38
|
+
def process_result(result, log)
|
39
|
+
if result.is_a?(Clickhouse::Connection::Query::ResultSet)
|
40
|
+
if result.size > 0
|
41
|
+
array = [result.names].concat(result.to_a)
|
42
|
+
lengths = array.inject([]) do |lengths, row|
|
43
|
+
row.each_with_index do |value, index|
|
44
|
+
length = value.to_s.strip.length
|
45
|
+
lengths[index] = [lengths[index].to_i, length].max
|
46
|
+
end
|
47
|
+
lengths
|
48
|
+
end
|
49
|
+
puts
|
50
|
+
array.each_with_index do |row, i|
|
51
|
+
values = [nil]
|
52
|
+
lengths.each_with_index do |length, index|
|
53
|
+
values << row[index].to_s.ljust(length, " ")
|
54
|
+
end
|
55
|
+
values << nil
|
56
|
+
separator = (i == 0) ? "+" : "|"
|
57
|
+
puts values.join(" #{separator} ")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
else
|
61
|
+
puts result == true ? "Ok." : (result || "Fail.")
|
62
|
+
end
|
63
|
+
|
64
|
+
if log
|
65
|
+
puts
|
66
|
+
puts log.strip
|
67
|
+
end
|
68
|
+
puts
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|