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

hashmap.HashMapStore.kt Maven / Gradle / Ivy

There is a newer version: 1.4.4
Show newest version
package com.hexagonkt.store.hashmap

import com.hexagonkt.helpers.filterEmpty
import com.hexagonkt.store.IndexOrder
import com.hexagonkt.store.Mapper
import com.hexagonkt.store.Store
import kotlin.UnsupportedOperationException
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1

class HashMapStore(
    override val type: KClass,
    override val key: KProperty1,
    override val name: String = type.java.simpleName,
    private val store: HashMap> = hashMapOf(),
    override val mapper: Mapper = HashMapMapper(type)) : Store {

    override fun createIndex(unique: Boolean, fields: Map): String {
        throw UnsupportedOperationException("Cannot create index on HashMap")
    }

    override fun insertOne(instance: T): K {
        store[key.get(instance)] = map(instance)
        return key.get(instance)
    }

    override fun insertMany(instances: List): List {
        instances.forEach {
            store[key.get(it)] = map(it)
        }

        return instances.map { key.get(it) }
    }

    override fun saveOne(instance: T): K? {
        if (store.containsKey(key.get(instance))) {
            store[key.get(instance)] = map(instance)
            return null
        }

        store[key.get(instance)] = map(instance)
        @Suppress("UNCHECKED_CAST")
        return mapper.fromStore(key.name, key.get(instance)) as K
    }

    override fun saveMany(instances: List): List {
        return instances.map(::saveOne)
    }

    override fun replaceOne(instance: T): Boolean =
        store.replace(key.get(instance), map(instance)) != null


    override fun replaceMany(instances: List): List =
        instances.mapNotNull { if (replaceOne(it)) it else null }


    override fun updateOne(key: K, updates: Map): Boolean {
        if (!store.containsKey(key)) return false

        val instance = store[key]!!.toMutableMap()

        updates
            .filterEmpty()
            .forEach {
                instance[it.key] = mapper.toStore(it.key, it.value)
            }

        return store.replace(key, instance) != null
    }

    override fun updateMany(filter: Map, updates: Map): Long {
        val filteredInstances = store.filter(filter)

        return filteredInstances.map { updateOne(it, updates) }.count { it }.toLong()
    }

    override fun deleteOne(id: K): Boolean =
        store.remove(id) != null

    override fun deleteMany(filter: Map): Long {
        val filteredInstances = store.filter(filter)

        return filteredInstances.map { deleteOne(it) }.count { it }.toLong()
    }

    override fun findOne(key: K): T? {
        val result = store[key]
        return result?.let { mapper.fromStore(result) }
    }

    override fun findOne(key: K, fields: List): Map? {
        val instance = store[key]

        return if (instance == null) null else fields.map { it to instance[it] }.toMap()
    }

    override fun findMany(
        filter: Map,
        limit: Int?,
        skip: Int?,
        sort: Map
    ): List {
        val filteredInstances = store.filter(filter)

        @Suppress("UNCHECKED_CAST")
        return filteredInstances
            .map { store[it]!! }
            .sort(sort)
            .paginate(skip ?: 0, limit ?: filteredInstances.size)
            .map { mapper.fromStore(it as Map) }
    }

    override fun findMany(
        filter: Map,
        fields: List,
        limit: Int?,
        skip: Int?,
        sort: Map
    ): List> {
        val filteredInstances = store.filter(filter)

        val result = filteredInstances.mapNotNull { findOne(it, fields) }
        return result
            .paginate(skip ?: 0, limit ?: result.size)
            .sort(sort)
    }

    override fun count(filter: Map): Long =
        store.filter(filter).size.toLong()

    override fun drop() =
        store.clear()

    private fun map(instance: T): Map = mapper.toStore(instance)

    private fun HashMap>.filter(filter: Map): List =
        filter { it.value.containsValues(filter) }
            .map { it.key }

    private fun Map.containsValues(filter: Map): Boolean =
        filter.all {
            when (val value = it.value) {
                is List<*> -> value.contains(this[it.key])
                else -> value == this[it.key]
            }
        }

    private fun List>.paginate(skip: Int, limit: Int): List> =
        let {
            var endIndex = skip + limit
            if (endIndex > this.size) endIndex = this.size

            this.subList(skip, endIndex)
        }

    // TODO: Add sorting functionality (now only sorts by first field)
    private fun List>.sort(sortFields: Map): List> =
        if (sortFields.isEmpty())
            this
        else
            sortedBy {
                val firstSortField = sortFields.entries.first()
                val sortingValue = it[firstSortField.key]
                @Suppress("UNCHECKED_CAST")
                if (sortingValue is Comparable<*>)
                    sortingValue as? Comparable
                else
                    error("Not comparable value")
            }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy