click_house 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '095426f805a20574d725842799b3e09368ef4239bf8a262d4ca061ef7689cedd'
4
- data.tar.gz: 77098569ba1c05b236bc6b68118116c63985c1cc91bc49cdc5ae49c2550459f6
3
+ metadata.gz: 3dbe7ae01f5130dc0d18d9f9456ad75c2fdcc04bfe815debac344c93ce9bd00e
4
+ data.tar.gz: 4f7c8ab45593d9d37744ea9125c202052a99f582cd0887e251af790973c8a22a
5
5
  SHA512:
6
- metadata.gz: a71819d5ea5c61bf85907501e9b80ca713dc3e78e97a066a9f3e8fb1713dfc0a81b91aef0b12c51389afad53c518ccca913544be0f44d60182d02ecb722e0e1c
7
- data.tar.gz: 95fb2a123492cb6f816ed4c8b1984ec1ba21b1784eceb489543081616ad5d0a5947d56623be63c7e8d5f4586977f4c2999a0bb8c229d20519e8d1f8fc2365749
6
+ metadata.gz: f865c9753769cfa587ce59e428d45a664d1b976b535418e86bba7688ab3b0255177d9de7201479a683635c7376ae0958ad7803490328f55f003ba10ec098c2fc
7
+ data.tar.gz: ae3cf74cc163b842f9e27d49c84165b94858fe9b91461aa6a0bfde7404d9c9175a663a099c75e9eaf4e05ec8a1bc2dbf1840e0ed1f26f48590dc217dd6a8b4e1
@@ -8,7 +8,7 @@ jobs:
8
8
 
9
9
  services:
10
10
  clickhouse:
11
- image: yandex/clickhouse-server:21.1.4
11
+ image: yandex/clickhouse-server:21.3
12
12
  ports:
13
13
  - 8123:8123
14
14
 
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
+ /.idea/
3
4
  /_yardoc/
4
5
  /coverage/
5
6
  /pkg/
data/.rubocop.yml CHANGED
@@ -13,9 +13,9 @@ AllCops:
13
13
  Bundler/OrderedGems:
14
14
  Enabled: false
15
15
 
16
- # ============================== Documentation ======================
17
- Style/Documentation:
18
- Enabled: false
16
+ # ============================== Gemspec ======================
17
+ Gemspec/DateAssignment:
18
+ Enabled: true
19
19
 
20
20
  # =============================== Performance =======================
21
21
  Performance/AncestorsInclude:
@@ -46,6 +46,10 @@ Performance/ConstantRegexp:
46
46
  Enabled: true
47
47
  Performance/MethodObjectAsBlock:
48
48
  Enabled: false
49
+ Performance/RedundantEqualityComparisonBlock:
50
+ Enabled: true
51
+ Performance/RedundantSplitRegexpArgument:
52
+ Enabled: true
49
53
 
50
54
  # ============================== Metrics ============================
51
55
  Metrics/ClassLength:
@@ -227,6 +231,10 @@ Style/EndlessMethod:
227
231
  Enabled: true
228
232
  Style/IfWithBooleanLiteralBranches:
229
233
  Enabled: true
234
+ Style/HashConversion:
235
+ Enabled: true
236
+ Style/Documentation:
237
+ Enabled: false
230
238
 
231
239
  # ============================== Lint ==============================
232
240
  Lint/DuplicateMethods:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
+ # 1.5.0
2
+ * add support for 'WITH TOTALS' modifier in response
3
+ * send SQL in GET request's body [#12](https://github.com/shlima/click_house/pull/12)
4
+ * add support of 'WITH TOTALS' on a resulting set
5
+
1
6
  # 1.4.0
2
- * fizx decimal type casting [#11](https://github.com/shlima/click_house/issues/11)
7
+ * fix decimal type casting [#11](https://github.com/shlima/click_house/issues/11)
3
8
 
4
9
  # 1.3.9
5
10
  * add `ClickHouse.connection.add_index`, `ClickHouse.connection.drop_index`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- click_house (1.4.0)
4
+ click_house (1.5.0)
5
5
  faraday
6
6
  faraday_middleware
7
7
 
@@ -11,11 +11,15 @@ GEM
11
11
  ast (2.4.2)
12
12
  coderay (1.1.3)
13
13
  diff-lcs (1.4.4)
14
- faraday (1.3.0)
14
+ faraday (1.4.1)
15
+ faraday-excon (~> 1.1)
15
16
  faraday-net_http (~> 1.0)
17
+ faraday-net_http_persistent (~> 1.1)
16
18
  multipart-post (>= 1.2, < 3)
17
- ruby2_keywords
19
+ ruby2_keywords (>= 0.0.4)
20
+ faraday-excon (1.1.0)
18
21
  faraday-net_http (1.0.1)
22
+ faraday-net_http_persistent (1.1.0)
19
23
  faraday_middleware (1.0.0)
20
24
  faraday (~> 1.0)
21
25
  method_source (1.0.0)
@@ -28,7 +32,7 @@ GEM
28
32
  method_source (~> 1.0)
29
33
  rainbow (3.0.0)
30
34
  rake (13.0.3)
31
- regexp_parser (2.0.3)
35
+ regexp_parser (2.1.1)
32
36
  rexml (3.2.4)
33
37
  rspec (3.10.0)
34
38
  rspec-core (~> 3.10.0)
@@ -43,7 +47,7 @@ GEM
43
47
  diff-lcs (>= 1.2.0, < 2.0)
44
48
  rspec-support (~> 3.10.0)
45
49
  rspec-support (3.10.2)
46
- rubocop (1.9.1)
50
+ rubocop (1.11.0)
47
51
  parallel (~> 1.10)
48
52
  parser (>= 3.0.0.0)
49
53
  rainbow (>= 2.2.2, < 4.0)
@@ -54,7 +58,7 @@ GEM
54
58
  unicode-display_width (>= 1.4.0, < 3.0)
55
59
  rubocop-ast (1.4.1)
56
60
  parser (>= 2.7.1.5)
57
- rubocop-performance (1.9.2)
61
+ rubocop-performance (1.10.1)
58
62
  rubocop (>= 0.90.0, < 2.0)
59
63
  rubocop-ast (>= 0.4.0)
60
64
  ruby-progressbar (1.11.0)
@@ -74,4 +78,4 @@ DEPENDENCIES
74
78
  rubocop-performance
75
79
 
76
80
  BUNDLED WITH
77
- 2.2.3
81
+ 2.2.14
data/docker-compose.yml CHANGED
@@ -2,7 +2,7 @@ version: '3.5'
2
2
 
3
3
  services:
4
4
  clickhouse:
5
- image: yandex/clickhouse-server:21.1.4
5
+ image: yandex/clickhouse-server:21.3
6
6
  ports:
7
7
  - "8123:8123"
8
8
  - "9000:9000"
@@ -49,11 +49,15 @@ module ClickHouse
49
49
  end
50
50
 
51
51
  def logger!
52
- @logger || Logger.new(IO::NULL)
52
+ @logger || null_logger
53
53
  end
54
54
 
55
55
  def url!
56
56
  @url || "#{scheme}://#{host}:#{port}"
57
57
  end
58
+
59
+ def null_logger
60
+ @null_logger ||= Logger.new(IO::NULL)
61
+ end
58
62
  end
59
63
  end
@@ -21,8 +21,25 @@ module ClickHouse
21
21
  post(body, query: { query: query }, database: database)
22
22
  end
23
23
 
24
- def get(path = '/', query: {}, database: config.database)
25
- transport.get(compose(path, query.merge(database: database)))
24
+ # @param path [String] Clickhouse HTTP endpoint, e.g. /ping, /replica_status
25
+ # @param body [String] SQL to run
26
+ # @param database [String|NilClass] database to use, nil to skip
27
+ # @param query [Hash] other CH settings to send through params, e.g. max_rows_to_read=1
28
+ # @example get(body: 'select number from system.numbers limit 100', query: { max_rows_to_read: 10 })
29
+ # @return [Faraday::Response]
30
+ def get(path = '/', body: '', query: {}, database: config.database)
31
+ # backward compatibility since
32
+ # https://github.com/shlima/click_house/pull/12/files#diff-9c6f3f06d3b575731eae4b6b95ddbcdcc20452c432b8f6e87a3a8e8645818107R24
33
+ if query.is_a?(String)
34
+ query = { query: query }
35
+ config.logger!.warn('since v1.4.0 use connection.get(body: "SELECT 1") instead of connection.get(query: "SELECT 1")')
36
+ end
37
+
38
+ transport.get(path) do |conn|
39
+ conn.params = query.merge(database: database).compact
40
+ conn.params[:send_progress_in_http_headers] = 1 unless body.empty?
41
+ conn.body = body
42
+ end
26
43
  end
27
44
 
28
45
  def post(body = nil, query: {}, database: config.database)
@@ -6,9 +6,11 @@ module ClickHouse
6
6
  EXPLAIN = 'EXPLAIN'
7
7
  EXPLAIN_RE = /\A(\s*#{EXPLAIN})/io.freeze
8
8
 
9
- def explain(sql, io: $stdout)
9
+ # @return String
10
+ def explain(sql, io: StringIO.new)
10
11
  res = execute("#{EXPLAIN} #{sql.gsub(EXPLAIN_RE, '')}")
11
- io << res.body
12
+ io.puts(res.body)
13
+ io.string
12
14
  end
13
15
  end
14
16
  end
@@ -4,8 +4,7 @@ module ClickHouse
4
4
  module Extend
5
5
  module ConnectionHealthy
6
6
  def ping
7
- # without +send_progress_in_http_headers: nil+ DB::Exception: Empty query returns
8
- get(database: nil, query: { send_progress_in_http_headers: nil }).success?
7
+ get('/ping', database: nil).success?
9
8
  end
10
9
 
11
10
  def replicas_status
@@ -5,17 +5,17 @@ module ClickHouse
5
5
  module ConnectionSelective
6
6
  # @return [ResultSet]
7
7
  def select_all(sql)
8
- response = execute(Util::Statement.format(sql, 'JSON'))
8
+ response = get(body: Util::Statement.format(sql, 'JSON'))
9
9
  Response::Factory[response]
10
10
  end
11
11
 
12
12
  def select_value(sql)
13
- response = execute(Util::Statement.format(sql, 'JSON'))
13
+ response = get(body: Util::Statement.format(sql, 'JSON'))
14
14
  Array(Response::Factory[response].first).dig(0, -1)
15
15
  end
16
16
 
17
17
  def select_one(sql)
18
- response = execute(Util::Statement.format(sql, 'JSON'))
18
+ response = get(body: Util::Statement.format(sql, 'JSON'))
19
19
  Response::Factory[response].first
20
20
  end
21
21
  end
@@ -29,11 +29,8 @@ module ClickHouse
29
29
  # rubocop:disable Layout/LineLength
30
30
  def on_complete(env)
31
31
  summary = extract_summary(env.response_headers)
32
- elapsed = duration
33
- query = CGI.parse(env.url.query.to_s).dig('query', 0) || '[NO QUERY]'
34
-
35
- logger.info("\e[1mSQL (#{Util::Pretty.measure(elapsed)})\e[0m #{query};")
36
- logger.debug(body) if body
32
+ logger.info("\e[1mSQL (#{duration_stats_log(env.body)})\e[0m #{query(env)};")
33
+ logger.debug(body) if body && !query_in_body?(env)
37
34
  logger.info("\e[1mRead: #{summary.fetch(:read_rows)} rows, #{summary.fetch(:read_bytes)}. Written: #{summary.fetch(:written_rows)} rows, #{summary.fetch(:written_bytes)}\e[0m")
38
35
  end
39
36
  # rubocop:enable Layout/LineLength
@@ -46,6 +43,28 @@ module ClickHouse
46
43
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
47
44
  end
48
45
 
46
+ def query_in_body?(env)
47
+ env.method == :get
48
+ end
49
+
50
+ def query(env)
51
+ if query_in_body?(env)
52
+ body
53
+ else
54
+ CGI.parse(env.url.query.to_s).dig('query', 0) || '[NO QUERY]'
55
+ end
56
+ end
57
+
58
+ def duration_stats_log(body)
59
+ elapsed = duration
60
+ clickhouse_elapsed = body['statistics'].fetch('elapsed') if body.is_a?(Hash) && body.key?('statistics')
61
+
62
+ [
63
+ "Total: #{Util::Pretty.measure(elapsed * 1000)}",
64
+ ("CH: #{Util::Pretty.measure(clickhouse_elapsed * 1000)}" if clickhouse_elapsed)
65
+ ].compact.join(', ')
66
+ end
67
+
49
68
  def extract_summary(headers)
50
69
  JSON.parse(headers.fetch('x-clickhouse-summary', '{}')).tap do |summary|
51
70
  summary[:read_rows] = summary['read_rows']
@@ -10,7 +10,12 @@ module ClickHouse
10
10
 
11
11
  return body if !body.is_a?(Hash) || !(body.key?('meta') && body.key?('data'))
12
12
 
13
- ResultSet.new(meta: body.fetch('meta'), data: body.fetch('data'), statistics: body['statistics'])
13
+ ResultSet.new(
14
+ meta: body.fetch('meta'),
15
+ data: body.fetch('data'),
16
+ totals: body['totals'],
17
+ statistics: body['statistics']
18
+ )
14
19
  end
15
20
  end
16
21
  end
@@ -14,7 +14,7 @@ module ClickHouse
14
14
  :inspect, :each, :fetch, :length, :count, :size,
15
15
  :first, :last, :[], :to_h
16
16
 
17
- attr_reader :meta, :data, :statistics
17
+ attr_reader :meta, :data, :totals, :statistics
18
18
 
19
19
  class << self
20
20
  # @return [Array<String, Array>]
@@ -48,9 +48,13 @@ module ClickHouse
48
48
 
49
49
  # @param meta [Array]
50
50
  # @param data [Array]
51
- def initialize(meta:, data:, statistics: nil)
51
+ # @param totals [Array|Hash|NilClass] Support for 'GROUP BY WITH TOTALS' modifier
52
+ # https://clickhouse.tech/docs/en/sql-reference/statements/select/group-by/#with-totals-modifier
53
+ # Hash in JSON format and Array in JSONCompact
54
+ def initialize(meta:, data:, totals: nil, statistics: nil)
52
55
  @meta = meta
53
56
  @data = data
57
+ @totals = totals
54
58
  @statistics = Hash(statistics)
55
59
  end
56
60
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClickHouse
4
- VERSION = '1.4.0'
4
+ VERSION = '1.5.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: click_house
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aliaksandr Shylau
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-15 00:00:00.000000000 Z
11
+ date: 2021-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -210,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
210
  - !ruby/object:Gem::Version
211
211
  version: '0'
212
212
  requirements: []
213
- rubygems_version: 3.2.3
213
+ rubygems_version: 3.2.15
214
214
  signing_key:
215
215
  specification_version: 4
216
216
  summary: Modern Ruby database driver for ClickHouse