clickhouse-activerecord 0.5.3 → 0.5.10

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: 41dd800df06e6269f91b1a39d3c9df2e1e903068b5f13913cd2aad863063685f
4
- data.tar.gz: 50252db6e694467f48669a3c7c52c89e6b1633f08586714db300b8eee59ebbbc
3
+ metadata.gz: e172255ef4610b0db49f84dea36cdd85951fc4ea596f1cbe7b63c62e9c9b2633
4
+ data.tar.gz: ec85d89e0274006250466bd8a96654d30eb6614512c4d0d0bee80dcf08285a20
5
5
  SHA512:
6
- metadata.gz: 539e7dfb17998dd1bcc95ee2c15c6111229775ec29837d8f102291bf5da64db2dcf74ef0f01087443c8c1b1d9902cfdf4a586357508d3d8ed97fa099b1545770
7
- data.tar.gz: f5f8acbf806f9bc8497dcd6aa29c6bfd18b651aae78c28cc0f9449effd4ddce965a1978027d91fa57a998fc1ba0bb0027d33917a3ef35379299185bfde06c784
6
+ metadata.gz: 5130aef7dc279582f73ca91fbd0be7f80cf7200d241b17ab747e356762a9a21d5060f2f10995762a29ba5c46942bda17643937a7f849b28da58214998e85462d
7
+ data.tar.gz: '00096694c1b25b72e1f45c1f0160714eceb0c1f0c101206a9e4bc0cb4abadc825c24665f68ad4bcc7950b07553ffbceaa809830df5b35c7c3043ae9acb969ce6'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
+ ### Version 0.5.8 (Oct 25, 2021)
2
+
3
+ * Added support rails 7
4
+
5
+ ### Version 0.5.6 (Oct 25, 2021)
6
+
7
+ * Added auto creating service distributed tables and additional options for creating view [@ygreeek](https://github.com/ygreeek)
8
+ * Added default user agent
9
+
1
10
  ### Version 0.5.3 (Sep 22, 2021)
2
-
11
+
3
12
  * Fix replica cluster for a new syntax MergeTree
4
13
  * Fix support rails 5.2 on alter table
5
14
  * Support array type of column
data/README.md CHANGED
@@ -196,6 +196,7 @@ false`. The default integer is `UInt32`
196
196
  | UInt32 | 0 to 4,294,967,295 | 3,4 |
197
197
  | UInt64 | 0 to 18446744073709551615 | 5,6,7,8 |
198
198
  | UInt256 | 0 to ... | 8+ |
199
+ | Array | ... | ... |
199
200
 
200
201
  Example:
201
202
 
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_runtime_dependency 'bundler', '>= 1.13.4'
27
27
  spec.add_runtime_dependency 'activerecord', '>= 5.2'
28
28
 
29
- spec.add_development_dependency 'bundler', '~> 1.15'
29
+ spec.add_development_dependency 'bundler', '>= 1.15'
30
30
  spec.add_development_dependency 'rake', '~> 13.0'
31
31
  spec.add_development_dependency 'rspec', '~> 3.4'
32
32
  spec.add_development_dependency 'pry', '~> 0.12'
@@ -0,0 +1,18 @@
1
+ module CoreExtensions
2
+ module ActiveRecord
3
+ module Migration
4
+ module CommandRecorder
5
+ def create_view(*args, &block)
6
+ record(:create_view, args, &block)
7
+ end
8
+
9
+ private
10
+
11
+ def invert_create_view(args)
12
+ view_name, options = args
13
+ [:drop_table, view_name, options]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -19,9 +19,18 @@ module ActiveRecord
19
19
  end
20
20
 
21
21
  def add_column_options!(sql, options)
22
+ if options[:value]
23
+ sql.gsub!(/\s+(.*)/, " \\1(#{options[:value]})")
24
+ end
25
+ if options[:fixed_string]
26
+ sql.gsub!(/\s+(.*)/, " FixedString(#{options[:fixed_string]})")
27
+ end
22
28
  if options[:null] || options[:null].nil?
23
29
  sql.gsub!(/\s+(.*)/, ' Nullable(\1)')
24
30
  end
31
+ if options[:low_cardinality]
32
+ sql.gsub!(/\s+(.*)/, ' LowCardinality(\1)')
33
+ end
25
34
  if options[:array]
26
35
  sql.gsub!(/\s+(.*)/, ' Array(\1)')
27
36
  end
@@ -46,17 +55,48 @@ module ActiveRecord
46
55
  create_sql
47
56
  end
48
57
 
58
+ def add_as_clause!(create_sql, options)
59
+ return unless options.as
60
+
61
+ assign_database_to_subquery!(options.as) if options.view
62
+ create_sql << " AS #{to_sql(options.as)}"
63
+ end
64
+
65
+ def assign_database_to_subquery!(subquery)
66
+ # If you do not specify a database explicitly, ClickHouse will use the "default" database.
67
+ return unless subquery
68
+
69
+ match = subquery.match(/(?<=from)[^.\w]+(?<database>\w+(?=\.))?(?<table_name>[.\w]+)/i)
70
+ return unless match
71
+ return if match[:database]
72
+
73
+ subquery[match.begin(:table_name)...match.end(:table_name)] =
74
+ "#{current_database}.#{match[:table_name].sub('.', '')}"
75
+ end
76
+
77
+ def add_to_clause!(create_sql, options)
78
+ # If you do not specify a database explicitly, ClickHouse will use the "default" database.
79
+ return unless options.to
80
+
81
+ match = options.to.match(/(?<database>.+(?=\.))?(?<table_name>.+)/i)
82
+ return unless match
83
+ return if match[:database]
84
+
85
+ create_sql << "TO #{current_database}.#{match[:table_name].sub('.', '')}"
86
+ end
87
+
49
88
  def visit_TableDefinition(o)
50
89
  create_sql = +"CREATE#{table_modifier_in_create(o)} #{o.view ? "VIEW" : "TABLE"} "
51
90
  create_sql << "IF NOT EXISTS " if o.if_not_exists
52
91
  create_sql << "#{quote_table_name(o.name)} "
92
+ add_to_clause!(create_sql, o) if o.materialized
53
93
 
54
94
  statements = o.columns.map { |c| accept c }
55
95
  statements << accept(o.primary_keys) if o.primary_keys
56
96
  create_sql << "(#{statements.join(', ')})" if statements.present?
57
- # Attach options for only table or materialized view
58
- add_table_options!(create_sql, o) if !o.view || o.view && o.materialized
59
- create_sql << " AS #{to_sql(o.as)}" if o.as
97
+ # Attach options for only table or materialized view without TO section
98
+ add_table_options!(create_sql, o) if !o.view || o.view && o.materialized && !o.to
99
+ add_as_clause!(create_sql, o)
60
100
  create_sql
61
101
  end
62
102
 
@@ -84,6 +124,9 @@ module ActiveRecord
84
124
  change_column_sql
85
125
  end
86
126
 
127
+ def current_database
128
+ ActiveRecord::Base.connection_db_config.database
129
+ end
87
130
  end
88
131
  end
89
132
  end
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  module Clickhouse
6
6
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
7
7
 
8
- attr_reader :view, :materialized, :if_not_exists
8
+ attr_reader :view, :materialized, :if_not_exists, :to
9
9
 
10
10
  def initialize(
11
11
  conn,
@@ -17,6 +17,7 @@ module ActiveRecord
17
17
  comment: nil,
18
18
  view: false,
19
19
  materialized: false,
20
+ to: nil,
20
21
  **
21
22
  )
22
23
  @conn = conn
@@ -32,6 +33,7 @@ module ActiveRecord
32
33
  @comment = comment
33
34
  @view = view || materialized
34
35
  @materialized = materialized
36
+ @to = to
35
37
  end
36
38
 
37
39
  def integer(*args, **options)
@@ -58,7 +60,39 @@ module ActiveRecord
58
60
  kind = :int256 if options[:limit] > 16
59
61
  end
60
62
  end
61
- args.each { |name| column(name, kind, options.except(:limit, :unsigned)) }
63
+ args.each { |name| column(name, kind, **options.except(:limit, :unsigned)) }
64
+ end
65
+
66
+ def datetime(*args, **options)
67
+ kind = :datetime
68
+
69
+ if options[:precision]
70
+ kind = :datetime64
71
+ options[:value] = options[:precision]
72
+ end
73
+
74
+ args.each { |name| column(name, kind, **options.except(:precision)) }
75
+ end
76
+
77
+ def uuid(*args, **options)
78
+ args.each { |name| column(name, :uuid, **options) }
79
+ end
80
+
81
+ def enum(*args, **options)
82
+ kind = :enum8
83
+
84
+ unless options[:value].is_a? Hash
85
+ raise ArgumentError, "Column #{args.first}: option 'value' must be Hash, got: #{options[:value].class}"
86
+ end
87
+
88
+ options[:value] = options[:value].each_with_object([]) { |(k, v), arr| arr.push("'#{k}' = #{v}") }.join(', ')
89
+
90
+ if options[:limit]
91
+ kind = :enum8 if options[:limit] == 1
92
+ kind = :enum16 if options[:limit] == 2
93
+ end
94
+
95
+ args.each { |name| column(name, kind, **options.except(:limit)) }
62
96
  end
63
97
  end
64
98
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'clickhouse-activerecord/version'
4
+
3
5
  module ActiveRecord
4
6
  module ConnectionAdapters
5
7
  module Clickhouse
@@ -37,7 +39,7 @@ module ActiveRecord
37
39
  end
38
40
 
39
41
  def tables(name = nil)
40
- result = do_system_execute('SHOW TABLES', name)
42
+ result = do_system_execute("SHOW TABLES WHERE name NOT LIKE '.inner_id.%'", name)
41
43
  return [] if result.nil?
42
44
  result['data'].flatten
43
45
  end
@@ -58,7 +60,7 @@ module ActiveRecord
58
60
 
59
61
  def do_system_execute(sql, name = nil)
60
62
  log_with_debug(sql, "#{adapter_name} #{name}") do
61
- res = @connection.post("/?#{@config.to_param}", "#{sql} FORMAT JSONCompact")
63
+ res = @connection.post("/?#{@config.to_param}", "#{sql} FORMAT JSONCompact", 'User-Agent' => "Clickhouse ActiveRecord #{ClickhouseActiverecord::VERSION}")
62
64
 
63
65
  process_response(res)
64
66
  end
@@ -68,7 +70,7 @@ module ActiveRecord
68
70
  log(sql, "#{adapter_name} #{name}") do
69
71
  formatted_sql = apply_format(sql, format)
70
72
  request_params = @config || {}
71
- res = @connection.post("/?#{request_params.merge(settings).to_param}", formatted_sql)
73
+ res = @connection.post("/?#{request_params.merge(settings).to_param}", formatted_sql, 'User-Agent' => "Clickhouse ActiveRecord #{ClickhouseActiverecord::VERSION}")
72
74
 
73
75
  process_response(res)
74
76
  end
@@ -90,7 +92,7 @@ module ActiveRecord
90
92
  if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
91
93
  raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
92
94
  end
93
- execute insert_versions_sql(inserting)
95
+ do_execute(insert_versions_sql(inserting), nil, settings: {max_partitions_per_insert_block: [100, inserting.size].max})
94
96
  end
95
97
  end
96
98
 
@@ -32,6 +32,7 @@ module ActiveRecord
32
32
  sslca: config[:sslca],
33
33
  read_timeout: config[:read_timeout],
34
34
  write_timeout: config[:write_timeout],
35
+ keep_alive_timeout: config[:keep_alive_timeout]
35
36
  }
36
37
  end
37
38
 
@@ -46,20 +47,18 @@ module ActiveRecord
46
47
  end
47
48
  end
48
49
 
49
- class Relation
50
-
51
- # Replace for only ClickhouseAdapter
50
+ module ClickhouseRelationReverseOrder
52
51
  def reverse_order!
53
- orders = order_values.uniq
54
- orders.reject!(&:blank?)
55
- if self.connection.is_a?(ConnectionAdapters::ClickhouseAdapter) && orders.empty? && !primary_key
56
- self.order_values = %w(date created_at).select {|c| column_names.include?(c) }.map{|c| arel_attribute(c).desc }
57
- else
58
- self.order_values = reverse_sql_order(orders)
59
- end
52
+ return super unless connection.is_a?(ConnectionAdapters::ClickhouseAdapter)
53
+
54
+ orders = order_values.uniq.compact_blank
55
+ return super unless orders.empty? && !primary_key
56
+
57
+ self.order_values = %w(date created_at).select {|c| column_names.include?(c) }.map{|c| arel_attribute(c).desc }
60
58
  self
61
59
  end
62
60
  end
61
+ Relation.prepend(ClickhouseRelationReverseOrder)
63
62
 
64
63
  module TypeCaster
65
64
  class Map
@@ -86,9 +85,8 @@ module ActiveRecord
86
85
  def arel_table # :nodoc:
87
86
  @arel_table ||= ClickhouseActiverecord::Arel::Table.new(table_name, type_caster: type_caster)
88
87
  end
89
-
90
88
  end
91
- end
89
+ end
92
90
 
93
91
  module ConnectionAdapters
94
92
  class ClickhouseColumn < Column
@@ -104,8 +102,13 @@ module ActiveRecord
104
102
  float: { name: 'Float32' },
105
103
  decimal: { name: 'Decimal' },
106
104
  datetime: { name: 'DateTime' },
105
+ datetime64: { name: 'DateTime64' },
107
106
  date: { name: 'Date' },
108
107
  boolean: { name: 'UInt8' },
108
+ uuid: { name: 'UUID' },
109
+
110
+ enum8: { name: 'Enum8' },
111
+ enum16: { name: 'Enum16' },
109
112
 
110
113
  int8: { name: 'Int8' },
111
114
  int16: { name: 'Int16' },
@@ -182,6 +185,20 @@ module ActiveRecord
182
185
  end
183
186
  end
184
187
 
188
+ # `extract_scale` and `extract_precision` are the same as in the Rails abstract base class,
189
+ # except this permits a space after the comma
190
+
191
+ def extract_scale(sql_type)
192
+ case sql_type
193
+ when /\((\d+)\)/ then 0
194
+ when /\((\d+)(,\s?(\d+))\)/ then $3.to_i
195
+ end
196
+ end
197
+
198
+ def extract_precision(sql_type)
199
+ $1.to_i if sql_type =~ /\((\d+)(,\s?\d+)?\)/
200
+ end
201
+
185
202
  def initialize_type_map(m) # :nodoc:
186
203
  super
187
204
  register_class_with_limit m, %r(String), Type::String
@@ -210,14 +227,22 @@ module ActiveRecord
210
227
  # Quoting time without microseconds
211
228
  def quoted_date(value)
212
229
  if value.acts_like?(:time)
213
- zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
230
+ if ActiveRecord::version >= Gem::Version.new('7')
231
+ zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal
232
+ else
233
+ zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
234
+ end
214
235
 
215
236
  if value.respond_to?(zone_conversion_method)
216
237
  value = value.send(zone_conversion_method)
217
238
  end
218
239
  end
219
240
 
220
- value.to_s(:db)
241
+ if ActiveRecord::version >= Gem::Version.new('7')
242
+ value.to_fs(:db)
243
+ else
244
+ value.to_s(:db)
245
+ end
221
246
  end
222
247
 
223
248
  def column_name_for_operation(operation, node) # :nodoc:
@@ -262,26 +287,36 @@ module ActiveRecord
262
287
  def create_view(table_name, **options)
263
288
  options.merge!(view: true)
264
289
  options = apply_replica(table_name, options)
265
- td = create_table_definition(apply_cluster(table_name), options)
290
+ td = create_table_definition(apply_cluster(table_name), **options)
266
291
  yield td if block_given?
267
292
 
268
293
  if options[:force]
269
294
  drop_table(table_name, options.merge(if_exists: true))
270
295
  end
271
296
 
272
- execute schema_creation.accept td
297
+ do_execute(schema_creation.accept(td), format: nil)
273
298
  end
274
299
 
275
- def create_table(table_name, **options)
300
+ def create_table(table_name, **options, &block)
276
301
  options = apply_replica(table_name, options)
277
- td = create_table_definition(apply_cluster(table_name), options)
278
- yield td if block_given?
302
+ td = create_table_definition(apply_cluster(table_name), **options)
303
+ block.call td if block_given?
279
304
 
280
305
  if options[:force]
281
306
  drop_table(table_name, options.merge(if_exists: true))
282
307
  end
283
308
 
284
- execute schema_creation.accept td
309
+ do_execute(schema_creation.accept(td), format: nil)
310
+
311
+ if options[:with_distributed]
312
+ distributed_table_name = options.delete(:with_distributed)
313
+ sharding_key = options.delete(:sharding_key) || 'rand()'
314
+ raise 'Set a cluster' unless cluster
315
+
316
+ distributed_options =
317
+ "Distributed(#{cluster}, #{@config[:database]}, #{table_name}, #{sharding_key})"
318
+ create_table(distributed_table_name, **options.merge(options: distributed_options), &block)
319
+ end
285
320
  end
286
321
 
287
322
  # Drops a ClickHouse database.
@@ -299,6 +334,11 @@ module ActiveRecord
299
334
 
300
335
  def drop_table(table_name, options = {}) # :nodoc:
301
336
  do_execute apply_cluster "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
337
+
338
+ if options[:with_distributed]
339
+ distributed_table_name = options.delete(:with_distributed)
340
+ drop_table(distributed_table_name, **options)
341
+ end
302
342
  end
303
343
 
304
344
  def change_column(table_name, column_name, type, options = {})
@@ -324,10 +364,24 @@ module ActiveRecord
324
364
  @full_config[:replica_name]
325
365
  end
326
366
 
367
+ def use_default_replicated_merge_tree_params?
368
+ database_engine_atomic? && @full_config[:use_default_replicated_merge_tree_params]
369
+ end
370
+
371
+ def use_replica?
372
+ (replica || use_default_replicated_merge_tree_params?) && cluster
373
+ end
374
+
327
375
  def replica_path(table)
328
376
  "/clickhouse/tables/#{cluster}/#{@config[:database]}.#{table}"
329
377
  end
330
378
 
379
+ def database_engine_atomic?
380
+ current_database_engine = "select engine from system.databases where name = '#{@config[:database]}'"
381
+ res = select_one(current_database_engine)
382
+ res['engine'] == 'Atomic' if res
383
+ end
384
+
331
385
  def apply_cluster(sql)
332
386
  cluster ? "#{sql} ON CLUSTER #{cluster}" : sql
333
387
  end
@@ -366,18 +420,33 @@ module ActiveRecord
366
420
  @connection.read_timeout = @connection_parameters[:read_timeout] if @connection_parameters[:read_timeout]
367
421
  @connection.write_timeout = @connection_parameters[:write_timeout] if @connection_parameters[:write_timeout]
368
422
 
423
+ # Use clickhouse default keep_alive_timeout value of 10, rather than Net::HTTP's default of 2
424
+ @connection.keep_alive_timeout = @connection_parameters[:keep_alive_timeout] || 10
425
+
369
426
  @connection
370
427
  end
371
428
 
372
429
  def apply_replica(table, options)
373
- if replica && cluster && options[:options]
374
- match = options[:options].match(/^(.*?MergeTree)(?:\(([^\)]*)\))?(.*?)$/)
375
- if match
376
- options[:options] = "Replicated#{match[1]}(#{([replica_path(table), replica].map{|v| "'#{v}'"} + [match[2].presence]).compact.join(', ')})#{match[3]}"
430
+ if use_replica? && options[:options]
431
+ if options[:options].match(/^Replicated/)
432
+ raise 'Do not try create Replicated table. It will be configured based on the *MergeTree engine.'
377
433
  end
434
+
435
+ options[:options] = configure_replica(table, options[:options])
378
436
  end
379
437
  options
380
438
  end
439
+
440
+ def configure_replica(table, options)
441
+ match = options.match(/^(.*?MergeTree)(?:\(([^\)]*)\))?((?:.|\n)*)/)
442
+ return options unless match
443
+
444
+ if replica
445
+ engine_params = ([replica_path(table), replica].map { |v| "'#{v}'" } + [match[2].presence]).compact.join(', ')
446
+ end
447
+
448
+ "Replicated#{match[1]}(#{engine_params})#{match[3]}"
449
+ end
381
450
  end
382
451
  end
383
452
  end
@@ -6,14 +6,24 @@ module ClickhouseActiverecord
6
6
  class << self
7
7
 
8
8
  def create_table
9
- unless table_exists?
10
- version_options = connection.internal_string_options_for_primary_key
11
-
12
- connection.create_table(table_name, id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version ORDER BY (version)', if_not_exists: true) do |t|
13
- t.string :version, **version_options
14
- t.column :active, 'Int8', null: false, default: '1'
15
- t.datetime :ver, null: false, default: -> { 'now()' }
16
- end
9
+ return if table_exists?
10
+
11
+ version_options = connection.internal_string_options_for_primary_key
12
+ table_options = {
13
+ id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version ORDER BY (version)', if_not_exists: true
14
+ }
15
+ full_config = connection.instance_variable_get(:@full_config) || {}
16
+
17
+ if full_config[:distributed_service_tables]
18
+ table_options.merge!(with_distributed: table_name, sharding_key: 'cityHash64(version)')
19
+
20
+ distributed_suffix = "_#{full_config[:distributed_service_tables_suffix] || 'distributed'}"
21
+ end
22
+
23
+ connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
24
+ t.string :version, **version_options
25
+ t.column :active, 'Int8', null: false, default: '1'
26
+ t.datetime :ver, null: false, default: -> { 'now()' }
17
27
  end
18
28
  end
19
29
 
@@ -26,14 +36,26 @@ module ClickhouseActiverecord
26
36
  class InternalMetadata < ::ActiveRecord::InternalMetadata
27
37
  class << self
28
38
  def create_table
29
- unless table_exists?
30
- key_options = connection.internal_string_options_for_primary_key
31
-
32
- connection.create_table(table_name, id: false, options: connection.adapter_name.downcase == 'clickhouse' ? 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)' : '', if_not_exists: true) do |t|
33
- t.string :key, key_options
34
- t.string :value
35
- t.timestamps
36
- end
39
+ return if table_exists?
40
+
41
+ key_options = connection.internal_string_options_for_primary_key
42
+ table_options = {
43
+ id: false,
44
+ options: connection.adapter_name.downcase == 'clickhouse' ? 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)' : '',
45
+ if_not_exists: true
46
+ }
47
+ full_config = connection.instance_variable_get(:@full_config) || {}
48
+
49
+ if full_config[:distributed_service_tables]
50
+ table_options.merge!(with_distributed: table_name, sharding_key: 'cityHash64(created_at)')
51
+
52
+ distributed_suffix = "_#{full_config[:distributed_service_tables_suffix] || 'distributed'}"
53
+ end
54
+
55
+ connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
56
+ t.string :key, **key_options
57
+ t.string :value
58
+ t.timestamps
37
59
  end
38
60
  end
39
61
  end
@@ -47,6 +69,16 @@ module ClickhouseActiverecord
47
69
  @schema_migration = schema_migration
48
70
  end
49
71
 
72
+ def up(target_version = nil)
73
+ selected_migrations = if block_given?
74
+ migrations.select { |m| yield m }
75
+ else
76
+ migrations
77
+ end
78
+
79
+ ClickhouseActiverecord::Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
80
+ end
81
+
50
82
  def down(target_version = nil)
51
83
  selected_migrations = if block_given?
52
84
  migrations.select { |m| yield m }
@@ -14,7 +14,7 @@ module ClickhouseActiverecord
14
14
  connection.create_database @configuration["database"]
15
15
  rescue ActiveRecord::StatementInvalid => e
16
16
  if e.cause.to_s.include?('already exists')
17
- raise ActiveRecord::Tasks::DatabaseAlreadyExists
17
+ raise ActiveRecord::DatabaseAlreadyExists
18
18
  else
19
19
  raise
20
20
  end
@@ -43,7 +43,15 @@ module ClickhouseActiverecord
43
43
  end
44
44
 
45
45
  def structure_load(*args)
46
- File.read(args.first).split(";\n\n").each { |sql| connection.execute(sql) }
46
+ File.read(args.first).split(";\n\n").each do |sql|
47
+ if sql.gsub(/[a-z]/i, '').blank?
48
+ next
49
+ elsif sql =~ /^INSERT INTO/
50
+ connection.do_execute(sql, nil, format: nil)
51
+ else
52
+ connection.execute(sql)
53
+ end
54
+ end
47
55
  end
48
56
 
49
57
  def migrate
@@ -1,3 +1,3 @@
1
1
  module ClickhouseActiverecord
2
- VERSION = '0.5.3'
2
+ VERSION = '0.5.10'
3
3
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'active_record/connection_adapters/clickhouse_adapter'
4
4
 
5
+ require_relative '../core_extensions/active_record/migration/command_recorder'
6
+ ActiveRecord::Migration::CommandRecorder.include CoreExtensions::ActiveRecord::Migration::CommandRecorder
7
+
5
8
  if defined?(Rails::Railtie)
6
9
  require 'clickhouse-activerecord/railtie'
7
10
  require 'clickhouse-activerecord/schema'
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.5.3
4
+ version: 0.5.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Odintsov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-22 00:00:00.000000000 Z
11
+ date: 2022-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.15'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.15'
55
55
  - !ruby/object:Gem::Dependency
@@ -112,6 +112,7 @@ files:
112
112
  - bin/console
113
113
  - bin/setup
114
114
  - clickhouse-activerecord.gemspec
115
+ - core_extensions/active_record/migration/command_recorder.rb
115
116
  - lib/active_record/connection_adapters/clickhouse/oid/array.rb
116
117
  - lib/active_record/connection_adapters/clickhouse/oid/big_integer.rb
117
118
  - lib/active_record/connection_adapters/clickhouse/oid/date.rb