class CQL::Query

Overview

The Query class is responsible for building SQL queries in a structured manner. It holds various components like selected columns, tables, conditions, and more. It provides methods to execute the query and return results.

Example Creating a new query

schema = CQL::Schema.new

CQL::Query.new(schema)
query.select(:name, :age).from(:users).where(name: "John").all(User)
=> [{"name" => "John", "age" => 30}]

Example Executing a query and iterating over results

schema = CQL::Schema.new
query = CQL::Query.new(schema)
query.select(:name, :age).from(:users).where(name: "John").each(User) do |user|
  puts user.name
end

=> John

Defined in:

query.cr

Constructors

Instance Method Summary

Constructor Detail

def self.new(schema : Schema) #

Initializes the Query object with the provided schema.

  • @param schema [Schema] The schema object to use for the query
  • @return [Query] The query object

Example Creating a new query

schema = CQL::Schema.new
query = CQL::Query.new(schema)

=> #<CQL::Query:0x00007f8b1b0b3b00>

[View source]

Instance Method Detail

def aggr_columns : Array(Expression::Aggregate) #

[View source]
def all(as as_kind) #

Executes the query and returns all records.

  • @param as [Type] The type to cast the results to
  • @return [Array(Type)] The results of the query

Example

schema = CQL::Schema.new
query = CQL::Query.new(schema)
query.select(:name, :age).from(:users).all(User)

=> [<User:0x00007f8b1b0b3b00 @name="John", @age=30>, <User:0x00007f8b1b0b3b00 @name="Jane", @age=25>]

[View source]
def all!(as as_kind) #
  • @param as [Type] The type to cast the results to
  • @return [Array(Type)] The results of the query

Example

schema = CQL::Schema.new
query = CQL::Query.new(schema)
query.select(:name, :age).from(:users).all!(User)

=> [<User:0x00007f8b1b0b3b00 @name="John", @age=30>, <User:0x00007f8b1b0b3b00 @name="Jane", @age=25>]

[View source]
def avg(column : Symbol) #

Adds an AVG aggregate function to the query.

  • @param column [Symbol] The column to average
  • @return [Query] The query object

Example

query.avg(:rating)
=> "SELECT AVG(rating) FROM users"

[View source]
def build #

Builds the final query expression.

  • @return [Expression::Query] The query expression

Example

query.build
=> #<Expression::Query:0x00007f8b1b0b3b00>

[View source]
def columns : Array(CQL::BaseColumn) #

[View source]
def count(column : Symbol = :*) #

Adds a COUNT aggregate function to the query.

  • @param column [Symbol] The column to count
  • @return [Query] The query object

Example

query.count(:id)
=> "SELECT COUNT(id) FROM users"

[View source]
def distinct #

Sets the distinct flag to true.

  • @return [Query] The query object

Example

query.from(:users).distinct
=> "SELECT DISTINCT * FROM users"

[View source]
def distinct=(distinct : Bool) #

[View source]
def distinct? : Bool #

[View source]
def each(as as_kind, &) #

Iterates over each result and yields it to the provided block. Example:

query.each(User) do |user|
  puts user.name
end

=> John

[View source]
def first(as as_kind) #

Executes the query and returns the first record.

  • @param as [Type] The type to cast the result to
  • @return [Type] The first result of the query

Example

schema = CQL::Schema.new
query = CQL::Query.new(schema)
query.select(:name, :age).from(:users).first(User)

=> <User:0x00007f8b1b0b3b00 @name="John", @age=30>

[View source]
def first!(as as_kind) #
  • @param as [Type] The type to cast the result to
  • @return [Type] The first result of the query

Example

schema = CQL::Schema.new
query = CQL::Query.new(schema)
query.select(:name, :age).from(:users).first!(User)

=> <User:0x00007f8b1b0b3b00 @name="John", @age=30>

[View source]
def from(*tbls_or_aliases : Symbol | Hash(Symbol, Symbol)) #

Specifies the tables to select from.

  • @param tbls [Symbol*] The tables to select from
  • @return [Query] The query object

Example

query.from(:users, :orders)
=> "SELECT * FROM users, orders"

[View source]
def from(**tables_with_aliases) #

Accept keyword arguments for table/alias pairs


[View source]
def get(as as_kind) #

Executes the query and returns a scalar value.

  • @param as [Type] The type to cast the result to
  • @return [Type] The scalar result of the query Example: query.get(Int64)
schema = CQL::Schema.new
query = CQL::Query.new(schema)
query.select(:count).from(:users).get(Int64)

=> 10

[View source]
def group(*columns : Symbol | String) #

Specifies the columns to group by. Handles qualified columns or aliases.

  • @param columns [Symbol* | String*] The columns to group by
  • @return [Query] The query object

[View source]
def group_by : Array(CQL::BaseColumn) #

[View source]
def having : Expression::Having | Nil #

[View source]
def having(&) #

Adds a HAVING condition to the grouped results. The block uses a HavingBuilder which needs alias awareness.

  • @yield [HavingBuilder] Block to build the condition.
  • @return [Query] The query object

[View source]
def having=(having : Expression::Having | Nil) #

[View source]
def inner(table_or_alias : Symbol | Hash(Symbol, Symbol), on : Hash(CQL::BaseColumn, CQL::BaseColumn | DB::Any)) #

Adds an INNER JOIN to the query.

  • @param table [Symbol | Hash(Symbol,Symbol)] Table name or alias mapping (e.g., :orders or {orders: :o})
  • @param on [Hash(CQL::BaseColumn, CQL::BaseColumn | DB::Any)] The join condition using BaseColumn objects.
  • @return [Query] The query object

Example

query.from(:users).inner(:orders, on: { users.id => orders.user_id })
# OR with alias
query.from(users: :u).inner({orders: :o}, on: { u.id => o.user_id })
=> "SELECT * FROM users AS u INNER JOIN orders AS o ON u.id = o.user_id"

[View source]
def inner(table_or_alias : Symbol | Hash(Symbol, Symbol), &) #

Adds an INNER JOIN to the query using a block for the condition.

  • @param table [Symbol | Hash(Symbol,Symbol)] Table name or alias mapping.
  • @yield [FilterBuilder] The block to build the ON condition.
  • @return [Query] The query object

Example

query.from(:users).inner(:orders) { |join| join.on { |cond| cond.users.id == cond.orders.user_id } }
# OR with alias
query.from(users: :u).inner({orders: :o}) { |join| join.on { |cond| cond.u.id == cond.o.user_id } }

[View source]
def joins : Array(Expression::Join) #

[View source]
def joins(*tables_to_join : Symbol) #

Accept single splat for table names (no explicit alias)


[View source]
def joins(**tables_to_join) #

Accept keyword arguments for table/alias pairs


[View source]
def left(table_or_alias : Symbol | Hash(Symbol, Symbol), on : Hash(CQL::BaseColumn, CQL::BaseColumn | DB::Any)) #

Adds a LEFT JOIN to the query. (Parameters and examples similar to #inner but using #left and LEFT JOIN)


[View source]
def left(table_or_alias : Symbol | Hash(Symbol, Symbol), &) #

Adds a LEFT JOIN to the query using a block. (Parameters and examples similar to #inner block version but using #left)


[View source]
def left_joins(*tables_to_join : Symbol) #

Accept single splat for table names (no explicit alias)


[View source]
def left_joins(**tables_to_join) #

Accept keyword arguments for table/alias pairs


[View source]
def limit(value : Int32) #

Sets the limit for the number of records to return.

  • @param value [Int32] The limit value
  • @return [Query] The query object

Example

query.from(:users).limit(10)
=> "SELECT * FROM users LIMIT 10"

[View source]
def limit : Int32 | Nil #

[View source]
def limit=(limit : Int32 | Nil) #

[View source]
def max(column : Symbol) #

Adds a MAX aggregate function to the query.

  • @param column [Symbol] The column to find the maximum value of
  • @return [Query] The query object

Example

query.from(:users).max(:price)
=> "SELECT MAX(price) FROM users"

[View source]
def merge(other_query : Query) : Query #

Merges the properties of another Query object into this one. The current query is modified in place.

  • @param other_query [Query] The query object to merge from.
  • @return [Query] The current query object, modified.

Behavior:

  • Schema: Must be the same for both queries.
  • Distinct: Becomes true if either query is distinct.
  • Select Columns (@columns): Concatenated and uniqued by object identity.
  • Aggregate Columns (@aggr_columns): Concatenated and uniqued by object identity.
  • Query Tables (@query_tables): Merged. Conflicts on alias pointing to different tables raise an error.
  • Joins (@joins): Concatenated and uniqued by object identity.
  • Where (@where): Conditions are combined using AND.
  • Group By (@group_by): Concatenated and uniqued by object identity.
  • Having (@having): Conditions are combined using AND.
  • Order By (@order_by): Entries from other_query take precedence.
  • Limit (@limit): The minimum of the two limits is taken if both are set; otherwise, the set limit is used.
  • Offset (@offset): The other_query's offset takes precedence if set.

ameba/disable Metrics/CyclomaticComplexity


[View source]
def min(column : Symbol) #

Adds a MIN aggregate function to the query.

  • @param column [Symbol] The column to find the minimum value of
  • @return [Query] The query object

Example

query.min(:price)
=> "SELECT MIN(price) FROM users"

[View source]
def offset(value : Int32) #

Sets the offset for the query.

  • @param value [Int32] The offset value
  • @return [Query] The query object

Example

query.from(:users).limit(10).offset(20)
=> "SELECT * FROM users LIMIT 10 OFFSET 20"

[View source]
def offset : Int32 | Nil #

[View source]
def offset=(offset : Int32 | Nil) #

[View source]
def order(*fields : Symbol | String) #

Specifies the columns to order by. Handles qualified columns like #order("users.name") or aliases #order("u.name").

  • @param fields [Symbol* | String*] The columns to order by (Symbol or "alias.column")
  • @return [Query] The query object

[View source]
def order(**fields) #

Specifies the columns to order by with direction. Handles qualified columns or aliases in keys.

  • @param fields [Hash(Symbol | String, Symbol)] Column => :asc/:desc
  • @return [Query] The query object

[View source]
def order_by : Hash(CQL::BaseColumn, Expression::OrderDirection) #

[View source]
def query_tables : Hash(String, QueryTableInfo) #

[View source]
def right(table_or_alias : Symbol | Hash(Symbol, Symbol), on : Hash(CQL::BaseColumn, CQL::BaseColumn | DB::Any)) #

Adds a RIGHT JOIN to the query. (Parameters and examples similar to #inner but using #right and RIGHT JOIN)


[View source]
def right(table_or_alias : Symbol | Hash(Symbol, Symbol), &) #

Adds a RIGHT JOIN to the query using a block. (Parameters and examples similar to #inner block version but using #right)


[View source]
def right_joins(*tables_to_join : Symbol) #

Accept single splat for table names (no explicit alias)


[View source]
def right_joins(**tables_to_join) #

Accept keyword arguments for table/alias pairs


[View source]
def schema : Schema #

[View source]
def select(*columns : Symbol | String) #

Specifies the columns to select.

  • @param columns [Symbol*] The columns to select
  • @return [Query] The query object

Example

query.select(:name, :age)
=> "SELECT name, age FROM users"

[View source]
def select(**fields : Hash(String | Symbol, Array(Symbol) | Symbol)) #

Specifies the columns to select.

  • @param fields [Hash(Symbol, Array(Symbol) | Symbol)] The columns to select
  • @return [Query] The query object

Example

query.from(:users, :address).select(users: [:name, :age], address: [:city, :state])
=> "SELECT users.name, users.age, address.city, address.state FROM users, address"

** Example with aggregates **

query.from(:users).select(count: :id)
=> "SELECT COUNT(id) FROM users"

** Example with aliases **

query.from(:users, :orders).select(users: [:name, :age], orders: [:total_amount, :status])
=> "SELECT users.name, users.age, orders.total_amount, orders.status FROM users, orders"

[View source]
def select(**fields) #

[View source]
def select(*cols : Symbol | String, **fields : Hash(String | Symbol, Array(Symbol) | Symbol)) #

Allow mixing String/Symbol args and Hash


[View source]
def select(*cols, **columns) #

[View source]
def sum(column : Symbol) #

Adds a SUM aggregate function to the query.

  • @param column [Symbol] The column to sum
  • @return [Query] The query object

Example

query.sum(:total_amount)
=> "SELECT SUM(total_amount) FROM users"

[View source]
def to_sql(gen = @schema.gen) #

Converts the query into an SQL string and its corresponding parameters.

  • @param gen [Generator] The generator to use for converting the query
  • @return [Tuple(String, Array(DB::Any))] The SQL query and its parameters

Example

query.to_sql
=> {"SELECT * FROM users WHERE name = ? AND age = ?", ["John", 30]}

[View source]
def where(hash : Hash(String | Symbol, DB::Any)) #

Accept Hash(Symbol, DB::Any) for backward compatibility


[View source]
def where : Expression::Where | Nil #

[View source]
def where(&) #

Correct implementation for where(&)


[View source]
def where(**fields) #

[View source]
def where=(where : Expression::Where | Nil) #

[View source]