When the client code is finished using a Builder
, it calls
run(lambda)
on the builder to run the statement. This tells
the builder to build the statement, prepare it, and then call the body
of the lambda.
With the exception of InsertStatement
, statements take
values for their Parameter
s. Client code does this with
the ParameterSetter.set(Parameter, T)
method. When the
client code is finished setting parameters, the statement is then
executed. For all but the SelectQuery
, this happens
when the user's code block finishes.
In the case of the SelectQuery
, executing the statement is
triggered by asking for the first results, with next()
, or,
when the client is certain there will be a result row,
nextOrFail()
. Once that is done, it is illegal to continue
to set parameters, and an attempt to do so generates an
IllegalStateException
. After the query is run, it becomes
legal to get table values, using get(TableColumn)
. If the
select statement is forUpdate()
, row values can be set
with set(TableColumn, T)
method, and the updates can
be written to the database with update()
.
InsertStatement
and UpdateStatement
objects'
builders take a code block that's used to establish which columns appear
in the statment, and to provide them values. Both builders have a
method called
run. When it completes, the statement is built,
prepared and executed.
InsertStatement
offers a different alternative, however.
An insert statement can produce a ResultSet
, containing
the value(s) of the primary key/keys. For this reason, there are two
variants of the
Database
method insertInto
:
db.insertInto(MyTable) run { row -> row[MyTable.myStringColumn] = "x" row[MyTable.myIntColumn] = 42 }and
val id : Int = db.insertInto(MyTable) { row -> row[MyTable.myStringColumn] = "x" row[MyTable.myIntColumn] = 42 } run { result -> row[MyTable.thePrimaryKey] }
In the first variant, the Database.insertInto(Table)
method actually produces an InsertStatement.BuilderNoResults
,
so named because the client code isn't asking for results. Then,
the user invokes the infix run
method with a body to
set the rows. The BuilderNoResults
internally creates a
Builder
, and provides that builder with a body
that discards the results.
In the second variant, the client is invoking the method
Database.insertInto(Table, lambda)
method. This
directly creates an InsertStatement.Builder
, which
has a run
method. This builder's run
method is
executed after the insert statement is run, and is given an
InsertStatement.Result
object wrapping
the ResultSet
, so that the client can query for the
values of the primary key(s).
This implementation of InsertStatement
is a little
subtle, but it's hopefully intuitive for clients. The rule is simple:
With all statments, you always call the infix
run method. It's just that with insert statement, you can
call run
after the code block that sets the values, so you can
provide a second code block to get the results of the insert.