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

commonMain.io.konform.validation.internal.Builder.kt Maven / Gradle / Ivy

package io.konform.validation.internal

import io.konform.validation.Constraint
import io.konform.validation.Valid
import io.konform.validation.Validation
import io.konform.validation.ValidationBuilder
import io.konform.validation.internal.ValidationBuilderImpl.Companion.PropModifier.*
import kotlin.collections.Map.Entry
import kotlin.reflect.KProperty1

internal class ValidationBuilderImpl : ValidationBuilder() {
    companion object {
        private enum class PropModifier {
            NonNull, Optional, OptionalRequired
        }

        private abstract class PropKey {
            abstract fun build(builder: ValidationBuilderImpl<*>): Validation
        }

        private data class SingleValuePropKey(
            val property: KProperty1,
            val modifier: PropModifier
        ) : PropKey() {
            override fun build(builder: ValidationBuilderImpl<*>): Validation {
                @Suppress("UNCHECKED_CAST")
                val validations = (builder as ValidationBuilderImpl).build()
                return when (modifier) {
                    NonNull -> NonNullPropertyValidation(property, validations)
                    Optional -> OptionalPropertyValidation(property, validations)
                    OptionalRequired -> RequiredPropertyValidation(property, validations)
                }
            }
        }

        private data class IterablePropKey(
            val property: KProperty1>,
            val modifier: PropModifier
        ) : PropKey() {
            override fun build(builder: ValidationBuilderImpl<*>): Validation {
                @Suppress("UNCHECKED_CAST")
                val validations = (builder as ValidationBuilderImpl).build()
                return when (modifier) {
                    NonNull -> NonNullPropertyValidation(property, IterableValidation(validations))
                    Optional -> OptionalPropertyValidation(property, IterableValidation(validations))
                    OptionalRequired -> RequiredPropertyValidation(property, IterableValidation(validations))
                }
            }
        }

        private data class ArrayPropKey(
            val property: KProperty1>,
            val modifier: PropModifier
        ) : PropKey() {
            override fun build(builder: ValidationBuilderImpl<*>): Validation {
                @Suppress("UNCHECKED_CAST")
                val validations = (builder as ValidationBuilderImpl).build()
                return when (modifier) {
                    NonNull -> NonNullPropertyValidation(property, ArrayValidation(validations))
                    Optional -> OptionalPropertyValidation(property, ArrayValidation(validations))
                    OptionalRequired -> RequiredPropertyValidation(property, ArrayValidation(validations))
                }
            }
        }

        private data class MapPropKey(
            val property: KProperty1>,
            val modifier: PropModifier
        ) : PropKey() {
            override fun build(builder: ValidationBuilderImpl<*>): Validation {
                @Suppress("UNCHECKED_CAST")
                val validations = (builder as ValidationBuilderImpl>).build()
                return when (modifier) {
                    NonNull -> NonNullPropertyValidation(property, MapValidation(validations))
                    Optional -> OptionalPropertyValidation(property, MapValidation(validations))
                    OptionalRequired -> RequiredPropertyValidation(property, MapValidation(validations))
                }
            }
        }


    }

    private val constraints = mutableListOf>()
    private val subValidations = mutableMapOf, ValidationBuilderImpl<*>>()
    private val prebuiltValidations = mutableListOf>()

    override fun Constraint.hint(hint: String): Constraint =
        Constraint(hint, this.templateValues, this.test).also { constraints.remove(this); constraints.add(it) }

    override fun addConstraint(errorMessage: String, vararg templateValues: String, test: (T) -> Boolean): Constraint {
        return Constraint(errorMessage, templateValues.toList(), test).also { constraints.add(it) }
    }

    private fun  KProperty1.getOrCreateBuilder(modifier: PropModifier): ValidationBuilder {
        val key = SingleValuePropKey(this, modifier)
        @Suppress("UNCHECKED_CAST")
        return (subValidations.getOrPut(key, { ValidationBuilderImpl() }) as ValidationBuilder)
    }

    private fun  KProperty1>.getOrCreateIterablePropertyBuilder(modifier: PropModifier): ValidationBuilder {
        val key = IterablePropKey(this, modifier)
        @Suppress("UNCHECKED_CAST")
        return (subValidations.getOrPut(key, { ValidationBuilderImpl() }) as ValidationBuilder)
    }

    private fun  PropKey.getOrCreateBuilder(): ValidationBuilder {
        @Suppress("UNCHECKED_CAST")
        return (subValidations.getOrPut(this, { ValidationBuilderImpl() }) as ValidationBuilder)
    }

    override fun  KProperty1.invoke(init: ValidationBuilder.() -> Unit) {
        getOrCreateBuilder(NonNull).also(init)
    }

    override fun  onEachIterable(prop: KProperty1>, init: ValidationBuilder.() -> Unit) {
        prop.getOrCreateIterablePropertyBuilder(NonNull).also(init)
    }

    override fun  onEachArray(prop: KProperty1>, init: ValidationBuilder.() -> Unit) {
        ArrayPropKey(prop, NonNull).getOrCreateBuilder().also(init)
    }

    override fun  onEachMap(prop: KProperty1>, init: ValidationBuilder>.() -> Unit) {
        MapPropKey(prop, NonNull).getOrCreateBuilder>().also(init)
    }

    override fun  KProperty1.ifPresent(init: ValidationBuilder.() -> Unit) {
        getOrCreateBuilder(Optional).also(init)
    }

    override fun  KProperty1.required(init: ValidationBuilder.() -> Unit) {
        getOrCreateBuilder(OptionalRequired).also(init)
    }

    override val  KProperty1.has: ValidationBuilder
        get() = getOrCreateBuilder(NonNull)

    override fun run(validation: Validation) {
        prebuiltValidations.add(validation)
    }

    override fun build(): Validation {
        val nestedValidations = subValidations.map { (key, builder) ->
            key.build(builder)
        }
        return ValidationNode(constraints, nestedValidations + prebuiltValidations)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy