How to Query a minimum value from a table in a room database? - kotlin

I am building a simple weight tracking app in Kotlin, using room, and am having a tough time finding the resource to figure out how to query and return just the one value from the database without it returning my entire data class.
I realize I am returning a list in my Dao, but can someone explain to me how to return just the minimum weight without the list?
I am still fairly new to room so any help is appreciated
my Dao
#Dao
interface WeightDao {
#Query("SELECT * FROM weight")
fun getAllWeightEntries():Flow<List<Weight>>
This does returns the lowest weight entry but includes everything else from my data class
#Query("SELECT * FROM weight WHERE weight_entry = (SELECT MIN(weight_entry) FROM weight)")
fun getLowestWeightEntry():Flow<List<Weight>>
My dataclass
#Entity(tableName = "weight")
data class Weight(
#PrimaryKey(autoGenerate = true)
val id: Int = 0,
#ColumnInfo(name = "weight_entry")
val weightEntry: Double,
#ColumnInfo(name = "weight_entry_notes")
val weightEntryNotes: String
)
Snippet from my viewmodel
val lowestWeightEntry: LiveData<List<Weight>> = weightDao.getLowestWeightEntry().asLiveData()
snippet from my u.i. fragment
viewModel.lowestWeightEntry.observe(this.viewLifecycleOwner) { item ->
item.let {
binding.tvLowestWeightTest.text = item.toString()
}
}

I believe that you could use the following:-
#Query("SELECT min(weight_entry) FROM weight")
fun getAllWeightEntries():Flow<Double>
Could also be String instead of Double (even Int or Long .... but you'd then reduce it to an integer value)
That is, if the output is a single column you can use the appropriate type for that value (as long as it's one of the types that Room supports directly for a column (i.e. no TypeConverter required)).
And obviously the viewmodel should expect to retrieve that type of value.
A Little more on the subject (POJO's for non #Entity types)
For anything other than a single value, other than for an #Entity annotated class that is defined in the entries parameter of the #Database annotation (which tells Room that the class is a table) then you need a POJO whose field names match the output field names.
e.g. say you had
#Query("SELECT min(weight_entry) AS min, max(weight_entry) AS max FROM weight")
fun getAllWeightEntries():Flow<weightMinAndMax>
The you could have a POJO such as:-
data class weightMinAndMax(
val min: Double,
val max: Int /* although should be Double */
)
note AS gives the output column an alias (min and max respectively) to suit the POJO fields (else output columns would be min(weight_entry) and max(weight_entry) respectively).
you can also use the name parameter of the #ColumnInfo to override the expected output column name
e.g. you could have
#Query("SELECT min(weight_entry) AS mymin, max(weight_entry) AS mymax FROM weight")
fun getAllWeightEntries():Flow<weightMinAndMax>
The you could have a POJO such as:-
data class weightMinAndMax(
#ColumnInfo(name = "mymin")
val min: Double,
#ColumnInfo(name = "mymax")
val max: Int /* although should be Double */
)
In Short; for a single value output from a Query Room does not need to match output columns with field names. For multiple value outputs from a Query then Room needs to be able to associate the output values with the respective fields in the recipient object.

Related

Jackson parses a map of strings to a declared class as a map of strings to maps. How do I make it create objects of the declared class instead?

I'm using jackson-module-kotlin:2.11.2 to parse some YAML. I'm trying to produce objects which contain a map, whose values are objects of a class that I have declared. This map instead contains values which are HashMaps.
Here are my declarations:
import com.fasterxml.jackson.module.kotlin.readValue
object Parser {
// ObjectMapper is thread safe as long as we don't mess with the config after this declaration.
val mapper: ObjectMapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
.registerModule(JavaTimeModule())
.registerModule(nullMapDeserialiserModule)
.registerModule(SimpleModule().setDeserializerModifier(ValidatingDeserializerModifier()))
// When parsing timestamps, we don't want to lose the offset information
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
// We would prefer an error if we're trying to store a float in an int
.disable(DeserializationFeature.ACCEPT_FLOAT_AS_INT)
// If a primitive field (like Int) is non-nullable (as in the Kotlin meaning), then we don't want nulls being converted to 0
.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
// Because enums could change order in future versions (if we keep them in lexicographic order, for example),
// we don't want the client to expect that they can give us the ordinal value of the enum.
.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
// When serialising schedule expressions, don't include null values
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
#Throws(JsonProcessingException::class)
inline fun <reified T: Any> deserialise(yaml: String): T = mapper.readValue(yaml)
}
data class ListValue (
val listValueKey: String,
val someOtherValue: Int
)
data class ExpectedValue (
val expectedValueKey: String,
val list: List<ListValue>
)
data class TestClass (
val testClassKey: String,
#param:JsonDeserialize(contentAs = ExpectedValue::class)
val testMap: Map<String, ExpectedValue>
)
Here is my test case:
#Test
fun `map parse test`() {
val testObj: TestClass? = RuleParser.deserialise(
//language=YAML
"""
testClassKey: the-key
testMap:
key1:
expectedValueKey: subKey1
list:
- listValueKey: someKey1
someOtherValue: 5
- listValueKey: anotherKey1
someOtherValue: 6
key2:
expectedValueKey: subKey2
list:
- listValueKey: someKey2
someOtherValue: 7
- listValueKey: anotherKey2
someOtherValue: 8
"""
)
assertTrue(testObj is TestClass)
assert(testObj.testMap is HashMap)
assertNotNull(testObj.testMap["key1"])
assert(testObj.testMap["key1"] is ExpectedValue)
assertEquals(
ExpectedValue(
expectedValueKey = "subKey1",
list = listOf(ListValue("someKey1", 5), ListValue("anotherKey1", 6))
),
testObj.testMap["key1"]
)
}
Currently, this test is failing on the final assertion, with the following error
Expected :ExpectedValue(expectedValueKey=subKey1, list=[ListValue(listValueKey=someKey1, someOtherValue=5), ListValue(listValueKey=anotherKey1, someOtherValue=6)])
Actual :{expectedValueKey=subKey1, list=[{listValueKey=someKey1, someOtherValue=5}, {listValueKey=anotherKey1, someOtherValue=6}]}
This is clearly not what I expected. If I instead parse a list of a declared class, this works correctly (example test follows).
#Test
fun `list parse test`() {
val testObj: ExpectedValue? = RuleParser.deserialise(
//language=YAML
"""
expectedValueKey: subKey1
list:
- listValueKey: someKey1
someOtherValue: 5
- listValueKey: anotherKey1
someOtherValue: 6
"""
)
assertTrue(testObj is ExpectedValue)
assertTrue(testObj.list[0] is ListValue)
assertEquals(
ListValue("someKey1", 5),
testObj.list[0]
)
}
So I'm a bit surprised that it is possible to parse a generic list in this way, but not a map. How do I get Jackson to create the map values that I expect, rather than HashMaps?
Your deserializer function is wrong. You must use the reified generic type in readValue method:
inline fun <reified T: Any> deserialise(yaml: String): T = mapper.readValue(yaml, T::class.java)
While it is odd that the annotation is needed at all (since it is not needed for lists of a declared type), it does work if the annotation is used as follows:
#field:JsonDeserialize(`as` = HashMap::class, contentAs = ExpectedValue::class)
This was not clear at first, because that javadoc for contentAs does not mention that as is also required.

How can I construct a generic object with a reified type parameter in Kotlin?

I have a class called Column<E> that delegates to a MutableList<E>.
To sort the Comparable elements ("e") of columns without providing a comparator, I pass a reified type argument ("type") to determine whether e implements comparable using reflection and then use e's compareTo method to construct a comparator. This all works fine.
I also have a function object called AggregateFunction that is used in reduce operations. AggregateFunction holds an actual function (to do the reduction operation), and a name (for programmatically creating a name for the result). There are several subtypes of AggregateFunction. NumericAggregateFunction, for example, takes an input column of type Column and always returns a Double.
The typical use case is to partition the input data into subgroups and return a Column containing the computed values for each subgroup. The catch is that I want to programmatically construct a column to hold the results. In the case of NumericAggregateFunction, I want to create a Column<Double>. For BooleanAggregateFunction, a Column<Boolean>, etc.
If I want Aggregate function to return a MutableList<Double> I can create it without a problem using:
fun resultList() : MutableList<OUT> {
return ArrayList<OUT>()
}
However, the same approach fails to compile for Column, apparently because of the reified type. If I attempt to use the inline function, e.g.
fun resultColumnA() : Column<OUT> {
return Column<OUT>("column name")
}
I get:
Cannot use 'OUT' as reified type parameter. Use a class instead.
I also attempted to call the primary constructor directly, passing in the type parameter as shown below, it also fails to compile:
fun resultColumn() : Column<OUT> {
return Column<OUT>(
inputColumn!!.type,
"column name")
}
I now get the error:
Type mismatch. Required: OUT Found: Any!
Finally, I tried reifying the type parameter in the context of the Aggregate function, adding these two methods:
inline fun <reified OUT> col(nm:String) =
Column(
OUT::class.java,
nm
)
fun resultColumnB() : Column<OUT> {
return this.col("name")
}
But the line return this.col("name") results in a compile time error:
Cannot use 'OUT' as reified type parameter. Use a class instead.
Is there a way to create a Column similar to how the MutableList was created?
If not, is there a way to determine whether the elements of a MutableList are comparable without using a reified type? If I didn't have to do that I could get rid of the type entirely.
Partial Implementation of class Column is included below
package com.fathom.core.tables
inline fun <reified E> Column(nm:String) =
Column(
E::class.java,
nm
)
open class Column<E>(val type: Class<E>, var name: String, val comparator : Comparator<E>? = null, val elements: MutableList<E?> = ArrayList()) : MutableList<E?> by elements{
var formatter: (E?) -> String = { e ->
if (e == null) "" else e.toString()
}
// when present, allows sorting on this vector without providing a comparator to the sort method
var defaultComparator: Comparator<E>? = null
/**
* Returns true if elements contained in this column implement comparable.
* That makes the column sortable
*/
fun isComparable(): Boolean {
return type.interfaces.contains(Comparable::class.java)
}
/**
* Returns an int comparator where the ints are the indexes of the elements of the column rather than the elements.
* It uses the indexes to get the values, which are then compared using
* (a) a Comparator<E> column property named 'comparator', or
* (b) the natural comparator for any column that implements Comparable
*
* #throws UnsupportedOperationException if the column has no comparator and doesn't implement Comparable
*/
#Suppress("UNCHECKED_CAST")
fun rowComparator() : Comparator<Int> {
if (comparator != null) {
return Comparator { r1, r2 ->
val v : E = get(r1) as E
val f1 : E = this[r1] as E
val f2 : E = this[r2] as E
comparator.compare(f1, f2)
}
}
if (!isComparable()) {
throw UnsupportedOperationException(
"Columns that are used in table sorts must either " +
"provide a comparator or contain elements that " +
"implement comparable"
)
}
return Comparator { r1, r2 ->
val v : E = get(r1) as E
val f1 : Comparable<E> = this[r1] as Comparable<E>
val f2 : E = get(r2) as E
f1.compareTo(f2)
}
}
}

Kotlin generic constraints - require param to be of same type as other

Let's say I have a set of two pojo's like so:
data class Test (
var id : Long? = null
)
data class TestOther (
var id : Long = 0,
var isCool : Boolean = false
}
and then I have an infix function like so:
infix fun <T : Any?> KProperty<T>.equal(rhs : KProperty<T>) = BinaryExpression<Boolean>(this, rhs, EQUALS)
then this works fine as I'd expect:
Test::id equal TestOther::id
but so does this, since T is all types that extend Any?:
Test::id equal TestOther::isCool
Is there anyway to specify generic constraints such that nullable and non nullable types can be compared, but objects of different types cannot without having to specify an overload for every possible concrete type?
It is not possible to do right now. You may follow the issue for more details
https://youtrack.jetbrains.com/issue/KT-13198
I see a workaround here (similar to the one from the issue). The idea is to wrap the KProperty<R> into a wrapper class without variance. As you see, the KProperty type has out R variance, which works against us in the example. You may follow the link for the details on the declaration-side variance in Kotlin
https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
The workaround works as strict as expected
class KWrapper<R>(val p : KProperty<R>)
infix fun <T : KWrapper<R>, R> T.equal(rhs : T) = false
val <T> KProperty<T>.wrap get() = KWrapper(this)
val a = Test::id.wrap equal TestOther::id.wrap //fails: Long vs Long?
val b = Test::id.wrap equal Test::id.wrap //works
val c = Test::id.wrap equal TestOther::isCool.wrap // fails Long vs Boolean
The downside is that you need to use .wrap extension property (or extension function) for the left and right parameters separately

Override getValue and setValue to capselate a Pair

Let's say I have following class:
class Person() {
var age: Pair<String, Int> = Pair("person_age", 23)
// override getValue and setValue here
}
Now I want to capsulate the actual Pair and only want the user to read/write the second value of the pair. Is it possible to override the getValue and setValue methods so I can do something like this:
val p = Person()
p.age = 25
if(p.age <= 30)
Of course I can write own getter and setter methods for each property but one nice thing about Kotlin is that you have to write such less boilerplate code which will get lost then.
The following should probably already suffice:
class Person() {
var age : Int = 23 // public by default
private /* or internal */ fun toAgePair() = "person_age" to age // narrow visibility
}
So all your code accesses the age as you have shown:
val p = Person()
p.age = 25
if (p.age <= 30) ...
But if you require your Pair you just do the following instead:
p.toAgePair() // or skip that method and use: '"person_age" to p.age' instead
Alternatives to access the Pair content are: Pair.first, Pair.second or destructured, e.g.:
val myPair = Pair("person_age", 23)
// myPair.second = 25 // setting will not work however
myPair.let { (name, age) -> /* do something with it */ }
Or alternatively:
val p = Person()
val (name, age) = p.toAgePair()
// age = 25 // setting will not work however (and it wouldn't set the actual value inside the Pair if it would contain vars)
if (age < 30) // accessing is OK
However then you get access to both values which you probably didn't want in the first place, if I understood you correctly.
You could overcome the setting part using your own data class with a var but then again, you do not really gain something from it.
I wouldn't recommend you to use Pair at all. Maybe you could modify it (inherit from it, use extension functions) to suit your needs, but why try to change something as simple as Pair?. It is much easier and in this case also cleaner to just create your own class which suits your needs:
data class MyPair<out A, B>(
val first: A,
var second: B
)
val pair = MyPair("age", 1)
pair.second = 2
pair.first = 1 // error
This class has all important features which Pair has: generic types for first and second, and you can use destructuring declarations.
Now I want to capselate the actual Pair and only want the user to read/write the second value of the pair.
Assuming this means you want the first value to be final, but not the second one, there are some options.
If you only want one of the values to be writeable and readable, don't use a pair. It's not designed to be used like that. All the items of a Pair are vals.
If you want a Pair either way, can do this:
class Person(var age: Int = 23){
val pair: Pair<String, Int>
get() = Pair("person_age", age)
//Alternatively, if you don't want to use a property:
//fun getPair() = "person_age" to age
}
What this does is creating a final pair where the first value can't be modified, but the second can.
So now:
fun example(){
val person = Person()
person.age = 25;//Fine: Age is an int, and a var
//person.pair = Pair("something", 45)//fails: "Val cannot be reassigned
val pair = person.pair // Allowed. Accessing the pair still works
assert(pair.second == person.age) // This is true
}
However, if you're fine with a non-Pair solution, this works too:
data class Person (var age: Int, val string: String = "person_age")
fun example(){
val person = Person(23)
val (name, string) = person// Allowed! Just like with Pairs
person.age = 25; // Also allowed
//person.string = "something"//Not allowed
}
The n-touple unpacking is supported for data classes. If you don't have a data class, you need to declare an operator fun for each component you want to unpack. Example:
class Person (val string: String = "person_age", var age: Int){
operator fun component1() = string
operator fun component2() = age
}
But tbh, it sounds like the data class solution is the one you're looking for. It would lock the String to what it's initialized with, and because of the default value and its position, you can initialize it with a single positioned argument*
You could also use generics if you want to use the same class for multiple types.
* Assumes the code is in Kotlin. Positioned and default arguments don't work from Java code.
Here's how to overwrite a getter method in Kotlin
class Person {
var age: Int = 0
get() = if (field < 0) 0 else field
}
The attribute is accessed directly
fun main(args: Array<String>) {
val p = Person()
p.age = -28
println(p.age) //0
}

Custom 'typesafe' Int Types

What I would like to have is two different integer types which are semantically distinguishable.
E.g. in this code a 'Meter' type and a 'Pixel' int type
typealias Meter = Int
typealias Pixel = Int
fun Meter.toPixel() = this * 100
fun Pixel.toMeter() = this / 100
fun calcSquareMeters(width: Meter, height: Meter) = width * height
fun calcSquarePixels(width: Pixel, height: Pixel) = width * height
fun main(args: Array<String>) {
val pixelWidth: Pixel = 50
val pixelHeight: Pixel = 50
val meterWidth: Meter = 50
val meterHeight: Meter = 50
calcSquareMeters(pixelWidth, pixelHeight) // (a) this should not work
pixelWidth.toPixel() // (b) this should not work
}
The problem with this solution is
(a) that I can call calcSquareMeters with my 'Pixel' type which I don't want to be possible and
(b) that I can call the toPixel() extension function which I only want to have for my 'Meter' type on my 'Pixel' type which I don't want to be possible.
I guess this is the intended behaviour of typealias, so I guess to achieve my goal I have to use something different than typealias...
So how can I achieve this?
In addition to the existing answer: If you have a lot of common functionality between the two types and don't want to duplicate it, you can work with an interface:
interface MetricType<T> {
val value: Int
fun new(value: Int): T
}
data class Meter(override val value: Int) : MetricType<Meter> {
override fun new(value: Int) = Meter(value)
}
data class Pixel(override val value: Int) : MetricType<Pixel> {
override fun new(value: Int) = Pixel(value)
}
Like this, you can easily define operations on the base interface, such as addition, subtraction and scaling:
operator fun <T : MetricType<T>> T.plus(rhs: T) = new(this.value + rhs.value)
operator fun <T : MetricType<T>> T.minus(rhs: T) = new(this.value + rhs.value)
operator fun <T : MetricType<T>> T.times(rhs: Int) = new(this.value * rhs)
The combination of interface and generics ensures type safety, so you do not accidentally mix types:
fun test() {
val m = Meter(3)
val p = Pixel(7)
val mm = m + m // OK
val pp = p + p // OK
val mp = m + p // does not compile
}
Keep in mind that this solution comes at a runtime cost due to the virtual functions (compared to rewriting the operators for each type separately). This in addition to the overhead of object creation.
Indeed, typealiases don't guarantee this sort of type safety. You'll have to create wrapper classes around an Int value instead to achieve this - it's a good idea to make these data classes so that equality comparisons work on them:
data class Meter(val value: Int)
data class Pixel(val value: Int)
Creation of instances of these classes can be solved with extension properties:
val Int.px
get() = Pixel(this)
val pixelWidth: Pixel = 50.px
The only problematic thing is that you can no longer directly perform arithmetic operations on Pixel and Meter instances, for example, the conversion functions would now look like this:
fun Meter.toPixel() = this.value * 100
Or the square calculations like this:
fun calcSquareMeters(width: Meter, height: Meter) = width.value * height.value
If you really need direct operator use, you can still define those, but it will be quite tedious:
class Meter(val value: Int) {
operator fun times(that: Meter) = this.value * that.value
}
fun calcSquareMeters(width: Meter, height: Meter) = width * height
There is a proposal (not yet guaranteed to be accepted) to add inline classes for this purpose. I.e.
#InlineOnly inline class Meter(val value: Int)
will really be an Int at runtime.
See https://github.com/zarechenskiy/KEEP/blob/28f7fdbe9ca22db5cfc0faeb8c2647949c9fd61b/proposals/inline-classes.md and https://github.com/Kotlin/KEEP/issues/104.
From kotlin doc:
Type aliases do not introduce new types. They are equivalent to the corresponding underlying types. When you add typealias Predicate and use Predicate in your code, the Kotlin compiler always expand it to (Int) -> Boolean. Thus you can pass a variable of your type whenever a general function type is required and vice versa
This means that there isn't possible check over your typealias, and you are rally declaring your extensions functions as:
fun Int.toPixel() = this * 100
fun Int.toMeter() = this / 100
fun calcSquareMeters(width: Int, height: Int) = width * height
fun calcSquarePixels(width: Int, height: Int) = width * height
I fear the only way to achieve that you want is implementing an extra class for each type.
I would also go with the solution from TheOperator. But I would like to add the inline keyword to the operator functions. By doing so you could avoid a virtual function call when ever you use this operators.
inline operator fun <T : MetricType<T>> T.plus(rhs: T) = new(this.value + rhs.value)
inline operator fun <T : MetricType<T>> T.minus(rhs: T) = new(this.value + rhs.value)
inline operator fun <T : MetricType<T>> T.times(rhs: Int) = new(this.value * rhs)