clickhouse-activerecord 0.5.7 → 0.5.15

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: 79b43575e5eef93daa11e1a2aca2984f696cbef59021f55d1470b2dc0a5d1e3d
4
- data.tar.gz: b79cccb85d8a07fa4dc533d7b7e9042eeaa2afead26214c075b3131e1843394b
3
+ metadata.gz: 6534694860bbb41c21789239e0589406bcbef64bc1750645c68485e77acb7310
4
+ data.tar.gz: c6640ccc74004a93bfaa18d93dd1c135411d66f27273eb65848f9843f64fd6d0
5
5
  SHA512:
6
- metadata.gz: 840b01cc1d5b88eee5e031fada23cfd35f7a8d948a35a767b2f5baf1596af665f28c56778e699960511004367b16ee3130be1f5bd2ee713a9a0d5053a9b58a37
7
- data.tar.gz: 4e613a19c51b362a05634da06d9528809ed09f01ebec4eac9984656156e9b877bdc4ce321e24bea63ae4e49d85609fa9dda781db60159e60b6d6ee06e8a99a3e
6
+ metadata.gz: f848ad57f80f061aa85a593a90bff65707e8dbe281caf3f4a41914d93a4723351bf7e5ca12bfdc7c8ed2cbed5df3db39472b8d015645875476b68941d7de6111
7
+ data.tar.gz: 1592560741198e983d43599ff78b145262e0638951a2825dcaac993e0dcc0195bf85980b5eeff80d973e0573aeaa865d6d6c8acdd7ee2b2b1ba6bb6740e734cf
data/CHANGELOG.md CHANGED
@@ -1,10 +1,16 @@
1
+ ### Version 0.5.10 (Jun 22, 2022)
2
+
3
+ * Fixes to create_table method (#70)
4
+ * Added support for rails 7 (#65)
5
+ * Use ClickHouse default KeepAlive timeout of 10 seconds (#67)
6
+
1
7
  ### Version 0.5.6 (Oct 25, 2021)
2
-
8
+
3
9
  * Added auto creating service distributed tables and additional options for creating view [@ygreeek](https://github.com/ygreeek)
4
10
  * Added default user agent
5
11
 
6
12
  ### Version 0.5.3 (Sep 22, 2021)
7
-
13
+
8
14
  * Fix replica cluster for a new syntax MergeTree
9
15
  * Fix support rails 5.2 on alter table
10
16
  * Support array type of column
@@ -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'
@@ -2,21 +2,12 @@ module CoreExtensions
2
2
  module ActiveRecord
3
3
  module Migration
4
4
  module CommandRecorder
5
- def create_table_with_distributed(*args, &block)
6
- record(:create_table_with_distributed, args, &block)
7
- end
8
-
9
5
  def create_view(*args, &block)
10
6
  record(:create_view, args, &block)
11
7
  end
12
8
 
13
9
  private
14
10
 
15
- def invert_create_table_with_distributed(args)
16
- table_name, options = args
17
- [:drop_table_with_distributed, table_name, options]
18
- end
19
-
20
11
  def invert_create_view(args)
21
12
  view_name, options = args
22
13
  [:drop_table, view_name, options]
@@ -23,6 +23,42 @@ module ActiveRecord
23
23
  @subtype
24
24
  end
25
25
 
26
+ def deserialize(value)
27
+ if value.is_a?(::Array)
28
+ value.map { |item| deserialize(item) }
29
+ else
30
+ return value if value.nil?
31
+ case @subtype
32
+ when :integer
33
+ value.to_i
34
+ when :datetime
35
+ ::DateTime.parse(value)
36
+ when :date
37
+ ::Date.parse(value)
38
+ else
39
+ super
40
+ end
41
+ end
42
+ end
43
+
44
+ def serialize(value)
45
+ if value.is_a?(::Array)
46
+ value.map { |item| serialize(item) }
47
+ else
48
+ return value if value.nil?
49
+ case @subtype
50
+ when :integer
51
+ value.to_i
52
+ when :datetime
53
+ DateTime.new.serialize(value)
54
+ when :date
55
+ Date.new.serialize(value)
56
+ else
57
+ super
58
+ end
59
+ end
60
+ end
61
+
26
62
  end
27
63
  end
28
64
  end
@@ -9,9 +9,8 @@ module ActiveRecord
9
9
  def serialize(value)
10
10
  value = super
11
11
  return unless value
12
- return value.strftime('%Y-%m-%d %H:%M:%S') unless value.acts_like?(:time)
13
12
 
14
- value.to_time.strftime('%Y-%m-%d %H:%M:%S')
13
+ value.strftime('%Y-%m-%d %H:%M:%S' + (@precision.present? && @precision > 0 ? ".%#{@precision}N" : ''))
15
14
  end
16
15
 
17
16
  def type_cast_from_database(value)
@@ -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
@@ -73,7 +82,7 @@ module ActiveRecord
73
82
  return unless match
74
83
  return if match[:database]
75
84
 
76
- create_sql << "TO #{current_database}.#{options.to.sub('.', '')} "
85
+ create_sql << "TO #{current_database}.#{match[:table_name].sub('.', '')}"
77
86
  end
78
87
 
79
88
  def visit_TableDefinition(o)
@@ -116,7 +125,11 @@ module ActiveRecord
116
125
  end
117
126
 
118
127
  def current_database
119
- ActiveRecord::Base.connection_db_config.database
128
+ if ActiveRecord::version >= Gem::Version.new('6')
129
+ ActiveRecord::Base.connection_db_config.database
130
+ else
131
+ ActiveRecord::Base.connection_config[:database]
132
+ end
120
133
  end
121
134
  end
122
135
  end
@@ -62,6 +62,38 @@ module ActiveRecord
62
62
  end
63
63
  args.each { |name| column(name, kind, **options.except(:limit, :unsigned)) }
64
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)) }
96
+ end
65
97
  end
66
98
  end
67
99
  end
@@ -6,8 +6,8 @@ module ActiveRecord
6
6
  module ConnectionAdapters
7
7
  module Clickhouse
8
8
  module SchemaStatements
9
- def execute(sql, name = nil)
10
- do_execute(sql, name)
9
+ def execute(sql, name = nil, settings: {})
10
+ do_execute(sql, name, settings: settings)
11
11
  end
12
12
 
13
13
  def exec_insert(sql, name, _binds, _pk = nil, _sequence_name = nil)
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
  end
40
40
 
41
41
  def tables(name = nil)
42
- result = do_system_execute('SHOW TABLES', name)
42
+ result = do_system_execute("SHOW TABLES WHERE name NOT LIKE '.inner_id.%'", name)
43
43
  return [] if result.nil?
44
44
  result['data'].flatten
45
45
  end
@@ -92,7 +92,7 @@ module ActiveRecord
92
92
  if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
93
93
  raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
94
94
  end
95
- execute insert_versions_sql(inserting)
95
+ do_execute(insert_versions_sql(inserting), nil, settings: {max_partitions_per_insert_block: [100, inserting.size].max})
96
96
  end
97
97
  end
98
98
 
@@ -11,6 +11,7 @@ require 'active_record/connection_adapters/clickhouse/schema_definitions'
11
11
  require 'active_record/connection_adapters/clickhouse/schema_creation'
12
12
  require 'active_record/connection_adapters/clickhouse/schema_statements'
13
13
  require 'net/http'
14
+ require 'openssl'
14
15
 
15
16
  module ActiveRecord
16
17
  class Base
@@ -32,6 +33,7 @@ module ActiveRecord
32
33
  sslca: config[:sslca],
33
34
  read_timeout: config[:read_timeout],
34
35
  write_timeout: config[:write_timeout],
36
+ keep_alive_timeout: config[:keep_alive_timeout]
35
37
  }
36
38
  end
37
39
 
@@ -46,21 +48,6 @@ module ActiveRecord
46
48
  end
47
49
  end
48
50
 
49
- class Relation
50
-
51
- # Replace for only ClickhouseAdapter
52
- 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
60
- self
61
- end
62
- end
63
-
64
51
  module TypeCaster
65
52
  class Map
66
53
  def is_view
@@ -74,7 +61,7 @@ module ActiveRecord
74
61
  end
75
62
 
76
63
  module ModelSchema
77
- module ClassMethods
64
+ module ClassMethods
78
65
  def is_view
79
66
  @is_view || false
80
67
  end
@@ -86,9 +73,8 @@ module ActiveRecord
86
73
  def arel_table # :nodoc:
87
74
  @arel_table ||= ClickhouseActiverecord::Arel::Table.new(table_name, type_caster: type_caster)
88
75
  end
89
-
90
76
  end
91
- end
77
+ end
92
78
 
93
79
  module ConnectionAdapters
94
80
  class ClickhouseColumn < Column
@@ -104,8 +90,13 @@ module ActiveRecord
104
90
  float: { name: 'Float32' },
105
91
  decimal: { name: 'Decimal' },
106
92
  datetime: { name: 'DateTime' },
93
+ datetime64: { name: 'DateTime64' },
107
94
  date: { name: 'Date' },
108
95
  boolean: { name: 'UInt8' },
96
+ uuid: { name: 'UUID' },
97
+
98
+ enum8: { name: 'Enum8' },
99
+ enum16: { name: 'Enum16' },
109
100
 
110
101
  int8: { name: 'Int8' },
111
102
  int16: { name: 'Int16' },
@@ -182,11 +173,25 @@ module ActiveRecord
182
173
  end
183
174
  end
184
175
 
176
+ # `extract_scale` and `extract_precision` are the same as in the Rails abstract base class,
177
+ # except this permits a space after the comma
178
+
179
+ def extract_scale(sql_type)
180
+ case sql_type
181
+ when /\((\d+)\)/ then 0
182
+ when /\((\d+)(,\s?(\d+))\)/ then $3.to_i
183
+ end
184
+ end
185
+
186
+ def extract_precision(sql_type)
187
+ $1.to_i if sql_type =~ /\((\d+)(,\s?\d+)?\)/
188
+ end
189
+
185
190
  def initialize_type_map(m) # :nodoc:
186
191
  super
187
192
  register_class_with_limit m, %r(String), Type::String
188
193
  register_class_with_limit m, 'Date', Clickhouse::OID::Date
189
- register_class_with_limit m, 'DateTime', Clickhouse::OID::DateTime
194
+ register_class_with_precision m, %r(datetime)i, Clickhouse::OID::DateTime
190
195
 
191
196
  register_class_with_limit m, %r(Int8), Type::Integer
192
197
  register_class_with_limit m, %r(Int16), Type::Integer
@@ -207,17 +212,34 @@ module ActiveRecord
207
212
  end
208
213
  end
209
214
 
215
+ def _quote(value)
216
+ case value
217
+ when Array
218
+ '[' + value.map { |v| _quote(v) }.join(', ') + ']'
219
+ else
220
+ super
221
+ end
222
+ end
223
+
210
224
  # Quoting time without microseconds
211
225
  def quoted_date(value)
212
226
  if value.acts_like?(:time)
213
- zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
227
+ if ActiveRecord::version >= Gem::Version.new('7')
228
+ zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal
229
+ else
230
+ zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
231
+ end
214
232
 
215
233
  if value.respond_to?(zone_conversion_method)
216
234
  value = value.send(zone_conversion_method)
217
235
  end
218
236
  end
219
237
 
220
- value.to_s(:db)
238
+ if ActiveRecord::version >= Gem::Version.new('7')
239
+ value.to_fs(:db)
240
+ else
241
+ value.to_s(:db)
242
+ end
221
243
  end
222
244
 
223
245
  def column_name_for_operation(operation, node) # :nodoc:
@@ -269,32 +291,30 @@ module ActiveRecord
269
291
  drop_table(table_name, options.merge(if_exists: true))
270
292
  end
271
293
 
272
- execute schema_creation.accept td
294
+ do_execute(schema_creation.accept(td), format: nil)
273
295
  end
274
296
 
275
297
  def create_table(table_name, **options, &block)
276
298
  options = apply_replica(table_name, options)
277
299
  td = create_table_definition(apply_cluster(table_name), **options)
278
300
  block.call td if block_given?
301
+ td.column(:id, options[:id], null: false) if options[:id].present? && td[:id].blank?
279
302
 
280
303
  if options[:force]
281
304
  drop_table(table_name, options.merge(if_exists: true))
282
305
  end
283
306
 
284
- execute schema_creation.accept td
285
- end
286
-
287
- def create_table_with_distributed(table_name, **options, &block)
288
- sharding_key = options.delete(:sharding_key) || 'rand()'
289
- create_table("#{table_name}_distributed", **options, &block)
290
- raise 'Set a cluster' unless cluster
307
+ do_execute(schema_creation.accept(td), format: nil)
291
308
 
292
- distributed_options = "Distributed(#{cluster},#{@config[:database]},#{table_name}_distributed,#{sharding_key})"
293
- create_table(table_name, **options.merge(options: distributed_options), &block)
294
- end
309
+ if options[:with_distributed]
310
+ distributed_table_name = options.delete(:with_distributed)
311
+ sharding_key = options.delete(:sharding_key) || 'rand()'
312
+ raise 'Set a cluster' unless cluster
295
313
 
296
- def drop_table_with_distributed(table_name, **options)
297
- ["#{table_name}_distributed", table_name].each { |name| drop_table(name, **options) }
314
+ distributed_options =
315
+ "Distributed(#{cluster}, #{@config[:database]}, #{table_name}, #{sharding_key})"
316
+ create_table(distributed_table_name, **options.merge(options: distributed_options), &block)
317
+ end
298
318
  end
299
319
 
300
320
  # Drops a ClickHouse database.
@@ -312,10 +332,29 @@ module ActiveRecord
312
332
 
313
333
  def drop_table(table_name, options = {}) # :nodoc:
314
334
  do_execute apply_cluster "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
335
+
336
+ if options[:with_distributed]
337
+ distributed_table_name = options.delete(:with_distributed)
338
+ drop_table(distributed_table_name, **options)
339
+ end
340
+ end
341
+
342
+ def add_column(table_name, column_name, type, **options)
343
+ return if options[:if_not_exists] == true && column_exists?(table_name, column_name, type)
344
+
345
+ at = create_alter_table table_name
346
+ at.add_column(column_name, type, **options)
347
+ execute(schema_creation.accept(at), nil, settings: {wait_end_of_query: 1, send_progress_in_http_headers: 1})
348
+ end
349
+
350
+ def remove_column(table_name, column_name, type = nil, **options)
351
+ return if options[:if_exists] == true && !column_exists?(table_name, column_name)
352
+
353
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{remove_column_for_alter(table_name, column_name, type, **options)}", nil, settings: {wait_end_of_query: 1, send_progress_in_http_headers: 1})
315
354
  end
316
355
 
317
356
  def change_column(table_name, column_name, type, options = {})
318
- result = do_execute "ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}"
357
+ result = do_execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_for_alter(table_name, column_name, type, options)}", nil, settings: {wait_end_of_query: 1, send_progress_in_http_headers: 1})
319
358
  raise "Error parse json response: #{result}" if result.presence && !result.is_a?(Hash)
320
359
  end
321
360
 
@@ -351,12 +390,18 @@ module ActiveRecord
351
390
 
352
391
  def database_engine_atomic?
353
392
  current_database_engine = "select engine from system.databases where name = '#{@config[:database]}'"
354
- res = ActiveRecord::Base.connection.select_one(current_database_engine)
393
+ res = select_one(current_database_engine)
355
394
  res['engine'] == 'Atomic' if res
356
395
  end
357
396
 
358
397
  def apply_cluster(sql)
359
- cluster ? "#{sql} ON CLUSTER #{cluster}" : sql
398
+ if cluster
399
+ normalized_cluster_name = cluster.start_with?('{') ? "'#{cluster}'" : cluster
400
+
401
+ "#{sql} ON CLUSTER #{normalized_cluster_name}"
402
+ else
403
+ sql
404
+ end
360
405
  end
361
406
 
362
407
  def supports_insert_on_duplicate_skip?
@@ -393,6 +438,9 @@ module ActiveRecord
393
438
  @connection.read_timeout = @connection_parameters[:read_timeout] if @connection_parameters[:read_timeout]
394
439
  @connection.write_timeout = @connection_parameters[:write_timeout] if @connection_parameters[:write_timeout]
395
440
 
441
+ # Use clickhouse default keep_alive_timeout value of 10, rather than Net::HTTP's default of 2
442
+ @connection.keep_alive_timeout = @connection_parameters[:keep_alive_timeout] || 10
443
+
396
444
  @connection
397
445
  end
398
446
 
@@ -10,16 +10,17 @@ module ClickhouseActiverecord
10
10
 
11
11
  version_options = connection.internal_string_options_for_primary_key
12
12
  table_options = {
13
- id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version ORDER BY (version)', if_not_exists: true
13
+ id: false, options: 'ReplacingMergeTree(ver) ORDER BY (version)', if_not_exists: true
14
14
  }
15
- if connection.instance_variable_get(:@full_config)[:distributed_service_tables]
16
- table_options.merge!(sharding_key: 'cityHash64(version)')
17
- table_creation_method = 'create_table_with_distributed'
18
- else
19
- table_creation_method = 'create_table'
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'}"
20
21
  end
21
22
 
22
- connection.public_send(table_creation_method, table_name, **table_options) do |t|
23
+ connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
23
24
  t.string :version, **version_options
24
25
  t.column :active, 'Int8', null: false, default: '1'
25
26
  t.datetime :ver, null: false, default: -> { 'now()' }
@@ -43,14 +44,15 @@ module ClickhouseActiverecord
43
44
  options: connection.adapter_name.downcase == 'clickhouse' ? 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)' : '',
44
45
  if_not_exists: true
45
46
  }
46
- if connection.instance_variable_get(:@full_config).try(:[], :distributed_service_tables)
47
- table_options.merge!(sharding_key: 'cityHash64(created_at)')
48
- table_creation_method = 'create_table_with_distributed'
49
- else
50
- table_creation_method = 'create_table'
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'}"
51
53
  end
52
54
 
53
- connection.public_send(table_creation_method, table_name, **table_options) do |t|
55
+ connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
54
56
  t.string :key, **key_options
55
57
  t.string :value
56
58
  t.timestamps
@@ -4,6 +4,12 @@ module ClickhouseActiverecord
4
4
  require 'rails'
5
5
 
6
6
  class Railtie < Rails::Railtie
7
+ initializer "clickhouse.load" do
8
+ ActiveSupport.on_load :active_record do
9
+ ClickhouseActiverecord.load
10
+ end
11
+ end
12
+
7
13
  rake_tasks { load 'tasks/clickhouse.rake' }
8
14
  end
9
15
  end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module ClickhouseActiverecord
2
- VERSION = '0.5.7'
2
+ VERSION = '0.5.15'
3
3
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'active_record/connection_adapters/clickhouse_adapter'
4
4
 
5
+ require 'core_extensions/active_record/relation'
6
+
5
7
  require_relative '../core_extensions/active_record/migration/command_recorder'
6
8
  ActiveRecord::Migration::CommandRecorder.include CoreExtensions::ActiveRecord::Migration::CommandRecorder
7
9
 
@@ -14,5 +16,7 @@ if defined?(Rails::Railtie)
14
16
  end
15
17
 
16
18
  module ClickhouseActiverecord
17
-
19
+ def self.load
20
+ ActiveRecord::Relation.prepend(CoreExtensions::ActiveRecord::Relation)
21
+ end
18
22
  end
@@ -0,0 +1,15 @@
1
+ module CoreExtensions
2
+ module ActiveRecord
3
+ module Relation
4
+ def reverse_order!
5
+ return super unless connection.is_a?(::ActiveRecord::ConnectionAdapters::ClickhouseAdapter)
6
+
7
+ orders = order_values.uniq.reject(&:blank?)
8
+ return super unless orders.empty? && !primary_key
9
+
10
+ self.order_values = (column_names & %w[date created_at]).map { |c| arel_table[c].desc }
11
+ self
12
+ end
13
+ end
14
+ end
15
+ end
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.7
4
+ version: 0.5.15
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: 2021-10-25 00:00:00.000000000 Z
11
+ date: 2023-07-21 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
@@ -130,13 +130,14 @@ files:
130
130
  - lib/clickhouse-activerecord/schema_dumper.rb
131
131
  - lib/clickhouse-activerecord/tasks.rb
132
132
  - lib/clickhouse-activerecord/version.rb
133
+ - lib/core_extensions/active_record/relation.rb
133
134
  - lib/generators/clickhouse_migration_generator.rb
134
135
  - lib/tasks/clickhouse.rake
135
136
  homepage: https://github.com/pnixx/clickhouse-activerecord
136
137
  licenses:
137
138
  - MIT
138
139
  metadata: {}
139
- post_install_message:
140
+ post_install_message:
140
141
  rdoc_options: []
141
142
  require_paths:
142
143
  - lib
@@ -151,8 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
152
  - !ruby/object:Gem::Version
152
153
  version: '0'
153
154
  requirements: []
154
- rubygems_version: 3.0.3
155
- signing_key:
155
+ rubygems_version: 3.0.4
156
+ signing_key:
156
157
  specification_version: 4
157
158
  summary: ClickHouse ActiveRecord
158
159
  test_files: []