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.
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