click_house 1.0.0 → 1.1.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: 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