• Stars
    star
    193
  • Rank 201,134 (Top 4 %)
  • Language
    Kotlin
  • License
    MIT License
  • Created almost 9 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A handy Database access library in Kotlin

KotliQuery

Awesome Kotlin Badge CI Builds Maven Central

KotliQuery is a handy RDB client library for Kotlin developers! The design is highly inspired by ScalikeJDBC, which is a proven database library in Scala. The priorities in this project are:

  • Less learning time
  • No breaking changes in releases
  • No additional complexity on top of JDBC

This library simply mitigates some pain points of the JDBC but our goal is not to completely encapsulate it.

Getting Started

The quickest way to try this library out would be to start with a simple Gradle project. You can find some examples here.

build.gradle

apply plugin: 'kotlin'

buildscript {
    ext.kotlin_version = '1.7.20'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
repositories {
    mavenCentral()
}
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'com.github.seratch:kotliquery:1.9.0'
    implementation 'com.h2database:h2:2.1.214'
}

Example

KotliQuery is much more easy-to-use than you expect. After just reading this short section, you will have learnt enough.

Creating DB Session

First thing you do is to create a Session object, which is a thin wrapper of java.sql.Connection instance. With this object, you can run queries using an established database connection.

import kotliquery.*

val session = sessionOf("jdbc:h2:mem:hello", "user", "pass") 

HikariCP

For production-grade applications, utilizing a connection pool library for better performance and resource management is highly recommended. KotliQuery provides an out-of-the-box solution that leverages HikariCP, which is a widely accepted connection pool library.

HikariCP.default("jdbc:h2:mem:hello", "user", "pass")

sessionOf(HikariCP.dataSource()).use { session ->
   // working with the session
}

DDL Execution

You can use a session for executing both DDLs and DMLs. The asExecute method if a query object sets the underlying JDBC Statement method to execute.

session.run(queryOf("""
  create table members (
    id serial not null primary key,
    name varchar(64),
    created_at timestamp not null
  )
""").asExecute) // returns Boolean

Update Operations

Using asUpdate is an appropriate way to perform insert/update/delete statements. This method sets the underlying JDBC Statement method to executeUpdate.

val insertQuery: String = "insert into members (name,  created_at) values (?, ?)"

session.run(queryOf(insertQuery, "Alice", Date()).asUpdate) // returns effected row count
session.run(queryOf(insertQuery, "Bob", Date()).asUpdate)

Select Queries

Now that you've got a database table named members, it's time to run your first SQL statement with this library! To build a callable SQL executor, your code follows the three steps for it:

  • Use queryOf factory method with a query statement and its parameters to create a new Query object
  • Use #map method to attache a result extracting function ((Row) -> A) to the Query object
  • Specify the response type (asList/asSingle) for the result

The following query returns a list of all member's IDs. In this line, the SQL statement is not yet executed. Also, this object allIdsQuery does not have any state. This means that you can reuse th object multiple times.

val allIdsQuery = queryOf("select id from members").map { row -> row.int("id") }.asList

With a valid session object, you can perform the SQL statement. The type of returned ids would be safely determined by Kotlin compiler.

val allIds: List<Int> = session.run(allIdsQuery)

As you see, the extractor function is greatly flexible. You can define functions with any return type. All you need to do is to implement a function that extracts values from JDBC ResultSet interator and map them into a single expected type value. Here is a complete example:

data class Member(
  val id: Int,
  val name: String?,
  val createdAt: java.time.ZonedDateTime)

val toMember: (Row) -> Member = { row -> 
  Member(
    row.int("id"), 
    row.stringOrNull("name"), 
    row.zonedDateTime("created_at")
  )
}

val allMembersQuery = queryOf("select id, name, created_at from members").map(toMember).asList
val allMembers: List<Member> = session.run(allMembersQuery)

If you are sure that a query can return zero or one row, asSingle returns an optional single value as below:

val aliceQuery = queryOf("select id, name, created_at from members where name = ?", "Alice").map(toMember).asSingle
val alice: Member? = session.run(aliceQuery)

Technically, it's also possible to use asSingle along with an SQL statement returning multiple rows. With the default setting, the result data extraction returns only the first row in the results and skips the rest. In other words, KotliQuery silently ignores the inefficiency and the potential misbehavior. If you prefer detection by an error in this scenario, you can pass strict flag to Session initializer. With strict set to true, the query execution throws an exception if it detects multiple rows for asSingle.

// Session object constructor
val session = Session(HikariCP.dataSource(), strict = true)

// an auto-closing code block for session
sessionOf(HikariCP.dataSource(), strict = true).use { session ->

}

Named query parameters

An alternative way to bind parameters is to use named parameters that start with : in the statement string. Note that, with this feature, KotliQuery still uses a prepared statement internally and your query execution is safe from SQL injection. The parameter parts like :name and :age in the following example query won't be just replaced as string values.

queryOf(
  """
  select id, name, created_at 
  from members 
  where (name = :name) and (age = :age)
  """, 
  mapOf("name" to "Alice", "age" to 20)
)

Performance-wise, the named parameter syntax can be slightly slower for parsing the statement plus a tiny bit more memory-consuming. But for most use case, the overhead should be ignorable. If you would like to make your SQL statements more readable and/or if your query has to repeat the same parameter in a query, using named query parameters should improve your productivity and the maintainability of the query a lot.

Typed params

You can specify the Java type for each parameter in the following way. Passing the class Parameter helps KotliQuery properly determine the type to bind for each parameter in queries.

val param = Parameter(param, String::class.java)
queryOf(
  """
  select id, name
  from members 
  where ? is null or ? = name
  """,
  param,
  param
)

As a handier way, you can use the following helper method.

queryOf(
  """
  select id, name 
  from members 
  where ? is null or ? = name
  """, 
  null.param<String>(),
  null.param<String>()
)

This functionality is particularly useful in the situations like the ones dsecribed here.

Working with Large Dataset

The #forEach allows you to work with each row with less memory consumption. With this way, your application code does not need to load all the query result data in memory at once. This feature is greatly useful when you load a large number of rows from a database table by a single query.

session.forEach(queryOf("select id from members")) { row ->
  // working with large data set
})

Transaction

Running queries in a transaction is of course supported! The Session object provides a way to start a transaction in a certain code block.

session.transaction { tx ->
  // begin
  tx.run(queryOf("insert into members (name,  created_at) values (?, ?)", "Alice", Date()).asUpdate)
}
// commit

session.transaction { tx ->
  // begin
  tx.run(queryOf("update members set name = ? where id = ?", "Chris", 1).asUpdate)
  throw RuntimeException() // rollback
}

As this library is a bit opinionated, transactions are available only with a code block. We intentionally do not support begin / commit methods. If you would like to manually manage the state of a transaction for some reason, you can use session.connection.commit() / session.connection.rollback() for it.

License

The MIT License Copyright (c) 2015 - Kazuhiro Sera

More Repositories

1

AWScala

Using AWS SDK on the Scala REPL
Scala
737
star
2

ChatGPT-in-Slack

Swift demonstration of how to build a Slack app that enables end-users to interact with a ChatGPT bot
Python
428
star
3

gistub

Sharing code snippets in-house
Ruby
242
star
4

deepl-for-slack

Slack app for DeepL Translate API users
TypeScript
145
star
5

notion-sdk-jvm

A Notion SDK for Any JVM Language
Kotlin
134
star
6

rspec-kickstarter

RSpec 3 code generator toward existing Ruby code.
Ruby
128
star
7

slack-edge

Slack app development framework for edge functions with streamlined TypeScript support
TypeScript
72
star
8

notion-translator

CLI tool to translate Notion pages into a different language
JavaScript
69
star
9

slack-cloudflare-workers

Slack app development framework for Cloudflare Workers
TypeScript
68
star
10

slack-app-examples

A collection of Slack App examples
TypeScript
59
star
11

bolt-starter

A Bolt ⚡️ app template with useful settings for easier development
JavaScript
52
star
12

chatgpt-on-deno

ChatGPT on Slack's next-gen modular platform
TypeScript
51
star
13

scalikesolr

Apache Solr Client for Scala/Java
Scala
51
star
14

serverless-slack-bolt-aws

Read this issue first - https://github.com/slackapi/bolt/issues/361
JavaScript
43
star
15

bigquery4s

A handy Scala wrapper of Google BigQuery API 's Java Client Library.
Scala
34
star
16

slack-bolt-extensions

Collection of bolt-js InstallationStore/Receiver implementations + Next.js support module
TypeScript
33
star
17

apriori.js

Apriori Algorithm implementation in TypeScript|JavaScript
JavaScript
30
star
18

junithelper

JUnit testing without dull routine
Java
30
star
19

slack-web-api-client

Streamlined Slack Web API client for TypeScript
TypeScript
29
star
20

apriori4j

Apriori Algorithm Implementation in Java, Scala
Java
26
star
21

bolt-on-cloud-functions-for-firebase

Read this issue first - https://github.com/slackapi/bolt/issues/361
JavaScript
24
star
22

finagle-cluster-demo

Finagle Hack-a-thon at Twitter Japan @yakitori
JavaScript
22
star
23

slack-timesheet

Timesheet, a Slack automation platform app for managing work hours
TypeScript
21
star
24

bit-valley-2020-slack-bolt-app

これは BIT VALLEY 2020 でのプレゼンテーション用のデモアプリです。インタラクティブな機能を使ったサンプルとして是非参考にしてみてください! https://git.io/BV_2020_Slack
JavaScript
20
star
25

bolt-on-heroku

Bolt example app in TypeScript on Heroku
TypeScript
16
star
26

slack_learning_app_ja

Slack プラットフォームの機能を学習するためのチュートリアルアプリ
Python
16
star
27

run-on-slack-template

"run-on-slack" app template
TypeScript
16
star
28

seratch-slack-types

Slack API TypeScript types generated by @seratch
TypeScript
15
star
29

inputvalidator

Scala Input Validator with quite readable DSL
Scala
15
star
30

slack-api-workshop-in-fukuoka-2019

Slack API workshop for Japanese developers
JavaScript
14
star
31

sadamasashi-compiler

さだまさしコンパイラ
Scala
14
star
32

slack-weather-radar-map

Japan Weather Radar Map (雨雲レーダー) on Slack ⛈️
TypeScript
13
star
33

deno-slack-data-mapper

A handy way to manage data in Slack's next-generation platform datastores
TypeScript
12
star
34

nhk4s

"NHK 番組表 API" client library for Scala
Scala
12
star
35

ltsv4s

LTSV parser implementation in Scala
Scala
11
star
36

r2dbc-samples-in-scala

Demonstrates how to use R2DBC - Reactive Relational Database Connectivity in Scala
Scala
11
star
37

new-relic-dashboard-in-slack

Tiny Bolt ⚡️ app demonstrating how to build Slack apps utilizing Slack's new features and New Relic APIs
JavaScript
11
star
38

testgenerator

Scala test generator sbt plugin
Scala
10
star
39

run-on-slack-deepl

A "run-on-slack" translator app powered by DeepL APIs
TypeScript
10
star
40

kenall-for-slack

ケンオール API (kenall.jp) を Slack から使えるようにするアプリ
Python
9
star
41

bolt-starter-ts

TypeScript
9
star
42

apriori-algorithm

Apriori Algorithm Ruby implementation
Ruby
9
star
43

send-it-later-for-slack

Send It Later for Slack users
Python
8
star
44

jslack-maintenance-releases

Maintenance releases for the jSlack library
Java
8
star
45

deepl-document-translator-for-slack

Translate the document files in Slack
Python
8
star
46

send-to-notion-in-slack-oss

Send to Notion in Slack (Simplified OSS Edition)
Python
8
star
47

hackernews4s

HackerNews API Client in Scala
Scala
8
star
48

bolt-aws-lambda-proof-of-concept

This repository was created in the aim of demonstrating the possibilities of proper FaaS (AWS Lambda, Google Cloud Functions etc) environment support by Bolt.
TypeScript
8
star
49

slack-new-emoji-notification

New Slack Emoji Notifications Built with Slack's Automation Platform
TypeScript
8
star
50

deepl-jvm

DeepL Kotlin/JavaVM Library
Kotlin
7
star
51

jp-holidays-for-slack

Slack app notifying national holidays in Japan
Python
7
star
52

spring-jersey-archetype

mvn archetype:generate -DarchetypeCatalog=http://seratch.github.com/mvn-repo/releases
Java
7
star
53

working-sql-in-scala

How to work with SQL queries in Scala - ScalikeJDBC, Slick StaticQuery and Anorm.
Scala
7
star
54

python-slack-scim

slack-scim - Slack SCIM API Client
Python
7
star
55

oauth-server-example

Just an OAuth 1.0a server example in Java
Java
7
star
56

slack-next-generation-platform-tutorials

Complete project examples for https://dev.to/seratch/series/21161
TypeScript
6
star
57

taskun

A simple crond thread on the JVM
Java
6
star
58

slack-cli-gh-actions-demo

Demonstrating Slack CLI Deployment Using GitHub Actions
TypeScript
6
star
59

bolt-kotlin-on-aws-lambda

Building Bolt Java apps on AWS Lambda
Kotlin
6
star
60

scalatra-thymeleaf-support

Scalatra Thymeleaf Support
Scala
6
star
61

dallish

An extended Dalli for memcached 1.4.x
Ruby
6
star
62

scaruby

Scala API in Ruby
Ruby
5
star
63

memcachedweaver

Caching methods result on memcached with AOP
Java
5
star
64

xsbt-scalag-plugin

Scala code/resource Generator Plugin for xsbt
Scala
5
star
65

sqlite3-foreigner

foreigner extension for SQLite3 users
Ruby
5
star
66

spring-boot-swagger-demo

Spring Boot example to demonstrate how to integrate Swagger 2.0 and swagger-codegen
Java
5
star
67

deno-daily-notification-workflow

Slack app demonstrating how to build a daily scheduled message notification
TypeScript
5
star
68

gyotaku

Saving complete web pages by using Selenium Web Driver
Scala
5
star
69

bolt-js-aws-lambda

Bolt for JavaScript: AWS Lambda Receiver prototype
TypeScript
5
star
70

slack-mention-reminder

"Mention Reminder" is a custom Slack app that allows you to set up reminders simply by mentioning its bot
TypeScript
5
star
71

signedrequest4j

A Java library supporting OAuth 1.0 signing and verifying
Java
4
star
72

apidays-workshop-2020

Apidays: Slack app workshop
Python
4
star
73

reactive-streams-jdbc

WIP: A sample to show how to work with RDBMS in the Reactive Streams way
Scala
4
star
74

redmine-reverse-scaffold

Rerverse scaffold demo from Redmine database schema
Scala
4
star
75

apache-module-samples

Learning Apache 2.4 module development
C
4
star
76

seratch-slack-app-toolkit

A toolkit to build Slack Apps in TypeScript
TypeScript
4
star
77

cloudflare-ai-translator-in-slack

Swift demonstration of how to utilize Cloudflare Workers AI within Slack's workflows
TypeScript
4
star
78

play-2.5-example

[scalikejdbc-users-group:526]
Scala
4
star
79

kansai-summit-handson

Scala Kansai Summit 2015 【ハンズオン】Skinny Framework 2.0 で試すお手軽 Scala Web アプリ開発
Scala
4
star
80

long-lasting-scala.g8

An sbt project template for long lasting OSS maintainers
Scala
4
star
81

ninja-coffee-example

CoffeeScript, wro4j, WebJars and Ninja Framework
Java
3
star
82

jslack-kotlin-examples

A collection of Slack API examples in Kotlin
Kotlin
3
star
83

scala3-slack-socket-mode-app

Slack Socket Mode App in Scala 3
Scala
3
star
84

deno-slack-data-mapper-starter

deno-slack-data-mapper project template
TypeScript
3
star
85

slack-daily-standup-ja

デイリースクラム(Slack スタンダードワークフロー)
TypeScript
3
star
86

slack-standard-workflow-collection

Collection of Slack's "standard" workflow templates
TypeScript
3
star
87

skinny-engine-example

Skinny Framework 2 has its own engine instead of Scalatra.
Scala
3
star
88

scalikejdbc-play-plugin

DEPRECATED: Moved to https://github.com/scalikejdbc/scalikejdbc-play-support
Scala
3
star
89

new-relic-dashboard-in-slack-kotlin

Tiny Lightning ⚡️ app demonstrating how to build Slack apps utilizing Slack's new features and New Relic APIs
Kotlin
3
star
90

slack-edge-app-template

Slack app project template demonstrating how to manage your slack-edge app using Slack CLI
TypeScript
3
star
91

rpscala-scalatra-example

#rpscala 72 Scalatra Example App
Scala
2
star
92

deno-slack-source-file-resolver

Automatically resolve functions' source_file for Slack's next-generation platform apps
TypeScript
2
star
93

my-tour-of-go

https://tour.golang.org/
Go
2
star
94

slack-remote-functions-on-cloudflare

Build a remote function for Slack's automation platform on Cloudflare Workers
TypeScript
2
star
95

bootstrap-downloader

curl -L http://git.io/bootstrap-downloader | sh
JavaScript
2
star
96

deno-editable-form-submissions

Slack automation platform app demonstrating how to build a workflow that allows a submitter to edit or delete their channel message
TypeScript
2
star
97

go-slack-sdk-experimental

WIP: Experimental Slack SDK in Go
Go
2
star
98

scalatra-with-jsp

A Scalatra demo app which works with legacy jsp files.
Scala
2
star
99

hash-ninja

Hash operations toolkit for Ruby Ninja
Ruby
2
star
100

scalatra-openid-provider-support

Scalatra OpenID Provider Support
Scala
2
star