Last active
December 15, 2025 09:51
-
-
Save nakamura-to/2f07e285a0c922bce38bf61cbb8c179e to your computer and use it in GitHub Desktop.
Kova( https://github.com/komapper/kova )のエッセンスを簡易的なコードで示したものです
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * コア機能群 | |
| */ | |
| // バリデーションを表すインタフェース | |
| 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