Skip to content

Instantly share code, notes, and snippets.

@nakamura-to
Last active December 15, 2025 09:51
Show Gist options
  • Select an option

  • Save nakamura-to/2f07e285a0c922bce38bf61cbb8c179e to your computer and use it in GitHub Desktop.

Select an option

Save nakamura-to/2f07e285a0c922bce38bf61cbb8c179e to your computer and use it in GitHub Desktop.
Kova( https://github.com/komapper/kova )のエッセンスを簡易的なコードで示したものです
/*
* コア機能群
*/
// バリデーションを表すインタフェース
fun interface Validator<T, S> {
fun execute(input: T): ValidationResult<S>
}
// バリデーションの結果(成功か失敗のどちらか)を表すインタフェース
sealed interface ValidationResult<out T> {
data class Success<out T>(val value: T) : ValidationResult<T>
data class Failure(val messages: List<String>) : ValidationResult<Nothing>
}
// 2つのValidatorをチェインするValidator
fun <T> Validator<T, T>.chain(next: Validator<T, T>): Validator<T, T> =
Validator { input ->
when (val result = execute(input)) {
is ValidationResult.Success -> next.execute(result.value)
is ValidationResult.Failure -> {
// 失敗しても次のバリデーションを実行し、エラーメッセージを収集する
when (val result2 = next.execute(input)) {
is ValidationResult.Success -> result
is ValidationResult.Failure -> ValidationResult.Failure(result.messages + result2.messages)
}
}
}
}
// Validatorの結果をtransform関数で変換するValidator
fun <T, S, U> Validator<T, S>.map(transform: (S) -> U): Validator<T, U> =
Validator { input ->
when (val result = execute(input)) {
is ValidationResult.Success -> ValidationResult.Success(transform(result.value))
is ValidationResult.Failure -> result
}
}
// 常に成功するValidatorを返す関数。この関数はエントリポイントとして使う。
fun <T> success(): Validator<T, T> = Validator { ValidationResult.Success(it) }
/*
* 部品となるValidator群
*/
// ブランクでないことを検証するValidator
fun Validator<String, String>.notBlank(): Validator<String, String> = chain {
if (it.isNotBlank()) ValidationResult.Success(it) else ValidationResult.Failure(listOf("not blank"))
}
// Intであることを検証するValidator
fun Validator<String, String>.isInt(): Validator<String, String> = chain {
val int = it.toIntOrNull()
if (int != null) ValidationResult.Success(it) else ValidationResult.Failure(listOf("'$it' is not int"))
}
// 文字列をIntに変換するValidator
fun <T> Validator<T, String>.toInt(): Validator<T, Int> = map { it.toInt() }
// Intを乗算するValidator
fun <T> Validator<T, Int>.times(n: Int): Validator<T, Int> = map { it * n }
/*
* デモンストレーション
*/
fun main() {
fun print(result: ValidationResult<*>) {
when (result) {
is ValidationResult.Success -> println("Success: " + result.value)
is ValidationResult.Failure -> println("Failure: " + result.messages)
}
}
// ブランクでなく数値であることを検証した上で数値に変換し3倍にするValidator(上述の部品を組み合わせて作成)
val validator = success<String>().notBlank().isInt().toInt().times(3)
// バリデーション成功例
validator.execute("100").let(::print) // Success: 300
// バリデーション失敗例
validator.execute("").let(::print) // Failure: [not blank, '' is not int]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment