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 = ?" } 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}") } } 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") } } 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") } } 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 && !resultSet.getBoolean("is_archived") } else { throw SQLException() } } catch (cause: SQLException) { throw DbElementNotFoundException("Could not find username or password") } } 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.") } } 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") ) } }