Daniel J. Summers d202c002b5 Initial Development (#1)
This project now contains:
- A generic JVM document library (with Kotlin extensions on the JDBC `Connection` object)
- A Groovy library which adds extension methods to the `Connection` object
- A Scala library, which uses native Scala collections and adds Scala-style extension methods to the `Connection` object
- A Kotlin library which uses `kotlinx.serialization` (no reflection, reified generic types) along with `Connection` extensions

Reviewed-on: #1
2025-04-16 01:29:19 +00:00

83 lines
2.9 KiB
Kotlin

@file:JvmName("QueryUtils")
package solutions.bitbadger.documents.query
import solutions.bitbadger.documents.*
import kotlin.jvm.Throws
// ~~~ TOP-LEVEL FUNCTIONS FOR THE QUERY PACKAGE ~~~
/**
* Combine a query (`SELECT`, `UPDATE`, etc.) and a `WHERE` clause
*
* @param statement The first part of the statement
* @param where The `WHERE` clause for the statement
* @return The two parts of the query combined with `WHERE`
*/
fun statementWhere(statement: String, where: String) =
"$statement WHERE $where"
/**
* Create a query by a document's ID
*
* @param statement The SQL statement to be run against a document by its ID
* @param docId The ID of the document targeted
* @returns A query addressing a document by its ID
* @throws DocumentException If the dialect has not been set
*/
@Throws(DocumentException::class)
fun <TKey> byId(statement: String, docId: TKey) =
statementWhere(statement, Where.byId(docId = docId))
/**
* Create a query on JSON fields
*
* @param statement The SQL statement to be run against matching fields
* @param fields The field conditions to be matched
* @param howMatched Whether to match any or all of the field conditions (optional; default ALL)
* @return A query addressing documents by field matching conditions
*/
@Throws(DocumentException::class)
@JvmOverloads
fun byFields(statement: String, fields: Collection<Field<*>>, howMatched: FieldMatch? = null) =
statementWhere(statement, Where.byFields(fields, howMatched))
/**
* Create an `ORDER BY` clause for the given fields
*
* @param fields One or more fields by which to order
* @param dialect The SQL dialect for the generated clause
* @return An `ORDER BY` clause for the given fields
*/
@Throws(DocumentException::class)
@JvmOverloads
fun orderBy(fields: Collection<Field<*>>, dialect: Dialect? = null): String {
val mode = dialect ?: Configuration.dialect("generate ORDER BY clause")
if (fields.isEmpty()) return ""
val orderFields = fields.joinToString(", ") {
val (field, direction) =
if (it.name.indexOf(' ') > -1) {
val parts = it.name.split(' ')
Pair(Field.named(parts[0]), " " + parts.drop(1).joinToString(" "))
} else {
Pair<Field<*>, String?>(it, null)
}
val path = when {
field.name.startsWith("n:") -> Field.named(field.name.substring(2)).let { fld ->
when (mode) {
Dialect.POSTGRESQL -> "(${fld.path(mode)})::numeric"
Dialect.SQLITE -> fld.path(mode)
}
}
field.name.startsWith("i:") -> Field.named(field.name.substring(2)).path(mode).let { p ->
when (mode) {
Dialect.POSTGRESQL -> "LOWER($p)"
Dialect.SQLITE -> "$p COLLATE NOCASE"
}
}
else -> field.path(mode)
}
"$path${direction ?: ""}"
}
return " ORDER BY $orderFields"
}