generated from y9vad9/kotlin-project-template
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: better validation (now it returns multiple CreationFailures)
- Loading branch information
Showing
32 changed files
with
432 additions
and
247 deletions.
There are no files selected for viewing
20 changes: 9 additions & 11 deletions
20
...c/commonMain/kotlin/org/timemates/sdk/authorization/email/types/value/VerificationHash.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,17 @@ | ||
package org.timemates.sdk.authorization.email.types.value | ||
|
||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.CreationFailure | ||
import org.timemates.sdk.common.constructor.factory | ||
import org.timemates.sdk.common.constructor.rules.ValidationRule | ||
import org.timemates.sdk.common.constructor.rules.lengthExact | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class VerificationHash private constructor(public val string: String) { | ||
public companion object : Factory<VerificationHash, String>() { | ||
public const val SIZE: Int = 128 | ||
|
||
override fun create(input: String): Result<VerificationHash> { | ||
return when (input.length) { | ||
SIZE -> Result.success(VerificationHash(input)) | ||
else -> Result.failure(CreationFailure.ofSizeExact(SIZE)) | ||
} | ||
} | ||
} | ||
public companion object : Factory<VerificationHash, String> by factory( | ||
rules = listOf( | ||
ValidationRule.lengthExact(128), | ||
), | ||
constructor = ::VerificationHash | ||
) | ||
} |
7 changes: 2 additions & 5 deletions
7
...commonMain/kotlin/org/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,10 @@ | ||
package org.timemates.sdk.authorization.sessions.types.value | ||
|
||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.factory | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class ApplicationName private constructor(public val string: String) { | ||
public companion object : Factory<ApplicationName, String>() { | ||
override fun create(input: String): Result<ApplicationName> { | ||
return Result.success(ApplicationName(input)) | ||
} | ||
} | ||
public companion object : Factory<ApplicationName, String> by factory(::ApplicationName) | ||
} |
7 changes: 2 additions & 5 deletions
7
...commonMain/kotlin/org/timemates/sdk/authorization/sessions/types/value/AuthorizationId.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,10 @@ | ||
package org.timemates.sdk.authorization.sessions.types.value | ||
|
||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.factory | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class AuthorizationId private constructor(public val int: Int) { | ||
public companion object : Factory<AuthorizationId, Int>() { | ||
override fun create(input: Int): Result<AuthorizationId> { | ||
return Result.success(AuthorizationId(input)) | ||
} | ||
} | ||
public companion object : Factory<AuthorizationId, Int> by factory(::AuthorizationId) | ||
} |
7 changes: 2 additions & 5 deletions
7
...commonMain/kotlin/org/timemates/sdk/authorization/sessions/types/value/ClientIpAddress.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,10 @@ | ||
package org.timemates.sdk.authorization.sessions.types.value | ||
|
||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.factory | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class ClientIpAddress private constructor(public val string: String) { | ||
public companion object : Factory<ClientIpAddress, String>() { | ||
override fun create(input: String): Result<ClientIpAddress> { | ||
return Result.success(ClientIpAddress(input)) | ||
} | ||
} | ||
public companion object : Factory<ClientIpAddress, String> by factory(::ClientIpAddress) | ||
} |
7 changes: 2 additions & 5 deletions
7
...c/commonMain/kotlin/org/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,10 @@ | ||
package org.timemates.sdk.authorization.sessions.types.value | ||
|
||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.factory | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class ClientVersion private constructor(public val double: Double) { | ||
public companion object : Factory<ClientVersion, Double>() { | ||
override fun create(input: Double): Result<ClientVersion> { | ||
return Result.success(ClientVersion(input)) | ||
} | ||
} | ||
public companion object : Factory<ClientVersion, Double> by factory(::ClientVersion) | ||
} |
23 changes: 11 additions & 12 deletions
23
...ommonMain/kotlin/org/timemates/sdk/authorization/sessions/types/value/ConfirmationCode.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,19 @@ | ||
package org.timemates.sdk.authorization.sessions.types.value | ||
|
||
import org.timemates.sdk.common.constructor.CreationFailure | ||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.factory | ||
import org.timemates.sdk.common.constructor.rules.ValidationRule | ||
import org.timemates.sdk.common.constructor.rules.lengthExact | ||
import org.timemates.sdk.common.constructor.rules.notBlank | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class ConfirmationCode private constructor(public val string: String) { | ||
public companion object : Factory<ConfirmationCode, String>() { | ||
public const val SIZE: Int = 8 | ||
|
||
override fun create(input: String): Result<ConfirmationCode> { | ||
return when { | ||
input.isBlank() -> Result.failure(CreationFailure.ofBlank()) | ||
input.length != SIZE -> Result.failure(CreationFailure.ofSizeExact(SIZE)) | ||
else -> Result.success(ConfirmationCode(input)) | ||
} | ||
} | ||
} | ||
public companion object : Factory<ConfirmationCode, String> by factory( | ||
rules = listOf( | ||
ValidationRule.notBlank(), | ||
ValidationRule.lengthExact(8), | ||
), | ||
constructor = ::ConfirmationCode, | ||
) | ||
} |
9 changes: 4 additions & 5 deletions
9
sdk/src/commonMain/kotlin/org/timemates/sdk/authorization/types/value/HashValue.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,12 @@ | ||
package org.timemates.sdk.authorization.types.value | ||
|
||
import org.timemates.sdk.common.constructor.Factory | ||
import org.timemates.sdk.common.constructor.factory | ||
import kotlin.jvm.JvmInline | ||
|
||
@JvmInline | ||
public value class HashValue private constructor(public val string: String) { | ||
public companion object : Factory<HashValue, String>() { | ||
override fun create(input: String): Result<HashValue> { | ||
return Result.success(HashValue(input)) | ||
} | ||
} | ||
public companion object : Factory<HashValue, String> by factory( | ||
constructor = ::HashValue, | ||
) | ||
} |
This file contains 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
84 changes: 57 additions & 27 deletions
84
sdk/src/commonMain/kotlin/org/timemates/sdk/common/constructor/Factory.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,87 @@ | ||
package org.timemates.sdk.common.constructor | ||
|
||
import org.timemates.sdk.common.constructor.rules.ValidationRule | ||
import org.timemates.sdk.common.constructor.results.SafeCreationResult | ||
import org.timemates.sdk.common.constructor.results.ValidationResult | ||
import org.timemates.sdk.common.constructor.results.getUnsafe | ||
|
||
/** | ||
* Represents a generic constructor class for creating objects of type [Output] from input of type [Input]. | ||
* Represents a generic constructor class for creating objects of type [TBoxed] from TRaw of type [TRaw]. | ||
* | ||
* This class is abstract and provides a template for creating objects. Even if there's no need | ||
* in validating, we should follow our code-style and provide only [Factory] API. | ||
* | ||
* Primary and secondary constructors should be private and use only [Factory] as public API. | ||
* | ||
* @param Output The type of object to be created. | ||
* @param Input The type of input used to create the object. | ||
* @param TBoxed The type of object to be created. | ||
* @param TRaw The type of TRaw used to create the object. | ||
*/ | ||
public abstract class Factory<Output, Input> { | ||
public interface Factory<TBoxed, TRaw> { | ||
public val rules: List<ValidationRule<TRaw>> | ||
|
||
|
||
/** | ||
* Instantiates the entity of given type [Output]. | ||
* | ||
* **Shouldn't throw anything, but instantiate object of type [Output]** | ||
* Creates [TBoxed] from [TRaw] in the safe way by validating | ||
* [rules] that are defined in the factory. | ||
*/ | ||
public abstract fun create(input: Input): Result<Output> | ||
public fun createSafe(value: TRaw): SafeCreationResult<TRaw, TBoxed> | ||
} | ||
|
||
public fun <TBoxed, TRaw> factory( | ||
rules: List<ValidationRule<TRaw>>, | ||
constructor: (TRaw) -> TBoxed, | ||
): Factory<TBoxed, TRaw> { | ||
return object : Factory<TBoxed, TRaw> { | ||
override val rules: List<ValidationRule<TRaw>> by ::rules | ||
override fun createSafe(value: TRaw): SafeCreationResult<TRaw, TBoxed> { | ||
val failures = rules.mapNotNull { rule -> | ||
(rule.validate(value) as? ValidationResult.Invalid)?.failure | ||
} | ||
|
||
return if (failures.any()) | ||
SafeCreationResult.Invalid(value, failures) | ||
else SafeCreationResult.Valid(value, constructor(value)) | ||
} | ||
} | ||
} | ||
|
||
public fun <TBoxed, TRaw> factory( | ||
constructor: (TRaw) -> TBoxed, | ||
): Factory<TBoxed, TRaw> { | ||
return object : Factory<TBoxed, TRaw> { | ||
override val rules: List<ValidationRule<TRaw>> get() = emptyList() | ||
override fun createSafe(value: TRaw): SafeCreationResult<TRaw, TBoxed> { | ||
return SafeCreationResult.Valid(value, constructor(value)) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Creates an instance of the specified [Output] type using the provided [input]. | ||
* Creates an instance of the specified [TBoxed] type using the provided [TRaw]. | ||
* | ||
* This function attempts to instantiate an entity of the given type [Output] based on the provided [input]. | ||
* This function attempts to instantiate an entity of the given type [TBoxed] based on the provided [TRaw]. | ||
* It returns the instantiated entity if the operation is successful, or throws an exception if an error occurs | ||
* during the instantiation process. | ||
* | ||
* @param input The input required for the entity creation. | ||
* @return The instantiated entity of type [Output]. | ||
* @param TRaw The TRaw required for the entity creation. | ||
* @return The instantiated entity of type [TBoxed]. | ||
* @throws Throwable if an error occurs during the entity creation process. | ||
*/ | ||
public fun <Output, Input> Factory<Output, Input>.createOrThrow(input: Input): Output { | ||
val result = create(input) | ||
|
||
return if(result.isSuccess) { | ||
result.getOrThrow() | ||
} else { | ||
throw result.exceptionOrNull() ?: error("Failed to create an object.") | ||
} | ||
public fun <TBoxed, TRaw> Factory<TBoxed, TRaw>.createOrThrow(value: TRaw): TBoxed { | ||
return createSafe(value).getUnsafe() | ||
} | ||
|
||
/** | ||
* Creates an instance of the specified [Output] type using the provided [input]. | ||
* Creates an instance of the specified [TBoxed] type using the provided [TRaw]. | ||
* | ||
* This function attempts to instantiate an entity of the given type [Output] based on the provided [input]. | ||
* This function attempts to instantiate an entity of the given type [TBoxed] based on the provided [TRaw]. | ||
* It returns the instantiated entity if the operation is successful, or returns `null` if an error occurs | ||
* during the instantiation process. | ||
* | ||
* @param input The input required for the entity creation. | ||
* @return The instantiated entity of type [Output], or `null` if an error occurs during the entity creation process. | ||
* @param TRaw The TRaw required for the entity creation. | ||
* @return The instantiated entity of type [TBoxed], or `null` if an error occurs during the entity creation process. | ||
*/ | ||
public fun <Output, Input> Factory<Output, Input>.createOrNull(input: Input): Output? { | ||
return create(input).getOrNull() | ||
} | ||
public fun <TBoxed, TRaw> Factory<TBoxed, TRaw>.createOrNull(value: TRaw): TBoxed? { | ||
@Suppress("UNCHECKED_CAST") | ||
return (createSafe(value) as? SafeCreationResult.Valid<*, *>)?.boxed as TBoxed | ||
} |
5 changes: 5 additions & 0 deletions
5
sdk/src/commonMain/kotlin/org/timemates/sdk/common/constructor/ValidationException.kt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.timemates.sdk.common.constructor | ||
|
||
public data class ValidationException( | ||
val failures: List<CreationFailure>, | ||
) : Exception("The following validation constraints have failed: \n ${failures.joinToString("\n") { "1. ${it.message}" }}") |
Oops, something went wrong.