Any suggestions on how to apply a set of checks to...
# announcements
m
Any suggestions on how to apply a set of checks to a data model? My first thoughts are to define various checks like this:
Copy code
interface ErrorCheck<T> {
    fun isValid(item: T): Boolean
}

class PropertyRangeCheck<T, R : Comparable<R>>(val prop: KProperty1<T, R>, val range: ClosedRange<R>) : ErrorCheck<T> {
    override fun isValid(item: T) = range.contains(prop.get(item))
}

class PropertyStringLengthCheck<T>(val prop: KProperty1<T, String>, val range: IntRange) : ErrorCheck<T>{
    override fun isValid(item: T) = range.contains(prop.get(item).length)
}
And then I can define a list of the checks such as :
Copy code
val model1checks = listOf(
        PropertyRangeCheck(DataClass::id, 1.rangeTo(4094)),
        PropertyRangeCheck(DataClass::time, 0.0f.rangeTo(2.0f)),
        PropertyStringLengthCheck(DataClass::name, 1.rangeTo(80))
    )
End goal is to perform a number of checks across a dozen or so different classes and their various properties and display a list of errors to the user
there will also be more complex checks such as relationships between different data classes
p
You can use
init
block along with
require
function to validate the Model like this
Copy code
data class User(val name: String, val email: String, val age: Int) {
    init {
        require(name.isNotEmpty()) { "name must not be empty" }
        require(email.isValidEmail()) { "email is not valid" }
        require(age >= 18) { "age must be greater than or equal to 18 years" }
    }
}
m
interesting...I wasn't familiar with require
however, my model has mutable properties that are changed via a GUI and some complex relationships so this wouldn't work for everything
the GUI does do some validation but some limits are specified by the user so I have to do a post check of all models
j
wouldn’t something like the following be enough?
Copy code
data class Person(val age: Int, val name: String)

val validations = listOf(
    PropertyRangeCheck(Person::age, 18.rangeTo(40)),
    PropertyStringLengthCheck(Person::name, 1.rangeTo(5))
)

val john = Person(7, "John")

validations.map {
    Pair(it.isValid(john), listOf(it.errorMessage()))
}.reduce { acc, pair ->
    Pair(acc.first && pair.first, acc.second + pair.second)
}.let {
    println(it)
}

// (false, [Out of range, Invalid size])
Added
errorMessage
to
ErrorCheck
m
yeah that's basically what I ended up doing