clickhouse-activerecord 0.4.3 → 0.4.8

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: 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: []