From aab5857b9450dc18d3f1690847ae44b05eeba818 Mon Sep 17 00:00:00 2001 From: Nicholas Kalar Date: Sun, 17 Aug 2025 14:00:09 -0400 Subject: [PATCH] initial Patron Service --- src/main/kotlin/service/PartonService.kt | 26 ----- src/main/kotlin/service/PatronService.kt | 131 +++++++++++++++++++++++ 2 files changed, 131 insertions(+), 26 deletions(-) delete mode 100644 src/main/kotlin/service/PartonService.kt create mode 100644 src/main/kotlin/service/PatronService.kt diff --git a/src/main/kotlin/service/PartonService.kt b/src/main/kotlin/service/PartonService.kt deleted file mode 100644 index 6f7eafb..0000000 --- a/src/main/kotlin/service/PartonService.kt +++ /dev/null @@ -1,26 +0,0 @@ -package codes.kalar.service - -import codes.kalar.exception.DbElementInsertionException -import codes.kalar.exception.DbElementNotFoundException -import kotlinx.serialization.json.Json -import java.sql.* - -class PartonService(private val connection: Connection) { - - companion object { - private const val SELECT_PATRON_BY_ = "" - private const val INSERT_PATRON = "" - private const val UPDATE_PATRON_BY_ID = "" - // In the event are "deleted" erroneously, having a flag set instead of actually removing the entry allows - // for quick reversal. - private const val ARCHIVE_PATRON_BY_ID = "" - } - - suspend fun create() {} - - suspend fun read() {} - - suspend fun update() {} - - suspend fun delete() {} -} diff --git a/src/main/kotlin/service/PatronService.kt b/src/main/kotlin/service/PatronService.kt new file mode 100644 index 0000000..3ad3c60 --- /dev/null +++ b/src/main/kotlin/service/PatronService.kt @@ -0,0 +1,131 @@ +package codes.kalar.service + +import codes.kalar.exception.DbElementNotFoundException +import codes.kalar.model.NewPatron +import codes.kalar.model.Patron +import java.sql.* + +class PatronService(private val connection: Connection) { + + companion object { + private const val SELECT_PATRON_BY_ID = "SELECT * FROM patron WHERE id = ?" + private const val SELECT_PATRON_BY_LOGIN_USERNAME = "SELECT * From patron where login_username = ?" + private const val INSERT_PATRON = + "INSERT INTO patron (name, has_good_standing, fee_total, is_archived, login_username, last_login, password) VALUES (?, ?, ?, ?, ?, ?, ?)" + private const val UPDATE_PATRON_BY_ID = + "UPDATE patron SET name = ?, has_good_standing = ?, fee_total = ?, is_archived = ?, login_username = ?, " + + "last_login = ?, password = ? WHERE id = ?" + + // In the event are "deleted" erroneously, having a flag set instead of actually removing the entry allows + // for quick reversal. + private const val ARCHIVE_PATRON_BY_ID = "UPDATE patron set is_archived = true WHERE id = ?" + } + + suspend fun create(newPatron: NewPatron): Long { + val statement = connection.prepareStatement(INSERT_PATRON, Statement.RETURN_GENERATED_KEYS) + statement.setString(1, newPatron.name) + statement.setBoolean(2, true) + statement.setLong(3, 0) + statement.setBoolean(4, false) + statement.setString(5, newPatron.loginUsername) + statement.setDate(6, Date(System.currentTimeMillis())) + statement.setString(7, newPatron.password) + statement.execute() + try { + val key = statement.generatedKeys + if (key.next()) { + return key.getLong(1) + } + return -1 + } catch (cause: SQLException) { + throw DbElementNotFoundException("Couldn't insert patron ${newPatron.name} into database. ${cause.message}") + } + } + + suspend fun readPatronById(id: Long): Patron { + try { + val statement = connection.prepareStatement(SELECT_PATRON_BY_ID, Statement.RETURN_GENERATED_KEYS) + statement.setLong(1, id) + val resultSet = statement.executeQuery() + if (resultSet.next()) { + val patron = createPatronFromResults(resultSet) + return patron + } else { + throw DbElementNotFoundException("Patron with ID $id not found") + } + } catch (cause: SQLException) { + throw DbElementNotFoundException("Patron with ID $id is not found") + } + } + + suspend fun readPatronByLoginUsername(username: String): Patron { + try { + val statement = connection.prepareStatement(SELECT_PATRON_BY_LOGIN_USERNAME) + statement.setString(1, username) + val resultSet = statement.executeQuery() + if (resultSet.next()) { + val patron = createPatronFromResults(resultSet) + return patron + } else { + throw SQLException() + } + } catch (cause: SQLException) { + throw DbElementNotFoundException("Could not find username or password") + } + } + + suspend fun loginPatronByLoginUsername(username: String, password: String): Boolean { + try { + val statement = connection.prepareStatement(SELECT_PATRON_BY_LOGIN_USERNAME) + statement.setString(1, username) + val resultSet = statement.executeQuery() + return if (resultSet.next()) { + resultSet.getString("password") == password + } else { + throw SQLException() + } + } catch (cause: SQLException) { + throw DbElementNotFoundException("Could not find username or password") + } + } + + suspend fun update(patron: Patron): Boolean { + val statement = connection.prepareStatement(UPDATE_PATRON_BY_ID) + statement.setString(1, patron.name) + statement.setBoolean(2, patron.hasGoodStanding) + statement.setLong(3, patron.feeTotal) + statement.setBoolean(4, patron.isArchived) + statement.setString(5, patron.loginUsername) + statement.setString(6, patron.lastLogin) + statement.setString(7, patron.password) + statement.setLong(8, patron.id) + try { + return !statement.execute() + } catch (cause: SQLException) { + throw DbElementNotFoundException("Patron with ID ${patron.id} not found.") + } + } + + suspend fun delete(id: Long) { + val statement = connection.prepareStatement(ARCHIVE_PATRON_BY_ID) + statement.setLong(1, id) + try { + statement.execute() + } catch (cause: SQLException) { + throw DbElementNotFoundException("Patron with ID $id not found.") + } + } + + fun createPatronFromResults(resultSet: ResultSet): Patron { + return Patron( + id = resultSet.getLong("id"), + name = resultSet.getString("name"), + hasGoodStanding = resultSet.getBoolean("has_good_standing"), + feeTotal = resultSet.getLong("fee_total"), + isArchived = resultSet.getBoolean("is_archived"), + lastLogin = resultSet.getString("last_login"), + password = "", // For security reasons... + loginUsername = resultSet.getString("login_username") + ) + } +}