click_house 1.0.0 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05f0f9426500a803ec5d2d37b1a2a06d2eb2d3e4b934eac19a434acc5086dc5c
4
- data.tar.gz: c079c080dedbcc3342bbfde789099ddacf714a16029779bddbd8352d1912f1b0
3
+ metadata.gz: e21fcc0831f8f6612fac22c8e64eebb78b6e6f5d5d371c6db57dbfc0556610fd
4
+ data.tar.gz: 792ac875a51e3f545b9b49b55618a4161183056b82cad7e213d05ef46974d69c
5
5
  SHA512:
6
- metadata.gz: f2f1d0d8f438b317ee475499e24f9d3ecae9f2b6a872a21695f11e0f8d744693790cd6f1caa50beab7e2c11f008952e453ca37d9282caeed18a95f54e99dff44
7
- data.tar.gz: 17f7aff9dad97b3ad4384618b8cf8ce92f550ec9ee5b7ee524413458dce48f7eb08a69d4f78abf5862ac01acd33f1257de37403f6ce42595b152435819bc2e2f
6
+ metadata.gz: bca7f416a90d0d92046c8ac171511110fe2c02329e67260279b36a475bf2b59a0c65051c3f25f1f12f5ceb26bdabc659a94a75fea499fa0de65a9d3473d85156
7
+ data.tar.gz: 5eee878068a827c4875a65a4435b44c87adc2fbe83b824bbb143e9086dc6ae2aad5fe4a07d43efc3fcb5bf8c2cc56003d7ca56d7fc9a4cf17db717bff90caa41
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /spec/reports/
7
7
  /log/*
8
8
  /tmp/*
9
+ /*.gem
9
10
 
10
11
  !/log/.keep
11
12
  !/tmp/.keep
data/Makefile CHANGED
@@ -3,7 +3,10 @@
3
3
  help:
4
4
  @echo 'Available targets:'
5
5
  @echo ' make dockerize OR make ARGS="--build" dockerize'
6
+ @echo ' make release'
6
7
 
7
8
  dockerize:
8
- rm -f tmp/pids/server.pid tmp/sockets/puma.sock
9
9
  docker-compose up ${ARGS}
10
+
11
+ release:
12
+ bin/release.sh
data/README.md CHANGED
@@ -28,7 +28,9 @@ Despite we have full compatibility of protocol of different versions of client a
28
28
  * [Usage](#usage)
29
29
  * [Queries](#queries)
30
30
  * [Insert](#insert)
31
+ * [Insert an Array](#insert-an-array)
31
32
  * [Create a table](#create-a-table)
33
+ * [Alter table](#alter-table)
32
34
  * [Type casting](#type-casting)
33
35
  * [Using with a connection pool](#using-with-a-connection-pool)
34
36
  * [Using with Rails](#using-with-rails)
@@ -89,6 +91,11 @@ ClickHouse.connection.describe_table('visits') #=> [{"name"=>"id", "type"=>"Fixe
89
91
  ClickHouse.connection.table_exists?('visits', temporary: nil) #=> true
90
92
  ClickHouse.connection.drop_table('visits', if_exists: true, temporary: nil, cluster: nil)
91
93
  ClickHouse.connection.create_table(*) # see <Create a table> section
94
+ ClickHouse.connection.truncate_table('name', if_exists: true, cluster: nil)
95
+ ClickHouse.connection.truncate_tables(['table_1', 'table_2'], if_exists: true, cluster: nil)
96
+ ClickHouse.connection.truncate_tables # will truncate all tables in database
97
+ ClickHouse.connection.rename_table('old_name', 'new_name', cluster: nil)
98
+ ClickHouse.connection.rename_table(%w[table_1 table_2], %w[new_1 new_2], cluster: nil)
92
99
  ```
93
100
 
94
101
  ## Queries
@@ -174,6 +181,24 @@ ClickHouse.connection.insert('table', columns: %i[id name], values: [[1, 'Mercur
174
181
  #=> true
175
182
  ```
176
183
 
184
+ ## Insert an Array
185
+
186
+ Serializing an Array of strings is pretty low level at the moment but it works (and thanks for that).
187
+ Array of numeric types works as expected without pre-serialization
188
+
189
+ ```ruby
190
+ string_type = ClickHouse::Type::StringType.new
191
+ array_of_string = ClickHouse::Type::ArrayType.new(string_type)
192
+
193
+ data = [
194
+ { id: 1, tags: array_of_string.serialize(%w[ruby redis rails node]) }
195
+ ]
196
+
197
+ subject.insert('rspec', columns: data.first.keys) do |buffer|
198
+ buffer.concat(data.map(&:values))
199
+ end
200
+ ```
201
+
177
202
  ## Create a table
178
203
  ### Create table using DSL
179
204
 
@@ -253,6 +278,27 @@ ClickHouse.connection.execute <<~SQL
253
278
  SQL
254
279
  ```
255
280
 
281
+ ## Alter table
282
+ ### Alter table with DSL
283
+ ```ruby
284
+ ClickHouse.connection.add_column('table', 'column_name', :UInt64, default: nil, after: nil, cluster: nil)
285
+ ClickHouse.connection.drop_column('table', 'column_name', if_exists: nil, cluster: nil)
286
+ ```
287
+
288
+ ### Alter table with SQL
289
+
290
+ ```ruby
291
+ # By SQL in argument
292
+ ClickHouse.connection.alter_table('table', 'DROP COLUMN user_id', cluster: nil)
293
+
294
+ # By SQL in a block
295
+ ClickHouse.connection.alter_table('table', cluster: nil) do
296
+ <<~SQL
297
+ DROP COLUMN user_id
298
+ SQL
299
+ end
300
+ ```
301
+
256
302
  ## Type casting
257
303
 
258
304
  By default gem provides all necessary type casting, but you may overwrite or define
@@ -404,6 +450,23 @@ scope = Visit.with_os.select('COUNT(*) as counter').group(:ipv4)
404
450
  ClickHouse.connection.select_all(scope.to_sql)
405
451
  ````
406
452
 
453
+ You can clear the data table before each test with RSpec
454
+
455
+ ```ruby
456
+ RSpec.configure do |config|
457
+ config.before(:each, clean_click_house: true) do
458
+ ClickHouse.connection.truncate_tables
459
+ end
460
+ end
461
+ ```
462
+
463
+ ```ruby
464
+ RSpec.describe Api::MetricsCountroller, clean_click_house: true do
465
+ it { }
466
+ it { }
467
+ end
468
+ ```
469
+
407
470
  ## Development
408
471
 
409
472
  ```bash
data/bin/release.sh ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+
3
+ rm ./*.gem
4
+ gem build click_house.gemspec
5
+ gem push click_house-*
data/lib/click_house.rb CHANGED
@@ -31,6 +31,11 @@ module ClickHouse
31
31
  add_type "Nullable(#{column})", Type::NullableType.new(Type::DateType.new)
32
32
  end
33
33
 
34
+ %w[String].each do |column|
35
+ add_type column, Type::StringType.new
36
+ add_type "Nullable(#{column})", Type::NullableType.new(Type::StringType.new)
37
+ end
38
+
34
39
  ['DateTime(%s)'].each do |column|
35
40
  add_type column, Type::DateTimeType.new
36
41
  add_type "Nullable(#{column})", Type::NullableType.new(Type::DateTimeType.new)
@@ -7,6 +7,7 @@ module ClickHouse
7
7
  include Extend::ConnectionTable
8
8
  include Extend::ConnectionSelective
9
9
  include Extend::ConnectionInserting
10
+ include Extend::ConnectionAltering
10
11
 
11
12
  attr_reader :config
12
13
 
@@ -4,4 +4,5 @@ module ClickHouse
4
4
  Error = Class.new(StandardError)
5
5
  NetworkException = Class.new(Error)
6
6
  DbException = Class.new(Error)
7
+ StatementException = Class.new(Error)
7
8
  end
@@ -10,5 +10,6 @@ module ClickHouse
10
10
  autoload :ConnectionTable, 'click_house/extend/connection_table'
11
11
  autoload :ConnectionSelective, 'click_house/extend/connection_selective'
12
12
  autoload :ConnectionInserting, 'click_house/extend/connection_inserting'
13
+ autoload :ConnectionAltering, 'click_house/extend/connection_altering'
13
14
  end
14
15
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/ParameterLists
4
+ module ClickHouse
5
+ module Extend
6
+ module ConnectionAltering
7
+ def add_column(table, name, type, default: nil, if_not_exists: false, after: nil, cluster: nil)
8
+ sql = 'ADD COLUMN %<exists>s %<name>s %<type>s %<default>s %<after>s'
9
+
10
+ pattern = {
11
+ name: name,
12
+ exists: Util::Statement.ensure(if_not_exists, 'IF NOT EXISTS'),
13
+ type: Util::Statement.ensure(type, type),
14
+ default: Util::Statement.ensure(default, "DEFAULT #{default}"),
15
+ after: Util::Statement.ensure(after, "AFTER #{after}")
16
+ }
17
+
18
+ alter_table(table, format(sql, pattern), cluster: cluster)
19
+ end
20
+
21
+ def drop_column(table, name, if_exists: false, cluster: nil)
22
+ sql = 'DROP COLUMN %<exists>s %<name>s'
23
+
24
+ pattern = {
25
+ name: name,
26
+ exists: Util::Statement.ensure(if_exists, 'IF EXISTS')
27
+ }
28
+
29
+ alter_table(table, format(sql, pattern), cluster: cluster)
30
+ end
31
+
32
+ def alter_table(name, sql = nil, cluster: nil)
33
+ template = 'ALTER TABLE %<name>s %<cluster>s %<sql>s'
34
+ sql = yield(sql) if sql.nil?
35
+
36
+ pattern = {
37
+ name: name,
38
+ sql: sql,
39
+ cluster: Util::Statement.ensure(cluster, "ON CLUSTER #{cluster}"),
40
+ }
41
+
42
+ execute(format(template, pattern)).success?
43
+ end
44
+ end
45
+ end
46
+ end
47
+ # rubocop:enable Metrics/ParameterLists
@@ -68,14 +68,48 @@ module ClickHouse
68
68
  sample: Util::Statement.ensure(sample, "SAMPLE BY #{sample}"),
69
69
  ttl: Util::Statement.ensure(ttl, "TTL #{ttl}"),
70
70
  settings: Util::Statement.ensure(settings, "SETTINGS #{settings}"),
71
- engine: Util::Statement.ensure(engine, "ENGINE = #{engine}"),
71
+ engine: Util::Statement.ensure(engine, "ENGINE = #{engine}")
72
72
  }
73
73
 
74
- puts format(sql, pattern)
75
-
76
74
  execute(format(sql, pattern)).success?
77
75
  end
78
76
  # rubocop:enable Metrics/ParameterLists
77
+
78
+ def truncate_table(name, if_exists: false, cluster: nil)
79
+ sql = 'TRUNCATE TABLE %<exists>s %<name>s %<cluster>s'
80
+
81
+ pattern = {
82
+ name: name,
83
+ exists: Util::Statement.ensure(if_exists, 'IF EXISTS'),
84
+ cluster: Util::Statement.ensure(cluster, "ON CLUSTER #{cluster}")
85
+ }
86
+
87
+ execute(format(sql, pattern)).success?
88
+ end
89
+
90
+ def truncate_tables(names = tables, *argv)
91
+ Array(names).each { |name| truncate_table(name, *argv) }
92
+ end
93
+
94
+ def rename_table(from, to, cluster: nil)
95
+ from = Array(from)
96
+ to = Array(to)
97
+
98
+ unless from.length == to.length
99
+ raise StatementException, '<from> tables length should equal <to> length'
100
+ end
101
+
102
+ sql = <<~SQL
103
+ RENAME TABLE %<names>s %<cluster>s
104
+ SQL
105
+
106
+ pattern = {
107
+ names: from.zip(to).map { |a| a.join(' TO ') }.join(', '),
108
+ cluster: Util::Statement.ensure(cluster, "ON CLUSTER #{cluster}")
109
+ }
110
+
111
+ execute(format(sql, pattern)).success?
112
+ end
79
113
  end
80
114
  end
81
115
  end
@@ -9,7 +9,7 @@ module ClickHouse
9
9
  TYPE_ARGV_DELIM = ','
10
10
  NULLABLE = 'Nullable'
11
11
 
12
- def_delegators :to_a, :each, :fetch
12
+ def_delegators :to_a, :each, :fetch, :length, :count, :size
13
13
 
14
14
  attr_reader :meta, :data, :statistics
15
15
 
@@ -12,5 +12,7 @@ module ClickHouse
12
12
  autoload :BooleanType, 'click_house/type/boolean_type'
13
13
  autoload :DecimalType, 'click_house/type/decimal_type'
14
14
  autoload :FixedStringType, 'click_house/type/fixed_string_type'
15
+ autoload :ArrayType, 'click_house/type/array_type'
16
+ autoload :StringType, 'click_house/type/string_type'
15
17
  end
16
18
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickHouse
4
+ module Type
5
+ class ArrayType < BaseType
6
+ attr_reader :subtype
7
+
8
+ STRING_QUOTE = "'"
9
+
10
+ def initialize(subtype)
11
+ @subtype = subtype
12
+ end
13
+
14
+ def cast(value, *)
15
+ value
16
+ end
17
+
18
+ def serialize(array, *argv)
19
+ return array unless string?
20
+
21
+ serialized = array.map do |value|
22
+ escaped = subtype.serialize(value, *argv).tr(STRING_QUOTE, '\\\\' + STRING_QUOTE)
23
+ format("%<quote>s#{escaped}%<quote>s", quote: STRING_QUOTE)
24
+ end
25
+
26
+ "[#{serialized.join(',')}]"
27
+ end
28
+
29
+ private
30
+
31
+ def string?
32
+ return @is_string if defined?(@is_string)
33
+
34
+ @is_string = subtype.is_a?(StringType) || subtype.is_a?(FixedStringType)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClickHouse
4
+ module Type
5
+ class StringType < BaseType
6
+ def cast(value)
7
+ value.to_s unless value.nil?
8
+ end
9
+
10
+ def serialize(value)
11
+ value.to_s unless value.nil?
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClickHouse
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.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.0.0
4
+ version: 1.1.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: 2019-11-09 00:00:00.000000000 Z
11
+ date: 2019-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -139,6 +139,7 @@ files:
139
139
  - README.md
140
140
  - Rakefile
141
141
  - bin/console
142
+ - bin/release.sh
142
143
  - bin/setup
143
144
  - click_house.gemspec
144
145
  - doc/logo.svg
@@ -153,6 +154,7 @@ files:
153
154
  - lib/click_house/extend.rb
154
155
  - lib/click_house/extend/configurable.rb
155
156
  - lib/click_house/extend/connectible.rb
157
+ - lib/click_house/extend/connection_altering.rb
156
158
  - lib/click_house/extend/connection_database.rb
157
159
  - lib/click_house/extend/connection_healthy.rb
158
160
  - lib/click_house/extend/connection_inserting.rb
@@ -167,6 +169,7 @@ files:
167
169
  - lib/click_house/response/factory.rb
168
170
  - lib/click_house/response/result_set.rb
169
171
  - lib/click_house/type.rb
172
+ - lib/click_house/type/array_type.rb
170
173
  - lib/click_house/type/base_type.rb
171
174
  - lib/click_house/type/boolean_type.rb
172
175
  - lib/click_house/type/date_time_type.rb
@@ -176,6 +179,7 @@ files:
176
179
  - lib/click_house/type/float_type.rb
177
180
  - lib/click_house/type/integer_type.rb
178
181
  - lib/click_house/type/nullable_type.rb
182
+ - lib/click_house/type/string_type.rb
179
183
  - lib/click_house/type/undefined_type.rb
180
184
  - lib/click_house/util.rb
181
185
  - lib/click_house/util/pretty.rb