class CQL::ActiveRecord::Queryable::QueryBuilder(T)

Overview

The QueryBuilder class provides a chainable interface for building queries while maintaining type safety and integration with the CQL::Query system.

Direct Known Subclasses

Defined in:

active_record/query_builder.cr

Constructors

Class Method Summary

Instance Method Summary

Constructor Detail

def self.new(query : CQL::Query, model_class : T.class = T) #

Initialize a new QueryBuilder with the given query

  • @param query [CQL::Query] The underlying query object
  • @param model_class [T.class] The model class

[View source]

Class Method Detail

def self.from_model(model_class : T.class) : QueryBuilder(T) forall T #

Create a QueryBuilder for the given model type

  • @param model_class [Class] The model class
  • @return [QueryBuilder(T)] A new query builder instance

[View source]

Instance Method Detail

def all(as as_kind) #

Execute the query and return all results as a custom type Note: Preloading is not applied when using a custom type.

  • @param as_kind [Class] The type to deserialize results as
  • @return [Array] Array of instances of the specified type

[View source]
def all #

Execute the query and return all results When preloads are configured, automatically applies them to the results.

  • @return [Array(T)] Array of model instances

[View source]
def any? #

Check if any records exist

  • @return [Bool] True if any records exist

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

Get average value of a column

  • @param column [Symbol] The column to average
  • @return [Float64?] The average value or nil

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

Add avg aggregate

  • @param column [Symbol] The column to average
  • @return [Float64] The average result

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

Counts the rows the query returns, or the non-NULL values of column. Without LIMIT or OFFSET, ORDER BY is dropped. With either it counts a derived table (SELECT COUNT(*) FROM (...) AS counted_rows); ORDER BY stays inside it when counting a column, since it decides which rows fall in the window, and #group counts the groups in the window. #distinct with joins plus LIMIT or OFFSET keeps every joined column inside the derived table (MySQL rejects duplicate column names there), and unaliased aggregate selects cannot be counted with LIMIT or OFFSET.

  • @param column [Symbol] The column to count (defaults to *)
  • @return [Int64] The count result

[View source]
def count_query(column : Symbol = :*) : CQL::Query #

The CQL::Query that #count runs, on the same executor as this query.


[View source]
def delete_all : Int64 #

Deletes the matching records and returns how many. A model with destroy callbacks or dependent: strategies loads and deletes each record so they run, all in one transaction; others delete by id in bulk (soft-deletable models set deleted_at).


[View source]
def distinct #

Set distinct flag

  • @return [QueryBuilder(T)] Self for chaining

[View source]
def distinct_values(column : Symbol, as as_kind = DB::Any) #

Get distinct values for a column

  • @param column [Symbol] The column to get distinct values
  • @return [Array(DB::Any)] Array of distinct values

[View source]
def each(& : T -> ) #

Iterate over each result

  • @yield [T] Each model instance

[View source]
def empty? #

Check if no records exist

  • @return [Bool] True if no records exist

[View source]
def exists? : Bool #

Check if any records exist

  • @return [Bool] True if records exist

[View source]
def exists?(**conditions) #

[View source]
def find(id) #

Find record by primary key

  • @param id [Int32 | Int64] The primary key value
  • @return [T?] The record or nil if not found

[View source]
def find!(id) #

Find record by primary key, raises if not found

  • @param id [Int32 | Int64] The primary key value
  • @return [T] The record

[View source]
def find_by(conditions : Hash(String | Symbol, DB::Any | Array(DB::Any))) #

Find record by attributes

  • @param conditions [Hash] The conditions to search by
  • @return [T?] The first matching record or nil

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

Find record by attributes with hash syntax

  • @param fields [Hash] The conditions using hash syntax
  • @return [T?] The first matching record or nil

[View source]
def find_by!(conditions : Hash(String | Symbol, DB::Any | Array(DB::Any))) #

Find record by attributes, raises if not found

  • @param conditions [Hash] The conditions to search by
  • @return [T] The first matching record

[View source]
def find_by!(**fields) #

Find record by attributes, raises if not found (hash syntax)

  • @param fields [Hash] The conditions using hash syntax
  • @return [T] The first matching record

[View source]
def find_each(batch_size : Int32 = 1000, & : T -> ) #

Yields each matching record, loading them batch_size at a time (see #find_in_batches).


[View source]
def find_in_batches(batch_size : Int32 = 1000, & : Array(T) -> ) #

Yields the matching records in batches of up to batch_size, ignoring the query's limit and offset. An unordered, unshaped query pages by primary key (WHERE pk > last ORDER BY pk LIMIT n), so rows deleted mid-iteration never shift later rows; any other query pages by OFFSET in its order, ties broken by primary key.


[View source]
def first(as as_kind = T) #

Execute the query and return the first result

  • @return [T?] First model instance or nil

[View source]
def first!(as as_kind = T) #

Execute the query and return the first result, raises if not found

  • @return [T] First model instance

[View source]
def get(as as_kind) #

Execute the query and return a scalar value

  • @param as [Type] The type to cast the result to
  • @return [Type] The scalar result

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

Add group by clauses

  • @param columns [Symbol*] The columns to group by
  • @return [QueryBuilder(T)] Self for chaining

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

Alias for group method to match ActiveRecord naming

  • @param columns [Symbol*] The columns to group by
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def having(&) #

Add having conditions

  • @yield [HavingBuilder] The block to build having conditions
  • @return [QueryBuilder(T)] Self for chaining

The block may use implicit self (having { count(:id) > 1 }) or take the builder (having { |h| h.count(:id) > 1 }).


[View source]
def ids(as as_kind = Int64) #

Get array of primary key values

  • @return [Array] Array of primary key values

[View source]
def join(table_or_alias : Symbol) #

Execute automatic inner join

  • @param table_or_alias [Symbol | Hash] The table or alias mapping
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def join(table_or_alias : Symbol, &block : Expression::FilterBuilder -> Expression::ConditionBuilder) #

Execute inner join with block conditions

  • @param table_or_alias [Symbol | Hash] The table or alias mapping
  • @yield [FilterBuilder] The block to build join conditions
  • @return [QueryBuilder(T)] Self for chaining

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

Execute automatic inner join using named arguments for table aliasing

  • @param tables_with_aliases [NamedTuple] Table name => alias
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def joins(association : Symbol) : self #

Joins an association declared on the model (has_one, has_many, belongs_to). The optional block adds typed conditions to the join, written against the model's columns and its associations (profile.country == "US").


[View source]
def joins(association : Symbol, &) : self #

[View source]
def last(as as_kind = T) #

Execute the query and return the last result (using reverse order)

  • @return [T?] Last model instance or nil

[View source]
def last!(as as_kind = T) #

Execute the query and return the last result, raises if not found

  • @return [T] Last model instance

[View source]
def left(table_or_alias : Symbol) #

Execute automatic left join

  • @param table_or_alias [Symbol | Hash] The table or alias mapping
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def left(table_or_alias : Symbol, &block : Expression::FilterBuilder -> Expression::ConditionBuilder) #

Execute left join with block conditions

  • @param table_or_alias [Symbol | Hash] The table or alias mapping
  • @yield [FilterBuilder] The block to build join conditions
  • @return [QueryBuilder(T)] Self for chaining

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

Execute automatic left join using named arguments for table aliasing

  • @param tables_with_aliases [NamedTuple] Table name => alias
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def left_joins(association : Symbol) : self #

[View source]
def left_joins(association : Symbol, &) : self #

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

Set limit for the query

  • @param value [Int32] The limit value
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def many? #

Check if many records exist (more than one)

  • @return [Bool] True if more than one record exists

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

Add max aggregate

  • @param column [Symbol] The column to find maximum
  • @return [DB::Any] The maximum result

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

Get maximum value of a column

  • @param column [Symbol] The column to find maximum
  • @return [DB::Any?] The maximum value or nil

[View source]
def merge(other : QueryBuilder(T)) #

Merge with another QueryBuilder

  • @param other [QueryBuilder(T)] The other query builder to merge
  • @return [QueryBuilder(T)] A new merged query builder

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

Add min aggregate

  • @param column [Symbol] The column to find minimum
  • @return [DB::Any] The minimum result

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

Get minimum value of a column

  • @param column [Symbol] The column to find minimum
  • @return [DB::Any?] The minimum value or nil

[View source]
def model_class : T.class #

Get the model class


[View source]
def none #

Return a QueryBuilder that will return no results

  • @return [QueryBuilder(T)] A query builder that returns no results

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

Set offset for the query

  • @param value [Int32] The offset value
  • @return [QueryBuilder(T)] Self for chaining

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

Add order by clauses

  • @param fields [Symbol*] The fields to order by
  • @return [QueryBuilder(T)] Self for chaining

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

Add order by clauses with hash syntax

  • @param fields [Hash] The fields and directions to order by
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def order_by(**fields : **N) : self forall N #

Order by typed columns; unknown column names are compile-time errors.

User.query.order_by(created_at: :desc, name: :asc)

[View source]
def pick(column : Symbol, as as_kind = DB::Any) #

Extract a single column value from the first matching record

  • @param column [Symbol] The column to extract
  • @return [DB::Any?] The value or nil if no records

[View source]
def pluck(*columns : Symbol, as as_kind) #

Extract column values from all matching records

  • @param columns [Symbol*] The columns to extract
  • @return [Array] Array of values or arrays if multiple columns

[View source]
def preload(*associations : Symbol) : self #

Add associations to preload (eager load) to avoid N+1 queries. Preloaded associations are fetched in separate batch queries after the main query executes, then injected into the parent records.

  • @param associations [Symbol*] The association names to preload
  • @return [QueryBuilder(T)] A new query builder with preload configured

Example

User.preload(:posts).all                     # Preload an association
User.where(active: true).preload(:posts).all # Chain with where

[View source]
def query #

Get the underlying CQL::Query object

  • @return [CQL::Query] The query object

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

Replace existing order clause

  • @param fields [Symbol*] The fields to order by
  • @return [QueryBuilder(T)] Self for chaining

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

Replace existing order clause with hash syntax

  • @param fields [Hash] The fields and directions to order by
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def reverse_order #

Reverse the order of records

  • @return [QueryBuilder(T)] Self for chaining

[View source]
def right(table_or_alias : Symbol) #

Execute automatic right join

  • @param table_or_alias [Symbol | Hash] The table or alias mapping
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def right(table_or_alias : Symbol, &block : Expression::FilterBuilder -> Expression::ConditionBuilder) #

Execute right join with block conditions

  • @param table_or_alias [Symbol | Hash] The table or alias mapping
  • @yield [FilterBuilder] The block to build join conditions
  • @return [QueryBuilder(T)] Self for chaining

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

Execute automatic right join using named arguments for table aliasing

  • @param tables_with_aliases [NamedTuple] Table name => alias
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def select(*columns : Symbol) : PartialBuilder(T) #

Select only these columns; the result rows (#to_a, #first, ...) are Model::Row records whose unselected columns are nil.


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

Add columns to select

  • @param columns [Symbol*] The columns to select
  • @return [QueryBuilder(T)] Self for chaining

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

Add columns to select with hash syntax

  • @param fields [Hash] The fields to select using hash syntax
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def size #

Get the count of records

  • @return [Int64] The number of records

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

Add sum aggregate

  • @param column [Symbol] The column to sum
  • @return [Float64 | Int64] The sum result

[View source]
def to_a #

Alias of #all.


[View source]
def to_sql #

Convert to SQL string for debugging

  • @return [String] The SQL query string

[View source]
def to_sql_with_params #

Get the SQL query and parameters

  • @return [Tuple(String, Array)] The SQL query and parameters

[View source]
def unscope(scope_type : Symbol) #

Remove specific scopes

  • @param scope_type [Symbol] The type of scope to remove
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def using(connection : DB::Connection) : self #

Runs this query on an explicit connection (see Schema#with_connection).


[View source]
def using(executor : CQL::Executor) : self #

Runs this query on another executor, e.g. a CQL::Postgres::AsyncEngine.


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

Add where conditions

  • @param conditions [Hash] The conditions to filter by
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def where(__sql sql : String, *positional, **named) #

A raw SQL fragment with bound ? / :name values (sql must be a literal).


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

Add where conditions with hash syntax

  • @param fields [Hash] The conditions using hash syntax
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def where(&) : self #

Add where conditions with block

  • @yield [FilterBuilder] The block to build conditions
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def where_gt(field : Symbol | String, value : DB::Any) #

Add greater-than condition Useful for cursor-based pagination and range queries.

  • @param field [Symbol | String] The field to compare
  • @param value [DB::Any] The value to compare against
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def where_like(field : Symbol | String, pattern : String) #

Add LIKE conditions

  • @param field [Symbol | String] The field to match
  • @param pattern [String] The LIKE pattern
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def where_lt(field : Symbol | String, value : DB::Any) #

Add less-than condition Useful for cursor-based pagination and range queries.

  • @param field [Symbol | String] The field to compare
  • @param value [DB::Any] The value to compare against
  • @return [QueryBuilder(T)] Self for chaining

[View source]
def where_primary_key(key : DB::Any | UUID) : QueryBuilder(T) #

Rows whose primary key (T.primary_key_column) is key. A UUID is bound as text.


[View source]
def where_primary_key(keys : Array) : QueryBuilder(T) #

Rows whose primary key is any of keys; none for an empty array.


[View source]
def with_query(&block : CQL::Query -> CQL::Query) #

Create a new QueryBuilder with a modified query using a block

  • @yield [CQL::Query] The query to modify
  • @return [QueryBuilder(T)] A new query builder instance

[View source]