clickhouse-native 0.1.1-x86_64-linux-gnu

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fa18bb35a5161587c5743d27cb4d17fd8c25f7ad5865938deeaa51179c0518b8
4
+ data.tar.gz: 2efe20b98476212884665ad681872e3af5558f8d8b6e2a366f4e846b39b0ea17
5
+ SHA512:
6
+ metadata.gz: b8e8f67bcfd88a96dff2896ec16540069c3a2bc560a65e62db30319b5706834ee98a39ff946856280fcc6fb37c3316408f0bcce1c7ecab39dab1e58c3026d649
7
+ data.tar.gz: 598d753e3ef3d70496c0f105525d8f8b7ae3e7ad57b2a17aad0dc5d4eec8fecb7b2bdf6dbeb8af7ae1168d10f038fd88554cee68c056d8036a47b4d597822e4d
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickhouseNative
4
+ class Client
5
+ attr_reader :host, :port, :database
6
+
7
+ def describe_table(table, db_name: nil)
8
+ fq = db_name ? "#{db_name}.#{table}" : table
9
+ query("DESCRIBE TABLE #{fq}")
10
+ end
11
+
12
+ # insert(table, rows, columns: nil, db_name: nil, types: nil)
13
+ #
14
+ # rows may be Array<Hash{Symbol|String => Object}> or Array<Array>.
15
+ # columns defaults to the first hash's keys (for Array<Hash>) or all table
16
+ # columns in DDL order (for Array<Array>).
17
+ # types may be supplied to skip the DESCRIBE lookup.
18
+ #
19
+ # Hash keys not present in the schema raise ArgumentError — if you need
20
+ # to insert a subset, pass `columns:` explicitly.
21
+ def insert(table, rows, columns: nil, db_name: nil, types: nil)
22
+ return 0 if rows.empty?
23
+
24
+ fq = db_name ? "#{db_name}.#{table}" : table
25
+ col_pairs =
26
+ if types && columns
27
+ zip_columns_and_types(columns, types)
28
+ else
29
+ columns_from_schema(table, rows, columns, db_name, fq)
30
+ end
31
+ row_arrays = rows.first.is_a?(Hash) ? hash_rows_to_arrays(rows, col_pairs) : rows
32
+
33
+ insert_block(fq, col_pairs, row_arrays)
34
+ end
35
+
36
+ def inspect
37
+ "#<#{self.class} #{host}:#{port}/#{database}>"
38
+ end
39
+
40
+ private
41
+
42
+ def zip_columns_and_types(columns, types)
43
+ if columns.size != types.size
44
+ raise ArgumentError, "types and columns must have the same length"
45
+ end
46
+ columns.zip(types).map { |n, t| [n.to_s, t] }
47
+ end
48
+
49
+ def columns_from_schema(table, rows, columns, db_name, fqn)
50
+ schema = describe_table(table, db_name: db_name)
51
+ type_by_name = schema.to_h { |c| [c[:name], c[:type]] }
52
+ columns ||= rows.first.is_a?(Hash) ? rows.first.keys.map(&:to_s) : schema.map { |c| c[:name] }
53
+ columns.map do |name|
54
+ name_s = name.to_s
55
+ t = type_by_name[name_s] or
56
+ raise ArgumentError, "unknown column #{name_s.inspect} in #{fqn}"
57
+ [name_s, t]
58
+ end
59
+ end
60
+
61
+ def hash_rows_to_arrays(rows, col_pairs)
62
+ lookup = col_pairs.map { |n, _| [n.to_sym, n] }
63
+ rows.map { |h| lookup.map { |sym, str| h.fetch(sym) { h[str] } } }
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickhouseNative
4
+ class Error < StandardError; end
5
+
6
+ class ConnectionError < Error; end
7
+ class TimeoutError < ConnectionError; end
8
+
9
+ class ProtocolError < Error; end
10
+
11
+ class ServerError < Error
12
+ attr_reader :server_code, :server_name, :server_stacktrace
13
+
14
+ def initialize(message, code: nil, name: nil, stacktrace: nil)
15
+ super(message)
16
+ @server_code = code
17
+ @server_name = name
18
+ @server_stacktrace = stacktrace
19
+ end
20
+ end
21
+
22
+ class EncoderError < Error; end
23
+ class DecoderError < Error; end
24
+ class UnsupportedTypeError < DecoderError; end
25
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickhouseNative
4
+ # Sequel-style logging wrapper. Prepended onto Client so it fires for the
5
+ # raw C-level execute/query/query_value/query_each/insert_block calls.
6
+ #
7
+ # client = Client.new(..., logger: Rails.logger)
8
+ # client.query("SELECT 1")
9
+ # # => DEBUG -- : (0.421ms) SELECT 1
10
+ #
11
+ # Errors are logged at ERROR with the elapsed time and exception class.
12
+ module Logging
13
+ LEVEL = :debug
14
+
15
+ def execute(sql)
16
+ log_sql(sql) { super }
17
+ end
18
+
19
+ def query(sql)
20
+ log_sql(sql) { super }
21
+ end
22
+
23
+ def query_value(sql)
24
+ log_sql(sql) { super }
25
+ end
26
+
27
+ def query_each(sql, &)
28
+ log_sql(sql) { super }
29
+ end
30
+
31
+ def insert_block(table, columns, rows)
32
+ col_list = columns.map(&:first).join(", ")
33
+ log_sql("INSERT INTO #{table} (#{col_list}) VALUES (#{rows.size} rows)") { super }
34
+ end
35
+
36
+ private
37
+
38
+ def log_sql(sql)
39
+ return yield unless @logger
40
+
41
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
42
+ begin
43
+ result = yield
44
+ elapsed_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000
45
+ @logger.public_send(LEVEL, format("(%<ms>.3fms) %<sql>s", ms: elapsed_ms, sql: sql))
46
+ result
47
+ rescue => error
48
+ elapsed_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000
49
+ first_line = error.message.to_s.lines.first.to_s.strip
50
+ @logger.error(format(
51
+ "(%<ms>.3fms) %<class>s: %<msg>s -- %<sql>s",
52
+ ms: elapsed_ms, class: error.class, msg: first_line, sql: sql,
53
+ ))
54
+ raise
55
+ end
56
+ end
57
+ end
58
+
59
+ class Client
60
+ attr_accessor :logger
61
+
62
+ prepend Logging
63
+ end
64
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "connection_pool"
4
+
5
+ module ClickhouseNative
6
+ class Pool
7
+ def initialize(host:, port:, database: "default", user: "default", password: "",
8
+ compression: :none, logger: nil, pool_size: 5, pool_timeout: 5)
9
+ client_kwargs = { host:, port:, database:, user:, password:, compression:, logger: }
10
+ @pool = ConnectionPool.new(size: pool_size, timeout: pool_timeout) do
11
+ Client.new(**client_kwargs)
12
+ end
13
+ end
14
+
15
+ def with(&)
16
+ @pool.with(&)
17
+ end
18
+
19
+ def execute(sql)
20
+ @pool.with { |c| c.execute(sql) }
21
+ end
22
+
23
+ def query(sql)
24
+ @pool.with { |c| c.query(sql) }
25
+ end
26
+
27
+ def query_each(sql, &block)
28
+ @pool.with { |c| c.query_each(sql, &block) }
29
+ end
30
+
31
+ def query_value(sql)
32
+ @pool.with { |c| c.query_value(sql) }
33
+ end
34
+
35
+ def insert(table, rows, **opts)
36
+ @pool.with { |c| c.insert(table, rows, **opts) }
37
+ end
38
+
39
+ def ping
40
+ @pool.with(&:ping)
41
+ end
42
+
43
+ def server_version
44
+ @pool.with(&:server_version)
45
+ end
46
+
47
+ def describe_table(table, db_name: nil)
48
+ @pool.with { |c| c.describe_table(table, db_name:) }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickhouseNative
4
+ VERSION = "0.1.1"
5
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+ require "bigdecimal"
5
+ require "clickhouse_native/version"
6
+ require "clickhouse_native/errors"
7
+ require "clickhouse_native/clickhouse_native"
8
+ require "clickhouse_native/client"
9
+ require "clickhouse_native/logging"
10
+ require "clickhouse_native/pool"
11
+
12
+ module ClickhouseNative
13
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clickhouse-native
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: x86_64-linux-gnu
6
+ authors:
7
+ - Yuri Smirnov
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: connection_pool
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.4'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.4'
26
+ description: A high-performance Ruby client for ClickHouse using the native binary
27
+ protocol via a C++ extension wrapping clickhouse-cpp.
28
+ email:
29
+ - tycoooon@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/clickhouse_native.rb
35
+ - lib/clickhouse_native/3.3/clickhouse_native.so
36
+ - lib/clickhouse_native/3.4/clickhouse_native.so
37
+ - lib/clickhouse_native/4.0/clickhouse_native.so
38
+ - lib/clickhouse_native/client.rb
39
+ - lib/clickhouse_native/errors.rb
40
+ - lib/clickhouse_native/logging.rb
41
+ - lib/clickhouse_native/pool.rb
42
+ - lib/clickhouse_native/version.rb
43
+ licenses:
44
+ - Apache-2.0
45
+ metadata:
46
+ precompiled: 'true'
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ - - "<"
56
+ - !ruby/object:Gem::Version
57
+ version: 4.1.dev
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 3.3.22
63
+ requirements: []
64
+ rubygems_version: 4.0.6
65
+ specification_version: 4
66
+ summary: ClickHouse Ruby driver over the native TCP protocol
67
+ test_files: []