clickhouse-activerecord 0.5.7 → 0.5.8
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/clickhouse-activerecord.gemspec +1 -1
- data/core_extensions/active_record/migration/command_recorder.rb +0 -9
- data/lib/active_record/connection_adapters/clickhouse/schema_creation.rb +10 -1
- data/lib/active_record/connection_adapters/clickhouse/schema_definitions.rb +32 -0
- data/lib/active_record/connection_adapters/clickhouse/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/clickhouse_adapter.rb +51 -26
- data/lib/clickhouse-activerecord/migration.rb +14 -12
- data/lib/clickhouse-activerecord/tasks.rb +1 -1
- data/lib/clickhouse-activerecord/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8f8d01291f12197d0b5d0b8f791631fe144cdc5d855de9dd9c8498e170fafdf
|
4
|
+
data.tar.gz: 2ebd5b6068a179a7c87679db0fe9c34bbe2f9197c6230da9aad1a6935fc9c7d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94abbef81ff0000ecbc05092dd3558dc90e53223fd0025c5a57549f4b5f98431a01ee9fceee5587887c9fa6fcc3411420e936ad942150caa8edc5146c7db54df
|
7
|
+
data.tar.gz: '03871bfe2bec394c9612928229cc3380615acd795b25c058072a3aec62a7852e06711f2811286438ab278c838d4ed65736bd47ae449bc0ca5bbad6763692a927'
|
@@ -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]
|
@@ -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)
|
@@ -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
|
@@ -46,20 +46,18 @@ module ActiveRecord
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
# Replace for only ClickhouseAdapter
|
49
|
+
module ClickhouseRelationReverseOrder
|
52
50
|
def reverse_order!
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
51
|
+
return super unless connection.is_a?(ConnectionAdapters::ClickhouseAdapter)
|
52
|
+
|
53
|
+
orders = order_values.uniq.compact_blank
|
54
|
+
return super unless orders.empty? && !primary_key
|
55
|
+
|
56
|
+
self.order_values = %w(date created_at).select {|c| column_names.include?(c) }.map{|c| arel_attribute(c).desc }
|
60
57
|
self
|
61
58
|
end
|
62
59
|
end
|
60
|
+
Relation.prepend(ClickhouseRelationReverseOrder)
|
63
61
|
|
64
62
|
module TypeCaster
|
65
63
|
class Map
|
@@ -82,13 +80,19 @@ module ActiveRecord
|
|
82
80
|
def is_view=(value)
|
83
81
|
@is_view = value
|
84
82
|
end
|
83
|
+
end
|
84
|
+
end
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
ActiveRecord::Core::ClassMethods.module_eval do
|
87
|
+
def arel_table
|
88
|
+
@arel_table ||=
|
89
|
+
if self.connection.is_a?(ConnectionAdapters::ClickhouseAdapter)
|
90
|
+
ClickhouseActiverecord::Arel::Table.new(table_name, type_caster: type_caster)
|
91
|
+
else
|
92
|
+
Arel::Table.new(table_name, klass: self)
|
93
|
+
end
|
90
94
|
end
|
91
|
-
|
95
|
+
end
|
92
96
|
|
93
97
|
module ConnectionAdapters
|
94
98
|
class ClickhouseColumn < Column
|
@@ -104,8 +108,13 @@ module ActiveRecord
|
|
104
108
|
float: { name: 'Float32' },
|
105
109
|
decimal: { name: 'Decimal' },
|
106
110
|
datetime: { name: 'DateTime' },
|
111
|
+
datetime64: { name: 'DateTime64' },
|
107
112
|
date: { name: 'Date' },
|
108
113
|
boolean: { name: 'UInt8' },
|
114
|
+
uuid: { name: 'UUID' },
|
115
|
+
|
116
|
+
enum8: { name: 'Enum8' },
|
117
|
+
enum16: { name: 'Enum16' },
|
109
118
|
|
110
119
|
int8: { name: 'Int8' },
|
111
120
|
int16: { name: 'Int16' },
|
@@ -182,6 +191,20 @@ module ActiveRecord
|
|
182
191
|
end
|
183
192
|
end
|
184
193
|
|
194
|
+
# `extract_scale` and `extract_precision` are the same as in the Rails abstract base class,
|
195
|
+
# except this permits a space after the comma
|
196
|
+
|
197
|
+
def extract_scale(sql_type)
|
198
|
+
case sql_type
|
199
|
+
when /\((\d+)\)/ then 0
|
200
|
+
when /\((\d+)(,\s?(\d+))\)/ then $3.to_i
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def extract_precision(sql_type)
|
205
|
+
$1.to_i if sql_type =~ /\((\d+)(,\s?\d+)?\)/
|
206
|
+
end
|
207
|
+
|
185
208
|
def initialize_type_map(m) # :nodoc:
|
186
209
|
super
|
187
210
|
register_class_with_limit m, %r(String), Type::String
|
@@ -282,19 +305,16 @@ module ActiveRecord
|
|
282
305
|
end
|
283
306
|
|
284
307
|
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
|
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,6 +332,11 @@ 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
|
315
340
|
end
|
316
341
|
|
317
342
|
def change_column(table_name, column_name, type, options = {})
|
@@ -12,14 +12,15 @@ module ClickhouseActiverecord
|
|
12
12
|
table_options = {
|
13
13
|
id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version 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
|
@@ -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
|
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.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey Odintsov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-26 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
|