Skip to content

Commit

Permalink
workin on submit/refresh issue
Browse files Browse the repository at this point in the history
  • Loading branch information
sombriks committed Feb 15, 2024
1 parent 6824768 commit e0eaf57
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 34 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ bin/
.vscode/

### Mac OS ###
.DS_Store
.DS_Store

### Misc ###
*.db
18 changes: 18 additions & 0 deletions .idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Sample application showing how htmx teams up with javalin
- jdbi 3.44
- htmx 2.x
- apache velocity 2.3
- docker 25
- spock 2.3

A [good kotlin ide][10] is also recommended.
Expand Down Expand Up @@ -44,9 +43,16 @@ java -jar build/libs/sample-htmx-javalin-1.0-SNAPSHOT-all.jar
- Spock demands us to enable the groovy language in the project
- Groovy support has issues to proper set jvm toolchain, fallbacks to system
- There is a [nice htmx plugin][70] for intellij
- JDBI [fluent api][80] makes database access easier
- TodoItem needs an empty constructor so JDBI bean mapper can fill attributes in

## Next steps

- A good form to object mapper would be handy. Javalin has [validators][90] but
mapping pretty much manual
- Need a coverage solution that handles spock properly
-

[00]: https://github.com/sombriks/sample-htmx-javalin
[10]: https://www.jetbrains.com/idea/download
[20]: https://imperceptiblethoughts.com/shadow/getting-started/
Expand All @@ -55,3 +61,4 @@ java -jar build/libs/sample-htmx-javalin-1.0-SNAPSHOT-all.jar
[50]: https://javalin.io/plugins/rendering#configuring-a-template-engine
[60]: https://javalin.io/tutorials/javalin-logging
[70]: https://plugins.jetbrains.com/plugin/20588-htmx-support
[80]: https://jdbi.org/releases/3.44.1/#_fluent_api
10 changes: 7 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ application {

dependencies {
implementation("io.javalin:javalin:6.0.1")
implementation("org.slf4j:slf4j-simple:2.0.10")
implementation("io.javalin:javalin-rendering:6.0.1")
implementation("org.apache.velocity:velocity-engine-core:2.3")
implementation("org.jdbi:jdbi3-kotlin-sqlobject:3.44.1")
implementation("io.github.cdimascio:dotenv-kotlin:6.4.1")
implementation("org.webjars.npm:htmx.org:2.0.0-alpha1")
implementation("com.fasterxml.jackson.core:jackson-databind:2.16.1")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1")
implementation("org.jdbi:jdbi3-kotlin-sqlobject:3.44.1")
implementation("com.zaxxer:HikariCP:5.1.0")
implementation("org.slf4j:slf4j-simple:2.0.10")
implementation("io.github.cdimascio:dotenv-kotlin:6.4.1")

testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.spockframework:spock-core:2.3-groovy-4.0")

runtimeOnly("com.h2database:h2:2.2.224")

}

tasks.test {
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/sample/htmx/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import sample.htmx.config.Database
import sample.htmx.controller.TodoController
import sample.htmx.model.TodoItem
import sample.htmx.service.TodoService
import javax.xml.crypto.Data

class App(
private val controller: TodoController = TodoController(),
Expand Down Expand Up @@ -40,6 +41,7 @@ class App(
}

fun main() {
Database.init()
val app = App()
app.start()
}
39 changes: 37 additions & 2 deletions src/main/kotlin/sample/htmx/config/Database.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,42 @@
package sample.htmx.config

import org.slf4j.LoggerFactory
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import io.github.cdimascio.dotenv.Dotenv
import org.jdbi.v3.core.Jdbi
import javax.sql.DataSource

class Database {
private val logger by lazy { LoggerFactory.getLogger(Database::class.java) }

companion object {

private val dotenv by lazy {
Dotenv.configure().load()
}

private val config by lazy {
HikariConfig(dotenv.get("DATASOURCE_PROPERTIES"))
}

private val dataSource: DataSource by lazy {
HikariDataSource(config)
}

val jdbi: Jdbi by lazy {
Jdbi.create(dataSource)
}

fun init() {
jdbi.withHandle<Any, Exception> { handle ->
handle.execute("""
create table if not exists todos(
id integer primary key auto_increment,
description text not null,
done boolean default false,
created timestamp default now()
);
""".trimIndent())
}
}
}
}
5 changes: 4 additions & 1 deletion src/main/kotlin/sample/htmx/controller/TodoController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ class TodoController(private val service: TodoService = TodoService()) {

fun update(ctx: Context): Context {
logger.info("update")
val todo = ctx.bodyAsClass<TodoItem>()
val todo = TodoItem(
description = ctx.formParam("description").toString(),
done = ctx.formParam("done").toBoolean()
)
val id = ctx.pathParam("id").toLong()
todo.id = id
service.update(todo)
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/sample/htmx/model/TodoItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import java.time.LocalDateTime

class TodoItem(
var id: Long? = -1,
var description: String?,
var description: String? = "",
var done: Boolean? = false,
var created: LocalDateTime? = LocalDateTime.now()
)
54 changes: 45 additions & 9 deletions src/main/kotlin/sample/htmx/service/TodoService.kt
Original file line number Diff line number Diff line change
@@ -1,34 +1,70 @@
package sample.htmx.service

import org.jdbi.v3.core.Jdbi
import org.slf4j.LoggerFactory
import sample.htmx.config.Database
import sample.htmx.model.TodoItem

class TodoService(private val db: Database = Database()) {
class TodoService(private val db: Jdbi = Database.jdbi) {

private val logger by lazy { LoggerFactory.getLogger(TodoService::class.java) }
fun list(q: String? = ""): List<TodoItem> {
logger.info("list todos")
return listOf(TodoItem(1, "test"), TodoItem(2, "test"))
return db.withHandle<List<TodoItem>, Exception> { handle ->
handle.createQuery(
"""
select * from todos
where lower(description) like lower(:q)
""".trimIndent()
).bind("q", "%$q%").mapToBean(TodoItem::class.java).list()
}
}

fun find(id: Long): TodoItem {
logger.info("find todos")
return TodoItem(id, "test")
return db.withHandle<TodoItem, Exception> { handle ->
handle.createQuery(
"""
select * from todos
where id = :id
""".trimIndent()
).bind("id", id).mapToBean(TodoItem::class.java).one()
}
}

fun insert(item: TodoItem): String {
fun insert(item: TodoItem): Int {
logger.info("insert todo")
return "OK"
return db.withHandle<Int, Exception> { handle ->
handle.createUpdate(
"""
insert into todos(description, done)
values (:description, :done)
""".trimIndent()
).bindBean(item).execute()
}
}

fun update(item: TodoItem): String {
fun update(item: TodoItem): Int {
logger.info("update todo")
return "OK"
return db.withHandle<Int, Exception> { handle ->
handle.createUpdate(
"""
update todos
set description = :description,
done = :done where id = :id
""".trimIndent()
).bindBean(item).execute()
}
}

fun delete(id: Long): String {
fun delete(id: Long): Int {
logger.info("delete todo")
return "OK"
return db.withHandle<Int, Exception> { handle ->
handle.createUpdate(
"""
delete from todos where id = :id
""".trimIndent()
).bind("id", id).execute()
}
}
}
4 changes: 1 addition & 3 deletions src/main/resources/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# the app is customizable via environment variables
DB_URL=
DB_USER=
DB_PASS=
DATASOURCE_PROPERTIES=/todo-datasource-dev.properties
# either development, test or production
MODE=development
8 changes: 1 addition & 7 deletions src/main/resources/templates/velocity/index.vm
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@
</head>
<body>
<h1>TODO List</h1>
<form hx-post="/todos"
hx-on::after-request="this.reset()" hx-swap="outerHTML" hx-target="#table">
<label>
<input name="description" placeholder="New todo here"/>
</label>
<button type="submit">Save</button>
</form>
#parse("/templates/velocity/todos/form.vm")
#parse("/templates/velocity/todos/list.vm")
</body>
</html>
7 changes: 7 additions & 0 deletions src/main/resources/templates/velocity/todos/form.vm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<form id="form" hx-post="/todos"
hx-on::after-request="this.reset()" hx-swap="outerHTML" hx-target="#table">
<label>Description
<input name="description" placeholder="New todo here"/>
</label>
<button type="submit">Save</button>
</form>
15 changes: 12 additions & 3 deletions src/main/resources/templates/velocity/todos/list.vm
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
<th>#</th>
<th>Description</th>
<th>Done?</th>
<th></th>
</tr>
#foreach($todo in $todos)
<tr>
<td>$todo.id</td>
<td>$todo.description</td>
<td>$todo.done</td>
<form hx-put="/todos/$todo.id" id="item$todo.id" hx-swap="outerHTML" hx-target="#table">
<td>$todo.id</td>
<td><input type="text" name="description" value="$todo.description"/></td>
<td>
<select name="done">
<option #if($todo.done) selected #end>true</option>
<option #if(!$todo.done) selected #end>false</option>
</select>
</td>
<td><button type="submit">Save</button></td>
</form>
</tr>
#end
</table>
8 changes: 8 additions & 0 deletions src/main/resources/todo-datasource-dev.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# src/main/resources/todo-datasource-dev.properties

driverClassName=org.h2.Driver
jdbcUrl=jdbc:h2:./todo
maximumPoolSize=10
minimumIdle=2
username=sa
password=sa
4 changes: 1 addition & 3 deletions src/test/resources/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# the app is customizable via environment variables
DB_URL=
DB_USER=
DB_PASS=
DATASOURCE_PROPERTIES=/todo-datasource-test.properties
# either development, test or production
MODE=test
8 changes: 8 additions & 0 deletions src/test/resources/todo-datasource-test.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# src/test/resources/todo-datasource-test.properties

driverClassName=org.h2.Driver
jdbcUrl=jdbc:h2:mem:todo
maximumPoolSize=10
minimumIdle=2
username=sa
password=sa

0 comments on commit e0eaf57

Please sign in to comment.