diff --git a/.gitignore b/.gitignore
index aa697a3..efff912 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@
*.iml
out
gen
+
+dependency-reduced-pom.xml
\ No newline at end of file
diff --git a/README.md b/README.md
index 73591d9..014ba8a 100644
--- a/README.md
+++ b/README.md
@@ -17,19 +17,21 @@ MySQL Kotlin wrapper based on HikariCP
#### From Kotlin
``` kotlin
val kuery = Kuery[file: File]
+val kuery = Kuery[config: KueryConfig]
```
#### From Java
``` java
final Kuery kuery = Kuery.get(file: File);
+final Kuery kuery = Kuery.get(config: KueryConfig);
```
### 1-1. To initialize and shutdown a database use these two methods
-``` kotlin
+``` java
kuery.enable()
```
and
-``` kotlin
+``` java
kuery.disable()
```
@@ -45,23 +47,54 @@ val resource = kuery.resource()
``` java
final Connection resource = kuery.resource();
```
-*[Database#resource](https://github.com/KDatabases/Core/blob/master/src/main/kotlin/com.sxtanna/database/base/Database.kt#L96) will throw an IllegalStateException if it's unable to create a resource a/o the database isn't enabled*
+*[Database#resource](https://github.com/KDatabases/Core/blob/master/src/main/kotlin/com.sxtanna/database/base/Database.kt#L96) will throw an IllegalStateException if it's unable to into a resource a/o the database isn't enabled*
-### 2-1. Or you could utilize the Database's ability to automatically manage the connection with the *invoke* methods
+### 2-1. Or you could utilize the Database's ability to automatically manage the connection with various sql functions
-#### From Kotlin
-``` kotlin
-kuery {
- createTable("Table", "UUID" co Char(36, true), "Name" co VarChar(36))
+#### Creating a Table
+##### From Kotlin
+``` java
+kuery {
+ create("User", "name" co VarChar.of(255, true)) // deprecated in favour of the cacheable builders
+ex.
+ Create.table("User").co("name", VarChar(255, true))()
}
```
-#### From Java
+##### From Java
``` java
-kuery.execute(task -> task.createTable("Users", Column.tableColumns(Column.col("UUID", new SqlType.Char(36, true)), Column.col("Name", new SqlType.VarChar(16)))));
+kuery.execute(task -> {
+ task.execute(Create.table("User").co("name", new VarChar(255, true)));
+});
```
-*Yes, I know the Java version is ugly AF, but this can be slightly fixed with static imports*
+
+##### Storing a Create Statement (syntax is nearly the same for Kotlin and Java)
+``` java
+val createUser = Create.table("User").co("name", VarChar.of(255, true))
+
+vs
+
+final CreateBuilder createUser = Create.table("User").co("name", VarChar.of(255, true));
+```
+#### Using them however is quite different
+##### From Kotlin
+``` java
+kuery {
+ createUser()
+}
+```
+##### From Java
``` java
-kuery.execute(task -> task.createTable("Users", tableColumns(col("UUID", new Char(36, true)), col("Name", new VarChar(16)))));
+kuery.execute(task -> {
+ task.execute(createUser);
+});
```
+
+## More examples soon.
+#### For Java examples.
+- [JKueryTest](src/test/java/com/sxtanna/database/tests/JKueryTest.java)
+- [JKueryTestOrm](src/test/java/com/sxtanna/database/tests/JKueryTestOrm.java)
+#### For Kotlin examples.
+- [KKueryTest](src/test/kotlin/com/sxtanna/database/tests/KKueryTest.kt)
+- [KKueryTestOrm](src/test/kotlin/com/sxtanna/database/tests/KKueryTestOrm.kt)
diff --git a/pom.xml b/pom.xml
index f8f7ea8..d5a1234 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,29 +5,29 @@
Super
com.sxtanna.database
- 1.3.1
+ 2.0
../Super/pom.xml
4.0.0
Kuery
- 1.3.4
+ 2.0
jar
${project.artifactId}
MySQL Kotlin wrapper based on HikariCP
- https://github.com/KDatabases/Keury
+ https://github.com/KDatabases/Kuery
- git://github.com/KDatabases/Keury.git
- scm:git:git://github.com/KDatabases/Keury.git
+ git://github.com/KDatabases/Kuery.git
+ scm:git:git://github.com/KDatabases/Kuery.git
com.sxtanna.database
Core
- 1.2
+ 1.3
com.zaxxer
@@ -44,6 +44,12 @@
mysql-connector-java
${versionMySQLConnector}
+
+
+ com.sxtanna.database
+ Tests
+ 1.0
+
diff --git a/src/main/kotlin/com/sxtanna/database/Kuery.kt b/src/main/kotlin/com/sxtanna/database/Kuery.kt
index 1b11fdc..bd0bff0 100644
--- a/src/main/kotlin/com/sxtanna/database/Kuery.kt
+++ b/src/main/kotlin/com/sxtanna/database/Kuery.kt
@@ -4,8 +4,9 @@ import com.sxtanna.database.base.Database
import com.sxtanna.database.config.DatabaseConfigManager
import com.sxtanna.database.config.KueryConfig
import com.sxtanna.database.ext.loadOrSave
+import com.sxtanna.database.struct.base.Creator
import com.sxtanna.database.task.KueryTask
-import com.sxtanna.database.type.SqlObject
+import com.sxtanna.database.type.base.SqlObject
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import java.io.File
@@ -13,13 +14,13 @@ import java.sql.Connection
import java.sql.ResultSet
import kotlin.reflect.KClass
-class Kuery(override val config : KueryConfig) : Database() {
+class Kuery private constructor(override val config : KueryConfig) : Database() {
override val name : String = "Kuery"
lateinit var pool : HikariDataSource
private set
- val debug get() = config.debug ?: false
+ val debug by lazy { config.debug ?: false }
val creators = mutableMapOf, ResultSet.() -> SqlObject>()
override fun load() {
@@ -60,11 +61,18 @@ class Kuery(override val config : KueryConfig) : Database addCreator(creator : Creator) {
+ creators[creator.clazz] = creator
+ }
+
companion object : DatabaseConfigManager {
@JvmStatic
- override fun get(file : File) : Kuery = Kuery(getConfig(file))
+ override fun get(file : File) = super.get(file)
+
+ @JvmStatic
+ override fun get(config : KueryConfig) = Kuery(config)
@JvmStatic
override fun getConfig(file : File) = file.loadOrSave(KueryConfig.DEFAULT)
diff --git a/src/main/kotlin/com/sxtanna/database/struct/obj/annotations.kt b/src/main/kotlin/com/sxtanna/database/ext/annotations.kt
similarity index 98%
rename from src/main/kotlin/com/sxtanna/database/struct/obj/annotations.kt
rename to src/main/kotlin/com/sxtanna/database/ext/annotations.kt
index 1f4050b..b6f6fa2 100644
--- a/src/main/kotlin/com/sxtanna/database/struct/obj/annotations.kt
+++ b/src/main/kotlin/com/sxtanna/database/ext/annotations.kt
@@ -1,4 +1,4 @@
-package com.sxtanna.database.struct.obj
+package com.sxtanna.database.ext
import com.sxtanna.database.struct.obj.SqlType.*
import com.sxtanna.database.struct.obj.SqlType.Char
diff --git a/src/main/kotlin/com/sxtanna/database/ext/extensions.kt b/src/main/kotlin/com/sxtanna/database/ext/extensions.kt
deleted file mode 100644
index cbcf1d9..0000000
--- a/src/main/kotlin/com/sxtanna/database/ext/extensions.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-@file:JvmName("Kext")
-package com.sxtanna.database.ext
-
-import com.sxtanna.database.struct.Duo
-import com.sxtanna.database.type.JsonObject
-import java.math.BigInteger
-import java.sql.ResultSet
-import java.util.*
-
-/**
- * Special infix function for [Duo]
- *
- * @param value The value to create with this Duo
- * @sample createColumns
- */
-infix fun String.co(value : T) = Duo(this, value)
-
-
-/**
- * Convenience method for reading a UUID from a ResultSet
- *
- * @param column The column name
- * @return The UUID read from the column
- */
-fun ResultSet.getUniqueID(column : String) : UUID = UUID.fromString(getString(column))
-
-/**
- * Convenience method for reading a UUID from a ResultSet
- *
- * @param column The column name
- * @return The UUID read from the column
- */
-fun ResultSet.getBigInteger(column : String) : BigInteger = BigInteger(getString(column))
-
-/**
- * Convenience method for reading Objects from a Json String
- *
- * @param column The column name
- * @return The Object read from the column
- */
-inline fun ResultSet.getJson(column : String) : E {
- return gson.fromJson(getString(column), E::class.java)
-}
-
-
-/**
- * Invoke this block for every result in this set
- *
- * @param block The action
- * @sample sayUserNames
- */
-inline fun ResultSet.whileNext(block: ResultSet.() -> Unit) {
- while (this.next()) this.block()
-}
-
-/**
- * Use this block to map each result to an object
- *
- * @param mapper The result mapper
- * @sample getUserNames
- */
-inline fun ResultSet.mapWhileNext(mapper: ResultSet.() -> O): List {
- val output = mutableListOf()
- this.whileNext { output.add(this.mapper()) }
-
- return output
-}
-
-
-private fun createColumns() : Array> {
- return Duo.valueColumns("One" co 1, "Two" co 2, "True" co true)
-}
-
-private fun getUserNames(resultSet : ResultSet) {
- val names : List = resultSet.mapWhileNext { getString("Username") }
- for (name in names) println("Found user $name")
-}
-
-private fun sayUserNames(resultSet : ResultSet) {
- resultSet.whileNext { println("Found user ${getString("Username")}") }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/com/sxtanna/database/ext/data.kt b/src/main/kotlin/com/sxtanna/database/ext/kdata.kt
similarity index 82%
rename from src/main/kotlin/com/sxtanna/database/ext/data.kt
rename to src/main/kotlin/com/sxtanna/database/ext/kdata.kt
index 8256b28..62772a2 100644
--- a/src/main/kotlin/com/sxtanna/database/ext/data.kt
+++ b/src/main/kotlin/com/sxtanna/database/ext/kdata.kt
@@ -1,6 +1,10 @@
+@file:JvmName("KData")
+
package com.sxtanna.database.ext
+import com.sxtanna.database.struct.obj.Sort
import com.sxtanna.database.struct.obj.SqlType
+import com.sxtanna.database.struct.obj.Target
import kotlin.reflect.KProperty1
/**
@@ -39,6 +43,11 @@ const val LONG_TEXT_SIZE = NORM_MAX_UNSIGN
/**
* Represents all rows in a select statement
*/
+@get:JvmName("allRows")
val ALL_ROWS = arrayOf("*")
+@get:JvmName("noSort")
+val NO_SORTS = arrayOf()
+@get:JvmName("noWhere")
+val NO_WHERE = arrayOf()
typealias Adapter = KProperty1<*, *>.() -> SqlType
\ No newline at end of file
diff --git a/src/main/kotlin/com/sxtanna/database/ext/kext.kt b/src/main/kotlin/com/sxtanna/database/ext/kext.kt
new file mode 100644
index 0000000..a8e5db0
--- /dev/null
+++ b/src/main/kotlin/com/sxtanna/database/ext/kext.kt
@@ -0,0 +1,71 @@
+@file:JvmName("Kext")
+
+package com.sxtanna.database.ext
+
+import com.sxtanna.database.struct.base.Creator
+import com.sxtanna.database.struct.base.Duo
+import com.sxtanna.database.struct.obj.Sort
+import com.sxtanna.database.struct.obj.Target
+import com.sxtanna.database.task.builder.CreateBuilder
+import com.sxtanna.database.task.builder.InsertBuilder
+import com.sxtanna.database.task.builder.SelectBuilder
+import com.sxtanna.database.task.builder.UpdateBuilder
+import com.sxtanna.database.type.base.SqlObject
+import java.sql.ResultSet
+import java.util.function.Function
+import java.util.function.Supplier
+
+
+@JvmSynthetic
+fun attempt(catch : Boolean = false, block : () -> O) : O? {
+ try {
+ return block()
+ }
+ catch (e : Exception) {}
+ return null
+}
+
+@JvmOverloads
+fun attempt(catch : Boolean = false, block : Supplier) : O? = attempt(catch) { block.get() }
+
+
+fun Boolean.value(input : String?) = if (this) input ?: "" else ""
+
+/**
+ * Special infix function for [Duo]
+ *
+ * @param value The value to into with this Duo
+ * @sample createColumns
+ */
+infix fun String.co(value : T) = Duo(this, value)
+
+
+fun create(clazz : Class, creator : Function) = object : Creator(clazz.kotlin) {
+ override fun apply(t : ResultSet) : O = creator.apply(t)
+}
+
+
+fun data(vararg any : Any) = any
+
+fun sorts(vararg sorts : Sort) = sorts
+
+fun targets(vararg targets : Target) = targets
+
+
+//region Build Function Creators
+@JvmSynthetic
+inline fun createTable(name : String = T::class.simpleName!!) = CreateBuilder.from(name)
+
+@JvmSynthetic
+inline fun selectFrom(table : String = T::class.simpleName!!, noinline block : SelectBuilder.() -> Unit = {}) = SelectBuilder(T::class, table).apply(block)
+
+@JvmSynthetic
+inline fun insertInto(table : String = T::class.simpleName!!, noinline block : InsertBuilder.() -> Unit = {}) = InsertBuilder(T::class, table).apply(block)
+
+@JvmSynthetic
+inline fun updateIn(table : String = T::class.simpleName!!, noinline block : UpdateBuilder.() -> Unit = {}) = UpdateBuilder(T::class, table).apply(block)
+//endregion
+
+
+private fun createColumns() = Duo.valueColumns("One" co 1, "Two" co 2, "True" co true)
+
diff --git a/src/main/kotlin/com/sxtanna/database/ext/krs.kt b/src/main/kotlin/com/sxtanna/database/ext/krs.kt
new file mode 100644
index 0000000..e8de81f
--- /dev/null
+++ b/src/main/kotlin/com/sxtanna/database/ext/krs.kt
@@ -0,0 +1,111 @@
+@file:JvmName("Krs")
+
+package com.sxtanna.database.ext
+
+import java.math.BigInteger
+import java.sql.ResultSet
+import java.util.*
+import java.util.UUID.fromString
+import java.util.function.Consumer
+import java.util.function.Function
+
+/**
+ * Read a [UUID] from a [ResultSet]
+ *
+ * @param column The column name
+ * @return The UUID read from the column
+ */
+@JvmSynthetic
+@JvmName("gUUID")
+fun ResultSet.getUUID(column : String) = getUUID(this, column)
+
+/**
+ * Read a [BigInteger] from a [ResultSet]
+ *
+ * @param column The column name
+ * @return The UUID read from the column
+ */
+@JvmSynthetic
+@JvmName("gBINT")
+fun ResultSet.getBigInt(column : String) = getBigInt(this, column)
+
+/**
+ * Read any object [J] from the [ResultSet]
+ *
+ * **Row data must actually contain serialized object**
+ */
+@JvmSynthetic
+inline fun ResultSet.getJson(column : String) = getJson(this, J::class.java, column)
+
+/**
+ * Read an Enum constant from a [ResultSet]
+ */
+@JvmSynthetic
+inline fun > ResultSet.getEnum(column : String) = getEnum(this, E::class.java, column)
+
+
+/**
+ * Execute this block of code for every result in the set
+ * @sample sayUserNames
+ */
+@JvmSynthetic
+inline fun ResultSet.whileNext(block : ResultSet.() -> Unit) {
+ while (this.next()) this.block()
+}
+
+/**
+ * Map each result in the set to an object and return a list of them
+ * @sample getUserNames
+ */
+@JvmSynthetic
+inline fun ResultSet.mapWhileNext(mapper : ResultSet.() -> O) : List {
+ val output = mutableListOf()
+ this.whileNext { output.add(this.mapper()) }
+
+ return output
+}
+
+
+/**
+ * Convenience methods for accessing ResultSet data without having to worry about catching exceptions
+ */
+
+fun getInt(rs : ResultSet, column : String) = attempt { rs.getInt(column) }
+
+fun getLong(rs : ResultSet, column : String) = attempt { rs.getLong(column) }
+
+fun getString(rs : ResultSet, column : String) = attempt { rs.getString(column) }
+
+fun getDouble(rs : ResultSet, column : String) = attempt { rs.getDouble(column) }
+
+fun getUUID(rs : ResultSet, column : String) : UUID {
+ val uuid = rs.getString(column)
+ return checkNotNull(fromString(uuid)) { "Bad UUID $uuid at column $column" }
+}
+
+fun getBigInt(rs : ResultSet, column : String) = BigInteger(rs.getString(column))
+
+fun getJson(rs : ResultSet, clazz : Class, column : String) : J {
+ val data = rs.getString(column)
+ return checkNotNull(attempt { gson.fromJson(data, clazz) }) { "Json data $data at column $column failed to be deserialized" }
+}
+
+fun > getEnum(rs : ResultSet, clazz : Class, column : String) : E {
+ val name = rs.getString(column)
+ return checkNotNull(clazz.enumConstants.find { it.name == name }) { "Enum value $name at column $column doesn't exist" }
+}
+
+
+fun whileNext(rs : ResultSet, block : Consumer) = rs.whileNext { block.accept(this) }
+
+fun mapWhileNext(rs : ResultSet, block : Function) = rs.mapWhileNext { block.apply(this) }
+
+
+private fun getUserNames(resultSet : ResultSet) {
+ val names = resultSet.mapWhileNext { getString("Username") }
+ for (name in names) println("Found user $name")
+}
+
+private fun sayUserNames(resultSet : ResultSet) {
+ resultSet.whileNext { println("Found user ${getString("Username")}") }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/sxtanna/database/struct/Resolver.kt b/src/main/kotlin/com/sxtanna/database/struct/Resolver.kt
index 7b1adc4..3e6e0ed 100644
--- a/src/main/kotlin/com/sxtanna/database/struct/Resolver.kt
+++ b/src/main/kotlin/com/sxtanna/database/struct/Resolver.kt
@@ -23,13 +23,14 @@ object Resolver {
private val adapters = mutableMapOf, Adapter>()
+
init {
- adapters[Char::class] = { SqlType.Char(1, isPrimaryKey(), isNotNull()) }
- adapters[UUID::class] = { SqlType.Char(36, isPrimaryKey(), isNotNull()) }
+ this[Char::class] = { SqlType.Char(1, isPrimaryKey(), isNotNull()) }
+ this[UUID::class] = { SqlType.Char(36, isPrimaryKey(), isNotNull()) }
- adapters[Boolean::class] = { SqlType.Bool(isPrimaryKey(), isNotNull()) }
+ this[Boolean::class] = { SqlType.Bool(isPrimaryKey(), isNotNull()) }
- adapters[Enum::class] = {
+ this[Enum::class] = {
if (isSerialized()) SqlType.VarChar(VARCHAR_SIZE, isPrimaryKey(), isNotNull())
else {
@Suppress("UNCHECKED_CAST")
@@ -37,14 +38,14 @@ object Resolver {
}
}
- adapters[Timestamp::class] = {
+ this[Timestamp::class] = {
val time = findAnnotation