[#6336] Add another Kotlin example using apply
This commit is contained in:
parent
3a039f6e5f
commit
962d7b6341
@ -41,7 +41,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<artifactId>kotlin-stdlib-jre8</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
</dependency>
|
||||
<!-- Testing -->
|
||||
|
||||
@ -48,6 +48,8 @@ import java.sql.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
// This example project simply uses a standalone JDBC connection, but you're free to use any other
|
||||
// means to connect to your database, including standard DataSources
|
||||
val properties = Properties();
|
||||
properties.load(properties::class.java.getResourceAsStream("/config.properties"));
|
||||
|
||||
@ -60,6 +62,9 @@ fun main(args: Array<String>) {
|
||||
val a = AUTHOR
|
||||
val b = BOOK
|
||||
|
||||
// This example shows just standard jOOQ API usage, which selects a couple of columns from a join expression
|
||||
// and then uses a closure to iterate over results. String interpolation is used, along with the implicit
|
||||
// it variable and the nice Record.get(Field) syntax sugar using it[field] syntax
|
||||
header("Books and their authors")
|
||||
ctx.select(a.FIRST_NAME, a.LAST_NAME, b.TITLE)
|
||||
.from(a)
|
||||
@ -69,6 +74,10 @@ fun main(args: Array<String>) {
|
||||
println("${it[b.TITLE]} by ${it[a.FIRST_NAME]} ${it[a.LAST_NAME]}")
|
||||
}
|
||||
|
||||
// Kotlin allows for destructuring any type that has component1(), component2(), component3(), ... methods
|
||||
// into a tuple of local variables. These methods are currently added ad-hoc as operators further down in this
|
||||
// file (scroll down). Future support for these methods is on the roadmap:
|
||||
// https://github.com/jOOQ/jOOQ/issues/6245
|
||||
header("Books and their authors with destructuring")
|
||||
for ((first, last, title) in ctx.select(a.FIRST_NAME, a.LAST_NAME, b.TITLE)
|
||||
.from(a)
|
||||
@ -76,10 +85,13 @@ fun main(args: Array<String>) {
|
||||
.orderBy(1, 2, 3))
|
||||
println("$title by $first $last")
|
||||
|
||||
// Generated records (available through selectFrom()) contain getters (and setters) for each column.
|
||||
// Kotlin allows for property access syntax of Java getters!
|
||||
header("An author")
|
||||
val author = ctx.selectFrom(a).where(a.ID.eq(1)).fetchOne();
|
||||
println("${author.firstName} ${author.lastName}")
|
||||
|
||||
// Setters can profit from this property access syntax as well.
|
||||
header("Creating a new author")
|
||||
val author2 = ctx.newRecord(a);
|
||||
author2.firstName = "Alice"
|
||||
@ -87,6 +99,8 @@ fun main(args: Array<String>) {
|
||||
author2.store()
|
||||
println("${author2.firstName} ${author2.lastName}")
|
||||
|
||||
// With "imports" the namespace of an object for a closure, so we can avoid repeating the owner
|
||||
// reference of the properties (and methods) every time
|
||||
header("Using the with 'clause'")
|
||||
with (author2) {
|
||||
firstName = "Bob"
|
||||
@ -94,6 +108,7 @@ fun main(args: Array<String>) {
|
||||
store()
|
||||
}
|
||||
|
||||
// This also works with tables, and their columns!
|
||||
header("With can be used with statements too, to locally import tables")
|
||||
with (a) {
|
||||
ctx.select(FIRST_NAME, LAST_NAME)
|
||||
@ -105,21 +120,46 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply is a nice method that also closes over an object making all its methods available without the
|
||||
// need to explicitly reference the owner object. That's very very nice for this type of dynamic SQL!
|
||||
header("Conditional query clauses")
|
||||
val filtering = true;
|
||||
val joining = true;
|
||||
ctx.select(a.FIRST_NAME, a.LAST_NAME, if (joining) count() else value(""))
|
||||
.from(a)
|
||||
.apply { if (filtering) where(a.ID.eq(1)) }
|
||||
.apply { if (joining) join(b).on(a.ID.eq(b.AUTHOR_ID)) }
|
||||
.apply { if (joining) groupBy(a.FIRST_NAME, a.LAST_NAME) }
|
||||
.orderBy(a.ID)
|
||||
.fetch {
|
||||
println("${it[a.FIRST_NAME]} ${it[a.LAST_NAME]} ${if (joining) it[count()] else ""}")
|
||||
}
|
||||
|
||||
// Map (key, value) destructuring in foreach loops!
|
||||
header("As a map")
|
||||
for ((k, v) in author2.intoMap())
|
||||
println("${k.padEnd(20)} = $v")
|
||||
|
||||
// More destructuring
|
||||
header("As maps")
|
||||
for (r in ctx.fetch(b))
|
||||
for ((k, v) in r.intoMap())
|
||||
println("${r[b.ID]}: ${k.padEnd(20)} = $v")
|
||||
|
||||
// We can use inline functions that we design ourselves very easily. E.g. ilike() is not part of the
|
||||
// jOOQ API. It's defined further down in this file
|
||||
header("Custom jOOQ API extensions")
|
||||
println("${ctx.select(b.TITLE).from(b).where(b.TITLE.ilike("%animal%")).fetchOne(b.TITLE)}")
|
||||
|
||||
// Classic elvis operator, etc.
|
||||
header("Null safe dereferencing")
|
||||
println("${ctx.fetchOne(b, b.ID.eq(5))?.title ?: "book not found"}")
|
||||
|
||||
// Some operators can profit from "overloading" in Kotlin. E.g.
|
||||
// - the unary minus operator "-" maps to Field.unaryMinus()
|
||||
// - the binary plus operator "+" maps to Field.plus(Number)
|
||||
// - the unary negation operator "!" maps to Condition.not()
|
||||
// - etc.
|
||||
header("Operator overloading")
|
||||
ctx.select(a.FIRST_NAME, a.LAST_NAME, -count(), a.ID + 3)
|
||||
.from(a)
|
||||
@ -131,6 +171,7 @@ fun main(args: Array<String>) {
|
||||
println("Actor ID ${id - 3}: $first $last wrote ${-count} books")
|
||||
}
|
||||
|
||||
// Don't we wish for multiline strings in Java?
|
||||
header("Using multiline strings with the plain SQL API")
|
||||
ctx.resultQuery("""
|
||||
SELECT *
|
||||
@ -144,6 +185,8 @@ fun main(args: Array<String>) {
|
||||
println("${it.intoMap()}")
|
||||
}
|
||||
|
||||
// If you parse a SQL (multiline) string with jOOQ, jOOQ will try to translate the syntax to
|
||||
// the target dialect.
|
||||
header("Using multiline strings with the parser")
|
||||
val colX = field("x")
|
||||
val colY = field("y")
|
||||
@ -162,6 +205,15 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Just some nice formatted header printing
|
||||
*/
|
||||
fun header(text : String) {
|
||||
println()
|
||||
println(text)
|
||||
println(text.toCharArray().map { _ -> '-' }.joinToString(separator = ""))
|
||||
}
|
||||
|
||||
// Operators for Kotlin language-supported operator overloading
|
||||
// Support for these will be added to jOOQ where not already available:
|
||||
// https://github.com/jOOQ/jOOQ/issues/6246
|
||||
|
||||
@ -1,74 +0,0 @@
|
||||
/**
|
||||
* This work is dual-licensed
|
||||
* - under the Apache Software License 2.0 (the "ASL")
|
||||
* - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
|
||||
* =============================================================================
|
||||
* You may choose which license applies to you:
|
||||
*
|
||||
* - If you're using this work with Open Source databases, you may choose
|
||||
* either ASL or jOOQ License.
|
||||
* - If you're using this work with at least one commercial database, you must
|
||||
* choose jOOQ License
|
||||
*
|
||||
* For more information, please visit http://www.jooq.org/licenses
|
||||
*
|
||||
* Apache Software License 2.0:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* jOOQ License and Maintenance Agreement:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Data Geekery grants the Customer the non-exclusive, timely limited and
|
||||
* non-transferable license to install and use the Software under the terms of
|
||||
* the jOOQ License and Maintenance Agreement.
|
||||
*
|
||||
* This library is distributed with a LIMITED WARRANTY. See the jOOQ License
|
||||
* and Maintenance Agreement for more details: http://www.jooq.org/licensing
|
||||
*/
|
||||
package org.jooq.example.kotlin
|
||||
|
||||
// This is from the stdlib, which doesn't support AutoCloseable yet
|
||||
// https://github.com/JetBrains/kotlin/pull/807
|
||||
inline fun <T : AutoCloseable, R> T.use(block: (T) -> R): R {
|
||||
var closed = false
|
||||
try {
|
||||
return block(this)
|
||||
} catch (e: Exception) {
|
||||
closed = true
|
||||
try {
|
||||
close()
|
||||
} catch (closeException: Exception) {
|
||||
// eat the closeException as we are already throwing the original cause
|
||||
// and we don't want to mask the real exception
|
||||
|
||||
// TODO on Java 7 we should call
|
||||
// e.addSuppressed(closeException)
|
||||
// to work like try-with-resources
|
||||
// http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html#suppressed-exceptions
|
||||
}
|
||||
throw e
|
||||
} finally {
|
||||
if (!closed) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Just some nice formatted header printing
|
||||
*/
|
||||
fun header(text : String) {
|
||||
println()
|
||||
println(text)
|
||||
println(text.toCharArray().map { _ -> '-' }.joinToString(separator = ""))
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user