Skip to content

Commit

Permalink
Use interfaces instead of data classes in api and fix other breaking …
Browse files Browse the repository at this point in the history
…changes
  • Loading branch information
alexstaeding committed May 22, 2024
1 parent 77f90da commit afd74d9
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ import java.util.UUID
*
* Represents a single user of a game.
*/
data class MinecraftUser(
override val uuid: UUID,
val username: String,
val ipAddress: String,
val nickname: String? = null,
) : DomainEntity {
interface MinecraftUser : DomainEntity {
val username: String
val ipAddress: String
val nickname: String?

data class CreateDto(
val id: UUID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ interface MinecraftUserRepository : MutableRepository<MinecraftUser, MinecraftUs
}

suspend fun MinecraftUserRepository.getOnlineUser(player: Player): MinecraftUser.Online =
getById(player.uniqueId)?.let { MinecraftUser.Online(it, player) }
findById(player.uniqueId)?.let { MinecraftUser.Online(it, player) }
?: throw IllegalStateException("User ${player.username} with id ${player.uniqueId} is not in the database!")
16 changes: 6 additions & 10 deletions api/src/main/kotlin/org/anvilpowered/catalyst/api/user/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@ import java.util.UUID
*
* Represents a single universal user across all games and platforms.
*/
data class User(
override val uuid: UUID,
val username: String,
val email: String? = null,
val discordUserId: Long? = null,
val minecraftUserId: UUID? = null,
) : DomainEntity, DomainFacet<User> {
interface User : DomainEntity, DomainFacet<User> {

val username: String
val email: String?
val discordUserId: Long?
val minecraftUser: MinecraftUser?

data class CreateDto(
val username: String,
Expand All @@ -48,9 +47,6 @@ data class User(
* Operations scoped within a platform context.
*/
interface PlatformScope {

val User.minecraftUser: MinecraftUser

val User.player: Player?
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ package org.anvilpowered.catalyst.proxy

import org.anvilpowered.anvil.core.config.Registry
import org.anvilpowered.catalyst.api.config.CatalystKeys
import org.anvilpowered.catalyst.proxy.db.user.MinecraftUserTable
import org.anvilpowered.catalyst.proxy.db.user.UserTable
import org.anvilpowered.catalyst.proxy.db.user.MinecraftUsers
import org.anvilpowered.catalyst.proxy.db.user.Users
import org.anvilpowered.catalyst.proxy.registrar.Registrar
import org.apache.logging.log4j.Logger
import org.jetbrains.exposed.sql.Database
Expand Down Expand Up @@ -65,8 +65,8 @@ class CatalystVelocityPlugin(
logger.info("Creating tables...")
transaction {
SchemaUtils.createMissingTablesAndColumns(
MinecraftUserTable,
UserTable,
MinecraftUsers,
Users,
)
}
logger.info("Finished creating tables.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ class PrivateMessageService(
private var replyMap = mutableMapOf<UUID, UUID>()

suspend fun sendMessage(source: Player, recipient: Player, content: Component) {
val sourceUser = minecraftUserRepository.getById(source.uniqueId)?.let { MinecraftUser.Online(it, source) }
val sourceUser = minecraftUserRepository.findById(source.uniqueId)?.let { MinecraftUser.Online(it, source) }
?: throw IllegalStateException("User ${source.username} with id ${source.uniqueId} is not in the database!")

val recipientUser = minecraftUserRepository.getById(recipient.uniqueId)?.let { MinecraftUser.Online(it, recipient) }
val recipientUser = minecraftUserRepository.findById(recipient.uniqueId)?.let { MinecraftUser.Online(it, recipient) }
?: throw IllegalStateException("User ${recipient.username} with id ${recipient.uniqueId} is not in the database!")

val message = PrivateMessage(sourceUser, recipientUser, content)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ internal class ChannelMessageBuilderImpl(
}

override suspend fun userId(userId: UUID): ChannelMessage.Builder =
user(requireNotNull(minecraftUserRepository.getById(userId)) { "Could not find user with id $userId" })
user(requireNotNull(minecraftUserRepository.findById(userId)) { "Could not find user with id $userId" })

override fun channel(channel: ChatChannel): ChannelMessage.Builder {
this.channel = channel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ suspend fun CommandExecutionScope<CommandSource>.extractMinecraftUserSource(
minecraftUserRepository: MinecraftUserRepository,
): MinecraftUser {
val player = extractPlayerSource()
val user = minecraftUserRepository.getById(player.uniqueId)
val user = minecraftUserRepository.findById(player.uniqueId)
if (user == null) {
context.source.sendMessage(
Component.text()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,64 +22,60 @@ import org.anvilpowered.anvil.core.db.MutableRepository
import org.anvilpowered.anvil.core.db.SizedIterable
import org.anvilpowered.catalyst.api.user.MinecraftUser
import org.anvilpowered.catalyst.api.user.MinecraftUserRepository
import org.anvilpowered.catalyst.api.user.User
import org.anvilpowered.catalyst.proxy.db.wrap
import org.apache.logging.log4j.Logger
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.mapLazy
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.jetbrains.exposed.sql.update
import java.util.UUID

class MinecraftUserRepositoryImpl(
private val logger: Logger,
) : MinecraftUserRepository {
class MinecraftUserRepositoryImpl(private val logger: Logger) : MinecraftUserRepository {

override suspend fun create(item: MinecraftUser.CreateDto): MinecraftUser = newSuspendedTransaction {
val user = MinecraftUserEntity.new(item.id) {
val user = DBMinecraftUser.new(item.id) {
username = item.username
ipAddress = item.ipAddress
}.let { MinecraftUser(it.id.value, item.username, item.ipAddress) }
}

logger.info("Created new MinecraftUser ${item.id} with data $item")

user
}

override suspend fun put(item: MinecraftUser.CreateDto): MutableRepository.PutResult<MinecraftUser> = newSuspendedTransaction {
val existingUser = getById(item.id)
val existingUser = findById(item.id)
if (existingUser == null) {
// create a new MinecraftUser and accompanying User
val newUser = MinecraftUserEntity.new(item.id) {
val newUser = DBMinecraftUser.new(item.id) {
username = item.username
ipAddress = item.ipAddress
}

// TODO: What if the user already exists?

val user = UserEntity.new {
val user = DBUser.new {
username = item.username
minecraftUser = newUser
}.let { User(it.id.value, item.username, minecraftUserId = item.id) }
}

logger.info("Created new MinecraftUser ${item.id} with data $item and accompanying User ${user.uuid}")

MutableRepository.PutResult(MinecraftUser(newUser.id.value, item.username, item.ipAddress), created = true)
MutableRepository.PutResult(newUser, created = true)
} else {
logger.info("Found existing MinecraftUser ${item.id} with username ${item.username}")
// update the existing MinecraftUser
if (existingUser.ipAddress != item.ipAddress) {
MinecraftUserTable.update({ MinecraftUserTable.id eq item.id }) {
MinecraftUsers.update({ MinecraftUsers.id eq item.id }) {
logger.info("Updating IP address of MinecraftUser ${item.id} from ${existingUser.ipAddress} to ${item.ipAddress}")
it[ipAddress] = item.ipAddress
}
}

if (existingUser.username != item.username) {
MinecraftUserTable.update({ MinecraftUserTable.id eq item.id }) {
MinecraftUsers.update({ MinecraftUsers.id eq item.id }) {
logger.info("Updating username of MinecraftUser ${item.id} from ${existingUser.username} to ${item.username}")
it[username] = item.username
}
Expand All @@ -90,47 +86,43 @@ class MinecraftUserRepositoryImpl(
}

override suspend fun getNickname(id: UUID): String? = newSuspendedTransaction {
MinecraftUserTable.select { MinecraftUserTable.id eq id }
MinecraftUsers.select { MinecraftUsers.id eq id }
.firstOrNull()
?.getOrNull(MinecraftUserTable.nickname)
?.getOrNull(MinecraftUsers.nickname)
}

override suspend fun updateNickname(id: UUID, nickname: String): Boolean = newSuspendedTransaction {
MinecraftUserTable.update({ MinecraftUserTable.id eq id }) {
it[MinecraftUserTable.nickname] = nickname
MinecraftUsers.update({ MinecraftUsers.id eq id }) {
it[MinecraftUsers.nickname] = nickname
} > 0
}

override suspend fun deleteNickname(id: UUID): Boolean = newSuspendedTransaction {
MinecraftUserTable.update({ MinecraftUserTable.id eq id }) {
MinecraftUsers.update({ MinecraftUsers.id eq id }) {
it[nickname] = null
} > 0
}

override suspend fun getAllUsernames(startWith: String): SizedIterable<String> = newSuspendedTransaction {
MinecraftUserEntity.find { MinecraftUserTable.username like "$startWith%" }.mapLazy { it.username }
DBMinecraftUser.find { MinecraftUsers.username like "$startWith%" }.mapLazy { it.username }
}.wrap()

override suspend fun getByUsername(username: String): MinecraftUser? = newSuspendedTransaction {
MinecraftUserTable.selectAll().where { MinecraftUserTable.username eq username }
.firstOrNull()
?.toMinecraftUser()
DBMinecraftUser.find { MinecraftUsers.username eq username }.firstOrNull()
}

override suspend fun countAll(): Long = newSuspendedTransaction {
MinecraftUserEntity.all().count()
DBMinecraftUser.all().count()
}

override suspend fun exists(id: UUID): Boolean =
newSuspendedTransaction { MinecraftUserEntity.findById(id) != null }
newSuspendedTransaction { DBMinecraftUser.findById(id) != null }

override suspend fun getById(id: UUID): MinecraftUser? = newSuspendedTransaction {
MinecraftUserTable.select { MinecraftUserTable.id eq id }
.firstOrNull()
?.toMinecraftUser()
override suspend fun findById(id: UUID): MinecraftUser? = newSuspendedTransaction {
DBMinecraftUser.findById(id)
}

override suspend fun deleteById(id: UUID): Boolean = newSuspendedTransaction {
MinecraftUserTable.deleteWhere { MinecraftUserTable.id eq id } > 0
MinecraftUsers.deleteWhere { MinecraftUsers.id eq id } > 0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,19 @@ import org.jetbrains.exposed.dao.UUIDEntity
import org.jetbrains.exposed.dao.UUIDEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.UUIDTable
import org.jetbrains.exposed.sql.ResultRow
import java.util.UUID

internal object MinecraftUserTable : UUIDTable("catalyst_minecraft_users") {
internal object MinecraftUsers : UUIDTable("catalyst_minecraft_users") {
val username = varchar("username", 255).uniqueIndex()
val ipAddress = varchar("ip_address", 255)
val nickname = varchar("nickname", 255).nullable()
}

internal class MinecraftUserEntity(id: EntityID<UUID>) : UUIDEntity(id) {
var username: String by MinecraftUserTable.username
var ipAddress: String by MinecraftUserTable.ipAddress
var nickname: String? by MinecraftUserTable.nickname
internal class DBMinecraftUser(id: EntityID<UUID>) : UUIDEntity(id), MinecraftUser {
override val uuid: UUID = id.value
override var username: String by MinecraftUsers.username
override var ipAddress: String by MinecraftUsers.ipAddress
override var nickname: String? by MinecraftUsers.nickname

companion object : UUIDEntityClass<MinecraftUserEntity>(MinecraftUserTable)
companion object : UUIDEntityClass<DBMinecraftUser>(MinecraftUsers)
}

internal fun ResultRow.toMinecraftUser() = MinecraftUser(
uuid = this[MinecraftUserTable.id].value,
username = this[MinecraftUserTable.username],
ipAddress = this[MinecraftUserTable.ipAddress],
nickname = this[MinecraftUserTable.nickname],
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,26 @@ import org.anvilpowered.anvil.core.db.Pagination
import org.anvilpowered.catalyst.api.user.User
import org.anvilpowered.catalyst.api.user.UserRepository
import org.apache.logging.log4j.Logger
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.SqlExpressionBuilder
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.jetbrains.exposed.sql.update
import java.util.UUID

class UserRepositoryImpl(
private val logger: Logger,
) : UserRepository {
class UserRepositoryImpl(private val logger: Logger) : UserRepository {
override suspend fun paginate(): Pagination<User> {
TODO("Not yet implemented")
}

override suspend fun create(item: User.CreateDto): User = newSuspendedTransaction {
val result = UserTable.insert {
it[username] = item.username
it[email] = item.email
it[discordUserId] = item.discordUserId
it[minecraftUserId] = item.minecraftUserId
}.resultedValues
val itemMinecraftUser = item.minecraftUserId?.let { id -> DBMinecraftUser.findById(id) }

val user = checkNotNull(result) { "Failed to create User ${item.username}" }
.single().toUser()
val user = DBUser.new {
username = item.username
email = item.email
discordUserId = item.discordUserId
minecraftUser = itemMinecraftUser
}

logger.info("Created new User ${user.uuid} with data $item")

Expand All @@ -65,22 +58,22 @@ class UserRepositoryImpl(
logger.info("Found existing User ${existingUser.uuid} with username ${existingUser.username}")

if (existingUser.email != item.email) {
UserTable.update({ UserTable.id eq existingUser.uuid }) {
Users.update({ Users.id eq existingUser.uuid }) {
logger.info("Updating email for User ${existingUser.uuid} from ${existingUser.email} to ${item.email}")
it[email] = item.email
}
}

if (existingUser.discordUserId != item.discordUserId) {
UserTable.update({ UserTable.id eq existingUser.uuid }) {
Users.update({ Users.id eq existingUser.uuid }) {
logger.info("Updating discordUserId for User ${existingUser.uuid} from ${existingUser.discordUserId} to ${item.discordUserId}")
it[discordUserId] = item.discordUserId
}
}

if (existingUser.minecraftUserId != item.minecraftUserId) {
UserTable.update({ UserTable.id eq existingUser.uuid }) {
logger.info("Updating minecraftUserId for User ${existingUser.uuid} from ${existingUser.minecraftUserId} to ${item.minecraftUserId}")
if (existingUser.minecraftUser?.uuid != item.minecraftUserId) {
Users.update({ Users.id eq existingUser.uuid }) {
logger.info("Updating minecraftUserId for User ${existingUser.uuid} from ${existingUser.minecraftUser?.uuid} to ${item.minecraftUserId}")
it[minecraftUserId] = item.minecraftUserId
}
}
Expand All @@ -89,24 +82,33 @@ class UserRepositoryImpl(
}
}

private suspend fun getOneWhere(condition: SqlExpressionBuilder.() -> Op<Boolean>): User? = newSuspendedTransaction {
UserTable.select { condition() }.firstOrNull()?.toUser()
override suspend fun findById(id: UUID): User? = newSuspendedTransaction {
DBUser.findById(id)
}

override suspend fun getByUsername(username: String): User? = newSuspendedTransaction {
DBUser.find { Users.username eq username }.firstOrNull()
}

override suspend fun getById(id: UUID): User? = getOneWhere { UserTable.id eq id }
override suspend fun getByUsername(username: String): User? = getOneWhere { UserTable.username eq username }
override suspend fun getByEmail(email: String): User? = getOneWhere { UserTable.email eq email }
override suspend fun getByDiscordUserId(id: Long): User? = getOneWhere { UserTable.discordUserId eq id }
override suspend fun getByEmail(email: String): User? = newSuspendedTransaction {
DBUser.find { Users.email eq email }.firstOrNull()
}

override suspend fun getByMinecraftUserId(id: UUID): User? = getOneWhere { UserTable.minecraftUserId eq id }
override suspend fun getByDiscordUserId(id: Long): User? = newSuspendedTransaction {
DBUser.find { Users.discordUserId eq id }.firstOrNull()
}

override suspend fun getByMinecraftUserId(id: UUID): User? = newSuspendedTransaction {
DBUser.find { Users.minecraftUserId eq id }.firstOrNull()
}

override suspend fun countAll(): Long = newSuspendedTransaction { UserEntity.all().count() }
override suspend fun countAll(): Long = newSuspendedTransaction { DBUser.all().count() }

override suspend fun exists(id: UUID): Boolean = newSuspendedTransaction {
UserEntity.findById(id) != null
DBUser.findById(id) != null
}

override suspend fun deleteById(id: UUID): Boolean = newSuspendedTransaction {
UserTable.deleteWhere { UserTable.id eq id } > 0
Users.deleteWhere { Users.id eq id } > 0
}
}
Loading

0 comments on commit afd74d9

Please sign in to comment.