module Jennifer::QueryBuilder::Executables

Overview

All query methods that invokes database query.

A lot of methods in this module accepts strings and symbols. Any string is considered as a plain SQL and is inserted as-is; any symbol - as a current table field.

Direct including types

Defined in:

jennifer/query_builder/executables.cr

Instance Method Summary

Instance Method Detail

def db_results : Array(Hash(String, DBAny)) #

Returns array of hashes representing result sets.

Jennifer::Query["contacts"].where { _id == 1 }.db_results # => [{"id" => 1, "name" => "Name", ...}]

[View source]
def decrement(fields : Hash(Symbol, _)) #

Decrements specified fields by given value.

For more details take a look at #increment.


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

Decrements specified fields by given value.

For more details take a look at #increment.


[View source]
def delete #

Delete all records which satisfy given conditions.

No model callbacks or validation will be executed.

Jennifer::Query["contacts"].where { _name.like("%dan%") }.delete

[View source]
def each(&) #

Yields each matched record to a block.

To iterate over records they are loaded from the DB so this may effect memory usage. Prefer #find_each.


[View source]
def each_result_set(&) #

Yields each result set object to a block.


[View source]
def exists? : Bool #

Returns whether any record satisfying given conditions exists.

Jennifer::Query["contacts"].where { _name.like("%dan%") }.exists?

[View source]
def explain : String #

Returns query execution explanation.

Format depends on used database adapter.

Jennifer::Query["contacts"].explain # => "Seq Scan on contacts  (cost=0.00..13.40 rows=340 width=206)"

[View source]
def find_each(primary_key : String, batch_size : Int32 = 1000, start = nil, direction : String | Symbol = "asc", &) #

Yields each record in batches from #find_in_batches.

Looping through a collection of records from the database is very inefficient since it will instantiate all the objects at once. In that case batch processing methods allow you to work with the records in batches, thereby greatly reducing memory consumption.

Jennifer::Query["contacts"].where { _age > 21 }.find_each("id") do |contact|
  puts contact.id
end

[View source]
def find_each(primary_key : Criteria, batch_size : Int32 = 1000, start = nil, direction : String | Symbol = "asc", &) #

[View source]
def find_each(primary_key : Nil, batch_size : Int32 = 1000, start : Int32 = 0, direction : String | Symbol = "asc", &) #

[View source]
def find_each(batch_size : Int32 = 1000, start : Int32 = 0, direction : String | Symbol = "asc", &) #

[View source]
def find_in_batches(primary_key : String, batch_size : Int32 = 1000, start : Int32? = nil, direction : String | Symbol = "asc", &) #

Yields each batch of records that was found by the specified query.

Jennifer::Query["contacts"].where { _age > 21 }.find_in_batches("id") do |batch|
  batch.each do |contact|
    puts contact.id
  end
end

To get each record one by one use #find_each instead.

NOTE any given ordering will be ignored and query will be reordered based on the primary_key and direction.


[View source]
def find_in_batches(batch_size : Int32 = 1000, start : Int32 = 0, &) #

[View source]
def find_in_batches(primary_key : Criteria, batch_size : Int32 = 1000, start = nil, direction : String | Symbol = "asc", &) #

[View source]
def find_in_batches(primary_key : Nil, batch_size : Int32 = 1000, start : Int32 = 0, &) #

[View source]
def find_records_by_sql(query : String, args : Array(DBAny) = [] of DBAny) #

Executes a custom SQL query against DB and returns array of Record.

Any query conditions specified earlier are ignored.

query = "SELECT name FROM users WHERE age > %1"
Jennifer::Query["contacts"].find_records_by_sql(query, [21]) # [<Record: name="Roland">]

[View source]
def first #

Returns first matched record or nil.

Doesn't modify query instance.

Contact.where { _city_id == 3 }.first

[View source]
def first! #

Returns first matched record or raise RecordNotFound exception otherwise.

Doesn't modify query instance.

Contact.where { _city_id == 3 }.first!

[View source]
def ids #

Returns array of record ids.

This method requires model to have field id : Int32.


[View source]
def increment(fields : Hash(Symbol, _)) #

Increments specified fields by given value.

Contact.all.increment({:likes => 1})

No validation or callback is invoked.


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

Increments specified fields by given value.

Contact.all.increment(likes: 1)

No validation or callback is invoked.


[View source]
def insert(fields : Array(String), values : Array(Array(DBAny))) #

Creates new record in a database with given fields and values.

Ignores any model callbacks.

Jennifer::Query["contacts"].insert(%w(name age), [["John", 60], ["Chris", 40]])

[View source]
def insert(options : Hash(String | Symbol, DBAny) | NamedTuple) #

Creates new record in a database with given options.

Ignores any model callbacks.

Jennifer::Query["contacts"].insert({name: "John", age: 60})

[View source]
def last #

Returns last matched record or nil.

Doesn't modify query instance.

Contact.where { _city_id == 3 }.last

[View source]
def last! #

Returns last matched record or raise RecordNotFound exception otherwise.

Doesn't modify query instance.

Contact.where { _city_id == 3 }.last!

[View source]
def pluck(fields : Array) : Array(Array(DBAny)) #

Returns array of given field values.

This method allows you load only those fields you need without loading records. If query is ModelQuery - take into consideration that fields will not be converted by model converters.

Contact.all.limit(2).pluck([:id, :name]) # [[1, "Name 1"], [2, "Name 2"]]

[View source]
def pluck(field : String | Symbol) : Array(DBAny) #

[View source]
def pluck(*fields : String | Symbol) : Array(Array(DBAny)) #

[View source]
def pluck(**types : **T) forall T #

[View source]
def results : Array(Record) #

Returns array of Record created based on result sets.

Jennifer::Query["contacts"].where { _id == 1 }.results
# => [Jennifer::Record(@attributes={"id" => 1, "name" => "Name", ...})]

[View source]
def to_a #

Alias for #results.


[View source]
def update(&) #

Updates specified fields by given value retrieved from the block.

Expects block to return Hash(Symbol, DBAny | Jennifer::QueryBuilder::Statement).

Contact.all.where { and(_name == "Jon", age > 100) }.update { {:name => "John", :age => _age - 15} }

[View source]
def update(options : Hash) #

Updates records with given options.

Contact.all.where { and(_name == "Jon", age > 100) }.update({:name => "John", :age => 40})

[View source]
def update(**options) #

Updates records with given options.

Contact.all.where { and(_name == "Jon", age > 100) }.update(name: "John", age: 40)

[View source]
def upsert(fields : Array(String), values : Array(Array(DBAny)), unique_fields : Array = [] of String) #

Inserts given values and ignores ones that would cause a duplicate values of UNIQUE index on given unique_fields.

Some RDBMS (like MySQL) doesn't require specifying exact constraint to be violated, therefore unique_fields argument by default is [] of String.

Jennifer::Query["orders"].insert({:name => "Order 1", :uid => 123})
# the first record will be skipped
Jennifer::Query["orders"].upsert(%w(name uid), [["Order 1", 123], ["Order 2", 321]], %w(uid))

[View source]
def upsert(fields : Array(String), values : Array(Array(DBAny)), unique_fields : Array, &) #

Inserts given values modifies existing row using hash returned by the block.

Some RDBMS (like MySQL) doesn't require specifying exact constraint to be violated, therefore unique_fields argument by default is [] of String.

Jennifer::Query["orders"].insert({:name => "Order 1", :uid => 123, :value => 2})
# the first record will be skipped
Jennifer::Query["orders"].upsert(%w(name uid value), [["Order 1", 123, 3], ["Order 2", 321, 4]], %w(uid)) do
  {:value => values(:value) + _value}
end

[View source]