WIP on tests
This commit is contained in:
@@ -45,15 +45,15 @@ enum class AutoId {
|
||||
* @param document The document whose need of an automatic ID should be determined
|
||||
* @param idProp The name of the document property containing the ID
|
||||
* @return `true` if the document needs an automatic ID, `false` if not
|
||||
* @throws IllegalArgumentException If bad input prevents the determination
|
||||
* @throws DocumentException If bad input prevents the determination
|
||||
*/
|
||||
fun <T> needsAutoId(strategy: AutoId, document: T, idProp: String): Boolean {
|
||||
if (document == null) throw IllegalArgumentException("document cannot be null")
|
||||
if (document == null) throw DocumentException("document cannot be null")
|
||||
|
||||
if (strategy == DISABLED) return false;
|
||||
|
||||
val id = document!!::class.memberProperties.find { it.name == idProp }
|
||||
if (id == null) throw IllegalArgumentException("$idProp not found in document")
|
||||
if (id == null) throw DocumentException("$idProp not found in document")
|
||||
|
||||
if (strategy == NUMBER) {
|
||||
return when (id.returnType) {
|
||||
@@ -61,7 +61,7 @@ enum class AutoId {
|
||||
Short::class.createType() -> id.call(document) == 0.toShort()
|
||||
Int::class.createType() -> id.call(document) == 0
|
||||
Long::class.createType() -> id.call(document) == 0.toLong()
|
||||
else -> throw IllegalArgumentException("$idProp was not a number; cannot auto-generate number ID")
|
||||
else -> throw DocumentException("$idProp was not a number; cannot auto-generate number ID")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ enum class AutoId {
|
||||
return id.call(document) == ""
|
||||
}
|
||||
|
||||
throw IllegalArgumentException("$idProp was not a string; cannot auto-generate UUID or random string")
|
||||
throw DocumentException("$idProp was not a string; cannot auto-generate UUID or random string")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,15 @@ class Comparison<T>(val op: Op, val value: T) {
|
||||
|
||||
/** Is the value for this comparison a numeric value? */
|
||||
val isNumeric: Boolean
|
||||
get() =
|
||||
if (op == Op.IN || op == Op.BETWEEN) {
|
||||
val values = value as? Collection<*>
|
||||
if (values.isNullOrEmpty()) {
|
||||
false
|
||||
} else {
|
||||
val first = values.elementAt(0)
|
||||
first is Byte || first is Short || first is Int || first is Long
|
||||
get() {
|
||||
val toCheck = when (op) {
|
||||
Op.IN -> {
|
||||
val values = value as? Collection<*>
|
||||
if (values.isNullOrEmpty()) "" else values.elementAt(0)
|
||||
}
|
||||
} else {
|
||||
value is Byte || value is Short || value is Int || value is Long
|
||||
Op.BETWEEN -> (value as Pair<*, *>).first
|
||||
else -> value
|
||||
}
|
||||
return toCheck is Byte || toCheck is Short || toCheck is Int || toCheck is Long
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ enum class Dialect {
|
||||
*/
|
||||
fun deriveFromConnectionString(connectionString: String): Dialect =
|
||||
when {
|
||||
connectionString.contains("sqlite") -> SQLITE
|
||||
connectionString.contains("postgresql") -> POSTGRESQL
|
||||
connectionString.contains(":sqlite:") -> SQLITE
|
||||
connectionString.contains(":postgresql:") -> POSTGRESQL
|
||||
else -> throw DocumentException("Cannot determine dialect from [$connectionString]")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,11 @@ class Field<T> private constructor(
|
||||
* @param paramName The parameter name to use for this field
|
||||
* @return A new `Field` with the parameter name specified
|
||||
*/
|
||||
fun withParameterName(paramName: String): Field<T> =
|
||||
Field(name, comparison, paramName, qualifier)
|
||||
fun withParameterName(paramName: String): Field<T> {
|
||||
if (!paramName.startsWith(':') && !paramName.startsWith('@'))
|
||||
throw DocumentException("Parameter must start with : or @ ($paramName)")
|
||||
return Field(name, comparison, paramName, qualifier)
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a qualifier (alias) for the document table
|
||||
@@ -29,7 +32,7 @@ class Field<T> private constructor(
|
||||
* @param alias The table alias for this field
|
||||
* @return A new `Field` with the table qualifier specified
|
||||
*/
|
||||
fun withQualifier(alias: String): Field<T> =
|
||||
fun withQualifier(alias: String) =
|
||||
Field(name, comparison, parameterName, alias)
|
||||
|
||||
/**
|
||||
@@ -74,16 +77,16 @@ class Field<T> private constructor(
|
||||
in listOf(Op.EXISTS, Op.NOT_EXISTS) -> ""
|
||||
Op.BETWEEN -> " ${parameterName}min AND ${parameterName}max"
|
||||
Op.IN -> " ($inParameterNames)"
|
||||
Op.IN_ARRAY -> if (dialect == Dialect.POSTGRESQL) " ARRAY['$inParameterNames']" else ""
|
||||
Op.IN_ARRAY -> if (dialect == Dialect.POSTGRESQL) " ARRAY[$inParameterNames]" else ""
|
||||
else -> " $parameterName"
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return if (dialect == Dialect.SQLITE && comparison.op == Op.IN_ARRAY) {
|
||||
val (table, _) = comparison.value as? Pair<String, *> ?: throw DocumentException("InArray field invalid")
|
||||
"EXISTS (SELECT 1 FROM json_each($table.data, '$.$name') WHERE value IN ($inParameterNames)"
|
||||
"EXISTS (SELECT 1 FROM json_each($table.data, '$.$name') WHERE value IN ($inParameterNames))"
|
||||
} else {
|
||||
"$fieldPath ${comparison.op.sql} $criteria"
|
||||
"$fieldPath ${comparison.op.sql}$criteria"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,60 +97,66 @@ class Field<T> private constructor(
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param value The value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> equal(name: String, value: T) =
|
||||
Field(name, Comparison(Op.EQUAL, value))
|
||||
fun <T> equal(name: String, value: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.EQUAL, value), paramName)
|
||||
|
||||
/**
|
||||
* Create a field greater-than comparison
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param value The value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> greater(name: String, value: T) =
|
||||
Field(name, Comparison(Op.GREATER, value))
|
||||
fun <T> greater(name: String, value: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.GREATER, value), paramName)
|
||||
|
||||
/**
|
||||
* Create a field greater-than-or-equal-to comparison
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param value The value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> greaterOrEqual(name: String, value: T) =
|
||||
Field(name, Comparison(Op.GREATER_OR_EQUAL, value))
|
||||
fun <T> greaterOrEqual(name: String, value: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.GREATER_OR_EQUAL, value), paramName)
|
||||
|
||||
/**
|
||||
* Create a field less-than comparison
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param value The value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> less(name: String, value: T) =
|
||||
Field(name, Comparison(Op.LESS, value))
|
||||
fun <T> less(name: String, value: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.LESS, value), paramName)
|
||||
|
||||
/**
|
||||
* Create a field less-than-or-equal-to comparison
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param value The value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> lessOrEqual(name: String, value: T) =
|
||||
Field(name, Comparison(Op.LESS_OR_EQUAL, value))
|
||||
fun <T> lessOrEqual(name: String, value: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.LESS_OR_EQUAL, value), paramName)
|
||||
|
||||
/**
|
||||
* Create a field inequality comparison
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param value The value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> notEqual(name: String, value: T) =
|
||||
Field(name, Comparison(Op.NOT_EQUAL, value))
|
||||
fun <T> notEqual(name: String, value: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.NOT_EQUAL, value), paramName)
|
||||
|
||||
/**
|
||||
* Create a field range comparison
|
||||
@@ -155,20 +164,22 @@ class Field<T> private constructor(
|
||||
* @param name The name of the field to be compared
|
||||
* @param minValue The lower value for the comparison
|
||||
* @param maxValue The upper value for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> between(name: String, minValue: T, maxValue: T) =
|
||||
Field(name, Comparison(Op.BETWEEN, Pair(minValue, maxValue)))
|
||||
fun <T> between(name: String, minValue: T, maxValue: T, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.BETWEEN, Pair(minValue, maxValue)), paramName)
|
||||
|
||||
/**
|
||||
* Create a field where any values match (SQL `IN`)
|
||||
*
|
||||
* @param name The name of the field to be compared
|
||||
* @param values The values for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> any(name: String, values: List<T>) =
|
||||
Field(name, Comparison(Op.IN, values))
|
||||
fun <T> any(name: String, values: Collection<T>, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.IN, values), paramName)
|
||||
|
||||
/**
|
||||
* Create a field where values should exist in a document's array
|
||||
@@ -176,10 +187,11 @@ class Field<T> private constructor(
|
||||
* @param name The name of the field to be compared
|
||||
* @param tableName The name of the document table
|
||||
* @param values The values for the comparison
|
||||
* @param paramName The parameter name for the field (optional, defaults to auto-generated)
|
||||
* @return A `Field` with the given comparison
|
||||
*/
|
||||
fun <T> inArray(name: String, tableName: String, values: List<T>) =
|
||||
Field(name, Comparison(Op.IN_ARRAY, Pair(tableName, values)))
|
||||
fun <T> inArray(name: String, tableName: String, values: Collection<T>, paramName: String? = null) =
|
||||
Field(name, Comparison(Op.IN_ARRAY, Pair(tableName, values)), paramName)
|
||||
|
||||
fun exists(name: String) =
|
||||
Field(name, Comparison(Op.EXISTS, ""))
|
||||
|
||||
@@ -34,7 +34,7 @@ object Query {
|
||||
* @param docId The ID value (optional; used for type determinations, string assumed if not provided)
|
||||
*/
|
||||
fun <TKey> byId(parameterName: String = ":id", docId: TKey? = null) =
|
||||
byFields(listOf(Field.equal(Configuration.idField, docId ?: "").withParameterName(parameterName)))
|
||||
byFields(listOf(Field.equal(Configuration.idField, docId ?: "", parameterName)))
|
||||
|
||||
/**
|
||||
* Create a `WHERE` clause fragment to implement a JSON containment query (PostgreSQL only)
|
||||
|
||||
Reference in New Issue
Block a user