clickhouse-activerecord 0.5.3 → 0.5.10

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