clickhouse 0.1.4 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +22 -0
  3. data/.travis.yml +0 -2
  4. data/CHANGELOG.md +21 -0
  5. data/README.md +28 -1
  6. data/VERSION +1 -1
  7. data/bin/clickhouse +9 -0
  8. data/clickhouse.gemspec +7 -2
  9. data/lib/clickhouse.rb +7 -2
  10. data/lib/clickhouse/cli.rb +55 -0
  11. data/lib/clickhouse/cli/client.rb +149 -0
  12. data/lib/clickhouse/cli/console.rb +73 -0
  13. data/lib/clickhouse/cli/server.rb +36 -0
  14. data/lib/clickhouse/cli/server/assets/css/clickhouse.css +177 -0
  15. data/lib/clickhouse/cli/server/assets/css/codemirror.css +341 -0
  16. data/lib/clickhouse/cli/server/assets/css/datatables.css +1 -0
  17. data/lib/clickhouse/cli/server/assets/css/normalize.css +427 -0
  18. data/lib/clickhouse/cli/server/assets/css/skeleton.css +418 -0
  19. data/lib/clickhouse/cli/server/assets/js/clickhouse.js +188 -0
  20. data/lib/clickhouse/cli/server/assets/js/codemirror.js +9096 -0
  21. data/lib/clickhouse/cli/server/assets/js/datatables.js +166 -0
  22. data/lib/clickhouse/cli/server/assets/js/disableswipeback.js +97 -0
  23. data/lib/clickhouse/cli/server/assets/js/jquery.js +11015 -0
  24. data/lib/clickhouse/cli/server/assets/js/sql.js +232 -0
  25. data/lib/clickhouse/cli/server/views/index.erb +46 -0
  26. data/lib/clickhouse/cluster.rb +2 -1
  27. data/lib/clickhouse/connection.rb +2 -2
  28. data/lib/clickhouse/connection/client.rb +79 -10
  29. data/lib/clickhouse/connection/query.rb +7 -8
  30. data/lib/clickhouse/connection/query/result_set.rb +2 -0
  31. data/lib/clickhouse/utils.rb +23 -0
  32. data/lib/clickhouse/version.rb +1 -1
  33. data/test/unit/connection/test_client.rb +75 -10
  34. data/test/unit/connection/test_cluster.rb +1 -1
  35. data/test/unit/connection/test_logger.rb +3 -3
  36. data/test/unit/connection/test_query.rb +25 -23
  37. data/test/unit/test_utils.rb +39 -0
  38. metadata +86 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ffb93716a6e9932f89d7d1942539402df85d1b0
4
- data.tar.gz: 990fff529eb352d62076b01a2650a62242c9fb07
3
+ metadata.gz: acc4fd253999310d9bfa4038d1dddeddf60e9108
4
+ data.tar.gz: c03da9aecb9d94b1fffbc190df88a57c6ac49979
5
5
  SHA512:
6
- metadata.gz: bca9c9ae26b8066ad10aae19b84b2c6c2c984125a7f9ed53299ff15b5ee9e1cec3cb4cef1733abb8515f51ee8a33f0dec61d9a03d7da36807f7935f980f9b761
7
- data.tar.gz: e819b57c54e604df2810d7e2c7e55ae5c18087c959581dda41ebc378310f9d0365e31020e9ad35798413356b6a12be71fc3969fd9ab62a5307be73058c21ba30
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
@@ -1,5 +1,3 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.3.1
4
- - 2.1.2
5
- - 2.0.0
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 [![Build Status](https://travis-ci.org/archan937/clickhouse.svg?branch=master)](https://travis-ci.org/archan937/clickhouse) [![Code Climate](https://codeclimate.com/github/archan937/clickhouse/badges/gpa.svg)](https://codeclimate.com/github/archan937/clickhouse) [![Test Coverage](https://codeclimate.com/github/archan937/clickhouse/badges/coverage.svg)](https://codeclimate.com/github/archan937/clickhouse/coverage) [![Gem](https://img.shields.io/gem/v/clickhouse.svg)](https://rubygems.org/gems/clickhouse) [![Gem](https://img.shields.io/gem/dt/clickhouse.svg)](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.4
1
+ 0.1.8
data/bin/clickhouse ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "clickhouse/cli"
5
+
6
+ begin
7
+ Clickhouse::CLI.start
8
+ rescue Interrupt
9
+ end
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