d11d2cd9-9fd7-4364-8864-c7961b139b18 — Commit 02b3108c
Changed files
Dockerfile | 15 ++++++++++++ README.md | 1 + docker-compose.yml | 31 ++++++++++++++++++++++++ src/main/kotlin/com/gs/db/Tables.kt | 2 +- src/main/kotlin/com/gs/routes/ItemRoutes.kt | 35 ++++++++++++++++----------- src/main/kotlin/com/gs/routes/ReviewRoutes.kt | 13 ++-------- 6 files changed, 71 insertions(+), 26 deletions(-)
Diff
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..b2935fb
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,15 @@
+# Build stage
+FROM gradle:8.12-jdk21 AS build
+WORKDIR /app
+COPY build.gradle.kts settings.gradle.kts ./
+COPY gradle ./gradle
+RUN gradle dependencies --no-daemon || true
+COPY src ./src
+RUN gradle buildFatJar --no-daemon
+
+# Run stage
+FROM eclipse-temurin:21-jre-alpine
+WORKDIR /app
+COPY --from=build /app/build/libs/*-all.jar app.jar
+EXPOSE 8080
+ENTRYPOINT ["java", "-jar", "app.jar"]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..207f106
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# d11d2cd9-9fd7-4364-8864-c7961b139b18.git
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..87d947e
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,31 @@
+services:
+ api:
+ build: .
+ ports:
+ - "8080:8080"
+ environment:
+ DB_URL: jdbc:postgresql://db:5432/grocery_scanner
+ DB_USER: postgres
+ DB_PASSWORD: postgres
+ depends_on:
+ db:
+ condition: service_healthy
+
+ db:
+ image: postgres:17-alpine
+ ports:
+ - "5432:5432"
+ environment:
+ POSTGRES_DB: grocery_scanner
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ volumes:
+ - pgdata:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+
+volumes:
+ pgdata:
diff --git a/src/main/kotlin/com/gs/db/Tables.kt b/src/main/kotlin/com/gs/db/Tables.kt
index 576dfc2..da42f4c 100644
--- a/src/main/kotlin/com/gs/db/Tables.kt
+++ b/src/main/kotlin/com/gs/db/Tables.kt
@@ -16,7 +16,7 @@ object Items : Table("items") {
object Reviews : Table("reviews") {
val id = varchar("id", 128)
- val itemId = varchar("item_id", 128).references(Items.id)
+ val itemId = varchar("item_id", 128).references(Items.id).index()
val rating = integer("rating")
val comment = text("comment")
diff --git a/src/main/kotlin/com/gs/routes/ItemRoutes.kt b/src/main/kotlin/com/gs/routes/ItemRoutes.kt
index 44f7ef1..060dae9 100644
--- a/src/main/kotlin/com/gs/routes/ItemRoutes.kt
+++ b/src/main/kotlin/com/gs/routes/ItemRoutes.kt
@@ -2,13 +2,29 @@ package com.gs.routes
import com.gs.db.Items
import com.gs.models.Item
-import io.ktor.http.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
+fun ensureItemExists(id: String) {
+ transaction {
+ val exists = Items.selectAll().where { Items.id eq id }.count() > 0
+ if (!exists) {
+ Items.insert {
+ it[Items.id] = id
+ it[productName] = ""
+ it[brands] = ""
+ it[quantity] = ""
+ it[categories] = ""
+ it[description] = ""
+ it[ingredientsText] = ""
+ }
+ }
+ }
+}
+
fun ResultRow.toItem() = Item(
id = this[Items.id],
productName = this[Items.productName],
@@ -23,25 +39,18 @@ fun Route.itemRoutes() {
route("/items/{id}") {
get {
val id = call.parameters["id"]!!
+ ensureItemExists(id)
val item = transaction {
- Items.selectAll().where { Items.id eq id }.singleOrNull()?.toItem()
- }
- if (item == null) {
- call.respond(HttpStatusCode.NotFound)
- return@get
+ Items.selectAll().where { Items.id eq id }.single().toItem()
}
call.respond(item)
}
put {
val id = call.parameters["id"]!!
- val exists = transaction { Items.selectAll().where { Items.id eq id }.count() > 0 }
- if (!exists) {
- call.respond(HttpStatusCode.NotFound)
- return@put
- }
val updated = call.receive<Item>()
- transaction {
+ ensureItemExists(id)
+ val item = transaction {
Items.update({ Items.id eq id }) {
it[productName] = updated.productName
it[brands] = updated.brands
@@ -50,8 +59,6 @@ fun Route.itemRoutes() {
it[description] = updated.description
it[ingredientsText] = updated.ingredientsText
}
- }
- val item = transaction {
Items.selectAll().where { Items.id eq id }.single().toItem()
}
call.respond(item)
diff --git a/src/main/kotlin/com/gs/routes/ReviewRoutes.kt b/src/main/kotlin/com/gs/routes/ReviewRoutes.kt
index 893bb58..7a546ef 100644
--- a/src/main/kotlin/com/gs/routes/ReviewRoutes.kt
+++ b/src/main/kotlin/com/gs/routes/ReviewRoutes.kt
@@ -1,6 +1,5 @@
package com.gs.routes
-import com.gs.db.Items
import com.gs.db.Reviews
import com.gs.models.Review
import io.ktor.http.*
@@ -20,11 +19,7 @@ private fun ResultRow.toReview() = Review(
fun Route.reviewRoutes() {
get("/items/{id}/reviews") {
val id = call.parameters["id"]!!
- val exists = transaction { Items.selectAll().where { Items.id eq id }.count() > 0 }
- if (!exists) {
- call.respond(HttpStatusCode.NotFound)
- return@get
- }
+ ensureItemExists(id)
val reviews = transaction {
Reviews.selectAll().where { Reviews.itemId eq id }.map { it.toReview() }
}
@@ -33,11 +28,7 @@ fun Route.reviewRoutes() {
post("/items/{id}/reviews") {
val id = call.parameters["id"]!!
- val exists = transaction { Items.selectAll().where { Items.id eq id }.count() > 0 }
- if (!exists) {
- call.respond(HttpStatusCode.NotFound)
- return@post
- }
+ ensureItemExists(id)
val input = call.receive<Review>()
val reviewId = UUID.randomUUID().toString()
val review = transaction {