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

com.github.mvysny.vokdataloader.ListDataLoader.kt Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
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