clickhouse-activerecord 0.4.10 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08f97b801fdb83a013dfeaf3aa11b9aa8bdaf4f66d7e63550666a3519f5cc2ce'
4
- data.tar.gz: b6e6e5e5b4ce521cf05fe994488625bf589843d340627ae957d827dba67c842e
3
+ metadata.gz: 92c0bdf3b6733bbe65fa0b4b096df7a171ca9625534965a82e675d2978141be6
4
+ data.tar.gz: f4a10214322bd7e1f36fd31d8c42821067d57ef8744727bcfd5ea975aa7b605c
5
5
  SHA512:
6
- metadata.gz: 26c2e974e5c4f0ec1e67b647c065b4d5bdc3cb98fd7c2f375f9b767214b004a278382723fbfcd998b372f9e1261262689faa1c05ff07d6f6b483985d2722303c
7
- data.tar.gz: a0def62c1153f5359653c8c1036201258b52813cb40bf0db9f00f4fafdd68bf0d70a3d1fabc3730fc2c8b5badcdd14daa66d283b56892f6d48b7f4b73089446d
6
+ metadata.gz: 29f6b4e129a393ad05d8d77386805d809cb6cbda37a6213122d5ad75edac3421dc51b70182a8f43cdac0b3d8b5a9208aa9aad3ba3d7161f108e5c1778e4c4cb0
7
+ data.tar.gz: 685b9c3b88819605ab596e41fe2a478e50b34d7c6d6eb53ce2ba603dd8324a6e4dc6a43498b063f98beac5a6301e3cb9be54283a15bd9f46bdf7fab94d2ba009
data/README.md CHANGED
@@ -35,6 +35,21 @@ default: &default
35
35
  replica_name: '{replica}' # replica macros name, optional for creating replicated tables
36
36
  ```
37
37
 
38
+ Alternatively if you wish to pass a custom `Net::HTTP` transport (or any other
39
+ object which supports a `.post()` function with the same parameters as
40
+ `Net::HTTP`'s), you can do this directly instead of specifying
41
+ `host`/`port`/`ssl`:
42
+
43
+ ```ruby
44
+ class ActionView < ActiveRecord::Base
45
+ establish_connection(
46
+ adapter: 'clickhouse',
47
+ database: 'database',
48
+ connection: Net::HTTP.start('http://example.org', 8123)
49
+ )
50
+ end
51
+ ```
52
+
38
53
  ## Usage in Rails 5
39
54
 
40
55
  Add your `database.yml` connection information with postfix `_clickhouse` for you environment:
@@ -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
@@ -1,9 +1,16 @@
1
1
  # frozen_string_literal: true
2
+ begin
3
+ require "active_record/connection_adapters/deduplicable"
4
+ rescue LoadError => e
5
+ # Rails < 6.1 does not have this file in this location, ignore
6
+ end
7
+
8
+ require "active_record/connection_adapters/abstract/schema_creation"
2
9
 
3
10
  module ActiveRecord
4
11
  module ConnectionAdapters
5
12
  module Clickhouse
6
- class SchemaCreation < AbstractAdapter::SchemaCreation# :nodoc:
13
+ class SchemaCreation < ConnectionAdapters::SchemaCreation# :nodoc:
7
14
 
8
15
  def visit_AddColumnDefinition(o)
9
16
  sql = +"ADD COLUMN #{accept(o.column)}"
@@ -15,14 +22,23 @@ module ActiveRecord
15
22
  if options[:null] || options[:null].nil?
16
23
  sql.gsub!(/\s+(.*)/, ' Nullable(\1)')
17
24
  end
25
+ if options[:array]
26
+ sql.gsub!(/\s+(.*)/, ' Array(\1)')
27
+ end
18
28
  sql.gsub!(/(\sString)\(\d+\)/, '\1')
19
29
  sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
20
30
  sql
21
31
  end
22
32
 
23
33
  def add_table_options!(create_sql, options)
24
- if options[:options].present?
25
- create_sql << " ENGINE = #{options[:options]}"
34
+ opts = options[:options]
35
+ if options.respond_to?(:options)
36
+ # rails 6.1
37
+ opts ||= options.options
38
+ end
39
+
40
+ if opts.present?
41
+ create_sql << " ENGINE = #{opts}"
26
42
  else
27
43
  create_sql << " ENGINE = Log()"
28
44
  end
@@ -37,11 +53,9 @@ module ActiveRecord
37
53
 
38
54
  statements = o.columns.map { |c| accept c }
39
55
  statements << accept(o.primary_keys) if o.primary_keys
40
-
41
56
  create_sql << "(#{statements.join(', ')})" if statements.present?
42
57
  # Attach options for only table or materialized view
43
- add_table_options!(create_sql, table_options(o)) if !o.view || o.view && o.materialized
44
-
58
+ add_table_options!(create_sql, o) if !o.view || o.view && o.materialized
45
59
  create_sql << " AS #{to_sql(o.as)}" if o.as
46
60
  create_sql
47
61
  end
@@ -17,8 +17,15 @@ module ActiveRecord
17
17
  def exec_query(sql, name = nil, binds = [], prepare: false)
18
18
  result = do_execute(sql, name)
19
19
  ActiveRecord::Result.new(result['meta'].map { |m| m['name'] }, result['data'])
20
- rescue StandardError => _e
21
- raise ActiveRecord::ActiveRecordError, "Response: #{result}"
20
+ rescue ActiveRecord::ActiveRecordError => e
21
+ raise e
22
+ rescue StandardError => e
23
+ raise ActiveRecord::ActiveRecordError, "Response: #{e.message}"
24
+ end
25
+
26
+ def exec_insert_all(sql, name)
27
+ do_execute(sql, name, format: nil)
28
+ true
22
29
  end
23
30
 
24
31
  def exec_update(_sql, _name = nil, _binds = [])
@@ -114,8 +121,8 @@ module ActiveRecord
114
121
  Clickhouse::SchemaCreation.new(self)
115
122
  end
116
123
 
117
- def create_table_definition(*args)
118
- Clickhouse::TableDefinition.new(self, *args)
124
+ def create_table_definition(table_name, options)
125
+ Clickhouse::TableDefinition.new(self, table_name, **options)
119
126
  end
120
127
 
121
128
  def new_column_from_field(table_name, field)
@@ -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,9 +18,22 @@ 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
20
- host = config[:host] || 'localhost'
21
- port = config[:port] || 8123
22
- ssl = config[:ssl].present? ? config[:ssl] : port == 443
21
+
22
+ if config[:connection]
23
+ connection = {
24
+ connection: config[:connection]
25
+ }
26
+ else
27
+ port = config[:port] || 8123
28
+ connection = {
29
+ host: config[:host] || 'localhost',
30
+ port: port,
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],
35
+ }
36
+ end
23
37
 
24
38
  if config.key?(:database)
25
39
  database = config[:database]
@@ -27,7 +41,7 @@ module ActiveRecord
27
41
  raise ArgumentError, 'No database specified. Missing argument: database.'
28
42
  end
29
43
 
30
- ConnectionAdapters::ClickhouseAdapter.new(logger, [host, port, ssl], { user: config[:username], password: config[:password], database: database }.compact, config)
44
+ ConnectionAdapters::ClickhouseAdapter.new(logger, connection, { user: config[:username], password: config[:password], database: database }.compact, config)
31
45
  end
32
46
  end
33
47
  end
@@ -50,7 +64,11 @@ module ActiveRecord
50
64
  module TypeCaster
51
65
  class Map
52
66
  def is_view
53
- types.is_view
67
+ if @klass.respond_to?(:is_view)
68
+ @klass.is_view # rails 6.1
69
+ else
70
+ types.is_view # less than 6.1
71
+ end
54
72
  end
55
73
  end
56
74
  end
@@ -177,12 +195,16 @@ module ActiveRecord
177
195
  register_class_with_limit m, %r(Int128), Type::Integer
178
196
  register_class_with_limit m, %r(Int256), Type::Integer
179
197
 
180
- register_class_with_limit m, %r(Uint8), Type::UnsignedInteger
198
+ register_class_with_limit m, %r(UInt8), Type::UnsignedInteger
181
199
  register_class_with_limit m, %r(UInt16), Type::UnsignedInteger
182
200
  register_class_with_limit m, %r(UInt32), Type::UnsignedInteger
183
201
  register_class_with_limit m, %r(UInt64), Type::UnsignedInteger
184
202
  #register_class_with_limit m, %r(UInt128), Type::UnsignedInteger #not implemnted in clickhouse
185
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
186
208
  end
187
209
 
188
210
  # Quoting time without microseconds
@@ -310,6 +332,19 @@ module ActiveRecord
310
332
  cluster ? "#{sql} ON CLUSTER #{cluster}" : sql
311
333
  end
312
334
 
335
+ def supports_insert_on_duplicate_skip?
336
+ true
337
+ end
338
+
339
+ def supports_insert_on_duplicate_update?
340
+ true
341
+ end
342
+
343
+ def build_insert_sql(insert) # :nodoc:
344
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
345
+ sql
346
+ end
347
+
313
348
  protected
314
349
 
315
350
  def last_inserted_id(result)
@@ -325,7 +360,13 @@ module ActiveRecord
325
360
  private
326
361
 
327
362
  def connect
328
- @connection = Net::HTTP.start(@connection_parameters[0], @connection_parameters[1], use_ssl: @connection_parameters[2], verify_mode: OpenSSL::SSL::VERIFY_NONE)
363
+ @connection = @connection_parameters[:connection] || Net::HTTP.start(@connection_parameters[:host], @connection_parameters[:port], use_ssl: @connection_parameters[:ssl], verify_mode: OpenSSL::SSL::VERIFY_NONE)
364
+
365
+ @connection.ca_file = @connection_parameters[:ca_file] if @connection_parameters[:ca_file]
366
+ @connection.read_timeout = @connection_parameters[:read_timeout] if @connection_parameters[:read_timeout]
367
+ @connection.write_timeout = @connection_parameters[:write_timeout] if @connection_parameters[:write_timeout]
368
+
369
+ @connection
329
370
  end
330
371
 
331
372
  def apply_replica(table, options)
@@ -1,3 +1,5 @@
1
+ require 'active_record/migration'
2
+
1
3
  module ClickhouseActiverecord
2
4
 
3
5
  class SchemaMigration < ::ActiveRecord::SchemaMigration
@@ -8,7 +10,7 @@ module ClickhouseActiverecord
8
10
  version_options = connection.internal_string_options_for_primary_key
9
11
 
10
12
  connection.create_table(table_name, id: false, options: 'ReplacingMergeTree(ver) PARTITION BY version ORDER BY (version)', if_not_exists: true) do |t|
11
- t.string :version, version_options
13
+ t.string :version, **version_options
12
14
  t.column :active, 'Int8', null: false, default: '1'
13
15
  t.datetime :ver, null: false, default: -> { 'now()' }
14
16
  end
@@ -27,7 +29,7 @@ module ClickhouseActiverecord
27
29
  unless table_exists?
28
30
  key_options = connection.internal_string_options_for_primary_key
29
31
 
30
- connection.create_table(table_name, id: false, options: 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)', if_not_exists: true) do |t|
32
+ connection.create_table(table_name, id: false, options: connection.adapter_name.downcase == 'clickhouse' ? 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)' : '', if_not_exists: true) do |t|
31
33
  t.string :key, key_options
32
34
  t.string :value
33
35
  t.timestamps
@@ -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
@@ -6,7 +6,7 @@ module ClickhouseActiverecord
6
6
  delegate :connection, :establish_connection, :clear_active_connections!, to: ActiveRecord::Base
7
7
 
8
8
  def initialize(configuration)
9
- @configuration = configuration
9
+ @configuration = configuration.with_indifferent_access
10
10
  end
11
11
 
12
12
  def create
@@ -1,3 +1,3 @@
1
1
  module ClickhouseActiverecord
2
- VERSION = '0.4.10'
2
+ VERSION = '0.5.1'
3
3
  end
@@ -13,7 +13,7 @@ class ClickhouseMigrationGenerator < ActiveRecord::Generators::MigrationGenerato
13
13
 
14
14
  def db_migrate_path
15
15
  if defined?(Rails.application) && Rails.application && respond_to?(:configured_migrate_path, true)
16
- configured_migrate_path
16
+ configured_migrate_path || default_migrate_path
17
17
  else
18
18
  default_migrate_path
19
19
  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.4.10
4
+ version: 0.5.1
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-03-10 00:00:00.000000000 Z
11
+ date: 2021-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -112,6 +112,7 @@ files:
112
112
  - bin/console
113
113
  - bin/setup
114
114
  - clickhouse-activerecord.gemspec
115
+ - lib/active_record/connection_adapters/clickhouse/oid/array.rb
115
116
  - lib/active_record/connection_adapters/clickhouse/oid/big_integer.rb
116
117
  - lib/active_record/connection_adapters/clickhouse/oid/date.rb
117
118
  - lib/active_record/connection_adapters/clickhouse/oid/date_time.rb