Module: CoreExtensions::ActiveRecord::Relation

Defined in:
lib/core_extensions/active_record/relation.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.prepended(base) ⇒ Object



5
6
7
# File 'lib/core_extensions/active_record/relation.rb', line 5

def self.prepended(base)
  base::VALID_UNSCOPING_VALUES << :final << :settings
end

Instance Method Details

#final(final = true) ⇒ Object

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. For example:

users = User.final.all
# SELECT users.* FROM users FINAL

An ActiveRecord::ActiveRecordError will be raised if database not ClickHouse.

Parameters:

  • final (Boolean) (defaults to: true)


69
70
71
# File 'lib/core_extensions/active_record/relation.rb', line 69

def final(final = true)
  spawn.final!(final)
end

#final!(final = true) ⇒ Object

Parameters:

  • final (Boolean) (defaults to: true)


74
75
76
77
78
# File 'lib/core_extensions/active_record/relation.rb', line 74

def final!(final = true)
  check_command!('FINAL')
  self.final_value = final
  self
end

#final_valueObject



89
90
91
# File 'lib/core_extensions/active_record/relation.rb', line 89

def final_value
  @values.fetch(:final, nil)
end

#final_value=(value) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/core_extensions/active_record/relation.rb', line 80

def final_value=(value)
  if ::ActiveRecord::version >= Gem::Version.new('7.2')
    assert_modifiable!
  else
    assert_mutability!
  end
  @values[:final] = value
end

#group_by_grouping_sets(*grouping_sets) ⇒ Object

GROUPING SETS allows you to specify multiple groupings in the GROUP BY clause. Whereas GROUP BY CUBE generates all possible groupings, GROUP BY GROUPING SETS generates only the specified groupings. For example:

users = User.group_by_grouping_sets([], [:name], [:name, :age]).select(:name, :age, 'count(*)')
# SELECT name, age, count(*) FROM users GROUP BY GROUPING SETS ( (), (name), (name, age) )

which is generally equivalent to:

# SELECT NULL, NULL, count(*) FROM users
# UNION ALL
# SELECT name, NULL, count(*) FROM users GROUP BY name
# UNION ALL
# SELECT name, age, count(*) FROM users GROUP BY name, age

Raises ArgumentError if no grouping sets are specified are provided.

Raises:

  • (ArgumentError)


108
109
110
111
112
# File 'lib/core_extensions/active_record/relation.rb', line 108

def group_by_grouping_sets(*grouping_sets)
  raise ArgumentError, 'The method .group_by_grouping_sets() must contain arguments.' if grouping_sets.blank?

  spawn.group_by_grouping_sets!(*grouping_sets)
end

#group_by_grouping_sets!(*grouping_sets) ⇒ Object

:nodoc:



114
115
116
117
118
# File 'lib/core_extensions/active_record/relation.rb', line 114

def group_by_grouping_sets!(*grouping_sets) # :nodoc:
  grouping_sets = grouping_sets.map { |set| arel_columns(set) }
  self.group_values += [::Arel::Nodes::GroupingSets.new(grouping_sets)]
  self
end

#limit_by(*opts) ⇒ Object

The LIMIT BY clause permit to improve deduplication based on a unique key, it has better performances than the GROUP BY clause

users = User.limit_by(1, id)
# SELECT users.* FROM users LIMIT 1 BY id

An ActiveRecord::ActiveRecordError will be reaised if database is not Clickhouse.

Parameters:

  • opts (Array)


162
163
164
# File 'lib/core_extensions/active_record/relation.rb', line 162

def limit_by(*opts)
  spawn.limit_by!(*opts)
end

#limit_by!(*opts) ⇒ Object

Parameters:

  • opts (Array)


167
168
169
170
# File 'lib/core_extensions/active_record/relation.rb', line 167

def limit_by!(*opts)
  @values[:limit_by] = *opts
  self
end

#reverse_order!Object



9
10
11
12
13
14
15
16
17
# File 'lib/core_extensions/active_record/relation.rb', line 9

def reverse_order!
  return super unless connection.is_a?(::ActiveRecord::ConnectionAdapters::ClickhouseAdapter)

  orders = order_values.uniq.reject(&:blank?)
  return super unless orders.empty? && !primary_key

  self.order_values = (column_names & %w[date created_at]).map { |c| arel_table[c].desc }
  self
end

#settings(**opts) ⇒ Object

Specify settings to be used for this single query. For example:

users = User.settings(use_skip_indexes: true).where(name: 'John')
# SELECT "users".* FROM "users"
# WHERE "users"."name" = 'John'
# SETTINGS use_skip_indexes = 1


36
37
38
# File 'lib/core_extensions/active_record/relation.rb', line 36

def settings(**opts)
  spawn.settings!(**opts)
end

#settings!(**opts) ⇒ Object

Parameters:

  • opts (Hash)


41
42
43
44
45
# File 'lib/core_extensions/active_record/relation.rb', line 41

def settings!(**opts)
  check_command!('SETTINGS')
  self.settings_values = settings_values.merge opts
  self
end

#settings_valuesObject



47
48
49
# File 'lib/core_extensions/active_record/relation.rb', line 47

def settings_values
  @values.fetch(:settings, ::ActiveRecord::QueryMethods::FROZEN_EMPTY_HASH)
end

#settings_values=(value) ⇒ Object



51
52
53
54
55
56
57
58
# File 'lib/core_extensions/active_record/relation.rb', line 51

def settings_values=(value)
  if ::ActiveRecord::version >= Gem::Version.new('7.2')
    assert_modifiable!
  else
    assert_mutability!
  end
  @values[:settings] = value
end

#using(*opts) ⇒ Object

The USING clause specifies one or more columns to join, which establishes the equality of these columns. For example:

users = User.joins(:joins).using(:event_name, :date)
# SELECT users.* FROM users INNER JOIN joins USING event_name,date

An ActiveRecord::ActiveRecordError will be raised if database not ClickHouse.

Parameters:

  • opts (Array)


127
128
129
# File 'lib/core_extensions/active_record/relation.rb', line 127

def using(*opts)
  spawn.using!(*opts)
end

#using!(*opts) ⇒ Object

Parameters:

  • opts (Array)


132
133
134
135
# File 'lib/core_extensions/active_record/relation.rb', line 132

def using!(*opts)
  @values[:using] = opts
  self
end

#window(name, **opts) ⇒ Object

Windows functions let you perform calculations across a set of rows that are related to the current row. For example:

users = User.window('x', order: 'date', partition: 'name', rows: 'UNBOUNDED PRECEDING').select('sum(value) OVER x')
# SELECT sum(value) OVER x FROM users WINDOW x AS (PARTITION BY name ORDER BY date ROWS UNBOUNDED PRECEDING)

Parameters:

  • name (String)
  • opts (Hash)


144
145
146
# File 'lib/core_extensions/active_record/relation.rb', line 144

def window(name, **opts)
  spawn.window!(name, **opts)
end

#window!(name, **opts) ⇒ Object



148
149
150
151
152
# File 'lib/core_extensions/active_record/relation.rb', line 148

def window!(name, **opts)
  @values[:windows] = [] unless @values[:windows]
  @values[:windows] << [name, opts]
  self
end