Initial Development #1
6
pom.xml
6
pom.xml
@ -113,6 +113,12 @@
|
|||||||
<version>3.46.1.2</version>
|
<version>3.46.1.2</version>
|
||||||
<scope>integration-test</scope>
|
<scope>integration-test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>42.7.5</version>
|
||||||
|
<scope>integration-test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -1,103 +0,0 @@
|
|||||||
package solutions.bitbadger.documents
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.DisplayName
|
|
||||||
import solutions.bitbadger.documents.query.Count
|
|
||||||
import solutions.bitbadger.documents.query.Find
|
|
||||||
import kotlin.test.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertNotNull
|
|
||||||
import kotlin.test.assertNull
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQLite integration tests for the `Custom` object / `custom*` connection extension functions
|
|
||||||
*/
|
|
||||||
@DisplayName("SQLite - Custom")
|
|
||||||
class CustomSQLiteIT {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("list succeeds with empty list")
|
|
||||||
fun listEmpty() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
|
||||||
db.conn.customNonQuery("DELETE FROM ${SQLiteDB.tableName}")
|
|
||||||
val result = db.conn.customList<JsonDocument>(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData)
|
|
||||||
assertEquals(0, result.size, "There should have been no results")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("list succeeds with a non-empty list")
|
|
||||||
fun listAll() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
|
||||||
val result = db.conn.customList<JsonDocument>(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData)
|
|
||||||
assertEquals(5, result.size, "There should have been 5 results")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("single succeeds when document not found")
|
|
||||||
fun singleNone() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
assertNull(
|
|
||||||
db.conn.customSingle(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData),
|
|
||||||
"There should not have been a document returned"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("single succeeds when a document is found")
|
|
||||||
fun singleOne() {
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
|
||||||
assertNotNull(
|
|
||||||
db.conn.customSingle<JsonDocument>(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData),
|
|
||||||
"There should not have been a document returned"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("nonQuery makes changes")
|
|
||||||
fun nonQueryChanges() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
|
||||||
assertEquals(
|
|
||||||
5L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
|
||||||
"There should have been 5 documents in the table"
|
|
||||||
)
|
|
||||||
db.conn.customNonQuery("DELETE FROM ${SQLiteDB.tableName}")
|
|
||||||
assertEquals(
|
|
||||||
0L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
|
||||||
"There should have been no documents in the table"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("nonQuery makes no changes when where clause matches nothing")
|
|
||||||
fun nonQueryNoChanges() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
|
||||||
assertEquals(
|
|
||||||
5L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
|
||||||
"There should have been 5 documents in the table"
|
|
||||||
)
|
|
||||||
db.conn.customNonQuery(
|
|
||||||
"DELETE FROM ${SQLiteDB.tableName} WHERE data->>'id' = :id",
|
|
||||||
listOf(Parameter(":id", ParameterType.STRING, "eighty-two"))
|
|
||||||
)
|
|
||||||
assertEquals(
|
|
||||||
5L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
|
||||||
"There should still have been 5 documents in the table"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("scalar succeeds")
|
|
||||||
fun scalar() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
assertEquals(
|
|
||||||
3L,
|
|
||||||
db.conn.customScalar("SELECT 3 AS it FROM ${SQLiteDB.catalog} LIMIT 1", mapFunc = Results::toCount),
|
|
||||||
"The number 3 should have been returned"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package solutions.bitbadger.documents
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.DisplayName
|
|
||||||
import kotlin.test.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.fail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQLite integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
|
||||||
*/
|
|
||||||
@DisplayName("SQLite - Document")
|
|
||||||
class DocumentSQLiteIT {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("insert works with default values")
|
|
||||||
fun insertDefault() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
assertEquals(0L, db.conn.countAll(SQLiteDB.tableName), "There should be no documents in the table")
|
|
||||||
val doc = JsonDocument("turkey", "", 0, SubDocument("gobble", "gobble"))
|
|
||||||
db.conn.insert(SQLiteDB.tableName, doc)
|
|
||||||
val after = db.conn.findAll<JsonDocument>(SQLiteDB.tableName)
|
|
||||||
assertEquals(1, after.size, "There should be one document in the table")
|
|
||||||
assertEquals(doc, after[0], "The document should be what was inserted")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("insert fails with duplicate key")
|
|
||||||
fun insertDupe() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
db.conn.insert(SQLiteDB.tableName, JsonDocument("a", "", 0, null))
|
|
||||||
try {
|
|
||||||
db.conn.insert(SQLiteDB.tableName, JsonDocument("a", "b", 22, null))
|
|
||||||
fail("Inserting a document with a duplicate key should have thrown an exception")
|
|
||||||
} catch (_: Exception) {
|
|
||||||
// yay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("insert succeeds with numeric auto IDs")
|
|
||||||
fun insertNumAutoId() =
|
|
||||||
SQLiteDB().use { db ->
|
|
||||||
try {
|
|
||||||
Configuration.autoIdStrategy = AutoId.NUMBER
|
|
||||||
Configuration.idField = "key"
|
|
||||||
assertEquals(0L, db.conn.countAll(SQLiteDB.tableName), "There should be no documents in the table")
|
|
||||||
|
|
||||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(0, "one"))
|
|
||||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(0, "two"))
|
|
||||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(77, "three"))
|
|
||||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(0, "four"))
|
|
||||||
|
|
||||||
val after = db.conn.findAll<NumIdDocument>(SQLiteDB.tableName, listOf(Field.named("key")))
|
|
||||||
assertEquals(4, after.size, "There should have been 4 documents returned")
|
|
||||||
assertEquals(
|
|
||||||
"1|2|77|78", after.joinToString("|") { it.key.toString() },
|
|
||||||
"The IDs were not generated correctly"
|
|
||||||
)
|
|
||||||
} finally {
|
|
||||||
Configuration.autoIdStrategy = AutoId.DISABLED
|
|
||||||
Configuration.idField = "id"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: UUID, Random String
|
|
||||||
}
|
|
@ -38,3 +38,6 @@ data class JsonDocument(val id: String, val value: String, val numValue: Int, va
|
|||||||
testDocuments.forEach { conn.insert(tableName, it) }
|
testDocuments.forEach { conn.insert(tableName, it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The test table name to use for integration tests */
|
||||||
|
val testTableName = "test_table"
|
||||||
|
80
src/integration-test/kotlin/common/Custom.kt
Normal file
80
src/integration-test/kotlin/common/Custom.kt
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package solutions.bitbadger.documents.common
|
||||||
|
|
||||||
|
import solutions.bitbadger.documents.*
|
||||||
|
import solutions.bitbadger.documents.query.Count
|
||||||
|
import solutions.bitbadger.documents.query.Find
|
||||||
|
import java.sql.Connection
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for the `Custom` object
|
||||||
|
*/
|
||||||
|
object Custom {
|
||||||
|
|
||||||
|
fun listEmpty(conn: Connection) {
|
||||||
|
JsonDocument.load(conn, testTableName)
|
||||||
|
conn.customNonQuery("DELETE FROM $testTableName")
|
||||||
|
val result = conn.customList<JsonDocument>(Find.all(testTableName), mapFunc = Results::fromData)
|
||||||
|
assertEquals(0, result.size, "There should have been no results")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun listAll(conn: Connection) {
|
||||||
|
JsonDocument.load(conn, testTableName)
|
||||||
|
val result = conn.customList<JsonDocument>(Find.all(testTableName), mapFunc = Results::fromData)
|
||||||
|
assertEquals(5, result.size, "There should have been 5 results")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun singleNone(conn: Connection) =
|
||||||
|
assertNull(
|
||||||
|
conn.customSingle(Find.all(testTableName), mapFunc = Results::fromData),
|
||||||
|
"There should not have been a document returned"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun singleOne(conn: Connection) {
|
||||||
|
JsonDocument.load(conn, testTableName)
|
||||||
|
assertNotNull(
|
||||||
|
conn.customSingle<JsonDocument>(Find.all(testTableName), mapFunc = Results::fromData),
|
||||||
|
"There should not have been a document returned"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonQueryChanges(conn: Connection) {
|
||||||
|
JsonDocument.load(conn, testTableName)
|
||||||
|
assertEquals(
|
||||||
|
5L, conn.customScalar(Count.all(testTableName), mapFunc = Results::toCount),
|
||||||
|
"There should have been 5 documents in the table"
|
||||||
|
)
|
||||||
|
conn.customNonQuery("DELETE FROM $testTableName")
|
||||||
|
assertEquals(
|
||||||
|
0L, conn.customScalar(Count.all(testTableName), mapFunc = Results::toCount),
|
||||||
|
"There should have been no documents in the table"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonQueryNoChanges(conn: Connection) {
|
||||||
|
JsonDocument.load(conn, testTableName)
|
||||||
|
assertEquals(
|
||||||
|
5L, conn.customScalar(Count.all(testTableName), mapFunc = Results::toCount),
|
||||||
|
"There should have been 5 documents in the table"
|
||||||
|
)
|
||||||
|
conn.customNonQuery(
|
||||||
|
"DELETE FROM $testTableName WHERE data->>'id' = :id",
|
||||||
|
listOf(Parameter(":id", ParameterType.STRING, "eighty-two"))
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
5L, conn.customScalar(Count.all(testTableName), mapFunc = Results::toCount),
|
||||||
|
"There should still have been 5 documents in the table"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun scalar(conn: Connection) {
|
||||||
|
JsonDocument.load(conn, testTableName)
|
||||||
|
assertEquals(
|
||||||
|
3L,
|
||||||
|
conn.customScalar("SELECT 3 AS it FROM $testTableName LIMIT 1", mapFunc = Results::toCount),
|
||||||
|
"The number 3 should have been returned"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
59
src/integration-test/kotlin/common/Document.kt
Normal file
59
src/integration-test/kotlin/common/Document.kt
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package solutions.bitbadger.documents.common
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import solutions.bitbadger.documents.*
|
||||||
|
import solutions.bitbadger.documents.sqlite.SQLiteDB
|
||||||
|
import java.sql.Connection
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
||||||
|
*/
|
||||||
|
object Document {
|
||||||
|
|
||||||
|
fun insertDefault(conn: Connection) {
|
||||||
|
assertEquals(0L, conn.countAll(testTableName), "There should be no documents in the table")
|
||||||
|
val doc = JsonDocument("turkey", "", 0, SubDocument("gobble", "gobble"))
|
||||||
|
conn.insert(testTableName, doc)
|
||||||
|
val after = conn.findAll<JsonDocument>(testTableName)
|
||||||
|
assertEquals(1, after.size, "There should be one document in the table")
|
||||||
|
assertEquals(doc, after[0], "The document should be what was inserted")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insertDupe(conn: Connection) {
|
||||||
|
conn.insert(testTableName, JsonDocument("a", "", 0, null))
|
||||||
|
try {
|
||||||
|
conn.insert(testTableName, JsonDocument("a", "b", 22, null))
|
||||||
|
fail("Inserting a document with a duplicate key should have thrown an exception")
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// yay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insertNumAutoId(conn: Connection) {
|
||||||
|
try {
|
||||||
|
Configuration.autoIdStrategy = AutoId.NUMBER
|
||||||
|
Configuration.idField = "key"
|
||||||
|
assertEquals(0L, conn.countAll(SQLiteDB.tableName), "There should be no documents in the table")
|
||||||
|
|
||||||
|
conn.insert(SQLiteDB.tableName, NumIdDocument(0, "one"))
|
||||||
|
conn.insert(SQLiteDB.tableName, NumIdDocument(0, "two"))
|
||||||
|
conn.insert(SQLiteDB.tableName, NumIdDocument(77, "three"))
|
||||||
|
conn.insert(SQLiteDB.tableName, NumIdDocument(0, "four"))
|
||||||
|
|
||||||
|
val after = conn.findAll<NumIdDocument>(SQLiteDB.tableName, listOf(Field.named("key")))
|
||||||
|
assertEquals(4, after.size, "There should have been 4 documents returned")
|
||||||
|
assertEquals(
|
||||||
|
"1|2|77|78", after.joinToString("|") { it.key.toString() },
|
||||||
|
"The IDs were not generated correctly"
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
Configuration.autoIdStrategy = AutoId.DISABLED
|
||||||
|
Configuration.idField = "id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: UUID, Random String
|
||||||
|
|
||||||
|
}
|
48
src/integration-test/kotlin/postgresql/CustomIT.kt
Normal file
48
src/integration-test/kotlin/postgresql/CustomIT.kt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package solutions.bitbadger.documents.postgresql
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import solutions.bitbadger.documents.common.Custom
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostgreSQL integration tests for the `Custom` object / `custom*` connection extension functions
|
||||||
|
*/
|
||||||
|
@DisplayName("PostgreSQL - Custom")
|
||||||
|
class CustomIT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("list succeeds with empty list")
|
||||||
|
fun listEmpty() =
|
||||||
|
PgDB().use { Custom.listEmpty(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("list succeeds with a non-empty list")
|
||||||
|
fun listAll() =
|
||||||
|
PgDB().use { Custom.listAll(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("single succeeds when document not found")
|
||||||
|
fun singleNone() =
|
||||||
|
PgDB().use { Custom.singleNone(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("single succeeds when a document is found")
|
||||||
|
fun singleOne() =
|
||||||
|
PgDB().use { Custom.singleOne(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("nonQuery makes changes")
|
||||||
|
fun nonQueryChanges() =
|
||||||
|
PgDB().use { Custom.nonQueryChanges(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("nonQuery makes no changes when where clause matches nothing")
|
||||||
|
fun nonQueryNoChanges() =
|
||||||
|
PgDB().use { Custom.nonQueryNoChanges(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("scalar succeeds")
|
||||||
|
fun scalar() =
|
||||||
|
PgDB().use { Custom.scalar(it.conn) }
|
||||||
|
}
|
27
src/integration-test/kotlin/postgresql/DocumentIT.kt
Normal file
27
src/integration-test/kotlin/postgresql/DocumentIT.kt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package solutions.bitbadger.documents.postgresql
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import solutions.bitbadger.documents.common.Document
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PostgreSQL integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
||||||
|
*/
|
||||||
|
@DisplayName("PostgreSQL - Document")
|
||||||
|
class DocumentIT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("insert works with default values")
|
||||||
|
fun insertDefault() =
|
||||||
|
PgDB().use { Document.insertDefault(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("insert fails with duplicate key")
|
||||||
|
fun insertDupe() =
|
||||||
|
PgDB().use { Document.insertDupe(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("insert succeeds with numeric auto IDs")
|
||||||
|
fun insertNumAutoId() =
|
||||||
|
PgDB().use { Document.insertNumAutoId(it.conn) }
|
||||||
|
}
|
53
src/integration-test/kotlin/postgresql/PgDB.kt
Normal file
53
src/integration-test/kotlin/postgresql/PgDB.kt
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package solutions.bitbadger.documents.postgresql
|
||||||
|
|
||||||
|
import solutions.bitbadger.documents.AutoId
|
||||||
|
import solutions.bitbadger.documents.Configuration
|
||||||
|
import solutions.bitbadger.documents.customNonQuery
|
||||||
|
import solutions.bitbadger.documents.ensureTable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper for a throwaway PostgreSQL database
|
||||||
|
*/
|
||||||
|
class PgDB : AutoCloseable {
|
||||||
|
|
||||||
|
private var dbName = ""
|
||||||
|
|
||||||
|
init {
|
||||||
|
dbName = "throwaway_${AutoId.generateRandomString(8)}"
|
||||||
|
Configuration.connectionString = connString("postgres")
|
||||||
|
Configuration.dbConn().use {
|
||||||
|
it.customNonQuery("CREATE DATABASE $dbName")
|
||||||
|
}
|
||||||
|
Configuration.connectionString = connString(dbName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val conn = Configuration.dbConn()
|
||||||
|
|
||||||
|
init {
|
||||||
|
conn.ensureTable(tableName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
conn.close()
|
||||||
|
Configuration.connectionString = connString("postgres")
|
||||||
|
Configuration.dbConn().use {
|
||||||
|
it.customNonQuery("DROP DATABASE $dbName")
|
||||||
|
}
|
||||||
|
Configuration.connectionString = null
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/** The table used for test documents */
|
||||||
|
val tableName = "test_table"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a connection string for the given database
|
||||||
|
*
|
||||||
|
* @param database The database to which the library should connect
|
||||||
|
* @return The connection string for the database
|
||||||
|
*/
|
||||||
|
private fun connString(database: String) =
|
||||||
|
"jdbc:postgresql://localhost/$database?user=postgres&password=postgres"
|
||||||
|
}
|
||||||
|
}
|
47
src/integration-test/kotlin/sqlite/CustomIT.kt
Normal file
47
src/integration-test/kotlin/sqlite/CustomIT.kt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package solutions.bitbadger.documents.sqlite
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import solutions.bitbadger.documents.common.Custom
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQLite integration tests for the `Custom` object / `custom*` connection extension functions
|
||||||
|
*/
|
||||||
|
@DisplayName("SQLite - Custom")
|
||||||
|
class CustomIT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("list succeeds with empty list")
|
||||||
|
fun listEmpty() =
|
||||||
|
SQLiteDB().use { Custom.listEmpty(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("list succeeds with a non-empty list")
|
||||||
|
fun listAll() =
|
||||||
|
SQLiteDB().use { Custom.listAll(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("single succeeds when document not found")
|
||||||
|
fun singleNone() =
|
||||||
|
SQLiteDB().use { Custom.singleNone(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("single succeeds when a document is found")
|
||||||
|
fun singleOne() =
|
||||||
|
SQLiteDB().use { Custom.singleOne(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("nonQuery makes changes")
|
||||||
|
fun nonQueryChanges() =
|
||||||
|
SQLiteDB().use { Custom.nonQueryChanges(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("nonQuery makes no changes when where clause matches nothing")
|
||||||
|
fun nonQueryNoChanges() =
|
||||||
|
SQLiteDB().use { Custom.nonQueryNoChanges(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("scalar succeeds")
|
||||||
|
fun scalar() =
|
||||||
|
SQLiteDB().use { Custom.scalar(it.conn) }
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package solutions.bitbadger.documents
|
package solutions.bitbadger.documents.sqlite
|
||||||
|
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import solutions.bitbadger.documents.*
|
||||||
import java.sql.Connection
|
import java.sql.Connection
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
@ -10,7 +11,7 @@ import kotlin.test.assertTrue
|
|||||||
* SQLite integration tests for the `Definition` object / `ensure*` connection extension functions
|
* SQLite integration tests for the `Definition` object / `ensure*` connection extension functions
|
||||||
*/
|
*/
|
||||||
@DisplayName("SQLite - Definition")
|
@DisplayName("SQLite - Definition")
|
||||||
class DefinitionSQLiteIT {
|
class DefinitionIT {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a database item exists
|
* Determine if a database item exists
|
28
src/integration-test/kotlin/sqlite/DocumentIT.kt
Normal file
28
src/integration-test/kotlin/sqlite/DocumentIT.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package solutions.bitbadger.documents.sqlite
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import solutions.bitbadger.documents.common.Document
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQLite integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
||||||
|
*/
|
||||||
|
@DisplayName("SQLite - Document")
|
||||||
|
class DocumentIT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("insert works with default values")
|
||||||
|
fun insertDefault() =
|
||||||
|
SQLiteDB().use { Document.insertDefault(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("insert fails with duplicate key")
|
||||||
|
fun insertDupe() =
|
||||||
|
SQLiteDB().use { Document.insertDupe(it.conn) }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("insert succeeds with numeric auto IDs")
|
||||||
|
fun insertNumAutoId() =
|
||||||
|
SQLiteDB().use { Document.insertNumAutoId(it.conn) }
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package solutions.bitbadger.documents
|
package solutions.bitbadger.documents.sqlite
|
||||||
|
|
||||||
|
import solutions.bitbadger.documents.AutoId
|
||||||
|
import solutions.bitbadger.documents.Configuration
|
||||||
|
import solutions.bitbadger.documents.ensureTable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
@ -23,16 +23,22 @@ object Document {
|
|||||||
val idField = Configuration.idField
|
val idField = Configuration.idField
|
||||||
val dialect = Configuration.dialect("Create auto-ID insert query")
|
val dialect = Configuration.dialect("Create auto-ID insert query")
|
||||||
val dataParam = if (AutoId.needsAutoId(strategy, document, idField)) {
|
val dataParam = if (AutoId.needsAutoId(strategy, document, idField)) {
|
||||||
|
when (dialect) {
|
||||||
|
Dialect.POSTGRESQL ->
|
||||||
|
when (strategy) {
|
||||||
|
AutoId.NUMBER -> "' || (SELECT coalesce(max(data->>'$idField')::numeric, 0) + 1 FROM $tableName) || '"
|
||||||
|
AutoId.UUID -> "\"${AutoId.generateUUID()}\""
|
||||||
|
AutoId.RANDOM_STRING -> "\"${AutoId.generateRandomString()}\""
|
||||||
|
else -> "\"' || (:data)->>'$idField' || '\""
|
||||||
|
}.let { ":data::jsonb || ('{\"$idField\":$it}')::jsonb" }
|
||||||
|
|
||||||
|
Dialect.SQLITE ->
|
||||||
when (strategy) {
|
when (strategy) {
|
||||||
AutoId.NUMBER -> "(SELECT coalesce(max(data->>'$idField'), 0) + 1 FROM $tableName)"
|
AutoId.NUMBER -> "(SELECT coalesce(max(data->>'$idField'), 0) + 1 FROM $tableName)"
|
||||||
AutoId.UUID -> "'${AutoId.generateUUID()}'"
|
AutoId.UUID -> "'${AutoId.generateUUID()}'"
|
||||||
AutoId.RANDOM_STRING -> "'${AutoId.generateRandomString()}'"
|
AutoId.RANDOM_STRING -> "'${AutoId.generateRandomString()}'"
|
||||||
else -> "(:data)->>'$idField'"
|
else -> "(:data)->>'$idField'"
|
||||||
}.let {
|
}.let { "json_set(:data, '$.$idField', $it)" }
|
||||||
when (dialect) {
|
|
||||||
Dialect.POSTGRESQL -> ":data::jsonb || ('{\"$idField\":$it}')::jsonb"
|
|
||||||
Dialect.SQLITE -> "json_set(:data, '$.$idField', $it)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
":data"
|
":data"
|
||||||
|
@ -47,7 +47,7 @@ object Parameters {
|
|||||||
* @return The query, with name parameters changed to `?`s
|
* @return The query, with name parameters changed to `?`s
|
||||||
*/
|
*/
|
||||||
fun replaceNamesInQuery(query: String, parameters: Collection<Parameter<*>>) =
|
fun replaceNamesInQuery(query: String, parameters: Collection<Parameter<*>>) =
|
||||||
parameters.sortedByDescending { it.name.length }.fold(query) { acc, param -> acc.replace(param.name, "?") }
|
parameters.sortedByDescending { it.name.length }.fold(query) { acc, param -> acc.replace(param.name, "?") }.also(::println)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the given parameters to the given query, returning a prepared statement
|
* Apply the given parameters to the given query, returning a prepared statement
|
||||||
@ -103,7 +103,7 @@ object Parameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParameterType.JSON -> stmt.setString(idx, param.value as String)
|
ParameterType.JSON -> stmt.setObject(idx, param.value as String, Types.OTHER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user