
com.github.mvysny.vokdataloader.ListDataLoader.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vok-dataloader Show documentation
Show all versions of vok-dataloader Show documentation
VOK-DataLoader: The Paged/Filtered/Sorted DataLoader API
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, or a
* comma-separated path of property names.
* The [DataLoaderPropertyName]s accepted for filters
* and sort clauses are always the Java Bean Property names, or a
* comma-separated path of property names.
*
* Only valid Bean Property Names for bean of type [itemClass]
* may be passed in; however passing in a comma-separated path of property names
* is supported as well since the loader is in-memory and calls [Filter.test] which supports property paths.
*
* Uses identity as mapping: turns a Java Bean into ... well, Java Bean ;)
*
* Uses [Filter.test] for filtering, [List.sortedBy] for sorting. Doesn't support [NativeSqlFilter].
*
* 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.
*/
public class ListDataLoader(public val itemClass: Class, public 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.first >= 0) { "range $range contains negative indices" }
var list: List = filter(filter)
list = list.sortedBy(sortBy, itemClass)
return list.subList(range.intRange.intersection(list.indices))
}
override fun toString(): String = "ListDataLoader{${items.size} items, first three items: ${items.take(3)}}"
}
/**
* 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).
*/
public 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.
*/
public fun SortClause.getComparator(itemClass: Class<*>): Comparator {
@Suppress("UNCHECKED_CAST")
val getter: PropertyPath = PropertyPath.of(itemClass, propertyName) as PropertyPath
val comparator: Comparator = compareBy { bean: Any -> 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`.
*/
public 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: 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.
*
* The sorting is done in-memory. [SortClause.propertyName] must be a valid Java
* Bean property name, or a comma-separated list of property names (see [PropertyPath]
* for more details).
*/
public 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))
}
}
/**
* Returns a copy of this list, sorted in-memory according to given [criteria]. [T] is used for reflection so that we can obtain
* the values of given property for all beans.
*/
public inline fun List.sortedBy(vararg criteria: SortClause): List =
sortedBy(criteria.toList(), T::class.java)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy