Class: ClickHouse::Client::QueryBuilder

Inherits:
QueryLike
  • Object
show all
Defined in:
lib/click_house/client/query_builder.rb

Constant Summary collapse

VALID_NODES =
[
  Arel::Nodes::In,
  Arel::Nodes::Equality,
  Arel::Nodes::LessThan,
  Arel::Nodes::LessThanOrEqual,
  Arel::Nodes::GreaterThan,
  Arel::Nodes::GreaterThanOrEqual,
  Arel::Nodes::NamedFunction,
  Arel::Nodes::NotIn,
  Arel::Nodes::NotEqual,
  Arel::Nodes::Between,
  Arel::Nodes::And,
  Arel::Nodes::Or,
  Arel::Nodes::Grouping
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from QueryLike

#prepared_placeholders

Constructor Details

#initialize(table_name) ⇒ QueryBuilder

Returns a new instance of QueryBuilder.



27
28
29
30
31
# File 'lib/click_house/client/query_builder.rb', line 27

def initialize(table_name)
  @table = Arel::Table.new(table_name)
  @manager = Arel::SelectManager.new(Arel::Table.engine).from(@table).project(Arel.star)
  @conditions = []
end

Instance Attribute Details

#conditionsObject

Returns the value of attribute conditions.



9
10
11
# File 'lib/click_house/client/query_builder.rb', line 9

def conditions
  @conditions
end

#managerObject

Returns the value of attribute manager.



9
10
11
# File 'lib/click_house/client/query_builder.rb', line 9

def manager
  @manager
end

#tableObject (readonly)

Returns the value of attribute table.



8
9
10
# File 'lib/click_house/client/query_builder.rb', line 8

def table
  @table
end

Instance Method Details

#group(*columns) ⇒ Object



98
99
100
101
102
# File 'lib/click_house/client/query_builder.rb', line 98

def group(*columns)
  deep_clone.tap do |new_instance|
    new_instance.manager.group(*columns)
  end
end

#limit(count) ⇒ Object



104
105
106
107
# File 'lib/click_house/client/query_builder.rb', line 104

def limit(count)
  manager.take(count)
  self
end

#offset(count) ⇒ Object



109
110
111
112
# File 'lib/click_house/client/query_builder.rb', line 109

def offset(count)
  manager.skip(count)
  self
end

#order(field, direction = :asc) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/click_house/client/query_builder.rb', line 88

def order(field, direction = :asc)
  validate_order_direction!(direction)

  deep_clone.tap do |new_instance|
    table_field = new_instance.table[field]
    new_order = direction.to_s.casecmp('desc').zero? ? table_field.desc : table_field.asc
    new_instance.manager.order(new_order)
  end
end

#select(*fields) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/click_house/client/query_builder.rb', line 60

def select(*fields)
  deep_clone.tap do |new_instance|
    existing_fields = new_instance.manager.projections.filter_map do |projection|
      if projection.is_a?(Arel::Attributes::Attribute)
        projection.name.to_s
      elsif projection.to_s == '*'
        nil
      end
    end

    new_projections = (existing_fields + fields).map do |field|
      if field.is_a?(Symbol)
        field.to_s
      else
        field
      end
    end

    new_instance.manager.projections = new_projections.uniq.map do |field|
      if field.is_a?(Arel::Expressions)
        field
      else
        new_instance.table[field.to_s]
      end
    end
  end
end

#to_redacted_sql(bind_index_manager = ClickHouse::Client::BindIndexManager.new) ⇒ Object



121
122
123
# File 'lib/click_house/client/query_builder.rb', line 121

def to_redacted_sql(bind_index_manager = ClickHouse::Client::BindIndexManager.new)
  ClickHouse::Client::Redactor.redact(self, bind_index_manager)
end

#to_sqlObject



114
115
116
117
118
119
# File 'lib/click_house/client/query_builder.rb', line 114

def to_sql
  apply_conditions!

  visitor = Arel::Visitors::ToSql.new(ClickHouse::Client::ArelEngine.new)
  visitor.accept(manager.ast, Arel::Collectors::SQLString.new).value
end

#where(conditions) ⇒ ClickHouse::QueryBuilder

The ‘where` method currently only supports IN and equal to queries along with above listed VALID_NODES. For example, using a range (start_date..end_date) will result in incorrect SQL. If you need to query a range, use greater than and less than conditions with Arel.

Correct usage:

query.where(query.table[:created_at].lteq(Date.today)).to_sql
"SELECT * FROM \"table\" WHERE \"table\".\"created_at\" <= '2023-08-01'"

This also supports array conditions which will result in an IN query.

query.where(entity_id: [1,2,3]).to_sql
"SELECT * FROM \"table\" WHERE \"table\".\"entity_id\" IN (1, 2, 3)"

Range support and more ‘Arel::Nodes` could be considered for future iterations.

Returns:

  • (ClickHouse::QueryBuilder)

    New instance of query builder.



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/click_house/client/query_builder.rb', line 48

def where(conditions)
  validate_condition_type!(conditions)

  deep_clone.tap do |new_instance|
    if conditions.is_a?(Arel::Nodes::Node)
      new_instance.conditions << conditions
    else
      add_conditions_to(new_instance, conditions)
    end
  end
end