clickhouse-ruby 0.1.0 → 0.2.0
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 +74 -1
- data/README.md +165 -79
- data/lib/clickhouse_ruby/active_record/arel_visitor.rb +205 -76
- data/lib/clickhouse_ruby/active_record/connection_adapter.rb +103 -98
- data/lib/clickhouse_ruby/active_record/railtie.rb +20 -15
- data/lib/clickhouse_ruby/active_record/relation_extensions.rb +398 -0
- data/lib/clickhouse_ruby/active_record/schema_statements.rb +90 -104
- data/lib/clickhouse_ruby/active_record.rb +24 -10
- data/lib/clickhouse_ruby/client.rb +181 -74
- data/lib/clickhouse_ruby/configuration.rb +51 -10
- data/lib/clickhouse_ruby/connection.rb +180 -64
- data/lib/clickhouse_ruby/connection_pool.rb +25 -19
- data/lib/clickhouse_ruby/errors.rb +13 -1
- data/lib/clickhouse_ruby/result.rb +11 -16
- data/lib/clickhouse_ruby/retry_handler.rb +172 -0
- data/lib/clickhouse_ruby/streaming_result.rb +309 -0
- data/lib/clickhouse_ruby/types/array.rb +11 -64
- data/lib/clickhouse_ruby/types/base.rb +59 -0
- data/lib/clickhouse_ruby/types/boolean.rb +28 -25
- data/lib/clickhouse_ruby/types/date_time.rb +10 -27
- data/lib/clickhouse_ruby/types/decimal.rb +173 -0
- data/lib/clickhouse_ruby/types/enum.rb +262 -0
- data/lib/clickhouse_ruby/types/float.rb +14 -28
- data/lib/clickhouse_ruby/types/integer.rb +21 -43
- data/lib/clickhouse_ruby/types/low_cardinality.rb +1 -1
- data/lib/clickhouse_ruby/types/map.rb +21 -36
- data/lib/clickhouse_ruby/types/null_safe.rb +81 -0
- data/lib/clickhouse_ruby/types/nullable.rb +2 -2
- data/lib/clickhouse_ruby/types/parser.rb +28 -18
- data/lib/clickhouse_ruby/types/registry.rb +40 -29
- data/lib/clickhouse_ruby/types/string.rb +9 -13
- data/lib/clickhouse_ruby/types/string_parser.rb +135 -0
- data/lib/clickhouse_ruby/types/tuple.rb +11 -68
- data/lib/clickhouse_ruby/types/uuid.rb +15 -22
- data/lib/clickhouse_ruby/types.rb +19 -15
- data/lib/clickhouse_ruby/version.rb +1 -1
- data/lib/clickhouse_ruby.rb +11 -11
- metadata +41 -6
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require_relative
|
|
5
|
-
require_relative
|
|
3
|
+
require "active_record/connection_adapters/abstract_adapter"
|
|
4
|
+
require_relative "arel_visitor"
|
|
5
|
+
require_relative "schema_statements"
|
|
6
|
+
require_relative "relation_extensions"
|
|
6
7
|
|
|
7
8
|
module ClickhouseRuby
|
|
8
9
|
module ActiveRecord
|
|
@@ -39,28 +40,28 @@ module ClickhouseRuby
|
|
|
39
40
|
# Event.where(status: 'old').delete_all # Raises on error!
|
|
40
41
|
#
|
|
41
42
|
class ConnectionAdapter < ::ActiveRecord::ConnectionAdapters::AbstractAdapter
|
|
42
|
-
ADAPTER_NAME =
|
|
43
|
+
ADAPTER_NAME = "Clickhouse"
|
|
43
44
|
|
|
44
45
|
include SchemaStatements
|
|
45
46
|
|
|
46
47
|
# Native database types mapping for ClickHouse
|
|
47
48
|
# Used by migrations and schema definitions
|
|
48
49
|
NATIVE_DATABASE_TYPES = {
|
|
49
|
-
primary_key:
|
|
50
|
-
string: { name:
|
|
51
|
-
text: { name:
|
|
52
|
-
integer: { name:
|
|
53
|
-
bigint: { name:
|
|
54
|
-
float: { name:
|
|
55
|
-
decimal: { name:
|
|
56
|
-
datetime: { name:
|
|
57
|
-
timestamp: { name:
|
|
58
|
-
time: { name:
|
|
59
|
-
date: { name:
|
|
60
|
-
binary: { name:
|
|
61
|
-
boolean: { name:
|
|
62
|
-
uuid: { name:
|
|
63
|
-
json: { name:
|
|
50
|
+
primary_key: "UInt64",
|
|
51
|
+
string: { name: "String" },
|
|
52
|
+
text: { name: "String" },
|
|
53
|
+
integer: { name: "Int32" },
|
|
54
|
+
bigint: { name: "Int64" },
|
|
55
|
+
float: { name: "Float32" },
|
|
56
|
+
decimal: { name: "Decimal", precision: 10, scale: 0 },
|
|
57
|
+
datetime: { name: "DateTime" },
|
|
58
|
+
timestamp: { name: "DateTime64", precision: 3 },
|
|
59
|
+
time: { name: "DateTime" },
|
|
60
|
+
date: { name: "Date" },
|
|
61
|
+
binary: { name: "String" },
|
|
62
|
+
boolean: { name: "UInt8" },
|
|
63
|
+
uuid: { name: "UUID" },
|
|
64
|
+
json: { name: "String" },
|
|
64
65
|
}.freeze
|
|
65
66
|
|
|
66
67
|
class << self
|
|
@@ -73,9 +74,9 @@ module ClickhouseRuby
|
|
|
73
74
|
# @param config [Hash] database configuration
|
|
74
75
|
# @return [ConnectionAdapter] the adapter instance
|
|
75
76
|
def new_client(config)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
ClickhouseRuby::Client.new(
|
|
77
|
+
clickhouse_config = build_clickhouse_config(config)
|
|
78
|
+
clickhouse_config.validate!
|
|
79
|
+
ClickhouseRuby::Client.new(clickhouse_config)
|
|
79
80
|
end
|
|
80
81
|
|
|
81
82
|
private
|
|
@@ -84,11 +85,11 @@ module ClickhouseRuby
|
|
|
84
85
|
#
|
|
85
86
|
# @param config [Hash] database configuration hash
|
|
86
87
|
# @return [ClickhouseRuby::Configuration] configured client
|
|
87
|
-
def
|
|
88
|
+
def build_clickhouse_config(config)
|
|
88
89
|
ClickhouseRuby::Configuration.new.tap do |c|
|
|
89
|
-
c.host = config[:host] ||
|
|
90
|
+
c.host = config[:host] || "localhost"
|
|
90
91
|
c.port = config[:port]&.to_i || 8123
|
|
91
|
-
c.database = config[:database] ||
|
|
92
|
+
c.database = config[:database] || "default"
|
|
92
93
|
c.username = config[:username]
|
|
93
94
|
c.password = config[:password]
|
|
94
95
|
c.ssl = config[:ssl]
|
|
@@ -110,12 +111,15 @@ module ClickhouseRuby
|
|
|
110
111
|
# @param logger [Logger] Rails logger
|
|
111
112
|
# @param connection_options [Array] connection options
|
|
112
113
|
# @param config [Hash] database configuration
|
|
113
|
-
def initialize(connection, logger = nil,
|
|
114
|
+
def initialize(connection, logger = nil, _connection_options = nil, config = {})
|
|
114
115
|
@config = config.symbolize_keys
|
|
115
|
-
@
|
|
116
|
+
@clickhouse_client = nil
|
|
116
117
|
@connection_parameters = nil
|
|
117
118
|
|
|
118
119
|
super(connection, logger, config)
|
|
120
|
+
|
|
121
|
+
# Extend ActiveRecord::Relation with our methods
|
|
122
|
+
::ActiveRecord::Relation.include(RelationExtensions)
|
|
119
123
|
end
|
|
120
124
|
|
|
121
125
|
# Returns the adapter name
|
|
@@ -140,10 +144,10 @@ module ClickhouseRuby
|
|
|
140
144
|
#
|
|
141
145
|
# @return [Boolean] true if connected and responding
|
|
142
146
|
def active?
|
|
143
|
-
return false unless @
|
|
147
|
+
return false unless @clickhouse_client
|
|
144
148
|
|
|
145
149
|
# Ping ClickHouse to verify connection
|
|
146
|
-
execute_internal(
|
|
150
|
+
execute_internal("SELECT 1")
|
|
147
151
|
true
|
|
148
152
|
rescue ClickhouseRuby::Error
|
|
149
153
|
false
|
|
@@ -153,7 +157,7 @@ module ClickhouseRuby
|
|
|
153
157
|
#
|
|
154
158
|
# @return [Boolean] true if we have a client instance
|
|
155
159
|
def connected?
|
|
156
|
-
!@
|
|
160
|
+
!@clickhouse_client.nil?
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
# Disconnect from the database
|
|
@@ -161,8 +165,8 @@ module ClickhouseRuby
|
|
|
161
165
|
# @return [void]
|
|
162
166
|
def disconnect!
|
|
163
167
|
super
|
|
164
|
-
@
|
|
165
|
-
@
|
|
168
|
+
@clickhouse_client&.close if @clickhouse_client.respond_to?(:close)
|
|
169
|
+
@clickhouse_client = nil
|
|
166
170
|
end
|
|
167
171
|
|
|
168
172
|
# Reconnect to the database
|
|
@@ -185,7 +189,7 @@ module ClickhouseRuby
|
|
|
185
189
|
#
|
|
186
190
|
# @return [void]
|
|
187
191
|
def connect
|
|
188
|
-
@
|
|
192
|
+
@clickhouse_client = self.class.new_client(@config)
|
|
189
193
|
end
|
|
190
194
|
|
|
191
195
|
# ========================================
|
|
@@ -322,7 +326,7 @@ module ClickhouseRuby
|
|
|
322
326
|
raise ClickhouseRuby::QueryError.new(
|
|
323
327
|
"Query execution failed: #{e.message}",
|
|
324
328
|
sql: sql,
|
|
325
|
-
original_error: e
|
|
329
|
+
original_error: e,
|
|
326
330
|
)
|
|
327
331
|
end
|
|
328
332
|
|
|
@@ -337,7 +341,7 @@ module ClickhouseRuby
|
|
|
337
341
|
# @param binds [Array] bind values
|
|
338
342
|
# @return [Object] the id value
|
|
339
343
|
# @raise [ClickhouseRuby::QueryError] on ClickHouse errors
|
|
340
|
-
def exec_insert(sql, name = nil,
|
|
344
|
+
def exec_insert(sql, name = nil, _binds = [], _pk = nil, _sequence_name = nil)
|
|
341
345
|
execute(sql, name)
|
|
342
346
|
# ClickHouse doesn't return inserted IDs
|
|
343
347
|
# Return nil as we can't get the last insert ID
|
|
@@ -355,7 +359,7 @@ module ClickhouseRuby
|
|
|
355
359
|
# @param binds [Array] bind values
|
|
356
360
|
# @return [Integer] number of affected rows (estimated, ClickHouse doesn't return exact count)
|
|
357
361
|
# @raise [ClickhouseRuby::QueryError] on ClickHouse errors - NEVER silently fails
|
|
358
|
-
def exec_delete(sql, name = nil,
|
|
362
|
+
def exec_delete(sql, name = nil, _binds = [])
|
|
359
363
|
ensure_connected!
|
|
360
364
|
|
|
361
365
|
# The Arel visitor should have already converted this to
|
|
@@ -363,7 +367,7 @@ module ClickhouseRuby
|
|
|
363
367
|
# But if it's standard DELETE, convert it here
|
|
364
368
|
clickhouse_sql = convert_delete_to_alter(sql)
|
|
365
369
|
|
|
366
|
-
log(clickhouse_sql, name ||
|
|
370
|
+
log(clickhouse_sql, name || "DELETE") do
|
|
367
371
|
result = execute_internal(clickhouse_sql)
|
|
368
372
|
# CRITICAL: Raise on any error
|
|
369
373
|
raise_if_error!(result)
|
|
@@ -379,7 +383,7 @@ module ClickhouseRuby
|
|
|
379
383
|
raise ClickhouseRuby::QueryError.new(
|
|
380
384
|
"DELETE failed: #{e.message}",
|
|
381
385
|
sql: sql,
|
|
382
|
-
original_error: e
|
|
386
|
+
original_error: e,
|
|
383
387
|
)
|
|
384
388
|
end
|
|
385
389
|
|
|
@@ -394,14 +398,14 @@ module ClickhouseRuby
|
|
|
394
398
|
# @param binds [Array] bind values
|
|
395
399
|
# @return [Integer] number of affected rows (estimated)
|
|
396
400
|
# @raise [ClickhouseRuby::QueryError] on ClickHouse errors
|
|
397
|
-
def exec_update(sql, name = nil,
|
|
401
|
+
def exec_update(sql, name = nil, _binds = [])
|
|
398
402
|
ensure_connected!
|
|
399
403
|
|
|
400
404
|
# The Arel visitor should have already converted this to
|
|
401
405
|
# ALTER TABLE ... UPDATE ... WHERE syntax
|
|
402
406
|
clickhouse_sql = convert_update_to_alter(sql)
|
|
403
407
|
|
|
404
|
-
log(clickhouse_sql, name ||
|
|
408
|
+
log(clickhouse_sql, name || "UPDATE") do
|
|
405
409
|
result = execute_internal(clickhouse_sql)
|
|
406
410
|
raise_if_error!(result)
|
|
407
411
|
|
|
@@ -414,7 +418,7 @@ module ClickhouseRuby
|
|
|
414
418
|
raise ClickhouseRuby::QueryError.new(
|
|
415
419
|
"UPDATE failed: #{e.message}",
|
|
416
420
|
sql: sql,
|
|
417
|
-
original_error: e
|
|
421
|
+
original_error: e,
|
|
418
422
|
)
|
|
419
423
|
end
|
|
420
424
|
|
|
@@ -425,7 +429,7 @@ module ClickhouseRuby
|
|
|
425
429
|
# @param binds [Array] bind values
|
|
426
430
|
# @param prepare [Boolean] whether to prepare (ignored, ClickHouse doesn't support)
|
|
427
431
|
# @return [ClickhouseRuby::Result] query result
|
|
428
|
-
def exec_query(sql, name =
|
|
432
|
+
def exec_query(sql, name = "SQL", _binds = [], prepare: false)
|
|
429
433
|
execute(sql, name)
|
|
430
434
|
end
|
|
431
435
|
|
|
@@ -456,7 +460,7 @@ module ClickhouseRuby
|
|
|
456
460
|
def exec_rollback_db_transaction
|
|
457
461
|
# No-op: ClickHouse doesn't support transactions
|
|
458
462
|
# Log a warning since rollback was requested but cannot be performed
|
|
459
|
-
@logger&.warn(
|
|
463
|
+
@logger&.warn("ClickHouse does not support transaction rollback")
|
|
460
464
|
end
|
|
461
465
|
|
|
462
466
|
# ========================================
|
|
@@ -469,7 +473,7 @@ module ClickhouseRuby
|
|
|
469
473
|
# @param name [String, Symbol] the column name
|
|
470
474
|
# @return [String] the quoted column name
|
|
471
475
|
def quote_column_name(name)
|
|
472
|
-
"`#{name.to_s.gsub(
|
|
476
|
+
"`#{name.to_s.gsub("`", "``")}`"
|
|
473
477
|
end
|
|
474
478
|
|
|
475
479
|
# Quote a table name for ClickHouse
|
|
@@ -477,7 +481,7 @@ module ClickhouseRuby
|
|
|
477
481
|
# @param name [String, Symbol] the table name
|
|
478
482
|
# @return [String] the quoted table name
|
|
479
483
|
def quote_table_name(name)
|
|
480
|
-
"`#{name.to_s.gsub(
|
|
484
|
+
"`#{name.to_s.gsub("`", "``")}`"
|
|
481
485
|
end
|
|
482
486
|
|
|
483
487
|
# Quote a string value for ClickHouse
|
|
@@ -509,58 +513,58 @@ module ClickhouseRuby
|
|
|
509
513
|
# @return [void]
|
|
510
514
|
def initialize_type_map(m = type_map)
|
|
511
515
|
# Register standard types
|
|
512
|
-
register_class_with_limit m,
|
|
513
|
-
register_class_with_limit m,
|
|
516
|
+
register_class_with_limit m, /^String/i, ::ActiveRecord::Type::String
|
|
517
|
+
register_class_with_limit m, /^FixedString/i, ::ActiveRecord::Type::String
|
|
514
518
|
|
|
515
519
|
# Integer types
|
|
516
|
-
m.register_type
|
|
517
|
-
m.register_type
|
|
518
|
-
m.register_type
|
|
519
|
-
m.register_type
|
|
520
|
-
m.register_type
|
|
521
|
-
m.register_type
|
|
522
|
-
m.register_type
|
|
523
|
-
m.register_type
|
|
520
|
+
m.register_type(/^Int8/i, ::ActiveRecord::Type::Integer.new(limit: 1))
|
|
521
|
+
m.register_type(/^Int16/i, ::ActiveRecord::Type::Integer.new(limit: 2))
|
|
522
|
+
m.register_type(/^Int32/i, ::ActiveRecord::Type::Integer.new(limit: 4))
|
|
523
|
+
m.register_type(/^Int64/i, ::ActiveRecord::Type::Integer.new(limit: 8))
|
|
524
|
+
m.register_type(/^UInt8/i, ::ActiveRecord::Type::Integer.new(limit: 1))
|
|
525
|
+
m.register_type(/^UInt16/i, ::ActiveRecord::Type::Integer.new(limit: 2))
|
|
526
|
+
m.register_type(/^UInt32/i, ::ActiveRecord::Type::Integer.new(limit: 4))
|
|
527
|
+
m.register_type(/^UInt64/i, ::ActiveRecord::Type::Integer.new(limit: 8))
|
|
524
528
|
|
|
525
529
|
# Float types
|
|
526
|
-
m.register_type
|
|
527
|
-
m.register_type
|
|
530
|
+
m.register_type(/^Float32/i, ::ActiveRecord::Type::Float.new)
|
|
531
|
+
m.register_type(/^Float64/i, ::ActiveRecord::Type::Float.new)
|
|
528
532
|
|
|
529
533
|
# Decimal types
|
|
530
|
-
m.register_type
|
|
534
|
+
m.register_type(/^Decimal/i, ::ActiveRecord::Type::Decimal.new)
|
|
531
535
|
|
|
532
536
|
# Date/Time types
|
|
533
|
-
m.register_type
|
|
534
|
-
m.register_type
|
|
535
|
-
m.register_type
|
|
537
|
+
m.register_type(/^Date$/i, ::ActiveRecord::Type::Date.new)
|
|
538
|
+
m.register_type(/^DateTime/i, ::ActiveRecord::Type::DateTime.new)
|
|
539
|
+
m.register_type(/^DateTime64/i, ::ActiveRecord::Type::DateTime.new)
|
|
536
540
|
|
|
537
541
|
# Boolean (UInt8 with 0/1)
|
|
538
|
-
m.register_type
|
|
542
|
+
m.register_type(/^Bool/i, ::ActiveRecord::Type::Boolean.new)
|
|
539
543
|
|
|
540
544
|
# UUID
|
|
541
|
-
m.register_type
|
|
545
|
+
m.register_type(/^UUID/i, ::ActiveRecord::Type::String.new)
|
|
542
546
|
|
|
543
547
|
# Nullable wrapper - extract inner type
|
|
544
|
-
m.register_type
|
|
545
|
-
inner_type = sql_type.match(
|
|
548
|
+
m.register_type(/^Nullable\((.+)\)/i) do |sql_type|
|
|
549
|
+
inner_type = sql_type.match(/^Nullable\((.+)\)/i)[1]
|
|
546
550
|
lookup_cast_type(inner_type)
|
|
547
551
|
end
|
|
548
552
|
|
|
549
553
|
# Array types
|
|
550
|
-
m.register_type
|
|
554
|
+
m.register_type(/^Array\(/i, ::ActiveRecord::Type::String.new)
|
|
551
555
|
|
|
552
556
|
# Map types
|
|
553
|
-
m.register_type
|
|
557
|
+
m.register_type(/^Map\(/i, ::ActiveRecord::Type::String.new)
|
|
554
558
|
|
|
555
559
|
# Tuple types
|
|
556
|
-
m.register_type
|
|
560
|
+
m.register_type(/^Tuple\(/i, ::ActiveRecord::Type::String.new)
|
|
557
561
|
|
|
558
562
|
# Enum types (treated as strings)
|
|
559
|
-
m.register_type
|
|
563
|
+
m.register_type(/^Enum/i, ::ActiveRecord::Type::String.new)
|
|
560
564
|
|
|
561
565
|
# LowCardinality wrapper
|
|
562
|
-
m.register_type
|
|
563
|
-
inner_type = sql_type.match(
|
|
566
|
+
m.register_type(/^LowCardinality\((.+)\)/i) do |sql_type|
|
|
567
|
+
inner_type = sql_type.match(/^LowCardinality\((.+)\)/i)[1]
|
|
564
568
|
lookup_cast_type(inner_type)
|
|
565
569
|
end
|
|
566
570
|
end
|
|
@@ -573,10 +577,10 @@ module ClickhouseRuby
|
|
|
573
577
|
def ensure_connected!
|
|
574
578
|
connect unless connected?
|
|
575
579
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
+
return if @clickhouse_client
|
|
581
|
+
|
|
582
|
+
raise ClickhouseRuby::ConnectionNotEstablished,
|
|
583
|
+
"No connection to ClickHouse. Call connect first."
|
|
580
584
|
end
|
|
581
585
|
|
|
582
586
|
# Execute SQL through the ClickhouseRuby client
|
|
@@ -584,7 +588,7 @@ module ClickhouseRuby
|
|
|
584
588
|
# @param sql [String] the SQL to execute
|
|
585
589
|
# @return [ClickhouseRuby::Result] the result
|
|
586
590
|
def execute_internal(sql)
|
|
587
|
-
@
|
|
591
|
+
@clickhouse_client.execute(sql)
|
|
588
592
|
end
|
|
589
593
|
|
|
590
594
|
# Check if result contains an error and raise it
|
|
@@ -598,7 +602,7 @@ module ClickhouseRuby
|
|
|
598
602
|
raise ClickhouseRuby::QueryError.new(
|
|
599
603
|
result.error_message,
|
|
600
604
|
code: result.error_code,
|
|
601
|
-
http_status: result.http_status
|
|
605
|
+
http_status: result.http_status,
|
|
602
606
|
)
|
|
603
607
|
end
|
|
604
608
|
|
|
@@ -610,22 +614,21 @@ module ClickhouseRuby
|
|
|
610
614
|
def raise_query_error(error, sql)
|
|
611
615
|
if error.is_a?(ClickhouseRuby::QueryError)
|
|
612
616
|
# Re-raise with SQL if not already set
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
end
|
|
617
|
+
raise error unless error.sql.nil?
|
|
618
|
+
|
|
619
|
+
raise ClickhouseRuby::QueryError.new(
|
|
620
|
+
error.message,
|
|
621
|
+
code: error.code,
|
|
622
|
+
http_status: error.http_status,
|
|
623
|
+
sql: sql,
|
|
624
|
+
original_error: error.original_error,
|
|
625
|
+
)
|
|
626
|
+
|
|
624
627
|
else
|
|
625
628
|
raise ClickhouseRuby::QueryError.new(
|
|
626
629
|
error.message,
|
|
627
630
|
sql: sql,
|
|
628
|
-
original_error: error
|
|
631
|
+
original_error: error,
|
|
629
632
|
)
|
|
630
633
|
end
|
|
631
634
|
end
|
|
@@ -705,19 +708,21 @@ module ClickhouseRuby
|
|
|
705
708
|
# @param sql_type [String] the SQL type
|
|
706
709
|
# @return [Integer, nil] the limit or nil
|
|
707
710
|
def extract_limit(sql_type)
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
+
return unless (match = sql_type.match(/\((\d+)\)/))
|
|
712
|
+
|
|
713
|
+
match[1].to_i
|
|
711
714
|
end
|
|
712
715
|
end
|
|
713
716
|
end
|
|
714
717
|
end
|
|
715
718
|
|
|
716
719
|
# Register the adapter with ActiveRecord
|
|
717
|
-
if defined?(
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
720
|
+
if defined?(ActiveRecord::ConnectionAdapters)
|
|
721
|
+
if ActiveRecord::ConnectionAdapters.respond_to?(:register)
|
|
722
|
+
ActiveRecord::ConnectionAdapters.register(
|
|
723
|
+
"clickhouse",
|
|
724
|
+
"ClickhouseRuby::ActiveRecord::ConnectionAdapter",
|
|
725
|
+
"clickhouse_ruby/active_record/connection_adapter",
|
|
726
|
+
)
|
|
727
|
+
end
|
|
723
728
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "rails/railtie"
|
|
4
4
|
|
|
5
5
|
module ClickhouseRuby
|
|
6
6
|
module ActiveRecord
|
|
@@ -28,24 +28,25 @@ module ClickhouseRuby
|
|
|
28
28
|
#
|
|
29
29
|
class Railtie < ::Rails::Railtie
|
|
30
30
|
# Initialize the adapter when ActiveRecord loads
|
|
31
|
-
initializer
|
|
31
|
+
initializer "clickhouse_ruby.initialize_active_record" do
|
|
32
32
|
# Register the adapter
|
|
33
33
|
::ActiveSupport.on_load(:active_record) do
|
|
34
|
-
require_relative
|
|
34
|
+
require_relative "connection_adapter"
|
|
35
35
|
|
|
36
36
|
# Log that the adapter is being registered
|
|
37
37
|
if defined?(Rails.logger) && Rails.logger
|
|
38
|
-
Rails.logger.info
|
|
38
|
+
Rails.logger.info "[ClickhouseRuby] ClickHouse adapter registered with ActiveRecord"
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# Configure database tasks (db:create, db:drop, etc.)
|
|
44
|
-
initializer
|
|
44
|
+
initializer "clickhouse_ruby.configure_database_tasks" do
|
|
45
45
|
::ActiveSupport.on_load(:active_record) do
|
|
46
46
|
# Register ClickHouse-specific database tasks
|
|
47
47
|
if defined?(::ActiveRecord::Tasks::DatabaseTasks)
|
|
48
|
-
::ActiveRecord::Tasks::DatabaseTasks.register_task(/clickhouse/,
|
|
48
|
+
::ActiveRecord::Tasks::DatabaseTasks.register_task(/clickhouse/,
|
|
49
|
+
"ClickhouseRuby::ActiveRecord::DatabaseTasks",)
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
end
|
|
@@ -55,21 +56,25 @@ module ClickhouseRuby
|
|
|
55
56
|
# Set up connection pool based on Rails configuration
|
|
56
57
|
if defined?(ActiveRecord::Base)
|
|
57
58
|
# Ensure connections are properly managed
|
|
58
|
-
|
|
59
|
+
begin
|
|
60
|
+
ActiveRecord::Base.connection_pool.disconnect!
|
|
61
|
+
rescue StandardError
|
|
62
|
+
nil
|
|
63
|
+
end
|
|
59
64
|
end
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
# Add generators namespace for Rails generators
|
|
63
68
|
generators do
|
|
64
|
-
require_relative
|
|
69
|
+
require_relative "generators/migration_generator" if defined?(::Rails::Generators)
|
|
65
70
|
end
|
|
66
71
|
|
|
67
72
|
# Log deprecation warnings for known issues
|
|
68
|
-
initializer
|
|
73
|
+
initializer "clickhouse_ruby.log_deprecation_warnings" do
|
|
69
74
|
::ActiveSupport.on_load(:active_record) do
|
|
70
75
|
# Warn about features that don't work with ClickHouse
|
|
71
76
|
if defined?(Rails.logger) && Rails.logger
|
|
72
|
-
Rails.logger.debug
|
|
77
|
+
Rails.logger.debug "[ClickhouseRuby] Note: ClickHouse does not support transactions, savepoints, or foreign keys"
|
|
73
78
|
end
|
|
74
79
|
end
|
|
75
80
|
end
|
|
@@ -94,7 +99,7 @@ module ClickhouseRuby
|
|
|
94
99
|
|
|
95
100
|
# Connect without database to create it
|
|
96
101
|
temp_config = config.dup
|
|
97
|
-
temp_config[:database] =
|
|
102
|
+
temp_config[:database] = "default"
|
|
98
103
|
|
|
99
104
|
adapter = ConnectionAdapter.new(nil, nil, nil, temp_config)
|
|
100
105
|
adapter.connect
|
|
@@ -117,7 +122,7 @@ module ClickhouseRuby
|
|
|
117
122
|
|
|
118
123
|
# Connect without database to drop it
|
|
119
124
|
temp_config = config.dup
|
|
120
|
-
temp_config[:database] =
|
|
125
|
+
temp_config[:database] = "default"
|
|
121
126
|
|
|
122
127
|
adapter = ConnectionAdapter.new(nil, nil, nil, temp_config)
|
|
123
128
|
adapter.connect
|
|
@@ -145,11 +150,11 @@ module ClickhouseRuby
|
|
|
145
150
|
adapter = ConnectionAdapter.new(nil, nil, nil, config)
|
|
146
151
|
adapter.connect
|
|
147
152
|
|
|
148
|
-
File.open(filename,
|
|
153
|
+
File.open(filename, "w") do |file|
|
|
149
154
|
# Dump each table's CREATE statement
|
|
150
155
|
adapter.tables.each do |table_name|
|
|
151
156
|
result = adapter.execute("SHOW CREATE TABLE #{adapter.quote_table_name(table_name)}")
|
|
152
|
-
create_statement = result.first[
|
|
157
|
+
create_statement = result.first["statement"] || result.first["Create Table"]
|
|
153
158
|
file.puts "#{create_statement};\n\n"
|
|
154
159
|
end
|
|
155
160
|
end
|
|
@@ -180,7 +185,7 @@ module ClickhouseRuby
|
|
|
180
185
|
|
|
181
186
|
# Charset (not applicable to ClickHouse)
|
|
182
187
|
def charset(_master_configuration_hash = configuration_hash)
|
|
183
|
-
|
|
188
|
+
"UTF-8"
|
|
184
189
|
end
|
|
185
190
|
|
|
186
191
|
# Collation (not applicable to ClickHouse)
|