com.github.mvysny.vokdataloader.ListDataLoader.kt Maven / Gradle / Ivy
package com.github.mvysny.vokdataloader
/**
* A simple in-memory data loader which provides beans from given [items] list.
*
* The [NativePropertyName] is always the Java Bean Property name. The [DataLoaderPropertyName]s accepted for filters
* and sort clauses are always the Java Bean Property names. Only valid Bean Property Names for bean of type [itemClass]
* may be passed in.
*
* Uses identity as mapping: turns a Java Bean into ... well, Java Bean ;)
*
* Thread-safe.
* @property itemClass every item is of this type. Used to lookup getters for Java Bean Properties.
* @property items provide instances of these items.
*/
class ListDataLoader(val itemClass: Class, val items: List) : DataLoader {
private fun filter(filter: Filter?): List = if (filter == null) items else items.filter { filter.test(it) }
override fun getCount(filter: Filter?): Long = filter(filter).size.toLong()
override fun fetch(filter: Filter?, sortBy: List, range: LongRange): List {
if (range.isEmpty()) return listOf()
require(range.start >= 0) { "range $range contains negative indices" }
var list = filter(filter)
list = list.sortedBy(sortBy, itemClass)
return list.subList(range.intRange.intersection(list.indices))
}
override fun toString() = "ListDataLoader($items)"
}
/**
* Returns [ListDataLoader] which loads given list. It may not reflect items added to the list post-construction
* of the loader (e.g. it optimizes by returning [EmptyDataLoader] when called on an empty list).
*/
inline fun List.dataLoader(): DataLoader = when {
isEmpty() -> EmptyDataLoader()
else -> ListDataLoader(T::class.java, this)
}
/**
* Creates a [Comparator] which compares items of given [itemClass] by [SortClause.propertyName]. Reads the property
* value using Java Reflection. Useful for doing in-memory comparisons.
*/
fun SortClause.getComparator(itemClass: Class<*>): Comparator {
val getter = itemClass.getGetter(propertyName)
val comparator: Comparator = compareBy { bean -> getter.invoke(bean) as Comparable<*>? }
return if (asc) comparator else comparator.reversed()
}
/**
* Creates a [Comparator] which compares items by all comparators in this list. If the list is empty, the comparator
* will always treat all items as equal and will return `0`.
*/
fun List>.toComparator(): Comparator = when {
isEmpty() -> Comparator { _, _ -> 0 }
size == 1 -> first()
else -> ComparatorList(this)
}
private class ComparatorList(val comparators: List>) : Comparator {
override fun compare(o1: T, o2: T): Int {
for (comparator in comparators) {
val result = comparator.compare(o1, o2)
if (result != 0) return result
}
return 0
}
}
/**
* Returns a copy of this list, sorted in-memory according to given [criteria]. [itemClass] is used for reflection so that we can obtain
* the values of given property for all beans.
*/
fun List.sortedBy(criteria: List, itemClass: Class): List = when {
criteria.isEmpty() || isEmpty() -> this
else -> {
val comparator: Comparator = criteria.map { it.getComparator(itemClass) } .toComparator()
sortedWith(nullsFirst(comparator))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy