Data.kt

  1. package com.hexagontk.core

  2. import kotlin.reflect.KProperty1

  3. /**
  4.  * .
  5.  *
  6.  * @receiver .
  7.  * @param keys .
  8.  * @return .
  9.  */
  10. inline fun <reified T : Any> Map<*, *>.getPath(vararg keys: Any): T? {
  11.     val mappedKeys = keys.map {
  12.         when (it) {
  13.             is KProperty1<*, *> -> it.name
  14.             else -> it
  15.         }
  16.     }

  17.     return mappedKeys
  18.         .dropLast(1)
  19.         .fold(this) { result, element ->
  20.             when (val value = result[element]) {
  21.                 is Map<*, *> -> value
  22.                 is Collection<*> -> value.mapIndexed { ii, item -> ii to item }.toMap()
  23.                 else -> emptyMap<Any, Any>()
  24.             }
  25.         }[mappedKeys.last()] as? T
  26. }

  27. /**
  28.  * .
  29.  *
  30.  * @receiver .
  31.  * @param name .
  32.  * @return .
  33.  */
  34. inline fun <reified T : Any> Map<*, *>.requirePath(vararg name: Any): T =
  35.     this.getPath(*name) ?: error("$name required key not found")

  36. /**
  37.  * .
  38.  *
  39.  * @param fields .
  40.  * @return .
  41.  */
  42. fun <T : Any> fieldsMapOf(vararg fields: Pair<KProperty1<T, *>, *>): Map<String, *> =
  43.     fields.associate { it.first.name to it.second }

  44. /**
  45.  * .
  46.  *
  47.  * @param fields .
  48.  * @return .
  49.  */
  50. fun <T : Any> fieldsMapOfNotNull(vararg fields: Pair<KProperty1<T, *>, *>): Map<String, *> =
  51.     fieldsMapOf(*fields).filterValues { it != null }

  52. /**
  53.  * .
  54.  *
  55.  * @param pairs .
  56.  * @return .
  57.  */
  58. fun <K : Any> mapOfNotNull(vararg pairs: Pair<K, *>): Map<K, *> =
  59.     mapOf(*pairs).filterValues { it != null }

  60. /**
  61.  * .
  62.  *
  63.  * @receiver .
  64.  * @param name .
  65.  * @return .
  66.  */
  67. fun <K, V> Map<K, V>.require(name: K): V =
  68.     this[name] ?: error("$name required key not found")

  69. /**
  70.  * .
  71.  *
  72.  * @param T .
  73.  * @param key .
  74.  * @return .
  75.  */
  76. inline operator fun <reified T : Any> Map<*, *>.get(key: KProperty1<*, *>): T? =
  77.     this[key.name] as? T

  78. /**
  79.  * .
  80.  *
  81.  * @param T .
  82.  * @param key .
  83.  * @param default .
  84.  * @return .
  85.  */
  86. inline fun <reified T : Any> Map<*, *>.getOrDefault(key: KProperty1<*, *>, default: T): T =
  87.     this[key] ?: default

  88. /**
  89.  * .
  90.  *
  91.  * @param mapA .
  92.  * @param mapB .
  93.  * @return .
  94.  */
  95. fun merge(mapA: Map<*, *>, mapB: Map<*, *>): Map<*, *> =
  96.     (mapA.entries + mapB.entries)
  97.         .groupBy { it.key }
  98.         .mapValues { (_, v) -> v.map { it.value } }
  99.         .mapValues { (_, v) ->
  100.             val isCollection = v.all { it is Collection<*> }
  101.             val isMap = v.all { it is Map<*, *> }
  102.             when {
  103.                 isCollection -> v.map { it as Collection<*> }.reduce { a, b -> a + b }
  104.                 isMap -> v.map { it as Map<*, *> }.reduce { a, b -> merge(a, b) }
  105.                 else -> v.last()
  106.             }
  107.         }

  108. /**
  109.  * .
  110.  *
  111.  * @param maps .
  112.  * @return .
  113.  */
  114. fun merge(maps: Collection<Map<*, *>>): Map<*, *> =
  115.     maps.reduce { a, b -> merge(a, b) }

  116. /**
  117.  * .
  118.  *
  119.  * @receiver .
  120.  * @return .
  121.  */
  122. fun <K, V> Map<K, Collection<V>>.pairs(): Collection<Pair<K, V>> =
  123.     flatMap { (k, v) -> v.map { k to it } }

  124. /**
  125.  * .
  126.  *
  127.  * @receiver .
  128.  * @return .
  129.  */
  130. fun <K, V> Map<K, V?>.filterNotEmpty(): Map<K, V> =
  131.     this.filterValues(::notEmpty).mapValues { (_, v) -> v ?: fail }

  132. /**
  133.  * .
  134.  *
  135.  * @receiver .
  136.  * @return .
  137.  */
  138. fun <V> Collection<V?>.filterNotEmpty(): Collection<V> =
  139.     this.filter(::notEmpty).map { it ?: fail }

  140. /**
  141.  * .
  142.  *
  143.  * @receiver .
  144.  * @return .
  145.  */
  146. fun Map<*, *>.filterNotEmptyRecursive(): Map<*, *> =
  147.     mapValues { (_, v) ->
  148.         when (v) {
  149.             is Collection<*> -> v.filterNotEmptyRecursive()
  150.             is Map<*, *> -> v.filterNotEmptyRecursive()
  151.             else -> v
  152.         }
  153.     }
  154.         .filterNotEmpty()

  155. /**
  156.  * .
  157.  *
  158.  * @receiver .
  159.  * @return .
  160.  */
  161. fun Collection<*>.filterNotEmptyRecursive(): Collection<*> =
  162.     map {
  163.         when (it) {
  164.             is Collection<*> -> it.filterNotEmptyRecursive()
  165.             is Map<*, *> -> it.filterNotEmptyRecursive()
  166.             else -> it
  167.         }
  168.     }
  169.         .filterNotEmpty()

  170. /**
  171.  * .
  172.  *
  173.  * @param value .
  174.  * @return .
  175.  */
  176. fun <V> notEmpty(value: V?): Boolean {
  177.     return when (value) {
  178.         null -> false
  179.         is Collection<*> -> value.isNotEmpty()
  180.         is Map<*, *> -> value.isNotEmpty()
  181.         else -> true
  182.     }
  183. }

  184. fun Map<*, *>.getInt(key: KProperty1<*, *>): Int? =
  185.     get(key)

  186. fun Map<*, *>.getLong(key: KProperty1<*, *>): Long? =
  187.     get(key)

  188. fun Map<*, *>.getFloat(key: KProperty1<*, *>): Float? =
  189.     get(key)

  190. fun Map<*, *>.getDouble(key: KProperty1<*, *>): Double? =
  191.     get(key)

  192. fun Map<*, *>.getBoolean(key: KProperty1<*, *>): Boolean? =
  193.     get(key)

  194. fun Map<*, *>.getString(key: KProperty1<*, *>): String? =
  195.     get(key)

  196. fun Map<*, *>.getList(key: KProperty1<*, *>): Collection<*>? =
  197.     get(key)

  198. fun Map<*, *>.getMap(key: KProperty1<*, *>): Map<String, *>? =
  199.     get(key)

  200. fun Map<*, *>.getInts(key: KProperty1<*, *>): Collection<Int>? =
  201.     get(key)

  202. fun Map<*, *>.getLongs(key: KProperty1<*, *>): Collection<Long>? =
  203.     get(key)

  204. fun Map<*, *>.getFloats(key: KProperty1<*, *>): Collection<Float>? =
  205.     get(key)

  206. fun Map<*, *>.getDoubles(key: KProperty1<*, *>): Collection<Double>? =
  207.     get(key)

  208. fun Map<*, *>.getBooleans(key: KProperty1<*, *>): Collection<Boolean>? =
  209.     get(key)

  210. fun Map<*, *>.getStrings(key: KProperty1<*, *>): Collection<String>? =
  211.     get(key)

  212. fun Map<*, *>.getLists(key: KProperty1<*, *>): Collection<List<*>>? =
  213.     get(key)

  214. fun Map<*, *>.getMaps(key: KProperty1<*, *>): Collection<Map<String, *>>? =
  215.     get(key)

  216. fun Map<*, *>.getListOrEmpty(key: KProperty1<*, *>): Collection<*> =
  217.     getList(key) ?: emptyList<Any>()

  218. fun Map<*, *>.getMapOrEmpty(key: KProperty1<*, *>): Map<String, *> =
  219.     getMap(key) ?: emptyMap<String, Any>()

  220. fun Map<*, *>.getIntsOrEmpty(key: KProperty1<*, *>): Collection<Int> =
  221.     getInts(key) ?: emptyList()

  222. fun Map<*, *>.getLongsOrEmpty(key: KProperty1<*, *>): Collection<Long> =
  223.     getLongs(key) ?: emptyList()

  224. fun Map<*, *>.getFloatsOrEmpty(key: KProperty1<*, *>): Collection<Float> =
  225.     getFloats(key) ?: emptyList()

  226. fun Map<*, *>.getDoublesOrEmpty(key: KProperty1<*, *>): Collection<Double> =
  227.     getDoubles(key) ?: emptyList()

  228. fun Map<*, *>.getBooleansOrEmpty(key: KProperty1<*, *>): Collection<Boolean> =
  229.     getBooleans(key) ?: emptyList()

  230. fun Map<*, *>.getStringsOrEmpty(key: KProperty1<*, *>): Collection<String> =
  231.     getStrings(key) ?: emptyList()

  232. fun Map<*, *>.getListsOrEmpty(key: KProperty1<*, *>): Collection<Collection<*>> =
  233.     getLists(key) ?: emptyList()

  234. fun Map<*, *>.getMapsOrEmpty(key: KProperty1<*, *>): Collection<Map<String, *>> =
  235.     getMaps(key) ?: emptyList()

  236. inline fun <reified T : Any> Map<*, *>.requireKey(key: KProperty1<*, *>): T =
  237.     get(key)
  238.         ?: error("'${key.name}' key not found, or wrong type (must be ${T::class.qualifiedName})")

  239. fun Map<*, *>.requireInt(key: KProperty1<*, *>): Int =
  240.     requireKey(key)

  241. fun Map<*, *>.requireLong(key: KProperty1<*, *>): Long =
  242.     requireKey(key)

  243. fun Map<*, *>.requireFloat(key: KProperty1<*, *>): Float =
  244.     requireKey(key)

  245. fun Map<*, *>.requireDouble(key: KProperty1<*, *>): Double =
  246.     requireKey(key)

  247. fun Map<*, *>.requireBoolean(key: KProperty1<*, *>): Boolean =
  248.     requireKey(key)

  249. fun Map<*, *>.requireString(key: KProperty1<*, *>): String =
  250.     requireKey(key)

  251. fun Map<*, *>.requireList(key: KProperty1<*, *>): Collection<*> =
  252.     requireKey(key)

  253. fun Map<*, *>.requireMap(key: KProperty1<*, *>): Map<String, *> =
  254.     requireKey(key)

  255. fun Map<*, *>.requireInts(key: KProperty1<*, *>): List<Int> =
  256.     requireKey(key)

  257. fun Map<*, *>.requireLongs(key: KProperty1<*, *>): Collection<Long> =
  258.     requireKey(key)

  259. fun Map<*, *>.requireFloats(key: KProperty1<*, *>): Collection<Float> =
  260.     requireKey(key)

  261. fun Map<*, *>.requireDoubles(key: KProperty1<*, *>): Collection<Double> =
  262.     requireKey(key)

  263. fun Map<*, *>.requireBooleans(key: KProperty1<*, *>): Collection<Boolean> =
  264.     requireKey(key)

  265. fun Map<*, *>.requireStrings(key: KProperty1<*, *>): Collection<String> =
  266.     requireKey(key)

  267. fun Map<*, *>.requireLists(key: KProperty1<*, *>): Collection<Collection<*>> =
  268.     requireKey(key)

  269. fun Map<*, *>.requireMaps(key: KProperty1<*, *>): Collection<Map<String, *>> =
  270.     requireKey(key)