Statements

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 Parameters. 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.