clickhouse-activerecord 0.6.2 → 1.0.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: 6533de4ab9b2415a4df22e72e7ef551d4fb58c5bdc6713ec355b85dbad1174fd
4
- data.tar.gz: 1c0a898f494c6dc7511897617ea86c2f12aa42461cf693e28e78124bde3638c6
3
+ metadata.gz: d56a19e32a58184c6c70b4cc56f30f4e7f742255a9f63441ce8c9b94ec63eebf
4
+ data.tar.gz: 2bd423580e61443e1b334e2182e4a05a7e712d79141ae6431730edcdc5dee7e3
5
5
  SHA512:
6
- metadata.gz: f6c5c2eba18dce09211cc6b8e5448aaaf2c40ca3eb5cc411aa76874ad6efc00ae257880e5997256808d02771aec7947559edfca941187c219b6724f09b9488f0
7
- data.tar.gz: 7b7e5f520c4189b4b5a1587789d0ea2ef8b74e86c077611ac18515c45105306c6e17cfd824623ab574420beeb45d205a9f301e2db9f3befd3c3b92c4d303b978
6
+ metadata.gz: 17a5a009eb6ece2d6835f5c37598891bde51fb4cf6c6e7ccb8fdc02cf9b1345d822e39d0f3d825b593606180db020357f4828e89f0c9c4cdf8352349ad6f4104
7
+ data.tar.gz: edc694713807b818d8f2e9c0b6a0592e0a3862a6b064d4110d12d82ebc1cb40133f7495e9e665007f91f0da5223d129ed110387f4922bf4de710729f462d4509
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Clickhouse::Activerecord
2
2
 
3
- A Ruby database ActiveRecord driver for ClickHouse. Support Rails >= 5.2.
3
+ A Ruby database ActiveRecord driver for ClickHouse. Support Rails >= 7.1.
4
4
  Support ClickHouse version from 22.0 LTS.
5
5
 
6
6
  ## Installation
@@ -50,41 +50,31 @@ class ActionView < ActiveRecord::Base
50
50
  end
51
51
  ```
52
52
 
53
- ## Usage in Rails 5
53
+ ## Usage in Rails
54
54
 
55
55
  Add your `database.yml` connection information with postfix `_clickhouse` for you environment:
56
56
 
57
57
  ```yml
58
- development_clickhouse:
58
+ development:
59
59
  adapter: clickhouse
60
60
  database: database
61
61
  ```
62
62
 
63
- Add to your model:
63
+ Your model example:
64
64
 
65
65
  ```ruby
66
66
  class Action < ActiveRecord::Base
67
- establish_connection "#{Rails.env}_clickhouse".to_sym
68
67
  end
69
68
  ```
70
69
 
71
70
  For materialized view model add:
72
71
  ```ruby
73
72
  class ActionView < ActiveRecord::Base
74
- establish_connection "#{Rails.env}_clickhouse".to_sym
75
73
  self.is_view = true
76
74
  end
77
75
  ```
78
76
 
79
- Or global connection:
80
-
81
- ```yml
82
- development:
83
- adapter: clickhouse
84
- database: database
85
- ```
86
-
87
- ## Usage in Rails 6 with second database
77
+ ## Usage in Rails with second database
88
78
 
89
79
  Add your `database.yml` connection information for you environment:
90
80
 
@@ -102,31 +92,31 @@ Connection [Multiple Databases with Active Record](https://guides.rubyonrails.or
102
92
 
103
93
  ```ruby
104
94
  class Action < ActiveRecord::Base
105
- connects_to database: { writing: :clickhouse, reading: :clickhouse }
95
+ establish_connection :clickhouse
106
96
  end
107
97
  ```
108
98
 
109
99
  ### Rake tasks
110
100
 
111
- **Note!** For Rails 6 you can use default rake tasks if you configure `migrations_paths` in your `database.yml`, for example: `rake db:migrate`
112
-
113
101
  Create / drop / purge / reset database:
114
102
 
115
- $ rake clickhouse:create
116
- $ rake clickhouse:drop
117
- $ rake clickhouse:purge
118
- $ rake clickhouse:reset
103
+ $ rake db:create
104
+ $ rake db:drop
105
+ $ rake db:purge
106
+ $ rake db:reset
119
107
 
120
- Prepare system tables for rails:
108
+ Or with multiple databases:
121
109
 
122
- $ rake clickhouse:prepare_schema_migration_table
123
- $ rake clickhouse:prepare_internal_metadata_table
110
+ $ rake db:create:clickhouse
111
+ $ rake db:drop:clickhouse
112
+ $ rake db:purge:clickhouse
113
+ $ rake db:reset:clickhouse
124
114
 
125
115
  Migration:
126
116
 
127
117
  $ rails g clickhouse_migration MIGRATION_NAME COLUMNS
128
- $ rake clickhouse:migrate
129
- $ rake clickhouse:rollback
118
+ $ rake db:migrate
119
+ $ rake db:rollback
130
120
 
131
121
  ### Dump / Load for multiple using databases
132
122
 
@@ -195,20 +185,20 @@ User.joins(:actions).using(:group_id)
195
185
  Integer types are unsigned by default. Specify signed values with `:unsigned =>
196
186
  false`. The default integer is `UInt32`
197
187
 
198
- | Type (bit size) | Range | :limit (byte size) |
199
- | :--- | :----: | ---: |
200
- | Int8 | -128 to 127 | 1 |
201
- | Int16 | -32768 to 32767 | 2 |
202
- | Int32 | -2147483648 to 2,147,483,647 | 3,4 |
203
- | Int64 | -9223372036854775808 to 9223372036854775807] | 5,6,7,8 |
204
- | Int128 | ... | 9 - 15 |
205
- | Int256 | ... | 16+ |
206
- | UInt8 | 0 to 255 | 1 |
207
- | UInt16 | 0 to 65,535 | 2 |
208
- | UInt32 | 0 to 4,294,967,295 | 3,4 |
209
- | UInt64 | 0 to 18446744073709551615 | 5,6,7,8 |
210
- | UInt256 | 0 to ... | 8+ |
211
- | Array | ... | ... |
188
+ | Type (bit size) | Range | :limit (byte size) |
189
+ |:----------------|:--------------------------------------------:|-------------------:|
190
+ | Int8 | -128 to 127 | 1 |
191
+ | Int16 | -32768 to 32767 | 2 |
192
+ | Int32 | -2147483648 to 2,147,483,647 | 3,4 |
193
+ | Int64 | -9223372036854775808 to 9223372036854775807] | 5,6,7,8 |
194
+ | Int128 | ... | 9 - 15 |
195
+ | Int256 | ... | 16+ |
196
+ | UInt8 | 0 to 255 | 1 |
197
+ | UInt16 | 0 to 65,535 | 2 |
198
+ | UInt32 | 0 to 4,294,967,295 | 3,4 |
199
+ | UInt64 | 0 to 18446744073709551615 | 5,6,7,8 |
200
+ | UInt256 | 0 to ... | 8+ |
201
+ | Array | ... | ... |
212
202
 
213
203
  Example:
214
204
 
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.require_paths = ['lib']
25
25
 
26
26
  spec.add_runtime_dependency 'bundler', '>= 1.13.4'
27
- spec.add_runtime_dependency 'activerecord', '~> 7.0.0'
27
+ spec.add_runtime_dependency 'activerecord', '>= 7.1'
28
28
 
29
29
  spec.add_development_dependency 'rake', '~> 13.0'
30
30
  spec.add_development_dependency 'rspec', '~> 3.4'
@@ -125,11 +125,7 @@ module ActiveRecord
125
125
  end
126
126
 
127
127
  def current_database
128
- if ActiveRecord::version >= Gem::Version.new('6.1')
129
- ActiveRecord::Base.connection_db_config.database
130
- else
131
- ActiveRecord::Base.connection_config[:database]
132
- end
128
+ ActiveRecord::Base.connection_db_config.database
133
129
  end
134
130
  end
135
131
  end
@@ -10,13 +10,13 @@ module ActiveRecord
10
10
  do_execute(sql, name, settings: settings)
11
11
  end
12
12
 
13
- def exec_insert(sql, name, _binds, _pk = nil, _sequence_name = nil)
13
+ def exec_insert(sql, name, _binds, _pk = nil, _sequence_name = nil, returning: nil)
14
14
  new_sql = sql.dup.sub(/ (DEFAULT )?VALUES/, " VALUES")
15
15
  do_execute(new_sql, name, format: nil)
16
16
  true
17
17
  end
18
18
 
19
- def exec_query(sql, name = nil, binds = [], prepare: false)
19
+ def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false)
20
20
  result = do_execute(sql, name)
21
21
  ActiveRecord::Result.new(result['meta'].map { |m| m['name'] }, result['data'], result['meta'].map { |m| [m['name'], type_map.lookup(m['type'])] }.to_h)
22
22
  rescue ActiveRecord::ActiveRecordError => e
@@ -30,12 +30,16 @@ module ActiveRecord
30
30
  true
31
31
  end
32
32
 
33
+ # @link https://clickhouse.com/docs/en/sql-reference/statements/alter/update
33
34
  def exec_update(_sql, _name = nil, _binds = [])
34
- raise ActiveRecord::ActiveRecordError, 'Clickhouse update is not supported'
35
+ do_execute(_sql, _name, format: nil)
36
+ true
35
37
  end
36
38
 
39
+ # @link https://clickhouse.com/docs/en/sql-reference/statements/delete
37
40
  def exec_delete(_sql, _name = nil, _binds = [])
38
- raise ActiveRecord::ActiveRecordError, 'Clickhouse delete is not supported'
41
+ do_execute(_sql, _name, format: nil)
42
+ true
39
43
  end
40
44
 
41
45
  def tables(name = nil)
@@ -137,17 +141,13 @@ module ActiveRecord
137
141
  Clickhouse::TableDefinition.new(self, table_name, **options)
138
142
  end
139
143
 
140
- def new_column_from_field(table_name, field)
144
+ def new_column_from_field(table_name, field, _definitions)
141
145
  sql_type = field[1]
142
146
  type_metadata = fetch_type_metadata(sql_type)
143
147
  default = field[3]
144
148
  default_value = extract_value_from_default(default)
145
149
  default_function = extract_default_function(default_value, default)
146
- if ActiveRecord::version >= Gem::Version.new('6')
147
- ClickhouseColumn.new(field[0], default_value, type_metadata, field[1].include?('Nullable'), default_function)
148
- else
149
- ClickhouseColumn.new(field[0], default_value, type_metadata, field[1].include?('Nullable'), table_name, default_function)
150
- end
150
+ ClickhouseColumn.new(field[0], default_value, type_metadata, field[1].include?('Nullable'), default_function)
151
151
  end
152
152
 
153
153
  protected
@@ -127,16 +127,17 @@ module ActiveRecord
127
127
  @full_config = full_config
128
128
 
129
129
  @prepared_statements = false
130
- if ActiveRecord::version == Gem::Version.new('6.0.0')
131
- @prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
132
- end
133
130
 
134
131
  connect
135
132
  end
136
133
 
137
134
  # Support SchemaMigration from v5.2.2 to v6+
138
135
  def schema_migration # :nodoc:
139
- ClickhouseActiverecord::SchemaMigration
136
+ ClickhouseActiverecord::SchemaMigration.new(self)
137
+ end
138
+
139
+ def internal_metadata # :nodoc:
140
+ ClickhouseActiverecord::InternalMetadata.new(self)
140
141
  end
141
142
 
142
143
  def migrations_paths
@@ -144,7 +145,7 @@ module ActiveRecord
144
145
  end
145
146
 
146
147
  def migration_context # :nodoc:
147
- ClickhouseActiverecord::MigrationContext.new(migrations_paths, schema_migration)
148
+ ClickhouseActiverecord::MigrationContext.new(migrations_paths, schema_migration, internal_metadata)
148
149
  end
149
150
 
150
151
  def arel_visitor # :nodoc:
@@ -234,30 +235,18 @@ module ActiveRecord
234
235
  # Quoting time without microseconds
235
236
  def quoted_date(value)
236
237
  if value.acts_like?(:time)
237
- if ActiveRecord::version >= Gem::Version.new('7')
238
- zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal
239
- else
240
- zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
241
- end
238
+ zone_conversion_method = ActiveRecord.default_timezone == :utc ? :getutc : :getlocal
242
239
 
243
240
  if value.respond_to?(zone_conversion_method)
244
241
  value = value.send(zone_conversion_method)
245
242
  end
246
243
  end
247
244
 
248
- if ActiveRecord::version >= Gem::Version.new('7')
249
- value.to_fs(:db)
250
- else
251
- value.to_s(:db)
252
- end
245
+ value.to_fs(:db)
253
246
  end
254
247
 
255
248
  def column_name_for_operation(operation, node) # :nodoc:
256
- if ActiveRecord::version >= Gem::Version.new('6')
257
- visitor.compile(node)
258
- else
259
- column_name_from_arel_node(node)
260
- end
249
+ visitor.compile(node)
261
250
  end
262
251
 
263
252
  # Executes insert +sql+ statement in the context of this connection using
@@ -15,7 +15,7 @@ module Arel
15
15
 
16
16
  def visit_Arel_Table o, collector
17
17
  collector = super
18
- collector << ' FINAL ' if o.final
18
+ collector << ' FINAL' if o.final
19
19
  collector
20
20
  end
21
21
 
@@ -23,6 +23,17 @@ module Arel
23
23
  maybe_visit o.settings, super
24
24
  end
25
25
 
26
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
27
+ o = prepare_update_statement(o)
28
+
29
+ collector << 'ALTER TABLE '
30
+ collector = visit o.relation, collector
31
+ collect_nodes_for o.values, collector, ' UPDATE '
32
+ collect_nodes_for o.wheres, collector, ' WHERE ', ' AND '
33
+ collect_nodes_for o.orders, collector, ' ORDER BY '
34
+ maybe_visit o.limit, collector
35
+ end
36
+
26
37
  def visit_Arel_Nodes_Settings(o, collector)
27
38
  return collector if o.expr.empty?
28
39
 
@@ -3,107 +3,96 @@ require 'active_record/migration'
3
3
  module ClickhouseActiverecord
4
4
 
5
5
  class SchemaMigration < ::ActiveRecord::SchemaMigration
6
- class << self
6
+ def create_table
7
+ return if table_exists?
7
8
 
8
- def create_table
9
- return if table_exists?
9
+ version_options = connection.internal_string_options_for_primary_key
10
+ table_options = {
11
+ id: false, options: 'ReplacingMergeTree(ver) ORDER BY (version)', if_not_exists: true
12
+ }
13
+ full_config = connection.instance_variable_get(:@full_config) || {}
10
14
 
11
- version_options = connection.internal_string_options_for_primary_key
12
- table_options = {
13
- id: false, options: 'ReplacingMergeTree(ver) ORDER BY (version)', if_not_exists: true
14
- }
15
- full_config = connection.instance_variable_get(:@full_config) || {}
15
+ if full_config[:distributed_service_tables]
16
+ table_options.merge!(with_distributed: table_name, sharding_key: 'cityHash64(version)')
16
17
 
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'}"
21
- end
22
-
23
- connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
24
- t.string :version, **version_options
25
- t.column :active, 'Int8', null: false, default: '1'
26
- t.datetime :ver, null: false, default: -> { 'now()' }
27
- end
18
+ distributed_suffix = "_#{full_config[:distributed_service_tables_suffix] || 'distributed'}"
28
19
  end
29
20
 
30
- def all_versions
31
- final.where(active: 1).order(:version).pluck(:version)
21
+ connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
22
+ t.string :version, **version_options
23
+ t.column :active, 'Int8', null: false, default: '1'
24
+ t.datetime :ver, null: false, default: -> { 'now()' }
32
25
  end
33
26
  end
34
- end
35
27
 
36
- class InternalMetadata < ::ActiveRecord::InternalMetadata
37
- class << self
28
+ def versions
29
+ table = arel_table.dup
30
+ table.final = true
31
+ sm = Arel::SelectManager.new(table)
32
+ sm.project(arel_table[primary_key])
33
+ sm.order(arel_table[primary_key].asc)
34
+ sm.where([arel_table['active'].eq(1)])
38
35
 
39
- def []=(key, value)
40
- row = final.find_by(key: key)
41
- if row.nil? || row.value != value
42
- create!(key: key, value: value)
43
- end
44
- end
36
+ connection.select_values(sm, "#{self.class} Load")
37
+ end
45
38
 
46
- def [](key)
47
- final.where(key: key).pluck(:value).first
48
- end
39
+ def delete_version(version)
40
+ im = Arel::InsertManager.new(arel_table)
41
+ im.insert(arel_table[primary_key] => version.to_s, arel_table['active'] => 0)
42
+ connection.insert(im, "#{self.class} Create Rollback Version", primary_key, version)
43
+ end
44
+ end
49
45
 
50
- def create_table
51
- return if table_exists?
46
+ class InternalMetadata < ::ActiveRecord::InternalMetadata
52
47
 
53
- key_options = connection.internal_string_options_for_primary_key
54
- table_options = {
55
- id: false,
56
- options: connection.adapter_name.downcase == 'clickhouse' ? 'ReplacingMergeTree(created_at) PARTITION BY key ORDER BY key' : '',
57
- if_not_exists: true
58
- }
59
- full_config = connection.instance_variable_get(:@full_config) || {}
48
+ def create_table
49
+ return if table_exists? || !enabled?
60
50
 
61
- if full_config[:distributed_service_tables]
62
- table_options.merge!(with_distributed: table_name, sharding_key: 'cityHash64(created_at)')
51
+ key_options = connection.internal_string_options_for_primary_key
52
+ table_options = {
53
+ id: false,
54
+ options: connection.adapter_name.downcase == 'clickhouse' ? 'ReplacingMergeTree(created_at) PARTITION BY key ORDER BY key' : '',
55
+ if_not_exists: true
56
+ }
57
+ full_config = connection.instance_variable_get(:@full_config) || {}
63
58
 
64
- distributed_suffix = "_#{full_config[:distributed_service_tables_suffix] || 'distributed'}"
65
- end
59
+ if full_config[:distributed_service_tables]
60
+ table_options.merge!(with_distributed: table_name, sharding_key: 'cityHash64(created_at)')
66
61
 
67
- connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
68
- t.string :key, **key_options
69
- t.string :value
70
- t.timestamps
71
- end
62
+ distributed_suffix = "_#{full_config[:distributed_service_tables_suffix] || 'distributed'}"
72
63
  end
73
- end
74
- end
75
64
 
76
- class MigrationContext < ::ActiveRecord::MigrationContext #:nodoc:
77
- attr_reader :migrations_paths, :schema_migration
78
-
79
- def initialize(migrations_paths, schema_migration)
80
- @migrations_paths = migrations_paths
81
- @schema_migration = schema_migration
65
+ connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
66
+ t.string :key, **key_options
67
+ t.string :value
68
+ t.timestamps
69
+ end
82
70
  end
83
71
 
84
- def up(target_version = nil)
85
- selected_migrations = if block_given?
86
- migrations.select { |m| yield m }
87
- else
88
- migrations
89
- end
72
+ private
90
73
 
91
- ClickhouseActiverecord::Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
74
+ def update_entry(key, new_value)
75
+ create_entry(key, new_value)
92
76
  end
93
77
 
94
- def down(target_version = nil)
95
- selected_migrations = if block_given?
96
- migrations.select { |m| yield m }
97
- else
98
- migrations
99
- end
78
+ def select_entry(key)
79
+ table = arel_table.dup
80
+ table.final = true
81
+ sm = Arel::SelectManager.new(table)
82
+ sm.project(Arel::Nodes::SqlLiteral.new("*"))
83
+ sm.where(table[primary_key].eq(Arel::Nodes::BindParam.new(key)))
84
+ sm.order(table[primary_key].asc)
85
+ sm.limit = 1
100
86
 
101
- ClickhouseActiverecord::Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
87
+ connection.select_all(sm, "#{self.class} Load").first
102
88
  end
89
+ end
90
+
91
+ class MigrationContext < ::ActiveRecord::MigrationContext #:nodoc:
103
92
 
104
93
  def get_all_versions
105
94
  if schema_migration.table_exists?
106
- schema_migration.all_versions.map(&:to_i)
95
+ schema_migration.versions.map(&:to_i)
107
96
  else
108
97
  []
109
98
  end
@@ -111,36 +100,4 @@ module ClickhouseActiverecord
111
100
 
112
101
  end
113
102
 
114
- class Migrator < ::ActiveRecord::Migrator
115
-
116
- def initialize(direction, migrations, schema_migration, target_version = nil)
117
- @direction = direction
118
- @target_version = target_version
119
- @migrated_versions = nil
120
- @migrations = migrations
121
- @schema_migration = schema_migration
122
-
123
- validate(@migrations)
124
-
125
- @schema_migration.create_table
126
- ClickhouseActiverecord::InternalMetadata.create_table
127
- end
128
-
129
- def record_version_state_after_migrating(version)
130
- if down?
131
- migrated.delete(version)
132
- @schema_migration.create!(version: version.to_s, active: 0)
133
- else
134
- super
135
- end
136
- end
137
-
138
- private
139
-
140
- def record_environment
141
- return if down?
142
- ClickhouseActiverecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
143
- end
144
-
145
- end
146
103
  end
@@ -1,3 +1,3 @@
1
1
  module ClickhouseActiverecord
2
- VERSION = '0.6.2'
2
+ VERSION = '1.0.1'
3
3
  end
@@ -11,21 +11,65 @@ module CoreExtensions
11
11
  self
12
12
  end
13
13
 
14
+ # Define settings in the SETTINGS clause of the SELECT query. The setting value is applied only to that query and is reset to the default or previous value after the query is executed.
15
+ # For example:
16
+ #
17
+ # users = User.settings(optimize_read_in_order: 1, cast_keep_nullable: 1).where(name: 'John')
18
+ # # SELECT users.* FROM users WHERE users.name = 'John' SETTINGS optimize_read_in_order = 1, cast_keep_nullable = 1
19
+ #
20
+ # An <tt>ActiveRecord::ActiveRecordError</tt> will be raised if database not ClickHouse.
14
21
  # @param [Hash] opts
15
22
  def settings(**opts)
23
+ spawn.settings!(**opts)
24
+ end
25
+
26
+ # @param [Hash] opts
27
+ def settings!(**opts)
28
+ assert_mutability!
16
29
  check_command('SETTINGS')
17
30
  @values[:settings] = (@values[:settings] || {}).merge opts
18
31
  self
19
32
  end
20
33
 
34
+ # When FINAL is specified, ClickHouse fully merges the data before returning the result and thus performs all data transformations that happen during merges for the given table engine.
35
+ # For example:
36
+ #
37
+ # users = User.final.all
38
+ # # SELECT users.* FROM users FINAL
39
+ #
40
+ # An <tt>ActiveRecord::ActiveRecordError</tt> will be raised if database not ClickHouse.
21
41
  # @param [Boolean] final
22
42
  def final(final = true)
43
+ spawn.final!(final)
44
+ end
45
+
46
+ # @param [Boolean] final
47
+ def final!(final = true)
48
+ assert_mutability!
23
49
  check_command('FINAL')
24
50
  @table = @table.dup
25
51
  @table.final = final
26
52
  self
27
53
  end
28
54
 
55
+ # The USING clause specifies one or more columns to join, which establishes the equality of these columns. For example:
56
+ #
57
+ # users = User.joins(:joins).using(:event_name, :date)
58
+ # # SELECT users.* FROM users INNER JOIN joins USING event_name,date
59
+ #
60
+ # An <tt>ActiveRecord::ActiveRecordError</tt> will be raised if database not ClickHouse.
61
+ # @param [Array] opts
62
+ def using(*opts)
63
+ spawn.using!(*opts)
64
+ end
65
+
66
+ # @param [Array] opts
67
+ def using!(*opts)
68
+ assert_mutability!
69
+ @values[:using] = opts
70
+ self
71
+ end
72
+
29
73
  private
30
74
 
31
75
  def check_command(cmd)
@@ -36,6 +80,7 @@ module CoreExtensions
36
80
  arel = super
37
81
 
38
82
  arel.settings(@values[:settings]) if @values[:settings].present?
83
+ arel.using(@values[:using]) if @values[:using].present?
39
84
 
40
85
  arel
41
86
  end
@@ -2,17 +2,13 @@
2
2
 
3
3
  namespace :clickhouse do
4
4
  task prepare_schema_migration_table: :environment do
5
- ClickhouseActiverecord::SchemaMigration.create_table unless ENV['simple'] || ARGV.any? { |a| a.include?('--simple') }
5
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
6
+ connection.schema_migration.create_table unless ENV['simple'] || ARGV.any? { |a| a.include?('--simple') }
6
7
  end
7
8
 
8
9
  task prepare_internal_metadata_table: :environment do
9
- ClickhouseActiverecord::InternalMetadata.create_table unless ENV['simple'] || ARGV.any? { |a| a.include?('--simple') }
10
- end
11
-
12
- task load_config: :environment do
13
- ENV['SCHEMA'] = 'db/clickhouse_schema.rb'
14
- ActiveRecord::Migrator.migrations_paths = %w[db/migrate_clickhouse]
15
- ActiveRecord::Base.establish_connection(:clickhouse)
10
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
11
+ connection.internal_metadata.create_table unless ENV['simple'] || ARGV.any? { |a| a.include?('--simple') }
16
12
  end
17
13
 
18
14
  namespace :schema do
@@ -37,52 +33,55 @@ namespace :clickhouse do
37
33
 
38
34
  namespace :structure do
39
35
  desc 'Load database structure'
40
- task load: [:load_config, 'db:check_protected_environments'] do
36
+ task load: ['db:check_protected_environments'] do
41
37
  config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
42
38
  ClickhouseActiverecord::Tasks.new(config).structure_load(Rails.root.join('db/clickhouse_structure.sql'))
43
39
  end
44
40
 
45
41
  desc 'Dump database structure'
46
- task dump: [:load_config, 'db:check_protected_environments'] do
42
+ task dump: ['db:check_protected_environments'] do
47
43
  config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
48
44
  ClickhouseActiverecord::Tasks.new(config).structure_dump(Rails.root.join('db/clickhouse_structure.sql'))
49
45
  end
50
46
  end
51
47
 
52
48
  desc 'Creates the database from DATABASE_URL or config/database.yml'
53
- task create: [:load_config] do
49
+ task create: [] do
54
50
  config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
55
51
  ActiveRecord::Tasks::DatabaseTasks.create(config)
56
52
  end
57
53
 
58
54
  desc 'Drops the database from DATABASE_URL or config/database.yml'
59
- task drop: [:load_config, 'db:check_protected_environments'] do
55
+ task drop: ['db:check_protected_environments'] do
60
56
  config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
61
57
  ActiveRecord::Tasks::DatabaseTasks.drop(config)
62
58
  end
63
59
 
64
60
  desc 'Empty the database from DATABASE_URL or config/database.yml'
65
- task purge: [:load_config, 'db:check_protected_environments'] do
61
+ task purge: ['db:check_protected_environments'] do
66
62
  config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
67
63
  ActiveRecord::Tasks::DatabaseTasks.purge(config)
68
64
  end
69
65
 
70
66
  # desc 'Resets your database using your migrations for the current environment'
71
- task reset: :load_config do
67
+ task :reset do
72
68
  Rake::Task['clickhouse:purge'].execute
73
69
  Rake::Task['clickhouse:migrate'].execute
74
70
  end
75
71
 
76
72
  desc 'Migrate the clickhouse database'
77
- task migrate: %i[load_config prepare_schema_migration_table prepare_internal_metadata_table] do
78
- Rake::Task['db:migrate'].execute
79
- if File.exists? "#{Rails.root}/db/clickhouse_schema_simple.rb"
73
+ task migrate: %i[prepare_schema_migration_table prepare_internal_metadata_table] do
74
+ Rake::Task['db:migrate:clickhouse'].execute
75
+ if File.exist? "#{Rails.root}/db/clickhouse_schema_simple.rb"
80
76
  Rake::Task['clickhouse:schema:dump'].execute(simple: true)
81
77
  end
82
78
  end
83
79
 
84
80
  desc 'Rollback the clickhouse database'
85
- task rollback: %i[load_config prepare_schema_migration_table prepare_internal_metadata_table] do
86
- Rake::Task['db:rollback'].execute
81
+ task rollback: %i[prepare_schema_migration_table prepare_internal_metadata_table] do
82
+ Rake::Task['db:rollback:clickhouse'].execute
83
+ if File.exist? "#{Rails.root}/db/clickhouse_schema_simple.rb"
84
+ Rake::Task['clickhouse:schema:dump'].execute(simple: true)
85
+ end
87
86
  end
88
87
  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.6.2
4
+ version: 1.0.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: 2023-11-29 00:00:00.000000000 Z
11
+ date: 2024-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: activerecord
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 7.0.0
33
+ version: '7.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 7.0.0
40
+ version: '7.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement