clickhouse-activerecord 0.5.0 → 0.5.7
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 +12 -0
- data/README.md +1 -0
- data/core_extensions/active_record/migration/command_recorder.rb +27 -0
- data/lib/active_record/connection_adapters/clickhouse/oid/array.rb +30 -0
- data/lib/active_record/connection_adapters/clickhouse/schema_creation.rb +41 -4
- data/lib/active_record/connection_adapters/clickhouse/schema_definitions.rb +4 -2
- data/lib/active_record/connection_adapters/clickhouse/schema_statements.rb +10 -3
- data/lib/active_record/connection_adapters/clickhouse_adapter.rb +76 -9
- data/lib/clickhouse-activerecord/migration.rb +46 -16
- data/lib/clickhouse-activerecord/schema_dumper.rb +5 -0
- data/lib/clickhouse-activerecord/tasks.rb +9 -1
- data/lib/clickhouse-activerecord/version.rb +1 -1
- data/lib/clickhouse-activerecord.rb +3 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79b43575e5eef93daa11e1a2aca2984f696cbef59021f55d1470b2dc0a5d1e3d
|
4
|
+
data.tar.gz: b79cccb85d8a07fa4dc533d7b7e9042eeaa2afead26214c075b3131e1843394b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 840b01cc1d5b88eee5e031fada23cfd35f7a8d948a35a767b2f5baf1596af665f28c56778e699960511004367b16ee3130be1f5bd2ee713a9a0d5053a9b58a37
|
7
|
+
data.tar.gz: 4e613a19c51b362a05634da06d9528809ed09f01ebec4eac9984656156e9b877bdc4ce321e24bea63ae4e49d85609fa9dda781db60159e60b6d6ee06e8a99a3e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
### Version 0.5.6 (Oct 25, 2021)
|
2
|
+
|
3
|
+
* Added auto creating service distributed tables and additional options for creating view [@ygreeek](https://github.com/ygreeek)
|
4
|
+
* Added default user agent
|
5
|
+
|
6
|
+
### Version 0.5.3 (Sep 22, 2021)
|
7
|
+
|
8
|
+
* Fix replica cluster for a new syntax MergeTree
|
9
|
+
* Fix support rails 5.2 on alter table
|
10
|
+
* Support array type of column
|
11
|
+
* Support Rails 6.1.0 [@bdevel](https://github.com/bdevel)
|
12
|
+
|
1
13
|
### Version 0.4.10 (Mar 10, 2021)
|
2
14
|
|
3
15
|
* Support ClickHouse 20.9+
|
data/README.md
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
module CoreExtensions
|
2
|
+
module ActiveRecord
|
3
|
+
module Migration
|
4
|
+
module CommandRecorder
|
5
|
+
def create_table_with_distributed(*args, &block)
|
6
|
+
record(:create_table_with_distributed, args, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_view(*args, &block)
|
10
|
+
record(:create_view, args, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
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
|
+
def invert_create_view(args)
|
21
|
+
view_name, options = args
|
22
|
+
[:drop_table, view_name, options]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module Clickhouse
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Array < Type::Value # :nodoc:
|
8
|
+
|
9
|
+
def initialize(sql_type)
|
10
|
+
@subtype = case sql_type
|
11
|
+
when /U?Int\d+/
|
12
|
+
:integer
|
13
|
+
when /DateTime/
|
14
|
+
:datetime
|
15
|
+
when /Date/
|
16
|
+
:date
|
17
|
+
else
|
18
|
+
:string
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
@subtype
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -22,6 +22,9 @@ module ActiveRecord
|
|
22
22
|
if options[:null] || options[:null].nil?
|
23
23
|
sql.gsub!(/\s+(.*)/, ' Nullable(\1)')
|
24
24
|
end
|
25
|
+
if options[:array]
|
26
|
+
sql.gsub!(/\s+(.*)/, ' Array(\1)')
|
27
|
+
end
|
25
28
|
sql.gsub!(/(\sString)\(\d+\)/, '\1')
|
26
29
|
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
27
30
|
sql
|
@@ -33,7 +36,7 @@ module ActiveRecord
|
|
33
36
|
# rails 6.1
|
34
37
|
opts ||= options.options
|
35
38
|
end
|
36
|
-
|
39
|
+
|
37
40
|
if opts.present?
|
38
41
|
create_sql << " ENGINE = #{opts}"
|
39
42
|
else
|
@@ -43,17 +46,48 @@ module ActiveRecord
|
|
43
46
|
create_sql
|
44
47
|
end
|
45
48
|
|
49
|
+
def add_as_clause!(create_sql, options)
|
50
|
+
return unless options.as
|
51
|
+
|
52
|
+
assign_database_to_subquery!(options.as) if options.view
|
53
|
+
create_sql << " AS #{to_sql(options.as)}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def assign_database_to_subquery!(subquery)
|
57
|
+
# If you do not specify a database explicitly, ClickHouse will use the "default" database.
|
58
|
+
return unless subquery
|
59
|
+
|
60
|
+
match = subquery.match(/(?<=from)[^.\w]+(?<database>\w+(?=\.))?(?<table_name>[.\w]+)/i)
|
61
|
+
return unless match
|
62
|
+
return if match[:database]
|
63
|
+
|
64
|
+
subquery[match.begin(:table_name)...match.end(:table_name)] =
|
65
|
+
"#{current_database}.#{match[:table_name].sub('.', '')}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_to_clause!(create_sql, options)
|
69
|
+
# If you do not specify a database explicitly, ClickHouse will use the "default" database.
|
70
|
+
return unless options.to
|
71
|
+
|
72
|
+
match = options.to.match(/(?<database>.+(?=\.))?(?<table_name>.+)/i)
|
73
|
+
return unless match
|
74
|
+
return if match[:database]
|
75
|
+
|
76
|
+
create_sql << "TO #{current_database}.#{options.to.sub('.', '')} "
|
77
|
+
end
|
78
|
+
|
46
79
|
def visit_TableDefinition(o)
|
47
80
|
create_sql = +"CREATE#{table_modifier_in_create(o)} #{o.view ? "VIEW" : "TABLE"} "
|
48
81
|
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
49
82
|
create_sql << "#{quote_table_name(o.name)} "
|
83
|
+
add_to_clause!(create_sql, o) if o.materialized
|
50
84
|
|
51
85
|
statements = o.columns.map { |c| accept c }
|
52
86
|
statements << accept(o.primary_keys) if o.primary_keys
|
53
87
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
54
|
-
# Attach options for only table or materialized view
|
55
|
-
add_table_options!(create_sql, o)
|
56
|
-
create_sql
|
88
|
+
# Attach options for only table or materialized view without TO section
|
89
|
+
add_table_options!(create_sql, o) if !o.view || o.view && o.materialized && !o.to
|
90
|
+
add_as_clause!(create_sql, o)
|
57
91
|
create_sql
|
58
92
|
end
|
59
93
|
|
@@ -81,6 +115,9 @@ module ActiveRecord
|
|
81
115
|
change_column_sql
|
82
116
|
end
|
83
117
|
|
118
|
+
def current_database
|
119
|
+
ActiveRecord::Base.connection_db_config.database
|
120
|
+
end
|
84
121
|
end
|
85
122
|
end
|
86
123
|
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,7 @@ 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)) }
|
62
64
|
end
|
63
65
|
end
|
64
66
|
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
|
@@ -23,6 +25,11 @@ module ActiveRecord
|
|
23
25
|
raise ActiveRecord::ActiveRecordError, "Response: #{e.message}"
|
24
26
|
end
|
25
27
|
|
28
|
+
def exec_insert_all(sql, name)
|
29
|
+
do_execute(sql, name, format: nil)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
26
33
|
def exec_update(_sql, _name = nil, _binds = [])
|
27
34
|
raise ActiveRecord::ActiveRecordError, 'Clickhouse update is not supported'
|
28
35
|
end
|
@@ -53,7 +60,7 @@ module ActiveRecord
|
|
53
60
|
|
54
61
|
def do_system_execute(sql, name = nil)
|
55
62
|
log_with_debug(sql, "#{adapter_name} #{name}") do
|
56
|
-
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}")
|
57
64
|
|
58
65
|
process_response(res)
|
59
66
|
end
|
@@ -63,7 +70,7 @@ module ActiveRecord
|
|
63
70
|
log(sql, "#{adapter_name} #{name}") do
|
64
71
|
formatted_sql = apply_format(sql, format)
|
65
72
|
request_params = @config || {}
|
66
|
-
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}")
|
67
74
|
|
68
75
|
process_response(res)
|
69
76
|
end
|
@@ -116,7 +123,7 @@ module ActiveRecord
|
|
116
123
|
Clickhouse::SchemaCreation.new(self)
|
117
124
|
end
|
118
125
|
|
119
|
-
def create_table_definition(table_name, options)
|
126
|
+
def create_table_definition(table_name, **options)
|
120
127
|
Clickhouse::TableDefinition.new(self, table_name, **options)
|
121
128
|
end
|
122
129
|
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'clickhouse-activerecord/arel/visitors/to_sql'
|
4
4
|
require 'clickhouse-activerecord/arel/table'
|
5
5
|
require 'clickhouse-activerecord/migration'
|
6
|
+
require 'active_record/connection_adapters/clickhouse/oid/array'
|
6
7
|
require 'active_record/connection_adapters/clickhouse/oid/date'
|
7
8
|
require 'active_record/connection_adapters/clickhouse/oid/date_time'
|
8
9
|
require 'active_record/connection_adapters/clickhouse/oid/big_integer'
|
@@ -17,6 +18,7 @@ module ActiveRecord
|
|
17
18
|
# Establishes a connection to the database that's used by all Active Record objects
|
18
19
|
def clickhouse_connection(config)
|
19
20
|
config = config.symbolize_keys
|
21
|
+
|
20
22
|
if config[:connection]
|
21
23
|
connection = {
|
22
24
|
connection: config[:connection]
|
@@ -27,6 +29,9 @@ module ActiveRecord
|
|
27
29
|
host: config[:host] || 'localhost',
|
28
30
|
port: port,
|
29
31
|
ssl: config[:ssl].present? ? config[:ssl] : port == 443,
|
32
|
+
sslca: config[:sslca],
|
33
|
+
read_timeout: config[:read_timeout],
|
34
|
+
write_timeout: config[:write_timeout],
|
30
35
|
}
|
31
36
|
end
|
32
37
|
|
@@ -190,12 +195,16 @@ module ActiveRecord
|
|
190
195
|
register_class_with_limit m, %r(Int128), Type::Integer
|
191
196
|
register_class_with_limit m, %r(Int256), Type::Integer
|
192
197
|
|
193
|
-
register_class_with_limit m, %r(
|
198
|
+
register_class_with_limit m, %r(UInt8), Type::UnsignedInteger
|
194
199
|
register_class_with_limit m, %r(UInt16), Type::UnsignedInteger
|
195
200
|
register_class_with_limit m, %r(UInt32), Type::UnsignedInteger
|
196
201
|
register_class_with_limit m, %r(UInt64), Type::UnsignedInteger
|
197
202
|
#register_class_with_limit m, %r(UInt128), Type::UnsignedInteger #not implemnted in clickhouse
|
198
203
|
register_class_with_limit m, %r(UInt256), Type::UnsignedInteger
|
204
|
+
# register_class_with_limit m, %r(Array), Clickhouse::OID::Array
|
205
|
+
m.register_type(%r(Array)) do |sql_type|
|
206
|
+
Clickhouse::OID::Array.new(sql_type)
|
207
|
+
end
|
199
208
|
end
|
200
209
|
|
201
210
|
# Quoting time without microseconds
|
@@ -253,7 +262,7 @@ module ActiveRecord
|
|
253
262
|
def create_view(table_name, **options)
|
254
263
|
options.merge!(view: true)
|
255
264
|
options = apply_replica(table_name, options)
|
256
|
-
td = create_table_definition(apply_cluster(table_name), options)
|
265
|
+
td = create_table_definition(apply_cluster(table_name), **options)
|
257
266
|
yield td if block_given?
|
258
267
|
|
259
268
|
if options[:force]
|
@@ -263,10 +272,10 @@ module ActiveRecord
|
|
263
272
|
execute schema_creation.accept td
|
264
273
|
end
|
265
274
|
|
266
|
-
def create_table(table_name, **options)
|
275
|
+
def create_table(table_name, **options, &block)
|
267
276
|
options = apply_replica(table_name, options)
|
268
|
-
td = create_table_definition(apply_cluster(table_name), options)
|
269
|
-
|
277
|
+
td = create_table_definition(apply_cluster(table_name), **options)
|
278
|
+
block.call td if block_given?
|
270
279
|
|
271
280
|
if options[:force]
|
272
281
|
drop_table(table_name, options.merge(if_exists: true))
|
@@ -275,6 +284,19 @@ module ActiveRecord
|
|
275
284
|
execute schema_creation.accept td
|
276
285
|
end
|
277
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
|
291
|
+
|
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
|
295
|
+
|
296
|
+
def drop_table_with_distributed(table_name, **options)
|
297
|
+
["#{table_name}_distributed", table_name].each { |name| drop_table(name, **options) }
|
298
|
+
end
|
299
|
+
|
278
300
|
# Drops a ClickHouse database.
|
279
301
|
def drop_database(name) #:nodoc:
|
280
302
|
sql = apply_cluster "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
@@ -315,14 +337,41 @@ module ActiveRecord
|
|
315
337
|
@full_config[:replica_name]
|
316
338
|
end
|
317
339
|
|
340
|
+
def use_default_replicated_merge_tree_params?
|
341
|
+
database_engine_atomic? && @full_config[:use_default_replicated_merge_tree_params]
|
342
|
+
end
|
343
|
+
|
344
|
+
def use_replica?
|
345
|
+
(replica || use_default_replicated_merge_tree_params?) && cluster
|
346
|
+
end
|
347
|
+
|
318
348
|
def replica_path(table)
|
319
349
|
"/clickhouse/tables/#{cluster}/#{@config[:database]}.#{table}"
|
320
350
|
end
|
321
351
|
|
352
|
+
def database_engine_atomic?
|
353
|
+
current_database_engine = "select engine from system.databases where name = '#{@config[:database]}'"
|
354
|
+
res = ActiveRecord::Base.connection.select_one(current_database_engine)
|
355
|
+
res['engine'] == 'Atomic' if res
|
356
|
+
end
|
357
|
+
|
322
358
|
def apply_cluster(sql)
|
323
359
|
cluster ? "#{sql} ON CLUSTER #{cluster}" : sql
|
324
360
|
end
|
325
361
|
|
362
|
+
def supports_insert_on_duplicate_skip?
|
363
|
+
true
|
364
|
+
end
|
365
|
+
|
366
|
+
def supports_insert_on_duplicate_update?
|
367
|
+
true
|
368
|
+
end
|
369
|
+
|
370
|
+
def build_insert_sql(insert) # :nodoc:
|
371
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
372
|
+
sql
|
373
|
+
end
|
374
|
+
|
326
375
|
protected
|
327
376
|
|
328
377
|
def last_inserted_id(result)
|
@@ -339,17 +388,35 @@ module ActiveRecord
|
|
339
388
|
|
340
389
|
def connect
|
341
390
|
@connection = @connection_parameters[:connection] || Net::HTTP.start(@connection_parameters[:host], @connection_parameters[:port], use_ssl: @connection_parameters[:ssl], verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
391
|
+
|
392
|
+
@connection.ca_file = @connection_parameters[:ca_file] if @connection_parameters[:ca_file]
|
393
|
+
@connection.read_timeout = @connection_parameters[:read_timeout] if @connection_parameters[:read_timeout]
|
394
|
+
@connection.write_timeout = @connection_parameters[:write_timeout] if @connection_parameters[:write_timeout]
|
395
|
+
|
396
|
+
@connection
|
342
397
|
end
|
343
398
|
|
344
399
|
def apply_replica(table, options)
|
345
|
-
if
|
346
|
-
|
347
|
-
|
348
|
-
options[:options] = "Replicated#{match[1]}(#{([replica_path(table), replica].map{|v| "'#{v}'"} + [match[2].presence]).compact.join(', ')})#{match[3]}"
|
400
|
+
if use_replica? && options[:options]
|
401
|
+
if options[:options].match(/^Replicated/)
|
402
|
+
raise 'Do not try create Replicated table. It will be configured based on the *MergeTree engine.'
|
349
403
|
end
|
404
|
+
|
405
|
+
options[:options] = configure_replica(table, options[:options])
|
350
406
|
end
|
351
407
|
options
|
352
408
|
end
|
409
|
+
|
410
|
+
def configure_replica(table, options)
|
411
|
+
match = options.match(/^(.*?MergeTree)(?:\(([^\)]*)\))?((?:.|\n)*)/)
|
412
|
+
return options unless match
|
413
|
+
|
414
|
+
if replica
|
415
|
+
engine_params = ([replica_path(table), replica].map { |v| "'#{v}'" } + [match[2].presence]).compact.join(', ')
|
416
|
+
end
|
417
|
+
|
418
|
+
"Replicated#{match[1]}(#{engine_params})#{match[3]}"
|
419
|
+
end
|
353
420
|
end
|
354
421
|
end
|
355
422
|
end
|
@@ -6,14 +6,23 @@ module ClickhouseActiverecord
|
|
6
6
|
class << self
|
7
7
|
|
8
8
|
def create_table
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
+
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'
|
20
|
+
end
|
21
|
+
|
22
|
+
connection.public_send(table_creation_method, table_name, **table_options) do |t|
|
23
|
+
t.string :version, **version_options
|
24
|
+
t.column :active, 'Int8', null: false, default: '1'
|
25
|
+
t.datetime :ver, null: false, default: -> { 'now()' }
|
17
26
|
end
|
18
27
|
end
|
19
28
|
|
@@ -26,14 +35,25 @@ module ClickhouseActiverecord
|
|
26
35
|
class InternalMetadata < ::ActiveRecord::InternalMetadata
|
27
36
|
class << self
|
28
37
|
def create_table
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
return if table_exists?
|
39
|
+
|
40
|
+
key_options = connection.internal_string_options_for_primary_key
|
41
|
+
table_options = {
|
42
|
+
id: false,
|
43
|
+
options: connection.adapter_name.downcase == 'clickhouse' ? 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)' : '',
|
44
|
+
if_not_exists: true
|
45
|
+
}
|
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'
|
51
|
+
end
|
52
|
+
|
53
|
+
connection.public_send(table_creation_method, table_name, **table_options) do |t|
|
54
|
+
t.string :key, **key_options
|
55
|
+
t.string :value
|
56
|
+
t.timestamps
|
37
57
|
end
|
38
58
|
end
|
39
59
|
end
|
@@ -47,6 +67,16 @@ module ClickhouseActiverecord
|
|
47
67
|
@schema_migration = schema_migration
|
48
68
|
end
|
49
69
|
|
70
|
+
def up(target_version = nil)
|
71
|
+
selected_migrations = if block_given?
|
72
|
+
migrations.select { |m| yield m }
|
73
|
+
else
|
74
|
+
migrations
|
75
|
+
end
|
76
|
+
|
77
|
+
ClickhouseActiverecord::Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
|
78
|
+
end
|
79
|
+
|
50
80
|
def down(target_version = nil)
|
51
81
|
selected_migrations = if block_given?
|
52
82
|
migrations.select { |m| yield m }
|
@@ -144,9 +144,14 @@ HEADER
|
|
144
144
|
(column.sql_type =~ /(Nullable)?\(?UInt\d+\)?/).nil? ? false : nil
|
145
145
|
end
|
146
146
|
|
147
|
+
def schema_array(column)
|
148
|
+
(column.sql_type =~ /Array?\(/).nil? ? nil : true
|
149
|
+
end
|
150
|
+
|
147
151
|
def prepare_column_options(column)
|
148
152
|
spec = {}
|
149
153
|
spec[:unsigned] = schema_unsigned(column)
|
154
|
+
spec[:array] = schema_array(column)
|
150
155
|
spec.merge(super).compact
|
151
156
|
end
|
152
157
|
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
|
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
|
@@ -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.
|
4
|
+
version: 0.5.7
|
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-
|
11
|
+
date: 2021-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -112,6 +112,8 @@ files:
|
|
112
112
|
- bin/console
|
113
113
|
- bin/setup
|
114
114
|
- clickhouse-activerecord.gemspec
|
115
|
+
- core_extensions/active_record/migration/command_recorder.rb
|
116
|
+
- lib/active_record/connection_adapters/clickhouse/oid/array.rb
|
115
117
|
- lib/active_record/connection_adapters/clickhouse/oid/big_integer.rb
|
116
118
|
- lib/active_record/connection_adapters/clickhouse/oid/date.rb
|
117
119
|
- lib/active_record/connection_adapters/clickhouse/oid/date_time.rb
|