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 +4 -4
- data/CHANGELOG.md +8 -2
- data/clickhouse-activerecord.gemspec +1 -1
- data/core_extensions/active_record/migration/command_recorder.rb +0 -9
- data/lib/active_record/connection_adapters/clickhouse/oid/array.rb +36 -0
- data/lib/active_record/connection_adapters/clickhouse/oid/date_time.rb +1 -2
- data/lib/active_record/connection_adapters/clickhouse/schema_creation.rb +15 -2
- data/lib/active_record/connection_adapters/clickhouse/schema_definitions.rb +32 -0
- data/lib/active_record/connection_adapters/clickhouse/schema_statements.rb +4 -4
- data/lib/active_record/connection_adapters/clickhouse_adapter.rb +85 -37
- data/lib/clickhouse-activerecord/migration.rb +15 -13
- data/lib/clickhouse-activerecord/railtie.rb +6 -0
- data/lib/clickhouse-activerecord/tasks.rb +1 -1
- data/lib/clickhouse-activerecord/version.rb +1 -1
- data/lib/clickhouse-activerecord.rb +5 -1
- data/lib/core_extensions/active_record/relation.rb +15 -0
- metadata +9 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6534694860bbb41c21789239e0589406bcbef64bc1750645c68485e77acb7310
|
4
|
+
data.tar.gz: c6640ccc74004a93bfaa18d93dd1c135411d66f27273eb65848f9843f64fd6d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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', '
|
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.
|
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}.#{
|
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::
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
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
|
-
|
297
|
-
|
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
|
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 =
|
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
|
-
|
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)
|
13
|
+
id: false, options: 'ReplacingMergeTree(ver) ORDER BY (version)', if_not_exists: true
|
14
14
|
}
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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.
|
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
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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.
|
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::
|
17
|
+
raise ActiveRecord::DatabaseAlreadyExists
|
18
18
|
else
|
19
19
|
raise
|
20
20
|
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.
|
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:
|
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.
|
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: []
|