clickhouse-activerecord 0.4.3 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b584e48174f94997dc9dd04d3ffde3ff7c4b24535117c565e580c646f2f2581c
4
- data.tar.gz: 9e7c01a185d23ac6e5ac16da635b118a59e7a7c7cdf86ce1c28e92aebacd3baa
3
+ metadata.gz: dd2cc6144472b64d9ffe1c8b61bc86e75cc74863566aa65ff9f86ffd526d9ff4
4
+ data.tar.gz: 34e95e5728a4d90c69e7f604eac303174a0c873cae7e503f7edcca36e8ab9c5f
5
5
  SHA512:
6
- metadata.gz: 8b3132522dbc7abaffa180049e350d4ceea82863ab3c208611c4b3227e6ebece1f706262daebec562bd13822fdcd31d44e6321ec97083543484e238e3e07ed2f
7
- data.tar.gz: 44f3c58ff30e78b4e83066fbf9609bd656bf9c3e64f56a6113713068b98393c680ec949b5d8832da533ea6cc12216584a9fcf7b34279efc8c499ec9ff376a166
6
+ metadata.gz: 3638e95511941d90a06a9df8c2d640ef68742fb54474ddf289d1d136a077bae0e1510cfd9752029d6654f4e2777b865ea5ed0d6703fdb31f64ab23fca7a500b1
7
+ data.tar.gz: 650b30cfc25416e6d0cce0fe4b48146c55a256e7a9a0df61b2addaf55ca5e7533f0e8facc5599030ddaaa93bc5a07cea498390d9ad750ba77650fec914a5f476
@@ -1,4 +1,4 @@
1
- ### Version 0.4.0 (Sep 18, 2020)
1
+ ### Version 0.4.4 (Sep 23, 2020)
2
2
 
3
3
  * Full support migration and rollback database
4
4
  * Support cluster and replica. Auto inject to SQL queries.
@@ -6,15 +6,17 @@ module ActiveRecord
6
6
  class SchemaCreation < AbstractAdapter::SchemaCreation# :nodoc:
7
7
 
8
8
  def visit_AddColumnDefinition(o)
9
- +"ADD COLUMN #{accept(o.column)}"
9
+ sql = +"ADD COLUMN #{accept(o.column)}"
10
+ sql << " AFTER " + quote_column_name(o.column.options[:after]) if o.column.options.key?(:after)
11
+ sql
10
12
  end
11
13
 
12
14
  def add_column_options!(sql, options)
13
- sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
14
15
  if options[:null] || options[:null].nil?
15
16
  sql.gsub!(/\s+(.*)/, ' Nullable(\1)')
16
17
  end
17
18
  sql.gsub!(/(\sString)\(\d+\)/, '\1')
19
+ sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
18
20
  sql
19
21
  end
20
22
 
@@ -47,6 +49,25 @@ module ActiveRecord
47
49
  " TEMPORARY" if o.temporary
48
50
  " MATERIALIZED" if o.materialized
49
51
  end
52
+
53
+ def visit_ChangeColumnDefinition(o)
54
+ column = o.column
55
+ column.sql_type = type_to_sql(column.type, column.options)
56
+ options = column_options(column)
57
+
58
+ quoted_column_name = quote_column_name(o.name)
59
+ type = column.sql_type
60
+ type = "Nullable(#{type})" if options[:null]
61
+ change_column_sql = +"MODIFY COLUMN #{quoted_column_name} #{type}"
62
+
63
+ if options.key?(:default)
64
+ quoted_default = quote_default_expression(options[:default], column)
65
+ change_column_sql << " DEFAULT #{quoted_default}"
66
+ end
67
+
68
+ change_column_sql
69
+ end
70
+
50
71
  end
51
72
  end
52
73
  end
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  @if_not_exists = if_not_exists
29
29
  @options = options
30
30
  @as = as
31
- @name = @conn.apply_cluster(name)
31
+ @name = name
32
32
  @comment = comment
33
33
  @view = view || materialized
34
34
  @materialized = materialized
@@ -36,7 +36,7 @@ module ActiveRecord
36
36
  end
37
37
 
38
38
  def table_options(table)
39
- sql = do_system_execute("SHOW CREATE TABLE `#{table}`")['data'].try(:first).try(:first)
39
+ sql = show_create_table(table)
40
40
  { options: sql.gsub(/^(?:.*?)ENGINE = (.*?)$/, '\\1') }
41
41
  end
42
42
 
@@ -156,6 +156,8 @@ module ActiveRecord
156
156
  when "true".freeze, "false".freeze
157
157
  default
158
158
  # Object identifier types
159
+ when "''"
160
+ ''
159
161
  when /\A-?\d+\z/
160
162
  $1
161
163
  else
@@ -201,11 +201,17 @@ module ActiveRecord
201
201
  ClickhouseActiverecord::SchemaDumper.create(self, options)
202
202
  end
203
203
 
204
+ # @param [String] table
205
+ # @return [String]
206
+ def show_create_table(table)
207
+ do_system_execute("SHOW CREATE TABLE `#{table}`")['data'].try(:first).try(:first).gsub(/[\n\s]+/m, ' ')
208
+ end
209
+
204
210
  # Create a new ClickHouse database.
205
211
  def create_database(name)
206
212
  sql = apply_cluster "CREATE DATABASE #{quote_table_name(name)}"
207
213
  log_with_debug(sql, adapter_name) do
208
- res = @connection.post("/?#{@config.except(:database).to_param}", "CREATE DATABASE #{quote_table_name(name)}")
214
+ res = @connection.post("/?#{@config.except(:database).to_param}", sql)
209
215
  process_response(res)
210
216
  end
211
217
  end
@@ -213,7 +219,7 @@ module ActiveRecord
213
219
  def create_view(table_name, **options)
214
220
  options.merge!(view: true)
215
221
  options = apply_replica(table_name, options)
216
- td = create_table_definition(table_name, options)
222
+ td = create_table_definition(apply_cluster(table_name), options)
217
223
  yield td if block_given?
218
224
 
219
225
  if options[:force]
@@ -225,7 +231,7 @@ module ActiveRecord
225
231
 
226
232
  def create_table(table_name, **options)
227
233
  options = apply_replica(table_name, options)
228
- td = create_table_definition(table_name, options)
234
+ td = create_table_definition(apply_cluster(table_name), options)
229
235
  yield td if block_given?
230
236
 
231
237
  if options[:force]
@@ -252,6 +258,21 @@ module ActiveRecord
252
258
  do_execute apply_cluster "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
253
259
  end
254
260
 
261
+ def change_column(table_name, column_name, type, options = {})
262
+ result = do_execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}"
263
+ raise "Error parse json response: #{result}" if result.presence && !result.is_a?(Hash)
264
+ end
265
+
266
+ def change_column_null(table_name, column_name, null, default = nil)
267
+ structure = table_structure(table_name).select{|v| v[0] == column_name.to_s}.first
268
+ raise "Column #{column_name} not found in table #{table_name}" if structure.nil?
269
+ change_column table_name, column_name, structure[1].gsub(/(Nullable\()?(.*?)\)?/, '\2'), {null: null, default: default}.compact
270
+ end
271
+
272
+ def change_column_default(table_name, column_name, default)
273
+ change_column table_name, column_name, nil, {default: default}.compact
274
+ end
275
+
255
276
  def cluster
256
277
  @full_config[:cluster_name]
257
278
  end
@@ -274,6 +295,12 @@ module ActiveRecord
274
295
  result
275
296
  end
276
297
 
298
+ def change_column_for_alter(table_name, column_name, type, options = {})
299
+ td = create_table_definition(table_name)
300
+ cd = td.new_column_definition(column_name, type, options)
301
+ schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))
302
+ end
303
+
277
304
  private
278
305
 
279
306
  def connect
@@ -7,7 +7,7 @@ module ClickhouseActiverecord
7
7
  unless table_exists?
8
8
  version_options = connection.internal_string_options_for_primary_key
9
9
 
10
- connection.create_table(table_name, id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version ORDER BY (version)') do |t|
10
+ connection.create_table(table_name, id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version ORDER BY (version)', if_not_exists: true) do |t|
11
11
  t.string :version, version_options
12
12
  t.column :active, 'Int8', null: false, default: '1'
13
13
  t.datetime :ver, null: false, default: -> { 'now()' }
@@ -27,7 +27,7 @@ module ClickhouseActiverecord
27
27
  unless table_exists?
28
28
  key_options = connection.internal_string_options_for_primary_key
29
29
 
30
- connection.create_table(table_name, id: false, options: 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)') do |t|
30
+ connection.create_table(table_name, id: false, options: 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)', if_not_exists: true) do |t|
31
31
  t.string :key, key_options
32
32
  t.string :value
33
33
  t.timestamps
@@ -33,11 +33,19 @@ module ClickhouseActiverecord
33
33
  HEADER
34
34
  end
35
35
 
36
+ def tables(stream)
37
+ sorted_tables = @connection.tables.sort {|a,b| @connection.show_create_table(a).match(/^CREATE\s+(MATERIALIZED)\s+VIEW/) ? 1 : a <=> b }
38
+
39
+ sorted_tables.each do |table_name|
40
+ table(table_name, stream) unless ignored?(table_name)
41
+ end
42
+ end
43
+
36
44
  def table(table, stream)
37
- if table.match(/^\.inner\./).nil?
45
+ if table.match(/^\.inner/).nil?
38
46
  unless simple
39
47
  stream.puts " # TABLE: #{table}"
40
- sql = @connection.do_system_execute("SHOW CREATE TABLE `#{table.gsub(/^\.inner\./, '')}`")['data'].try(:first).try(:first)
48
+ sql = @connection.show_create_table(table)
41
49
  stream.puts " # SQL: #{sql.gsub(/ENGINE = Replicated(.*?)\('[^']+',\s*'[^']+',?\s?([^\)]*)?\)/, "ENGINE = \\1(\\2)")}" if sql
42
50
  # super(table.gsub(/^\.inner\./, ''), stream)
43
51
 
@@ -85,13 +93,15 @@ HEADER
85
93
  tbl.puts ", force: :cascade do |t|"
86
94
 
87
95
  # then dump all non-primary key columns
88
- columns.each do |column|
89
- raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
90
- next if column.name == pk
91
- type, colspec = column_spec(column)
92
- tbl.print " t.#{type} #{column.name.inspect}"
93
- tbl.print ", #{format_colspec(colspec)}" if colspec.present?
94
- tbl.puts
96
+ if simple || !match
97
+ columns.each do |column|
98
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
99
+ next if column.name == pk
100
+ type, colspec = column_spec(column)
101
+ tbl.print " t.#{type} #{column.name.inspect}"
102
+ tbl.print ", #{format_colspec(colspec)}" if colspec.present?
103
+ tbl.puts
104
+ end
95
105
  end
96
106
 
97
107
  indexes_in_create(table, tbl)
@@ -118,7 +128,7 @@ HEADER
118
128
 
119
129
  def format_colspec(colspec)
120
130
  if simple
121
- super.gsub(/CAST\(([^,]+),.*?\)/, "\\1")
131
+ super.gsub(/CAST\('?([^,']*)'?,\s?'.*?'\)/, "\\1")
122
132
  else
123
133
  super
124
134
  end
@@ -1,3 +1,3 @@
1
1
  module ClickhouseActiverecord
2
- VERSION = '0.4.3'
2
+ VERSION = '0.4.8'
3
3
  end
@@ -20,8 +20,9 @@ namespace :clickhouse do
20
20
 
21
21
  # todo not testing
22
22
  desc 'Load database schema'
23
- task load: [:load_config, :prepare_schema_migration_table, :prepare_internal_metadata_table] do |t, args|
23
+ task load: [:load_config, :prepare_internal_metadata_table] do |t, args|
24
24
  simple = ENV['simple'] || ARGV.map{|a| a.include?('--simple') ? true : nil}.compact.any? ? '_simple' : nil
25
+ ClickhouseActiverecord::SchemaMigration.drop_table
25
26
  load("#{Rails.root}/db/clickhouse_schema#{simple}.rb")
26
27
  end
27
28
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clickhouse-activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Odintsov
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-22 00:00:00.000000000 Z
11
+ date: 2020-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -134,7 +134,7 @@ homepage: https://github.com/pnixx/clickhouse-activerecord
134
134
  licenses:
135
135
  - MIT
136
136
  metadata: {}
137
- post_install_message:
137
+ post_install_message:
138
138
  rdoc_options: []
139
139
  require_paths:
140
140
  - lib
@@ -150,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
150
  version: '0'
151
151
  requirements: []
152
152
  rubygems_version: 3.0.1
153
- signing_key:
153
+ signing_key:
154
154
  specification_version: 4
155
155
  summary: ClickHouse ActiveRecord
156
156
  test_files: []