Query the database¶
SQLair-proof your types¶
The first step in building your query is to decide what you would like to put into/get out of the database. Identify the types in your Go program that hold this information or create them if they don’t already exist.
Make sure that the types are in the right format to work with SQLair. For example:
type Employee struct {
ID string `db:"id"`
Name string `db:"name"`
LocationID string `db:"location_id"`
}
type Location struct {
ID string `db:"id"`
City string `db:"city"`
}
See more
Write your query string using the types¶
SQLair queries are regular SQL queries with special input and output expressions that enable you to reference the Go types directly from SQL.
Write your SQL query with SQLair input expressions instead of query parameters and SQLair output expressions instead of columns to select.
For example:
query := `
SELECT &Employee.*
FROM employee
WHERE location_id = $Location.id
`
See more
Prepare your query string to get a statement¶
Now you have your query string, you need to pass it to sqlair.Prepare
along
with samples of all the types mentioned in the input and output expressions.
SQLair uses the type information from the type samples to generate the SQL and
verify the input/output expressions. If there is an issue with the actual SQL in
the query, this will not catch it. The returned Statement
holds the parsed and
verified query.
Note
SQLair also provides the sqlair.MustPrepare
method which panics on error
instead of returning.
For example:
stmt, err := sqlair.Prepare(ctx, query, Employee{}, Location{})
if err != nil {
return err
}
See more
Execute the statement on the database¶
To execute the statement on a SQLair wrapped DB
or a TX
, use the Query
method, passing as parameters the Statement
and all the input arguments
specified in the input expressions. This returns a Query
object that can then
be run with one of four methods below.
Note
The Query
object returned from DB.Query
/TX.Query
is not designed to be
reused. One of the methods on Query
should immediately be called. It should
not be saved as variable.
See more
Get one row¶
To get only the first row returned from the database use Query.Get
, passing
pointers to all the output variables mentioned in the query.
For example:
location := Location{City: "Edinburgh"}
var employee Employee
err := db.Query(ctx, stmt, location).Get(&employee)
if err != nil {
return err
}
// employee now contains the first employee returned from the database.
See more
Get all the rows¶
To get all the rows returned from the database use Query.GetAll
, passing
pointers to slices of all the output variables in the query.
For example:
location := Location{City: "Edinburgh"}
var employees []Employee
err := db.Query(ctx, stmt, location).GetAll(&employees)
if err != nil {
return err
}
// employees now contains all the employees returned from the database.
See more
Iterate over the rows¶
To iterate over the rows returned from the query, get an Iterator
with
Query.Iter
.
Iterator.Next
prepares the next row for Iterator.Get
. It will return false
if there are no more rows or there is an error. Iterator.Get
works the same as
Query.Get
above, except it gets the current row.
Make sure to run Iterator.Close
once you are finished iterating. The
Iterator.Close
operation should generally be deferred when the Iterator
is
created. Any errors encountered during iteration will be returned with
Iterator.Close
.
For example:
location := Location{City: "Edinburgh"}
iter := db.Query(ctx, stmt, location).Iter()
// Defer closing of the iterator and set its error to the error returned from
// the function (if the function error is not nil).
defer func(){
closeErr := iter.Close()
if err == nil {
err = closeErr
}
}()
for iter.Next() {
var employee Employee
err := iter.Get(&employee)
if err != nil {
return err
}
}
See more
Query.Iter
,
sqlair.Iterator
,
Iterator.Next
,
Iterator.Get
,
Iterator.Close
Just run¶
To run a query that does not return any rows, use Query.Run
. This is useful
when doing operations that are not expected to return anything.
For example:
stmt, err := sqlair.Prepare("INSERT INTO employee (*) VALUES ($Employee.*)", Employee{})
if err != nil {
return err
}
employee := Employee{
ID: 1
Name: "Joe"
LocationID: 17
}
err := tx.Query(ctx, stmt, employee).Run()
if err != nil {
return err
}
// employee has been inserted into the database.
See more
(Optional) Get the query outcome¶
To get the query outcome, use any of the Get
methods, providing as a first
argument a pointer to a sqlair.Outcome
object. This will fill the
sqlair.Outcome
with information about the outcome of the query.
Note
The query outcome contains metadata about the execution of a query. Currently,
it only contains a sql.Result
object which contains information returned from
the driver such as the number of rows affected. It may contain more in the
future.
For example:
stmt, err := sqlair.Prepare("DELETE FROM employee WHERE name = $Employee.name", Employee{})
if err != nil {
return err
}
var outcome sqlair.Outcome
err := tx.Query(ctx, stmt, Employee{Name: "Joe"}).Get(&outcome)
if err != nil {
return err
}
result := outcome.Result()
rowsAffected, err := reslut.RowsAffected()
if err != nil {
return err
}
See more