All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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