struct

Interro::QueryBuilder(T)

Inherits Interro::Validations / Iterable / Enumerable / Struct / Value / Object

Defining QueryBuilder objects is a way to create composable queries. For example, if you have the following Model and QueryBuilder:

struct User
  include Interro::Model

  getter id : UUID
  getter name : String
  getter email : String
  getter team_id : UUID?
  getter role : Role

  enum Role
    Member
    TeamAdmin
    SiteAdmin
  end
end

struct UserQuery < Interro::QueryBuilder(User)
  table "users"

  def find(id : UUID)
    where(id: id).first?
  end

  def on_team(team : Team)
    where team_id: team.id
  end

  def with_role(role : User::Role)
    # We pass `role.value` to the SQL query since it's stored in `INTEGER`
    # column type.
    where role: role.value
  end

  def sorted_by_name(direction : Interro::QueryBuilder::OrderByDirection = :asc)
    order_by name: direction
  end
end

Then you can find all team admins like this:

users = UserQuery.new
  .on_team(team)
  .with_role(:team_admin)
  .sorted_by_name

You can insert records with the insert method:

struct UserQuery < Interro::QueryBuilder(User)
  # ...
  def create(name : String, email : String, team : Team, role : User::Role)
    # This generates the following SQL:
    #   INSERT INTO users (name, email, team_id, role) VALUES ($1, $2, $3, $4)
    # And it passes these args to the parameterized query:
    #   [name, email, team.id, role.value]
    insert(
      name: name,
      email: email,
      team_id: team.id,
      role: role.value,
    )
  end
end

You can also use Interro::Validations::Result objects to validate the inputs before saving them to the DB. Since Interro::QueryBuilder includes the Interro::Validations mixin, you can simply refer to it as Result.

struct UserQuery < Interro::QueryBuilder(User)
  # ...
  def create(name : String, email : String, team : Team, role : User::Role)
    Result(User).new
      .validate_presence(name: name, email: email)
      .validate_uniqueness("email") { where(email: email).any? }
      .valid do
        insert(
          name: name,
          email: email,
          team_id: team.id,
          role: role.value,
        )
      end
  end
end

Constructors

[](transaction : Transaction) : self
Source
[](transaction : DB::Transaction) : self
Source
[](transaction : Nil) : self
Source
new(transaction_owner : Interro::QueryBuilder)
Source

Instance methods

&(other : self) : CompoundQuery
Source
-(other : self) : CompoundQuery
Source
|(other : self) : CompoundQuery
Source
any?

Returns true if at least one of the collection's members is truthy.

[nil, true, 99].any? # => true
[nil, false].any?    # => false
([] of Int32).any?   # => false
  • #present? does not consider truthiness of elements.
  • #any?(&) and #any(pattern) allow custom conditions.

NOTE: #any? usually has the same semantics as #present?. They only differ if the element type can be falsey (i.e. T <= Nil || T <= Pointer || T <= Bool). It's typically advised to prefer #present? unless these specific truthiness semantics are required.

Source
count
Source
each

Must return an Iterator over the elements in this collection.

Source
each

Must yield this collection's elements to the block.

Source
empty?

Returns true if self does not contain any element.

([] of Int32).empty? # => true
([1]).empty?         # => false
[nil, false].empty?  # => false
  • #present? returns the inverse.
Source
first(count : Int)

Returns an Array with the first count elements in the collection.

If count is bigger than the number of elements in the collection, returns as many as possible. This include the case of calling it over an empty collection, in which case it returns an empty array.

Source
first

Returns the first element in the collection. Raises Enumerable::EmptyError if the collection is empty.

([1, 2, 3]).first   # => 1
([] of Int32).first # raises Enumerable::EmptyError
Source
first?

Returns the first element in the collection. When the collection is empty, returns nil.

([1, 2, 3]).first?   # => 1
([] of Int32).first? # => nil
Source
initialize
Source
merge(other : QueryBuilder) : self
Source
none?

Returns true if all of the elements of the collection are falsey.

[nil, false].none?       # => true
[nil, false, true].none? # => false

It's the opposite of all?.

Source
subquery(select select_clause : String) : Subquery
Source
to_json(json : JSON::Builder) : Nil
Source
to_sql
Source
where_exists
Source

Macros

from(name, *joins)
Source
table(name, as table_alias = nil)
Source

Nested types