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
Instance methods
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.
Returns true if self does not contain any element.
([] of Int32).empty? # => true
([1]).empty? # => false
[nil, false].empty? # => false
#present?returns the inverse.
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.
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
Returns the first element in the collection.
When the collection is empty, returns nil.
([1, 2, 3]).first? # => 1
([] of Int32).first? # => nil
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?.