clickhouse-activerecord 0.5.15 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6534694860bbb41c21789239e0589406bcbef64bc1750645c68485e77acb7310
4
- data.tar.gz: c6640ccc74004a93bfaa18d93dd1c135411d66f27273eb65848f9843f64fd6d0
3
+ metadata.gz: 823fdbf17f27c65446c01b1599a3c61d9fa9b310d7ce153e9c64a912719e552e
4
+ data.tar.gz: 5b6dd44cdc44b2d1350e0f1c5937cf08051a5ff7a4f73cf56a5dc7567b4be800
5
5
  SHA512:
6
- metadata.gz: f848ad57f80f061aa85a593a90bff65707e8dbe281caf3f4a41914d93a4723351bf7e5ca12bfdc7c8ed2cbed5df3db39472b8d015645875476b68941d7de6111
7
- data.tar.gz: 1592560741198e983d43599ff78b145262e0638951a2825dcaac993e0dcc0195bf85980b5eeff80d973e0573aeaa865d6d6c8acdd7ee2b2b1ba6bb6740e734cf
6
+ metadata.gz: 5a8d48c078f5bf79a50fddf9b29ade13694019e8666c8c071e5b1ee7ab5b16c7e92116b794a82ce3fa6f927f0bd1186e7e87a65ed5f4eda0f1e6ed113f590de4
7
+ data.tar.gz: 2be66ae7ac2cb71b20486685f00552890559f2944777d8557aabb60d2318baa868c3c4bc0cf4be82a97eeee920de0049851771253129022e8fbbb0758190f917
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Clickhouse::Activerecord
2
2
 
3
- A Ruby database ActiveRecord driver for ClickHouse. Support Rails >= 5.2.
4
- Support ClickHouse version from 20.9 LTS.
3
+ A Ruby database ActiveRecord driver for ClickHouse. Support Rails >= 7.1.
4
+ Support ClickHouse version from 22.0 LTS.
5
5
 
6
6
  ## Installation
7
7
 
@@ -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
 
@@ -165,7 +155,7 @@ Structure load from `db/clickhouse_structure.sql` file:
165
155
 
166
156
  ```ruby
167
157
  Action.where(url: 'http://example.com', date: Date.current).where.not(name: nil).order(created_at: :desc).limit(10)
168
- # Clickhouse Action Load (10.3ms) SELECT actions.* FROM actions WHERE actions.date = '2017-11-29' AND actions.url = 'http://example.com' AND (actions.name IS NOT NULL) ORDER BY actions.created_at DESC LIMIT 10
158
+ # Clickhouse Action Load (10.3ms) SELECT actions.* FROM actions WHERE actions.date = '2017-11-29' AND actions.url = 'http://example.com' AND (actions.name IS NOT NULL) ORDER BY actions.created_at DESC LIMIT 10
169
159
  #=> #<ActiveRecord::Relation [#<Action *** >]>
170
160
 
171
161
  Action.create(url: 'http://example.com', date: Date.yesterday)
@@ -175,6 +165,18 @@ Action.create(url: 'http://example.com', date: Date.yesterday)
175
165
  ActionView.maximum(:date)
176
166
  # Clickhouse (10.3ms) SELECT maxMerge(actions.date) FROM actions
177
167
  #=> 'Wed, 29 Nov 2017'
168
+
169
+ Action.where(date: Date.current).final.limit(10)
170
+ # Clickhouse Action Load (10.3ms) SELECT actions.* FROM actions FINAL WHERE actions.date = '2017-11-29' LIMIT 10
171
+ #=> #<ActiveRecord::Relation [#<Action *** >]>
172
+
173
+ Action.settings(optimize_read_in_order: 1).where(date: Date.current).limit(10)
174
+ # Clickhouse Action Load (10.3ms) SELECT actions.* FROM actions FINAL WHERE actions.date = '2017-11-29' LIMIT 10 SETTINGS optimize_read_in_order = 1
175
+ #=> #<ActiveRecord::Relation [#<Action *** >]>
176
+
177
+ User.joins(:actions).using(:group_id)
178
+ # Clickhouse User Load (10.3ms) SELECT users.* FROM users INNER JOIN actions USING group_id
179
+ #=> #<ActiveRecord::Relation [#<Action *** >]>
178
180
  ```
179
181
 
180
182
 
@@ -183,20 +185,20 @@ ActionView.maximum(:date)
183
185
  Integer types are unsigned by default. Specify signed values with `:unsigned =>
184
186
  false`. The default integer is `UInt32`
185
187
 
186
- | Type (bit size) | Range | :limit (byte size) |
187
- | :--- | :----: | ---: |
188
- | Int8 | -128 to 127 | 1 |
189
- | Int16 | -32768 to 32767 | 2 |
190
- | Int32 | -2147483648 to 2,147,483,647 | 3,4 |
191
- | Int64 | -9223372036854775808 to 9223372036854775807] | 5,6,7,8 |
192
- | Int128 | ... | 9 - 15 |
193
- | Int256 | ... | 16+ |
194
- | UInt8 | 0 to 255 | 1 |
195
- | UInt16 | 0 to 65,535 | 2 |
196
- | UInt32 | 0 to 4,294,967,295 | 3,4 |
197
- | UInt64 | 0 to 18446744073709551615 | 5,6,7,8 |
198
- | UInt256 | 0 to ... | 8+ |
199
- | 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 | ... | ... |
200
202
 
201
203
  Example:
202
204
 
@@ -24,9 +24,8 @@ 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', '>= 5.2'
27
+ spec.add_runtime_dependency 'activerecord', '>= 7.1'
28
28
 
29
- spec.add_development_dependency 'bundler', '>= 1.15'
30
29
  spec.add_development_dependency 'rake', '~> 13.0'
31
30
  spec.add_development_dependency 'rspec', '~> 3.4'
32
31
  spec.add_development_dependency 'pry', '~> 0.12'
@@ -125,7 +125,7 @@ module ActiveRecord
125
125
  end
126
126
 
127
127
  def current_database
128
- if ActiveRecord::version >= Gem::Version.new('6')
128
+ if ActiveRecord::version >= Gem::Version.new('6.1')
129
129
  ActiveRecord::Base.connection_db_config.database
130
130
  else
131
131
  ActiveRecord::Base.connection_config[:database]
@@ -10,15 +10,15 @@ 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
- ActiveRecord::Result.new(result['meta'].map { |m| m['name'] }, result['data'])
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
23
23
  raise e
24
24
  rescue StandardError => e
@@ -105,10 +105,20 @@ module ActiveRecord
105
105
  def process_response(res)
106
106
  case res.code.to_i
107
107
  when 200
108
- res.body.presence && JSON.parse(res.body)
108
+ if res.body.to_s.include?("DB::Exception")
109
+ raise ActiveRecord::ActiveRecordError, "Response code: #{res.code}:\n#{res.body}"
110
+ else
111
+ res.body.presence && JSON.parse(res.body)
112
+ end
109
113
  else
110
- raise ActiveRecord::ActiveRecordError,
111
- "Response code: #{res.code}:\n#{res.body}"
114
+ case res.body
115
+ when /DB::Exception:.*\(UNKNOWN_DATABASE\)/
116
+ raise ActiveRecord::NoDatabaseError
117
+ when /DB::Exception:.*\(DATABASE_ALREADY_EXISTS\)/
118
+ raise ActiveRecord::DatabaseAlreadyExists
119
+ else
120
+ raise ActiveRecord::ActiveRecordError, "Response code: #{res.code}:\n#{res.body}"
121
+ end
112
122
  end
113
123
  rescue JSON::ParserError
114
124
  res.body
@@ -127,7 +137,7 @@ module ActiveRecord
127
137
  Clickhouse::TableDefinition.new(self, table_name, **options)
128
138
  end
129
139
 
130
- def new_column_from_field(table_name, field)
140
+ def new_column_from_field(table_name, field, _definitions)
131
141
  sql_type = field[1]
132
142
  type_metadata = fetch_type_metadata(sql_type)
133
143
  default = field[3]
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'clickhouse-activerecord/arel/visitors/to_sql'
4
- require 'clickhouse-activerecord/arel/table'
3
+ require 'arel/visitors/clickhouse'
4
+ require 'arel/nodes/settings'
5
+ require 'arel/nodes/using'
5
6
  require 'clickhouse-activerecord/migration'
6
7
  require 'active_record/connection_adapters/clickhouse/oid/array'
7
8
  require 'active_record/connection_adapters/clickhouse/oid/date'
@@ -62,6 +63,8 @@ module ActiveRecord
62
63
 
63
64
  module ModelSchema
64
65
  module ClassMethods
66
+ delegate :final, :settings, to: :all
67
+
65
68
  def is_view
66
69
  @is_view || false
67
70
  end
@@ -69,10 +72,10 @@ module ActiveRecord
69
72
  def is_view=(value)
70
73
  @is_view = value
71
74
  end
72
-
73
- def arel_table # :nodoc:
74
- @arel_table ||= ClickhouseActiverecord::Arel::Table.new(table_name, type_caster: type_caster)
75
- end
75
+ #
76
+ # def arel_table # :nodoc:
77
+ # @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
78
+ # end
76
79
  end
77
80
  end
78
81
 
@@ -92,7 +95,7 @@ module ActiveRecord
92
95
  datetime: { name: 'DateTime' },
93
96
  datetime64: { name: 'DateTime64' },
94
97
  date: { name: 'Date' },
95
- boolean: { name: 'UInt8' },
98
+ boolean: { name: 'Bool' },
96
99
  uuid: { name: 'UUID' },
97
100
 
98
101
  enum8: { name: 'Enum8' },
@@ -133,7 +136,11 @@ module ActiveRecord
133
136
 
134
137
  # Support SchemaMigration from v5.2.2 to v6+
135
138
  def schema_migration # :nodoc:
136
- ClickhouseActiverecord::SchemaMigration
139
+ ClickhouseActiverecord::SchemaMigration.new(self)
140
+ end
141
+
142
+ def internal_metadata # :nodoc:
143
+ ClickhouseActiverecord::InternalMetadata.new(self)
137
144
  end
138
145
 
139
146
  def migrations_paths
@@ -141,11 +148,11 @@ module ActiveRecord
141
148
  end
142
149
 
143
150
  def migration_context # :nodoc:
144
- ClickhouseActiverecord::MigrationContext.new(migrations_paths, schema_migration)
151
+ ClickhouseActiverecord::MigrationContext.new(migrations_paths, schema_migration, internal_metadata)
145
152
  end
146
153
 
147
154
  def arel_visitor # :nodoc:
148
- ClickhouseActiverecord::Arel::Visitors::ToSql.new(self)
155
+ Arel::Visitors::Clickhouse.new(self)
149
156
  end
150
157
 
151
158
  def native_database_types #:nodoc:
@@ -156,66 +163,73 @@ module ActiveRecord
156
163
  !native_database_types[type].nil?
157
164
  end
158
165
 
159
- def extract_limit(sql_type) # :nodoc:
160
- case sql_type
161
- when /(Nullable)?\(?String\)?/
162
- super('String')
163
- when /(Nullable)?\(?U?Int8\)?/
164
- 1
165
- when /(Nullable)?\(?U?Int16\)?/
166
- 2
167
- when /(Nullable)?\(?U?Int32\)?/
168
- nil
169
- when /(Nullable)?\(?U?Int64\)?/
170
- 8
171
- else
172
- super
166
+ class << self
167
+ def extract_limit(sql_type) # :nodoc:
168
+ case sql_type
169
+ when /(Nullable)?\(?String\)?/
170
+ super('String')
171
+ when /(Nullable)?\(?U?Int8\)?/
172
+ 1
173
+ when /(Nullable)?\(?U?Int16\)?/
174
+ 2
175
+ when /(Nullable)?\(?U?Int32\)?/
176
+ nil
177
+ when /(Nullable)?\(?U?Int64\)?/
178
+ 8
179
+ else
180
+ super
181
+ end
173
182
  end
174
- end
175
183
 
176
- # `extract_scale` and `extract_precision` are the same as in the Rails abstract base class,
177
- # except this permits a space after the comma
184
+ # `extract_scale` and `extract_precision` are the same as in the Rails abstract base class,
185
+ # except this permits a space after the comma
178
186
 
179
- def extract_scale(sql_type)
180
- case sql_type
181
- when /\((\d+)\)/ then 0
182
- when /\((\d+)(,\s?(\d+))\)/ then $3.to_i
187
+ def extract_scale(sql_type)
188
+ case sql_type
189
+ when /\((\d+)\)/ then 0
190
+ when /\((\d+)(,\s?(\d+))\)/ then $3.to_i
191
+ end
192
+ end
193
+
194
+ def extract_precision(sql_type)
195
+ $1.to_i if sql_type =~ /\((\d+)(,\s?\d+)?\)/
183
196
  end
184
- end
185
197
 
186
- def extract_precision(sql_type)
187
- $1.to_i if sql_type =~ /\((\d+)(,\s?\d+)?\)/
188
- end
189
-
190
- def initialize_type_map(m) # :nodoc:
191
- super
192
- register_class_with_limit m, %r(String), Type::String
193
- register_class_with_limit m, 'Date', Clickhouse::OID::Date
194
- register_class_with_precision m, %r(datetime)i, Clickhouse::OID::DateTime
195
-
196
- register_class_with_limit m, %r(Int8), Type::Integer
197
- register_class_with_limit m, %r(Int16), Type::Integer
198
- register_class_with_limit m, %r(Int32), Type::Integer
199
- register_class_with_limit m, %r(Int64), Type::Integer
200
- register_class_with_limit m, %r(Int128), Type::Integer
201
- register_class_with_limit m, %r(Int256), Type::Integer
202
-
203
- register_class_with_limit m, %r(UInt8), Type::UnsignedInteger
204
- register_class_with_limit m, %r(UInt16), Type::UnsignedInteger
205
- register_class_with_limit m, %r(UInt32), Type::UnsignedInteger
206
- register_class_with_limit m, %r(UInt64), Type::UnsignedInteger
207
- #register_class_with_limit m, %r(UInt128), Type::UnsignedInteger #not implemnted in clickhouse
208
- register_class_with_limit m, %r(UInt256), Type::UnsignedInteger
209
- # register_class_with_limit m, %r(Array), Clickhouse::OID::Array
210
- m.register_type(%r(Array)) do |sql_type|
211
- Clickhouse::OID::Array.new(sql_type)
198
+ def initialize_type_map(m) # :nodoc:
199
+ super
200
+ register_class_with_limit m, %r(String), Type::String
201
+ register_class_with_limit m, 'Date', Clickhouse::OID::Date
202
+ register_class_with_precision m, %r(datetime)i, Clickhouse::OID::DateTime
203
+
204
+ register_class_with_limit m, %r(Int8), Type::Integer
205
+ register_class_with_limit m, %r(Int16), Type::Integer
206
+ register_class_with_limit m, %r(Int32), Type::Integer
207
+ register_class_with_limit m, %r(Int64), Type::Integer
208
+ register_class_with_limit m, %r(Int128), Type::Integer
209
+ register_class_with_limit m, %r(Int256), Type::Integer
210
+
211
+ register_class_with_limit m, %r(UInt8), Type::UnsignedInteger
212
+ register_class_with_limit m, %r(UInt16), Type::UnsignedInteger
213
+ register_class_with_limit m, %r(UInt32), Type::UnsignedInteger
214
+ register_class_with_limit m, %r(UInt64), Type::UnsignedInteger
215
+ #register_class_with_limit m, %r(UInt128), Type::UnsignedInteger #not implemnted in clickhouse
216
+ register_class_with_limit m, %r(UInt256), Type::UnsignedInteger
217
+ # register_class_with_limit m, %r(Array), Clickhouse::OID::Array
218
+ m.register_type(%r(Array)) do |sql_type|
219
+ Clickhouse::OID::Array.new(sql_type)
220
+ end
212
221
  end
213
222
  end
214
223
 
215
- def _quote(value)
224
+ # In Rails 7 used constant TYPE_MAP, we need redefine method
225
+ def type_map
226
+ @type_map ||= Type::TypeMap.new.tap { |m| ClickhouseAdapter.initialize_type_map(m) }
227
+ end
228
+
229
+ def quote(value)
216
230
  case value
217
231
  when Array
218
- '[' + value.map { |v| _quote(v) }.join(', ') + ']'
232
+ '[' + value.map { |v| quote(v) }.join(', ') + ']'
219
233
  else
220
234
  super
221
235
  end
@@ -331,7 +345,13 @@ module ActiveRecord
331
345
  end
332
346
 
333
347
  def drop_table(table_name, options = {}) # :nodoc:
334
- do_execute apply_cluster "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}"
348
+ query = "DROP TABLE"
349
+ query = "#{query} IF EXISTS " if options[:if_exists]
350
+ query = "#{query} #{quote_table_name(table_name)}"
351
+ query = apply_cluster(query)
352
+ query = "#{query} SYNC" if options[:sync]
353
+
354
+ do_execute(query)
335
355
 
336
356
  if options[:with_distributed]
337
357
  distributed_table_name = options.delete(:with_distributed)
@@ -0,0 +1,11 @@
1
+ module Arel # :nodoc: all
2
+ module Nodes
3
+ class Settings < Arel::Nodes::Unary
4
+ def initialize(expr)
5
+ raise ArgumentError, 'Settings must be a Hash' unless expr.is_a?(Hash)
6
+
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module Arel # :nodoc: all
2
+ module Nodes
3
+ class Using < Arel::Nodes::Unary
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,60 @@
1
+ require 'arel/visitors/to_sql'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class Clickhouse < ::Arel::Visitors::ToSql
6
+
7
+ def aggregate(name, o, collector)
8
+ # replacing function name for materialized view
9
+ if o.expressions.first && o.expressions.first != '*' && !o.expressions.first.is_a?(String) && o.expressions.first.relation&.is_view
10
+ super("#{name.downcase}Merge", o, collector)
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def visit_Arel_Table o, collector
17
+ collector = super
18
+ collector << ' FINAL' if o.final
19
+ collector
20
+ end
21
+
22
+ def visit_Arel_Nodes_SelectOptions(o, collector)
23
+ maybe_visit o.settings, super
24
+ end
25
+
26
+ def visit_Arel_Nodes_Settings(o, collector)
27
+ return collector if o.expr.empty?
28
+
29
+ collector << "SETTINGS "
30
+ o.expr.each_with_index do |(key, value), i|
31
+ collector << ", " if i > 0
32
+ collector << key.to_s.gsub(/\W+/, "")
33
+ collector << " = "
34
+ collector << sanitize_as_setting_value(value)
35
+ end
36
+ collector
37
+ end
38
+
39
+ def visit_Arel_Nodes_Using o, collector
40
+ collector << "USING "
41
+ visit o.expr, collector
42
+ collector
43
+ end
44
+
45
+ def sanitize_as_setting_value(value)
46
+ if value == :default
47
+ 'DEFAULT'
48
+ else
49
+ quote(value)
50
+ end
51
+ end
52
+
53
+ def sanitize_as_setting_name(value)
54
+ return value if Arel::Nodes::SqlLiteral === value
55
+ @connection.sanitize_as_setting_name(value)
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -3,124 +3,101 @@ 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
- from("#{table_name} 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
38
- def create_table
39
- return if table_exists?
40
-
41
- key_options = connection.internal_string_options_for_primary_key
42
- table_options = {
43
- id: false,
44
- options: connection.adapter_name.downcase == 'clickhouse' ? 'MergeTree() PARTITION BY toDate(created_at) ORDER BY (created_at)' : '',
45
- if_not_exists: true
46
- }
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'}"
53
- end
54
-
55
- connection.create_table(table_name + distributed_suffix.to_s, **table_options) do |t|
56
- t.string :key, **key_options
57
- t.string :value
58
- t.timestamps
59
- end
60
- end
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)])
35
+
36
+ connection.select_values(sm, "#{self.class} Load")
37
+ end
38
+
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)
61
43
  end
62
44
  end
63
45
 
64
- class MigrationContext < ::ActiveRecord::MigrationContext #:nodoc:
65
- attr_reader :migrations_paths, :schema_migration
46
+ class InternalMetadata < ::ActiveRecord::InternalMetadata
66
47
 
67
- def initialize(migrations_paths, schema_migration)
68
- @migrations_paths = migrations_paths
69
- @schema_migration = schema_migration
70
- end
48
+ def create_table
49
+ return if table_exists? || !enabled?
71
50
 
72
- def up(target_version = nil)
73
- selected_migrations = if block_given?
74
- migrations.select { |m| yield m }
75
- else
76
- migrations
77
- end
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) || {}
78
58
 
79
- ClickhouseActiverecord::Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
80
- end
59
+ if full_config[:distributed_service_tables]
60
+ table_options.merge!(with_distributed: table_name, sharding_key: 'cityHash64(created_at)')
81
61
 
82
- def down(target_version = nil)
83
- selected_migrations = if block_given?
84
- migrations.select { |m| yield m }
85
- else
86
- migrations
62
+ distributed_suffix = "_#{full_config[:distributed_service_tables_suffix] || 'distributed'}"
87
63
  end
88
64
 
89
- ClickhouseActiverecord::Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
90
- end
91
-
92
- def get_all_versions
93
- if schema_migration.table_exists?
94
- schema_migration.all_versions.map(&:to_i)
95
- else
96
- []
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
97
69
  end
98
70
  end
99
71
 
100
- end
101
-
102
- class Migrator < ::ActiveRecord::Migrator
72
+ private
103
73
 
104
- def initialize(direction, migrations, schema_migration, target_version = nil)
105
- @direction = direction
106
- @target_version = target_version
107
- @migrated_versions = nil
108
- @migrations = migrations
109
- @schema_migration = schema_migration
74
+ def update_entry(key, new_value)
75
+ create_entry(key, new_value)
76
+ end
110
77
 
111
- validate(@migrations)
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
112
86
 
113
- @schema_migration.create_table
114
- ClickhouseActiverecord::InternalMetadata.create_table
87
+ connection.select_all(sm, "#{self.class} Load").first
115
88
  end
89
+ end
90
+
91
+ class MigrationContext < ::ActiveRecord::MigrationContext #:nodoc:
116
92
 
117
- def record_version_state_after_migrating(version)
118
- if down?
119
- migrated.delete(version)
120
- @schema_migration.create!(version: version.to_s, active: 0)
93
+ def get_all_versions
94
+ if schema_migration.table_exists?
95
+ schema_migration.versions.map(&:to_i)
121
96
  else
122
- super
97
+ []
123
98
  end
124
99
  end
100
+
125
101
  end
102
+
126
103
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  module ClickhouseActiverecord
4
4
  class Tasks
5
-
6
5
  delegate :connection, :establish_connection, :clear_active_connections!, to: ActiveRecord::Base
7
6
 
8
7
  def initialize(configuration)
@@ -11,7 +10,7 @@ module ClickhouseActiverecord
11
10
 
12
11
  def create
13
12
  establish_master_connection
14
- connection.create_database @configuration["database"]
13
+ connection.create_database @configuration['database']
15
14
  rescue ActiveRecord::StatementInvalid => e
16
15
  if e.cause.to_s.include?('already exists')
17
16
  raise ActiveRecord::DatabaseAlreadyExists
@@ -22,7 +21,7 @@ module ClickhouseActiverecord
22
21
 
23
22
  def drop
24
23
  establish_master_connection
25
- connection.drop_database @configuration["database"]
24
+ connection.drop_database @configuration['database']
26
25
  end
27
26
 
28
27
  def purge
@@ -1,3 +1,3 @@
1
1
  module ClickhouseActiverecord
2
- VERSION = '0.5.15'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -4,6 +4,10 @@ require 'active_record/connection_adapters/clickhouse_adapter'
4
4
 
5
5
  require 'core_extensions/active_record/relation'
6
6
 
7
+ require 'core_extensions/arel/nodes/select_statement'
8
+ require 'core_extensions/arel/select_manager'
9
+ require 'core_extensions/arel/table'
10
+
7
11
  require_relative '../core_extensions/active_record/migration/command_recorder'
8
12
  ActiveRecord::Migration::CommandRecorder.include CoreExtensions::ActiveRecord::Migration::CommandRecorder
9
13
 
@@ -18,5 +22,9 @@ end
18
22
  module ClickhouseActiverecord
19
23
  def self.load
20
24
  ActiveRecord::Relation.prepend(CoreExtensions::ActiveRecord::Relation)
25
+
26
+ Arel::Nodes::SelectStatement.prepend(CoreExtensions::Arel::Nodes::SelectStatement)
27
+ Arel::SelectManager.prepend(CoreExtensions::Arel::SelectManager)
28
+ Arel::Table.prepend(CoreExtensions::Arel::Table)
21
29
  end
22
30
  end
@@ -10,6 +10,80 @@ module CoreExtensions
10
10
  self.order_values = (column_names & %w[date created_at]).map { |c| arel_table[c].desc }
11
11
  self
12
12
  end
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.
21
+ # @param [Hash] opts
22
+ def settings(**opts)
23
+ spawn.settings!(**opts)
24
+ end
25
+
26
+ # @param [Hash] opts
27
+ def settings!(**opts)
28
+ assert_mutability!
29
+ check_command('SETTINGS')
30
+ @values[:settings] = (@values[:settings] || {}).merge opts
31
+ self
32
+ end
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.
41
+ # @param [Boolean] final
42
+ def final(final = true)
43
+ spawn.final!(final)
44
+ end
45
+
46
+ # @param [Boolean] final
47
+ def final!(final = true)
48
+ assert_mutability!
49
+ check_command('FINAL')
50
+ @table = @table.dup
51
+ @table.final = final
52
+ self
53
+ end
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
+
73
+ private
74
+
75
+ def check_command(cmd)
76
+ raise ::ActiveRecord::ActiveRecordError, cmd + ' is a ClickHouse specific query clause' unless connection.is_a?(::ActiveRecord::ConnectionAdapters::ClickhouseAdapter)
77
+ end
78
+
79
+ def build_arel(aliases = nil)
80
+ arel = super
81
+
82
+ arel.settings(@values[:settings]) if @values[:settings].present?
83
+ arel.using(@values[:using]) if @values[:using].present?
84
+
85
+ arel
86
+ end
13
87
  end
14
88
  end
15
89
  end
@@ -0,0 +1,18 @@
1
+ module CoreExtensions
2
+ module Arel # :nodoc: all
3
+ module Nodes
4
+ module SelectStatement
5
+ attr_accessor :settings
6
+
7
+ def initialize(relation = nil)
8
+ super
9
+ @settings = nil
10
+ end
11
+
12
+ def eql?(other)
13
+ super && settings == other.settings
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ module CoreExtensions
2
+ module Arel
3
+ module SelectManager
4
+
5
+ # @param [Hash] values
6
+ def settings(values)
7
+ @ast.settings = ::Arel::Nodes::Settings.new(values)
8
+ self
9
+ end
10
+
11
+ def using(*exprs)
12
+ @ctx.source.right.last.right = ::Arel::Nodes::Using.new(::Arel.sql(exprs.join(',')))
13
+ self
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,6 +1,8 @@
1
- module ClickhouseActiverecord
1
+ module CoreExtensions
2
2
  module Arel
3
- class Table < ::Arel::Table
3
+ module Table
4
+ attr_accessor :final
5
+
4
6
  def is_view
5
7
  type_caster.is_view
6
8
  end
@@ -1,86 +1,87 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :clickhouse do
4
-
5
4
  task prepare_schema_migration_table: :environment do
6
- ClickhouseActiverecord::SchemaMigration.create_table unless ENV['simple'] || ARGV.map{|a| a.include?('--simple') ? true : nil}.compact.any?
5
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
6
+ connection.schema_migration.create_table unless ENV['simple'] || ARGV.any? { |a| a.include?('--simple') }
7
7
  end
8
8
 
9
9
  task prepare_internal_metadata_table: :environment do
10
- ClickhouseActiverecord::InternalMetadata.create_table unless ENV['simple'] || ARGV.map{|a| a.include?('--simple') ? true : nil}.compact.any?
11
- end
12
-
13
- task load_config: :environment do
14
- ENV['SCHEMA'] = "db/clickhouse_schema.rb"
15
- ActiveRecord::Migrator.migrations_paths = ["db/migrate_clickhouse"]
16
- ActiveRecord::Base.establish_connection(:"#{Rails.env}_clickhouse")
10
+ connection = ActiveRecord::Tasks::DatabaseTasks.migration_connection
11
+ connection.internal_metadata.create_table unless ENV['simple'] || ARGV.any? { |a| a.include?('--simple') }
17
12
  end
18
13
 
19
14
  namespace :schema do
20
-
21
- # todo not testing
15
+ # TODO: not testing
22
16
  desc 'Load database schema'
23
- task load: [:load_config, :prepare_internal_metadata_table] do |t, args|
24
- simple = ENV['simple'] || ARGV.map{|a| a.include?('--simple') ? true : nil}.compact.any? ? '_simple' : nil
17
+ task load: %i[load_config prepare_internal_metadata_table] do
18
+ simple = ENV['simple'] || ARGV.any? { |a| a.include?('--simple') } ? '_simple' : nil
25
19
  ClickhouseActiverecord::SchemaMigration.drop_table
26
- load("#{Rails.root}/db/clickhouse_schema#{simple}.rb")
20
+ load(Rails.root.join("db/clickhouse_schema#{simple}.rb"))
27
21
  end
28
22
 
29
23
  desc 'Dump database schema'
30
- task dump: :environment do |t, args|
31
- simple = ENV['simple'] || args[:simple] || ARGV.map{|a| a.include?('--simple') ? true : nil}.compact.any? ? '_simple' : nil
32
- filename = "#{Rails.root}/db/clickhouse_schema#{simple}.rb"
24
+ task dump: :environment do |_, args|
25
+ simple = ENV['simple'] || args[:simple] || ARGV.any? { |a| a.include?('--simple') } ? '_simple' : nil
26
+ filename = Rails.root.join("db/clickhouse_schema#{simple}.rb")
33
27
  File.open(filename, 'w:utf-8') do |file|
34
- ActiveRecord::Base.establish_connection(:"#{Rails.env}_clickhouse")
35
- ClickhouseActiverecord::SchemaDumper.dump(ActiveRecord::Base.connection, file, ActiveRecord::Base, !!simple)
28
+ ActiveRecord::Base.establish_connection(:clickhouse)
29
+ ClickhouseActiverecord::SchemaDumper.dump(ActiveRecord::Base.connection, file, ActiveRecord::Base, simple.present?)
36
30
  end
37
31
  end
38
-
39
32
  end
40
33
 
41
34
  namespace :structure do
42
35
  desc 'Load database structure'
43
- task load: [:load_config, 'db:check_protected_environments'] do
44
- ClickhouseActiverecord::Tasks.new(ActiveRecord::Base.configurations["#{Rails.env}_clickhouse"]).structure_load("#{Rails.root}/db/clickhouse_structure.sql")
36
+ task load: ['db:check_protected_environments'] do
37
+ config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
38
+ ClickhouseActiverecord::Tasks.new(config).structure_load(Rails.root.join('db/clickhouse_structure.sql'))
45
39
  end
46
40
 
47
41
  desc 'Dump database structure'
48
- task dump: [:load_config, 'db:check_protected_environments'] do
49
- ClickhouseActiverecord::Tasks.new(ActiveRecord::Base.configurations["#{Rails.env}_clickhouse"]).structure_dump("#{Rails.root}/db/clickhouse_structure.sql")
42
+ task dump: ['db:check_protected_environments'] do
43
+ config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
44
+ ClickhouseActiverecord::Tasks.new(config).structure_dump(Rails.root.join('db/clickhouse_structure.sql'))
50
45
  end
51
46
  end
52
47
 
53
48
  desc 'Creates the database from DATABASE_URL or config/database.yml'
54
- task create: [:load_config] do
55
- ActiveRecord::Tasks::DatabaseTasks.create(ActiveRecord::Base.configurations["#{Rails.env}_clickhouse"])
49
+ task create: [] do
50
+ config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
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
60
- ActiveRecord::Tasks::DatabaseTasks.drop(ActiveRecord::Base.configurations["#{Rails.env}_clickhouse"])
55
+ task drop: ['db:check_protected_environments'] do
56
+ config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
57
+ ActiveRecord::Tasks::DatabaseTasks.drop(config)
61
58
  end
62
59
 
63
60
  desc 'Empty the database from DATABASE_URL or config/database.yml'
64
- task purge: [:load_config, 'db:check_protected_environments'] do
65
- ActiveRecord::Tasks::DatabaseTasks.purge(ActiveRecord::Base.configurations["#{Rails.env}_clickhouse"])
61
+ task purge: ['db:check_protected_environments'] do
62
+ config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: 'clickhouse')
63
+ ActiveRecord::Tasks::DatabaseTasks.purge(config)
66
64
  end
67
65
 
68
66
  # desc 'Resets your database using your migrations for the current environment'
69
- task reset: :load_config do
67
+ task :reset do
70
68
  Rake::Task['clickhouse:purge'].execute
71
69
  Rake::Task['clickhouse:migrate'].execute
72
70
  end
73
71
 
74
72
  desc 'Migrate the clickhouse database'
75
- task migrate: [:load_config, :prepare_schema_migration_table, :prepare_internal_metadata_table] do
76
- Rake::Task['db:migrate'].execute
73
+ task migrate: %i[prepare_schema_migration_table prepare_internal_metadata_table] do
74
+ Rake::Task['db:migrate:clickhouse'].execute
77
75
  if File.exists? "#{Rails.root}/db/clickhouse_schema_simple.rb"
78
76
  Rake::Task['clickhouse:schema:dump'].execute(simple: true)
79
77
  end
80
78
  end
81
79
 
82
80
  desc 'Rollback the clickhouse database'
83
- task rollback: [:load_config, :prepare_schema_migration_table, :prepare_internal_metadata_table] do
84
- 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.exists? "#{Rails.root}/db/clickhouse_schema_simple.rb"
84
+ Rake::Task['clickhouse:schema:dump'].execute(simple: true)
85
+ end
85
86
  end
86
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.5.15
4
+ version: 1.0.0
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-07-21 00:00:00.000000000 Z
11
+ date: 2023-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,28 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '5.2'
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: '5.2'
41
- - !ruby/object:Gem::Dependency
42
- name: bundler
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '1.15'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '1.15'
40
+ version: '7.1'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rake
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -121,9 +107,10 @@ files:
121
107
  - lib/active_record/connection_adapters/clickhouse/schema_definitions.rb
122
108
  - lib/active_record/connection_adapters/clickhouse/schema_statements.rb
123
109
  - lib/active_record/connection_adapters/clickhouse_adapter.rb
110
+ - lib/arel/nodes/settings.rb
111
+ - lib/arel/nodes/using.rb
112
+ - lib/arel/visitors/clickhouse.rb
124
113
  - lib/clickhouse-activerecord.rb
125
- - lib/clickhouse-activerecord/arel/table.rb
126
- - lib/clickhouse-activerecord/arel/visitors/to_sql.rb
127
114
  - lib/clickhouse-activerecord/migration.rb
128
115
  - lib/clickhouse-activerecord/railtie.rb
129
116
  - lib/clickhouse-activerecord/schema.rb
@@ -131,6 +118,9 @@ files:
131
118
  - lib/clickhouse-activerecord/tasks.rb
132
119
  - lib/clickhouse-activerecord/version.rb
133
120
  - lib/core_extensions/active_record/relation.rb
121
+ - lib/core_extensions/arel/nodes/select_statement.rb
122
+ - lib/core_extensions/arel/select_manager.rb
123
+ - lib/core_extensions/arel/table.rb
134
124
  - lib/generators/clickhouse_migration_generator.rb
135
125
  - lib/tasks/clickhouse.rake
136
126
  homepage: https://github.com/pnixx/clickhouse-activerecord
@@ -152,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
152
142
  - !ruby/object:Gem::Version
153
143
  version: '0'
154
144
  requirements: []
155
- rubygems_version: 3.0.4
145
+ rubygems_version: 3.1.6
156
146
  signing_key:
157
147
  specification_version: 4
158
148
  summary: ClickHouse ActiveRecord
@@ -1,20 +0,0 @@
1
- require 'arel/visitors/to_sql'
2
-
3
- module ClickhouseActiverecord
4
- module Arel
5
- module Visitors
6
- class ToSql < ::Arel::Visitors::ToSql
7
-
8
- def aggregate(name, o, collector)
9
- # replacing function name for materialized view
10
- if o.expressions.first && o.expressions.first != '*' && !o.expressions.first.is_a?(String) && o.expressions.first.relation&.is_view
11
- super("#{name.downcase}Merge", o, collector)
12
- else
13
- super
14
- end
15
- end
16
-
17
- end
18
- end
19
- end
20
- end