Skip to content

Commit

Permalink
Merge pull request #53 from flytegg/clone/master
Browse files Browse the repository at this point in the history
Clone/master
  • Loading branch information
joshbker authored Feb 17, 2024
2 parents d4674e9 + ff1e5b3 commit ba61e99
Show file tree
Hide file tree
Showing 28 changed files with 739 additions and 77 deletions.
75 changes: 71 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Maven
<dependency>
<groupId>gg.flyte</groupId>
<artifactId>twilight</artifactId>
<version>1.1.6</version>
<version>1.1.7</version>
</dependency>
```

Expand All @@ -31,14 +31,14 @@ maven {
url "https://repo.flyte.gg/releases"
}
implementation "gg.flyte:twilight:1.1.6"
implementation "gg.flyte:twilight:1.1.7"
```

Gradle (Kotlin DSL)
```kotlin
maven("https://repo.flyte.gg/releases")

implementation("gg.flyte:twilight:1.1.6")
implementation("gg.flyte:twilight:1.1.7")
```

Certain features of Twilight require configuration, which can be done via the Twilight class. To setup a Twilight class instance, you can use the `twilight` function as shown below:
Expand Down Expand Up @@ -264,7 +264,8 @@ repeat(5, 10, TimeUnit.SECONDS, true) {

> Twilight `repeat` conflicting with Kotlin's `repeat`? As an alternative, you can use `repeatingTask`.
### Databases
## Databases
### MongoDB
Currently we have support for MongoDB. To configure it, you can take one of two routes:

#### Environment variables
Expand Down Expand Up @@ -333,6 +334,72 @@ collection.deleteById(id) // id must be the same type as the field marked as the

If we need something that isn't already wrapped by the TwilightMongoCollection, it exposes us the MongoCollection of Documents, which we can get with `collection.documents`.

### SQL (MySQL, Postgres)

#### Getting Started
To get started you need to create an instance of the SQL Wrapper like so
```kotlin
val db = SQLWrapper(url = "your db url", user="user", password="password")
db.connect()
```

#### QueryBuilder
The QueryBuilder class will help you in creating everything from simple queries like SELECT's to even complex JOIN's.
All you need to start is an instance of the query builder, here's an example usage
```kotlin
val queryBuilder = QueryBuilder()

// Example SELECT query
val selectQuery = queryBuilder.select("id", "name").from("person").where("age" gt 18).build()

// Example INSERT query
val insertQuery = queryBuilder.insertInto("person", "id", "name").values(1, "John").build()

// Example UPDATE query
val updateQuery = queryBuilder.update().table("person").set("name", "John Doe").where("id" eq 1).build()

// Example DELETE query
val deleteQuery = queryBuilder.delete().table("person").where("id = 1").build()
```
#### Using objects in your database
If you would like to retrieve and store data as objects within your database there a some methods provided for this


1 - Your object must implement SQLSerializable
2 - You must have a table that fits the structure of your object, you can create by calling `convertToSQLTable()` on your object, then execute the statement like so
```kotlin
// NOTE: convertToSQLTable() takes a optional dialect parameter, at this time the only additional dialect is postgres
val createTable = yourObjectInstace.convertToSQLTable()

if(db.execute(createTable)) {
// successfully executed
}
```
3 - To insert your object call `toInsertQuery()` like so
```kotlin
val insertToTable = yourObjectInstace.toInsertQuery()

if(db.execute(insertToTable)) {
// successfully executed
}
```

4 - To retrieve objects from your database you call a select statement like normal but call `toListOfObjects<Type>()` on the returned `Results` class

#### Running queries
Once you have your query using either the QueryBuilder or your own you can run it like so
```kotlin
val result = result.executeQuery(selectQuery)
```
once you have run the query it will return a `Results` class, it can be used like so
```kotlin
result?.let { res ->
println("MyColumn Value: " + res["my_column"])
}
```
The results class contains a list of all the rows and columns returned by the database.
You can access any of the columns values the same way you would with a map.

### Ternary Operator
There is a basic ternary operator implementation added which can be used like so:
```kotlin
Expand Down
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = "gg.flyte"
version = "1.1.6"
version = "1.1.7"

repositories {
mavenLocal()
Expand All @@ -28,6 +28,7 @@ dependencies {
api("org.mongodb:mongodb-driver-kotlin-sync:4.11.0")
api("com.google.code.gson:gson:2.10.1")

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0-RC2")
implementation(kotlin("reflect"))

// api("com.github.okkero:Skedule:v1.2.6")
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/gg/flyte/twilight/Twilight.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import gg.flyte.twilight.environment.Environment
import gg.flyte.twilight.event.custom.chat.command.ChatClickCommand
import gg.flyte.twilight.event.customEventListeners
import gg.flyte.twilight.extension.applyForEach
import gg.flyte.twilight.itembuilder.ItemBuilder
import gg.flyte.twilight.builders.item.ItemBuilder
import org.bukkit.plugin.java.JavaPlugin

class Twilight(javaPlugin: JavaPlugin) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package gg.flyte.twilight.itembuilder
package gg.flyte.twilight.builders.item

import gg.flyte.twilight.Twilight
import gg.flyte.twilight.event.event
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.attribute.Attribute
Expand All @@ -15,6 +14,9 @@ import org.bukkit.event.player.PlayerDropItemEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import java.util.*
import kotlin.collections.HashMap
import kotlin.collections.HashSet

class ItemBuilder(
var type: Material,
Expand All @@ -24,7 +26,7 @@ class ItemBuilder(
var unbreakable: Boolean = false,
val enchantments: MutableMap<Enchantment, Int> = HashMap(),
var customModelData: Int? = null,
var attributes: MutableMap<Attribute, AttributeModifier> = HashMap(),
var attributes: MutableMap<Attribute, AttributeModifier> = EnumMap(org.bukkit.attribute.Attribute::class.java),

val persistentStrings: MutableMap<String, String> = HashMap<String, String>().apply {
put(INTERACTION_UUID_KEY, uuidPdc())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gg.flyte.twilight.itembuilder
package gg.flyte.twilight.builders.item

enum class ItemInteraction {
RIGHT,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gg.flyte.twilight.itembuilder
package gg.flyte.twilight.builders.item

import org.bukkit.persistence.PersistentDataType
import java.util.*
Expand Down
43 changes: 43 additions & 0 deletions src/main/kotlin/gg/flyte/twilight/builders/recipe/RecipeBuilder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package gg.flyte.twilight.builders.recipe

import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.ShapedRecipe
import org.bukkit.plugin.java.JavaPlugin

class RecipeBuilder(result: ItemStack, plugin: JavaPlugin, key: String) {
private val recipe: ShapedRecipe = ShapedRecipe(NamespacedKey(plugin, key), result)
private val ingredients: MutableMap<Char, RecipeIngredient> = HashMap()

fun setShape(vararg shape: String): RecipeBuilder {
recipe.shape(*shape)
return this
}

fun setIngredient(key: Char, material: Material, amount: Int): RecipeBuilder {
val recipeIngredient = RecipeIngredient(ItemStack(material, amount))
recipe.setIngredient(key, recipeIngredient.materialData)
ingredients[key] = recipeIngredient
return this
}

fun setIngredient(key: Char, itemStack: ItemStack, amount: Int): RecipeBuilder {
val recipeIngredient = RecipeIngredient(itemStack.clone(), amount)
recipe.setIngredient(key, recipeIngredient.materialData)
ingredients[key] = recipeIngredient
return this
}

fun build(): ShapedRecipe {
ingredients.forEach { (key, value) ->
recipe.setIngredient(key, value.materialData)
}
return recipe
}

private inner class RecipeIngredient(private val itemStack: ItemStack, private val amount: Int = 1) {
val materialData: ItemStack
get() = itemStack.clone().apply { this.amount = amount }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ object NameCacheService {
private fun queryMongoNameByUUID(uuid: UUID): String? {
mongoCache.let {
mongoCache.find(Filters.eq("_id", uuid.toString())).first()
?.let {
.let {
val name =
it.getString("name") ?: throw MongoException("Document with '_id' '$uuid' has no field 'name'.")
cache[uuid] = name
return name
} ?: return null
}
}
}

Expand Down Expand Up @@ -78,12 +78,12 @@ object NameCacheService {
"name",
Pattern.compile("^$name$", Pattern.CASE_INSENSITIVE)
)
).first()?.let {
).first().let {
val uuid = UUID.fromString(it.getString("_id"))
?: throw MongoException("Document with 'name' '$name' has no valid UUID at '_id'.")
cache[uuid] = name
return uuid
} ?: return null
}
}
}

Expand Down
61 changes: 61 additions & 0 deletions src/main/kotlin/gg/flyte/twilight/data/sql/AsyncSQLWrapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package gg.flyte.twilight.data.sql

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import java.sql.Connection
import java.sql.DriverManager
import java.sql.PreparedStatement
import java.sql.Statement

class AsyncSQLWrapper(private val url: String, private val user: String, private val password: String) {

private var connection: Connection? = null

suspend fun connect() {
coroutineScope {
connection = DriverManager.getConnection(url, user, password)
}
}

suspend fun executeQuery(query: String): Results? {
return coroutineScope {
val resultSet = async(Dispatchers.IO) {
val statement: Statement? = connection?.createStatement()
statement?.executeQuery(query)
}
val rs = resultSet.await()
rs?.toResults()
}
}

suspend fun execute(sql: String): Boolean {
return coroutineScope {
var result = false
try {
val statement: Statement? = connection?.createStatement()
statement?.execute(sql)
result = true
} catch (e: Exception) {
e.printStackTrace()
}
result
}
}

suspend fun executeUpdate(query: String): Int {
return coroutineScope {
val rowsAffected = async(Dispatchers.IO) {
val statement: PreparedStatement? = connection?.prepareStatement(query)
statement?.executeUpdate() ?: 0
}
rowsAffected.await()
}
}

suspend fun close() {
coroutineScope {
connection?.close()
}
}
}
Loading

0 comments on commit ba61e99

Please sign in to comment.