diff --git a/404.html b/404.html index 91e4df4..18f3789 100644 --- a/404.html +++ b/404.html @@ -2,19 +2,19 @@ - + Page Not Found | Refined4s - - - + + + -
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

diff --git a/docs/chimney/index.html b/docs/chimney/index.html index d9192b1..83cc7cc 100644 --- a/docs/chimney/index.html +++ b/docs/chimney/index.html @@ -2,19 +2,19 @@ - + chimney module | Refined4s - - - + + + -
Skip to main content

chimney module

Import

+

chimney module

Import

import refined4s.modules.chimney.derivation.types.all.given
import refined4s.modules.chimney.derivation.*

Use Drived Instances for Pre-defined Types

@@ -32,7 +32,7 @@

import refined4s.*
import refined4s.modules.chimney.derivation.*

import io.scalaland.chimney.*
import io.scalaland.chimney.dsl.*

final case class XMen(name: XMen.NotEmptyStr)
object XMen {
type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String], ChimneyRefined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""
}
}

final case class MarvelCharacter(name: String)

import refined4s.types.all.*

final case class Hero(name: Hero.Name)
object Hero {
type Name = Name.Type
object Name extends Newtype[NonEmptyString], ChimneyNewtype[NonEmptyString]
}

val logan = XMen(XMen.NotEmptyStr("James Howlett"))
// logan: XMen = XMen(name = "James Howlett")
val wolverine = logan.transformInto[MarvelCharacter]
// wolverine: MarvelCharacter = MarvelCharacter(name = "James Howlett")

wolverine.transformIntoPartial[XMen]
// res7: Result[XMen] = Value(value = XMen(name = "James Howlett"))

val hero = logan.transformIntoPartial[Hero]
// hero: Result[Hero] = Value(value = Hero(name = "James Howlett"))

With auto derivation

If you want to implicitly have Transformer and PartialTransformer type-class instances for your Newtype or Refined or InlinedRefined, you can use the refined4s.modules.chimney.derivation.generic.auto.

-
import cats.*

import refined4s.*
import refined4s.modules.chimney.derivation.generic.auto.given

import io.scalaland.chimney.*
import io.scalaland.chimney.dsl.*

type Name = Name.Type
object Name extends Newtype[String]

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "NonEmptyStr should be a non-empty String"

inline def predicate(a: String): Boolean = a != ""
}

final case class Person(name: Name)

final case class User(name: String)

final case class AnotherUser(name: NotEmptyStr)

val person = Person(Name("Wade Wilson"))
// person: Person = Person(name = "Wade Wilson")

person.into[User].transform
// res9: User = User(name = "Wade Wilson")

val user = person.transformInto[User]
// user: User = User(name = "Wade Wilson")

user.transformIntoPartial[Person]
// res10: Result[Person] = Value(value = Person(name = "Wade Wilson"))

val anotherUser = person.transformIntoPartial[AnotherUser]
// anotherUser: Result[AnotherUser] = Value(
// value = AnotherUser(name = "Wade Wilson")
// )

anotherUser.flatMap(_.transformIntoPartial[Person])
// res11: Result[Person] = Value(value = Person(name = "Wade Wilson"))

val personWithEmptyName = Person(Name(""))
// personWithEmptyName: Person = Person(name = "")

personWithEmptyName.transformInto[User]
// res12: User = User(name = "")

personWithEmptyName.transformIntoPartial[AnotherUser]
// res13: Result[AnotherUser] = Errors(
// errors = NonEmptyErrorsChain(
// Error(
// message = StringMessage(
// message = "Invalid value: []. NonEmptyStr should be a non-empty String"
// ),
// path = Path(elements = List(Accessor(name = "name")))
// )
// )
// )
diff --git a/docs/circe/index.html b/docs/circe/index.html index 63a8ca9..bee0255 100644 --- a/docs/circe/index.html +++ b/docs/circe/index.html @@ -2,19 +2,19 @@ - + circe module | Refined4s - - - + + + -
Skip to main content

circe module

Import

+

circe module

Import

import refined4s.modules.circe.derivation.types.all.given
import refined4s.modules.circe.derivation.*

Use Drived Instances for Pre-defined Types

@@ -43,7 +43,7 @@

With If you want to have explicit Encoder and Decoder (or Codec) type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.

NOTE

This works only when the actual type already has Encoder and Decoder (or Codec).

import cats.*

import refined4s.*
import refined4s.modules.circe.derivation.*

import io.circe.*

type Name = Name.Type
object Name extends Newtype[String] {
given encoderName: Encoder[Name] = deriving[Encoder]
given decoderName: Decoder[Name] = deriving[Decoder]
}

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""

given encoderNotEmptyStr: Encoder[NotEmptyStr] = deriving[Encoder]
given decoderNotEmptyStr: Decoder[NotEmptyStr] = Decoder[String].emap(NotEmptyStr.from)
}

import io.circe.*

final case class Person(name: Name) derives Codec.AsObject

final case class Item(id: NotEmptyStr) derives Codec.AsObject

import io.circe.syntax.*

def printJson[A: Encoder](a: A): Unit = println(a.asJson.spaces2)
-
printJson(Name("Tony Stark"))
// "Tony Stark"

printJson(NotEmptyStr("Thor Odinson"))
// "Thor Odinson"

printJson(Person(Name("Steve Rogers")))
// {
// "name" : "Steve Rogers"
// }

printJson(Item(NotEmptyStr("abc-999")))
// {
// "id" : "abc-999"
// }

import io.circe.parser.*

println(decode[Person]("""{ "name": "Kevin" }"""))
// Right(Person(Kevin))

println(decode[Item]("""{ "id": "a-1234" }"""))
// Right(Item(a-1234))

println(decode[Item]("""{ "id": "" }"""))
// Left(DecodingFailure(Invalid value: []. non-empty String, List(DownField(id))))

diff --git a/docs/core/index.html b/docs/core/index.html index 007d98e..f2f5b33 100644 --- a/docs/core/index.html +++ b/docs/core/index.html @@ -2,19 +2,19 @@ - + core module | Refined4s - - - + + + -
Skip to main content

core module

Import

+
diff --git a/docs/core/newtype/index.html b/docs/core/newtype/index.html index 91ed326..077c00b 100644 --- a/docs/core/newtype/index.html +++ b/docs/core/newtype/index.html @@ -2,19 +2,19 @@ - + Newtype | Refined4s - - - + + + -
Skip to main content

Newtype

Import

+

Newtype

Import

import refined4s.*

Define Newtype

type NewtypeName = NewtypeName.Type
object NewtypeName extends Newtype[ActualType]
@@ -34,8 +34,8 @@

Pattern Mat
name match {
case Name(value) =>
println(s"Pattern matched value: $value")
}
// Pattern matched value: Kevin

Example

import refined4s.*

type Name = Name.Type
object Name extends Newtype[String]

type Email = Email.Type
object Email extends Newtype[String]

def hello(name: Name): Unit = println(s"Hello ${name.value}")

def send(email: Email): Unit = println(s"Sending email to ${email.value}")

val name = Name("Kevin")
// name: Type = "Kevin"
// Name.Type = "Kevin"
name.value
// res3: String = "Kevin"

hello(name)
// Hello Kevin

val email = Email("kevin@blah.blah")
// email: Type = "kevin@blah.blah"
// Email.Type = "kevin@blah.blah"
email.value
// res5: String = "kevin@blah.blah"

send(email)
// Sending email to kevin@blah.blah
-
hello("Kevin")
// error:
// Found: ("Kevin" : String)
// Required: repl.MdocSession.MdocApp0.Name
// hello("Kevin")
// ^^^^^^^
// error:
// Line is indented too far to the left, or a `}` is missing
// error:
// Line is indented too far to the left, or a `}` is missing
-
send("kevin@blah.blah")
// error:
// Found: ("kevin@blah.blah" : String)
// Required: repl.MdocSession.MdocApp0.Email
// send("kevin@blah.blah")
// ^^^^^^^^^^^^^^^^^
// error:
// Line is indented too far to the left, or a `}` is missing
// error:
// Line is indented too far to the left, or a `}` is missing
diff --git a/docs/core/refined/custom-type/index.html b/docs/core/refined/custom-type/index.html index 4c5a534..cabb9c5 100644 --- a/docs/core/refined/custom-type/index.html +++ b/docs/core/refined/custom-type/index.html @@ -2,19 +2,19 @@ - + Custom Type | Refined4s - - - + + + -
Skip to main content

Custom Type

Import

+

Custom Type

Import

import refined4s.*

Define Refined Type

type RefinedTypeName = RefinedTypeName.Type
object RefinedTypeName extends Refined[ActualType] {
override inline def invalidReason(a: ActualType): String =
expectedMessage("something with blah blah")

override inline def predicate(a: ActualType): Boolean =
// validation logic here
}
diff --git a/docs/core/refined/index.html b/docs/core/refined/index.html index 4039020..15d6854 100644 --- a/docs/core/refined/index.html +++ b/docs/core/refined/index.html @@ -2,19 +2,19 @@ - + Refined | Refined4s - - - + + + -

Refined

import refined4s.*
+ diff --git a/docs/core/refined/types/index.html b/docs/core/refined/types/index.html index 07b2833..bc826e8 100644 --- a/docs/core/refined/types/index.html +++ b/docs/core/refined/types/index.html @@ -2,19 +2,19 @@ - + Pre-defined Types | Refined4s - - - + + + -

Pre-defined Types

Import

+

Pre-defined Types

Import

import refined4s.types.all.*

Refined Int

NegInt: negative Int

@@ -23,8 +23,8 @@

Comp
NegInt(0)
// error:
// Invalid value: [0]. It must be a negative Int
NegInt(1)
// error:
// Invalid value: [1]. It must be a negative Int

Runtime Validation

-
val validNegInt = -1 
// validNegInt: Int = -1
NegInt.from(validNegInt)
// res3: Either[String, Type] = Right(value = -1)
-
val invalidNegInt1 = 0 
// invalidNegInt1: Int = 0
NegInt.from(invalidNegInt1)
// res4: Either[String, Type] = Left(
// value = "Invalid value: [0]. It must be a negative Int"
// )

val invalidNegInt2 = 1
// invalidNegInt2: Int = 1
NegInt.from(invalidNegInt2)
// res5: Either[String, Type] = Left(
// value = "Invalid value: [1]. It must be a negative Int"
// )
+
val validNegInt = -1 
// validNegInt: Int = -1
NegInt.from(validNegInt)
// res3: Either[String, Type] = Right(value = -1)
+
val invalidNegInt1 = 0 
// invalidNegInt1: Int = 0
NegInt.from(invalidNegInt1)
// res4: Either[String, Type] = Left(
// value = "Invalid value: [0]. It must be a negative Int"
// )

val invalidNegInt2 = 1
// invalidNegInt2: Int = 1
NegInt.from(invalidNegInt2)
// res5: Either[String, Type] = Left(
// value = "Invalid value: [1]. It must be a negative Int"
// )

Comparison

val negInt1 = NegInt(-1)
// negInt1: Type = -1
val negInt2 = NegInt(-2)
// negInt2: Type = -2

negInt1 > negInt2
// res6: Boolean = true
negInt1 >= negInt2
// res7: Boolean = true
negInt1 == negInt2
// res8: Boolean = false
negInt1 < negInt2
// res9: Boolean = false
negInt1 <= negInt2
// res10: Boolean = false

Get Value

@@ -37,7 +37,7 @@

Co
NonNegInt(0)
// res15: Type = 0
NonNegInt(1)
// res16: Type = 1
NonNegInt(-2)
// error:
// Invalid value: [-2]. It must be a non-negative Int

Runtime Validation

-
val validNonNegInt = 1 
// validNonNegInt: Int = 1
NonNegInt.from(validNonNegInt)
// res17: Either[String, Type] = Right(value = 1)
+
val validNonNegInt = 1 
// validNonNegInt: Int = 1
NonNegInt.from(validNonNegInt)
// res17: Either[String, Type] = Right(value = 1)
val invalidNonNegInt1 = -1
// invalidNonNegInt1: Int = -1
NonNegInt.from(invalidNonNegInt1)
// res18: Either[String, Type] = Left(
// value = "Invalid value: [-1]. It must be a non-negative Int"
// )

val invalidNonNegInt2 = -999
// invalidNonNegInt2: Int = -999
NonNegInt.from(invalidNonNegInt2)
// res19: Either[String, Type] = Left(
// value = "Invalid value: [-999]. It must be a non-negative Int"
// )

Comparison

val nonNegInt1 = NonNegInt(0)
// nonNegInt1: Type = 0
val nonNegInt2 = NonNegInt(999)
// nonNegInt2: Type = 999

nonNegInt1 > nonNegInt2
// res20: Boolean = false
nonNegInt1 >= nonNegInt2
// res21: Boolean = false
nonNegInt1 == nonNegInt2
// res22: Boolean = false
nonNegInt1 < nonNegInt2
// res23: Boolean = true
nonNegInt1 <= nonNegInt2
// res24: Boolean = true
@@ -82,8 +82,8 @@

Co
NegLong(0L)
// error:
// Invalid value: [0L]. It must be a negative Long
NegLong(1L)
// error:
// Invalid value: [1L]. It must be a negative Long

Runtime Validation

-
val validNegLong = -1L 
// validNegLong: Long = -1L
NegLong.from(validNegLong)
// res59: Either[String, Type] = Right(value = -1L)
-
val invalidNegLong1 = 0L 
// invalidNegLong1: Long = 0L
NegLong.from(invalidNegLong1)
// res60: Either[String, Type] = Left(
// value = "Invalid value: [0]. It must be a negative Long"
// )

val invalidNegLong2 = 1L
// invalidNegLong2: Long = 1L
NegLong.from(invalidNegLong2)
// res61: Either[String, Type] = Left(
// value = "Invalid value: [1]. It must be a negative Long"
// )
+
val validNegLong = -1L 
// validNegLong: Long = -1L
NegLong.from(validNegLong)
// res59: Either[String, Type] = Right(value = -1L)
+
val invalidNegLong1 = 0L 
// invalidNegLong1: Long = 0L
NegLong.from(invalidNegLong1)
// res60: Either[String, Type] = Left(
// value = "Invalid value: [0]. It must be a negative Long"
// )

val invalidNegLong2 = 1L
// invalidNegLong2: Long = 1L
NegLong.from(invalidNegLong2)
// res61: Either[String, Type] = Left(
// value = "Invalid value: [1]. It must be a negative Long"
// )

Comparison

val negLong1 = NegLong(-1L)
// negLong1: Type = -1L
val negLong2 = NegLong(-2L)
// negLong2: Type = -2L

negLong1 > negLong2
// res62: Boolean = true
negLong1 >= negLong2
// res63: Boolean = true
negLong1 == negLong2
// res64: Boolean = false
negLong1 < negLong2
// res65: Boolean = false
negLong1 <= negLong2
// res66: Boolean = false

Get Value

@@ -141,8 +141,8 @@

Co
NegDouble(0d)
// error:
// Invalid value: [0.0d]. It must be a negative Double
NegDouble(999.999d)
// error:
// Invalid value: [999.999d]. It must be a negative Double

Runtime Validation

-
val validNegDouble = -0.00001d 
// validNegDouble: Double = -1.0E-5
NegDouble.from(validNegDouble)
// res116: Either[String, Type] = Right(value = -1.0E-5)
-
val invalidNegDouble1 = 0d 
// invalidNegDouble1: Double = 0.0
NegDouble.from(invalidNegDouble1)
// res117: Either[String, Type] = Left(
// value = "Invalid value: [0.0]. It must be a negative Double"
// )

val invalidNegDouble2 = 999.999d
// invalidNegDouble2: Double = 999.999
NegDouble.from(invalidNegDouble2)
// res118: Either[String, Type] = Left(
// value = "Invalid value: [999.999]. It must be a negative Double"
// )
+
val validNegDouble = -0.00001d 
// validNegDouble: Double = -1.0E-5
NegDouble.from(validNegDouble)
// res116: Either[String, Type] = Right(value = -1.0E-5)
+
val invalidNegDouble1 = 0d 
// invalidNegDouble1: Double = 0.0
NegDouble.from(invalidNegDouble1)
// res117: Either[String, Type] = Left(
// value = "Invalid value: [0.0]. It must be a negative Double"
// )

val invalidNegDouble2 = 999.999d
// invalidNegDouble2: Double = 999.999
NegDouble.from(invalidNegDouble2)
// res118: Either[String, Type] = Left(
// value = "Invalid value: [999.999]. It must be a negative Double"
// )

Comparison

val negDouble1 = NegDouble(-0.1d)
// negDouble1: Type = -0.1
val negDouble2 = NegDouble(-0.2d)
// negDouble2: Type = -0.2

negDouble1 > negDouble2
// res119: Boolean = true
negDouble1 >= negDouble2
// res120: Boolean = true
negDouble1 == negDouble2
// res121: Boolean = false
negDouble1 < negDouble2
// res122: Boolean = false
negDouble1 <= negDouble2
// res123: Boolean = false

Get Value

@@ -202,8 +202,8 @@

C
NegFloat(0f)
// error:
// Invalid value: [0.0f]. It must be a negative Float
NegFloat(999.999f)
// error:
// Invalid value: [999.999f]. It must be a negative Float

Runtime Validation

-
val validNegFloat = -0.00001f 
// validNegFloat: Float = -1.0E-5F
NegFloat.from(validNegFloat)
// res175: Either[String, Type] = Right(value = -1.0E-5F)
-
val invalidNegFloat1 = 0f 
// invalidNegFloat1: Float = 0.0F
NegFloat.from(invalidNegFloat1)
// res176: Either[String, Type] = Left(
// value = "Invalid value: [0.0]. It must be a negative Float"
// )

val invalidNegFloat2 = 999.999f
// invalidNegFloat2: Float = 999.999F
NegFloat.from(invalidNegFloat2)
// res177: Either[String, Type] = Left(
// value = "Invalid value: [999.999]. It must be a negative Float"
// )
+
val validNegFloat = -0.00001f 
// validNegFloat: Float = -1.0E-5F
NegFloat.from(validNegFloat)
// res175: Either[String, Type] = Right(value = -1.0E-5F)
+
val invalidNegFloat1 = 0f 
// invalidNegFloat1: Float = 0.0F
NegFloat.from(invalidNegFloat1)
// res176: Either[String, Type] = Left(
// value = "Invalid value: [0.0]. It must be a negative Float"
// )

val invalidNegFloat2 = 999.999f
// invalidNegFloat2: Float = 999.999F
NegFloat.from(invalidNegFloat2)
// res177: Either[String, Type] = Left(
// value = "Invalid value: [999.999]. It must be a negative Float"
// )

Comparison

val negFloat1 = NegFloat(-0.1f)
// negFloat1: Type = -0.1F
val negFloat2 = NegFloat(-0.2f)
// negFloat2: Type = -0.2F

negFloat1 > negFloat2
// res178: Boolean = true
negFloat1 >= negFloat2
// res179: Boolean = true
negFloat1 == negFloat2
// res180: Boolean = false
negFloat1 < negFloat2
// res181: Boolean = false
negFloat1 <= negFloat2
// res182: Boolean = false

Get Value

@@ -263,8 +263,8 @@

C
NegBigInt(0)
// error:
// Invalid value: [BigInt.apply(0)]. It must be a negative BigInt
NegBigInt(1)
// error:
// Invalid value: [BigInt.apply(1)]. It must be a negative BigInt

Runtime Validation

-
val validNegBigInt = -1 
// validNegBigInt: Int = -1
NegBigInt.from(validNegBigInt)
// res233: Either[String, Type] = Right(value = -1)
-
val invalidNegBigInt1 = 0 
// invalidNegBigInt1: Int = 0
NegBigInt.from(invalidNegBigInt1)
// res234: Either[String, Type] = Left(
// value = "Invalid value: [0]. It must be a negative BigInt"
// )

val invalidNegBigInt2 = 1
// invalidNegBigInt2: Int = 1
NegBigInt.from(invalidNegBigInt2)
// res235: Either[String, Type] = Left(
// value = "Invalid value: [1]. It must be a negative BigInt"
// )
+
val validNegBigInt = -1 
// validNegBigInt: Int = -1
NegBigInt.from(validNegBigInt)
// res233: Either[String, Type] = Right(value = -1)
+
val invalidNegBigInt1 = 0 
// invalidNegBigInt1: Int = 0
NegBigInt.from(invalidNegBigInt1)
// res234: Either[String, Type] = Left(
// value = "Invalid value: [0]. It must be a negative BigInt"
// )

val invalidNegBigInt2 = 1
// invalidNegBigInt2: Int = 1
NegBigInt.from(invalidNegBigInt2)
// res235: Either[String, Type] = Left(
// value = "Invalid value: [1]. It must be a negative BigInt"
// )

Comparison

val negBigInt1 = NegBigInt(-1)
// negBigInt1: Type = -1
val negBigInt2 = NegBigInt(-2)
// negBigInt2: Type = -2

negBigInt1 > negBigInt2
// res236: Boolean = true
negBigInt1 >= negBigInt2
// res237: Boolean = true
negBigInt1 == negBigInt2
// res238: Boolean = false
negBigInt1 < negBigInt2
// res239: Boolean = false
negBigInt1 <= negBigInt2
// res240: Boolean = false

Get Value

@@ -275,7 +275,7 @@

C
NonNegBigInt(0)
// res243: Type = 0
NonNegBigInt(1)
// res244: Type = 1
NonNegBigInt(-2)
// error:
// Invalid value: [BigInt.apply(-2)]. It must be a non-negative BigInt

Runtime Validation

-
val validNonNegBigInt = 1 
// validNonNegBigInt: Int = 1
NonNegBigInt.from(validNonNegBigInt)
// res245: Either[String, Type] = Right(value = 1)
+
val validNonNegBigInt = 1 
// validNonNegBigInt: Int = 1
NonNegBigInt.from(validNonNegBigInt)
// res245: Either[String, Type] = Right(value = 1)
val invalidNonNegBigInt1 = -1
// invalidNonNegBigInt1: Int = -1
NonNegBigInt.from(invalidNonNegBigInt1)
// res246: Either[String, Type] = Left(
// value = "Invalid value: [-1]. It must be a non-negative BigInt"
// )

val invalidNonNegBigInt2 = -999
// invalidNonNegBigInt2: Int = -999
NonNegBigInt.from(invalidNonNegBigInt2)
// res247: Either[String, Type] = Left(
// value = "Invalid value: [-999]. It must be a non-negative BigInt"
// )

Comparison

val nonNegBigInt1 = NonNegBigInt(0)
// nonNegBigInt1: Type = 0
val nonNegBigInt2 = NonNegBigInt(999)
// nonNegBigInt2: Type = 999

nonNegBigInt1 > nonNegBigInt2
// res248: Boolean = false
nonNegBigInt1 >= nonNegBigInt2
// res249: Boolean = false
nonNegBigInt1 == nonNegBigInt2
// res250: Boolean = false
nonNegBigInt1 < nonNegBigInt2
// res251: Boolean = true
nonNegBigInt1 <= nonNegBigInt2
// res252: Boolean = true
@@ -314,8 +314,8 @@

C
NegBigDecimal(0d)
// error:
// Invalid value: [BigDecimal.apply(0.0d)]. It must be a negative BigDecimal
NegBigDecimal(999.999d)
// error:
// Invalid value: [BigDecimal.apply(999.999d)]. It must be a negative BigDecimal

Runtime Validation

-
val validNegBigDecimal = -0.00001d 
// validNegBigDecimal: Double = -1.0E-5
NegBigDecimal.from(validNegBigDecimal)
// res282: Either[String, Type] = Right(value = -0.000010)
-
val invalidNegBigDecimal1 = 0d 
// invalidNegBigDecimal1: Double = 0.0
NegBigDecimal.from(invalidNegBigDecimal1)
// res283: Either[String, Type] = Left(
// value = "Invalid value: [0.0]. It must be a negative BigDecimal"
// )

val invalidNegBigDecimal2 = 999.999d
// invalidNegBigDecimal2: Double = 999.999
NegBigDecimal.from(invalidNegBigDecimal2)
// res284: Either[String, Type] = Left(
// value = "Invalid value: [999.999]. It must be a negative BigDecimal"
// )
+
val validNegBigDecimal = -0.00001d 
// validNegBigDecimal: Double = -1.0E-5
NegBigDecimal.from(validNegBigDecimal)
// res282: Either[String, Type] = Right(value = -0.000010)
+
val invalidNegBigDecimal1 = 0d 
// invalidNegBigDecimal1: Double = 0.0
NegBigDecimal.from(invalidNegBigDecimal1)
// res283: Either[String, Type] = Left(
// value = "Invalid value: [0.0]. It must be a negative BigDecimal"
// )

val invalidNegBigDecimal2 = 999.999d
// invalidNegBigDecimal2: Double = 999.999
NegBigDecimal.from(invalidNegBigDecimal2)
// res284: Either[String, Type] = Left(
// value = "Invalid value: [999.999]. It must be a negative BigDecimal"
// )

Comparison

val negBigDecimal1 = NegBigDecimal(-0.1d)
// negBigDecimal1: Type = -0.1
val negBigDecimal2 = NegBigDecimal(-0.2d)
// negBigDecimal2: Type = -0.2

negBigDecimal1 > negBigDecimal2
// res285: Boolean = true
negBigDecimal1 >= negBigDecimal2
// res286: Boolean = true
negBigDecimal1 == negBigDecimal2
// res287: Boolean = false
negBigDecimal1 < negBigDecimal2
// res288: Boolean = false
negBigDecimal1 <= negBigDecimal2
// res289: Boolean = false

Get Value

@@ -365,8 +365,8 @@

C
NonEmptyString("blah")
// res331: Type = "blah"
NonEmptyString("Lorem Ipsum is simply dummy text of the printing and typesetting industry.")
// res332: Type = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
NonEmptyString("")
// error:
// Invalid value: [""]. It must be a non-empty String

Runtime Validation

-
val validNonEmptyString1 = "blah" 
// validNonEmptyString1: String = "blah"
NonEmptyString.from(validNonEmptyString1)
// res333: Either[String, Type] = Right(value = "blah")

val validNonEmptyString2 = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
// validNonEmptyString2: String = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
NonEmptyString.from(validNonEmptyString2)
// res334: Either[String, Type] = Right(
// value = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
// )
-
val invalidNonEmptyString = "" 
// invalidNonEmptyString: String = ""
NonEmptyString.from(invalidNonEmptyString)
// res335: Either[String, Type] = Left(
// value = "Invalid value: []. It must be a non-empty String"
// )
+
val validNonEmptyString1 = "blah" 
// validNonEmptyString1: String = "blah"
NonEmptyString.from(validNonEmptyString1)
// res333: Either[String, Type] = Right(value = "blah")

val validNonEmptyString2 = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
// validNonEmptyString2: String = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
NonEmptyString.from(validNonEmptyString2)
// res334: Either[String, Type] = Right(
// value = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
// )
+
val invalidNonEmptyString = "" 
// invalidNonEmptyString: String = ""
NonEmptyString.from(invalidNonEmptyString)
// res335: Either[String, Type] = Left(
// value = "Invalid value: []. It must be a non-empty String"
// )

Concatenation

val nonEmptyString1 = NonEmptyString("Hello")
// nonEmptyString1: Type = "Hello"
val nonEmptyString2 = NonEmptyString(" World")
// nonEmptyString2: Type = " World"

nonEmptyString1 ++ nonEmptyString2
// res336: Type = "Hello World"

Get Value

@@ -386,11 +386,11 @@

Get Value

Refined Uuid

Compile-time Validation

-
import refined4s.types.all.*
Uuid("3596f062-a6bd-4d2c-978e-3ed6f97a264b")
// res352: Type = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"

val uuid1 = java.util.UUID.randomUUID()
// uuid1: UUID = e5dfc301-84e6-4585-b14c-0b89b1f84c62
Uuid(uuid1)
// res353: Type = "e5dfc301-84e6-4585-b14c-0b89b1f84c62"
+
import refined4s.types.all.*
Uuid("3596f062-a6bd-4d2c-978e-3ed6f97a264b")
// res352: Type = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"

val uuid1 = java.util.UUID.randomUUID()
// uuid1: UUID = 5700e9f1-2f57-4d07-b289-c739876d9e5f
Uuid(uuid1)
// res353: Type = "5700e9f1-2f57-4d07-b289-c739876d9e5f"
Uuid("")
// error:
// Invalid value: [""]. It must be UUID

Uuid("blah")
// error:
// Invalid value: ["blah"]. It must be UUID

Runtime Validation

-
val validUuidString = "3596f062-a6bd-4d2c-978e-3ed6f97a264b" 
// validUuidString: String = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"
Uuid.from(validUuidString)
// res354: Either[String, Type] = Right(
// value = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"
// )
-
val invalidUuid = "iuhsfd9f-f32wfwf3-d1i2j" 
// invalidUuid: String = "iuhsfd9f-f32wfwf3-d1i2j"
Uuid.from(invalidUuid)
// res355: Either[String, Type] = Left(
// value = "Invalid value: [iuhsfd9f-f32wfwf3-d1i2j]. It must be UUID"
// )
+
val validUuidString = "3596f062-a6bd-4d2c-978e-3ed6f97a264b" 
// validUuidString: String = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"
Uuid.from(validUuidString)
// res354: Either[String, Type] = Right(
// value = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"
// )
+
val invalidUuid = "iuhsfd9f-f32wfwf3-d1i2j" 
// invalidUuid: String = "iuhsfd9f-f32wfwf3-d1i2j"
Uuid.from(invalidUuid)
// res355: Either[String, Type] = Left(
// value = "Invalid value: [iuhsfd9f-f32wfwf3-d1i2j]. It must be UUID"
// )

To java.util.UUID

val uuid2 = Uuid("3596f062-a6bd-4d2c-978e-3ed6f97a264b")
// uuid2: Type = "3596f062-a6bd-4d2c-978e-3ed6f97a264b"

uuid2.toUUID
// res356: UUID = 3596f062-a6bd-4d2c-978e-3ed6f97a264b

Get Value

@@ -401,8 +401,8 @@

C
Uri("https://www.google.com")
// res358: Type = "https://www.google.com"
Uri("https://github.com/kevin-lee")
// res359: Type = "https://github.com/kevin-lee"
Uri("%^<>[]`{}")
// error:
// Invalid value: ["%^<>[]`{}"]. It must be a URI String

Runtime Validation

-
val validUri1 = "https://www.google.com" 
// validUri1: String = "https://www.google.com"
Uri.from(validUri1)
// res360: Either[String, Type] = Right(value = "https://www.google.com")

val validUri2 = "https://github.com/kevin-lee"
// validUri2: String = "https://github.com/kevin-lee"
Uri.from(validUri2)
// res361: Either[String, Type] = Right(value = "https://github.com/kevin-lee")
-
val invalidUri = "%^<>[]`{}" 
// invalidUri: String = "%^<>[]`{}"
Uri.from(invalidUri)
// res362: Either[String, Type] = Left(
// value = "Invalid value: [%^<>[]`{}]. It must be a URI String"
// )
+
val validUri1 = "https://www.google.com" 
// validUri1: String = "https://www.google.com"
Uri.from(validUri1)
// res360: Either[String, Type] = Right(value = "https://www.google.com")

val validUri2 = "https://github.com/kevin-lee"
// validUri2: String = "https://github.com/kevin-lee"
Uri.from(validUri2)
// res361: Either[String, Type] = Right(value = "https://github.com/kevin-lee")
+
val invalidUri = "%^<>[]`{}" 
// invalidUri: String = "%^<>[]`{}"
Uri.from(invalidUri)
// res362: Either[String, Type] = Left(
// value = "Invalid value: [%^<>[]`{}]. It must be a URI String"
// )

Get Value

val uriA = Uri("https://www.google.com")
// uriA: Type = "https://www.google.com"
val uriB = Uri("https://github.com/kevin-lee")
// uriB: Type = "https://github.com/kevin-lee"

uriA.value
// res363: String = "https://www.google.com"

uriB.value
// res364: String = "https://github.com/kevin-lee"

Convert to java.net.URI

diff --git a/docs/doobie/index.html b/docs/doobie/index.html index 6cb0108..118c51a 100644 --- a/docs/doobie/index.html +++ b/docs/doobie/index.html @@ -2,19 +2,19 @@ - + doobie module | Refined4s - - - + + + -

doobie module

Import

+

doobie module

Import

import refined4s.modules.doobie.derivation.types.all.given
import refined4s.modules.doobie.derivation.*

Use Drived Instances for Pre-defined Types

@@ -42,7 +42,7 @@

With If you want to have explicit Get and Put type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.

NOTE

This works only when the actual type already has Get and Put.

import cats.effect.*

import refined4s.*

import doobie.*

type Name = Name.Type
object Name extends Newtype[NotEmptyStr] {
given getName: Get[Name] = deriving[Get]
given putName: Put[Name] = deriving[Put]
}

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""

given getNotEmptyStr: Get[NotEmptyStr] = Get[String].temap(NotEmptyStr.from)
given putNotEmptyStr: Put[NotEmptyStr] = deriving[Put]
}

type Id = Id.Type
object Id extends Newtype[Long] {
given getId: Get[Id] = deriving[Get]
given putId: Put[Id] = deriving[Put]
}

final case class Person(id: Id, name: Name)

import doobie.syntax.all.*

def insertOrUpdate[F[*]](fragment: Fragment)(transactor: Transactor[F])(
using bracket: Bracket[F, Throwable]
): F[Int] =
fragment
.update
.run
.transact(transactor)
-
val person = Person(Id(1), Name(NotEmptyStr("Kevin")))

insertOrUpdate[F](
sql"""
INSERT INTO db_tools_test.example (id, name) VALUES (${person.id}, ${person.name})
"""
)(transactor)

// You don't have to use .value or .value.value like
// insertOrUpdate[F](
// sql"""
// INSERT INTO db_tools_test.example (id, name) VALUES (${person.id.value}, ${person.name.value.value})
// """
// )(transactor)

diff --git a/docs/extras-render/index.html b/docs/extras-render/index.html index faee4ff..97eab08 100644 --- a/docs/extras-render/index.html +++ b/docs/extras-render/index.html @@ -2,19 +2,19 @@ - + extras-render module | Refined4s - - - + + + -

extras-render module

Import

+

extras-render module

Import

import refined4s.modules.extras.derivation.types.all.given
import refined4s.modules.extras.derivation.*

Use Drived Instances for Pre-defined Types

@@ -39,7 +39,7 @@

With If you want to have explicit Render type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.

NOTE

This works only when the actual type already has Render.

import cats.*

import refined4s.*
import refined4s.modules.extras.derivation.*

import extras.render.*

type Name = Name.Type
object Name extends Newtype[String] {
given renderName: Render[Name] = deriving[Render]
}

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""

given renderNotEmptyStr: Render[NotEmptyStr] = deriving[Render]
}

import extras.render.syntax.*

final case class Person(name: Name)

final case class Item(id: NotEmptyStr)

import extras.render.syntax.*

def renderA[A: Render](a: A): Unit = println(a.render)
-
renderA(Name("Tony Stark"))
// Tony Stark

renderA(NotEmptyStr("Thor Odinson"))
// Thor Odinson

renderA(Person(Name("Steve Rogers")).name)
// Steve Rogers

renderA(Item(NotEmptyStr("abc-999")).id)
// abc-999

diff --git a/docs/index.html b/docs/index.html index 4957a5f..ff7c89a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,19 +2,19 @@ - + Refined4s | Refined4s - - - + + + -

Refined4s

+

Refined4s

Build Status Release Status Latest version

@@ -24,28 +24,28 @@

Getting Started

To get refined4s for your project,

refined4s-core

-

In build.sbt,

"io.kevinlee" %% "refined4s-core" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-core" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-core" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-core" % "0.19.0"

refined4s-cats

-

In build.sbt,

"io.kevinlee" %% "refined4s-cats" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-cats" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-cats" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-cats" % "0.19.0"

refined4s-chimney

-

In build.sbt,

"io.kevinlee" %% "refined4s-chimney" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-chimney" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-chimney" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-chimney" % "0.19.0"

refined4s-circe

-

In build.sbt,

"io.kevinlee" %% "refined4s-circe" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-circe" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-circe" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-circe" % "0.19.0"

refined4s-pureconfig

-

In build.sbt,

"io.kevinlee" %% "refined4s-pureconfig" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-pureconfig" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-pureconfig" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-pureconfig" % "0.19.0"

refined4s-doobie-ce2

-

In build.sbt,

"io.kevinlee" %% "refined4s-doobie-ce2" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-doobie-ce2" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-doobie-ce2" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-doobie-ce2" % "0.19.0"

refined4s-doobie-ce3

-

In build.sbt,

"io.kevinlee" %% "refined4s-doobie-ce3" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-doobie-ce3" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-doobie-ce3" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-doobie-ce3" % "0.19.0"

refined4s-extras-render

-

In build.sbt,

"io.kevinlee" %% "refined4s-extras-render" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-extras-render" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-extras-render" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-extras-render" % "0.19.0"

refined4s-tapir

-

In build.sbt,

"io.kevinlee" %% "refined4s-tapir" % "0.18.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-tapir" % "0.18.0"
+

In build.sbt,

"io.kevinlee" %% "refined4s-tapir" % "0.19.0"

or for Scala.js

"io.kevinlee" %%% "refined4s-tapir" % "0.19.0"

All refined4s modules

-

In build.sbt,

"io.kevinlee" %% "refined4s-core" % "0.18.0",
"io.kevinlee" %% "refined4s-cats" % "0.18.0",
"io.kevinlee" %% "refined4s-chimney" % "0.18.0",
"io.kevinlee" %% "refined4s-circe" % "0.18.0",
"io.kevinlee" %% "refined4s-pureconfig" % "0.18.0",
"io.kevinlee" %% "refined4s-doobie-ce2" % "0.18.0", // Use either refined4s-doobie-ce2
"io.kevinlee" %% "refined4s-doobie-ce3" % "0.18.0", // OR refined4s-doobie-ce3
"io.kevinlee" %% "refined4s-extras-render" % "0.18.0",
"io.kevinlee" %% "refined4s-tapir" % "0.18.0",

or for Scala.js

"io.kevinlee" %%% "refined4s-core" % "0.18.0",
"io.kevinlee" %%% "refined4s-cats" % "0.18.0",
"io.kevinlee" %%% "refined4s-chimney" % "0.18.0",
"io.kevinlee" %%% "refined4s-circe" % "0.18.0",
"io.kevinlee" %%% "refined4s-pureconfig" % "0.18.0",
"io.kevinlee" %%% "refined4s-doobie-ce2" % "0.18.0", // Use either refined4s-doobie-ce2
"io.kevinlee" %%% "refined4s-doobie-ce3" % "0.18.0", // OR refined4s-doobie-ce3
"io.kevinlee" %%% "refined4s-extras-render" % "0.18.0",
"io.kevinlee" %%% "refined4s-tapir" % "0.18.0",
+

In build.sbt,

"io.kevinlee" %% "refined4s-core" % "0.19.0",
"io.kevinlee" %% "refined4s-cats" % "0.19.0",
"io.kevinlee" %% "refined4s-chimney" % "0.19.0",
"io.kevinlee" %% "refined4s-circe" % "0.19.0",
"io.kevinlee" %% "refined4s-pureconfig" % "0.19.0",
"io.kevinlee" %% "refined4s-doobie-ce2" % "0.19.0", // Use either refined4s-doobie-ce2
"io.kevinlee" %% "refined4s-doobie-ce3" % "0.19.0", // OR refined4s-doobie-ce3
"io.kevinlee" %% "refined4s-extras-render" % "0.19.0",
"io.kevinlee" %% "refined4s-tapir" % "0.19.0",

or for Scala.js

"io.kevinlee" %%% "refined4s-core" % "0.19.0",
"io.kevinlee" %%% "refined4s-cats" % "0.19.0",
"io.kevinlee" %%% "refined4s-chimney" % "0.19.0",
"io.kevinlee" %%% "refined4s-circe" % "0.19.0",
"io.kevinlee" %%% "refined4s-pureconfig" % "0.19.0",
"io.kevinlee" %%% "refined4s-doobie-ce2" % "0.19.0", // Use either refined4s-doobie-ce2
"io.kevinlee" %%% "refined4s-doobie-ce3" % "0.19.0", // OR refined4s-doobie-ce3
"io.kevinlee" %%% "refined4s-extras-render" % "0.19.0",
"io.kevinlee" %%% "refined4s-tapir" % "0.19.0",

Why refined4s?

Given the following methods

def hello(name: String): Unit = println(s"Hello $name")
def sendEmail(email: String): Unit = {
println(s"Sending email to [email address: $email]")
// ... send email
}
@@ -57,7 +57,7 @@

Why refi

If you pass the right types, it works.

val name = Name("Kevin")
// name: Type = "Kevin"
val email = Email("blah@blah.blah")
// email: Type = "blah@blah.blah"

hello(name)
// Hello Kevin
sendEmail(email)
// Sending email to [email address: blah@blah.blah]

If you don't, it does not compile.

-
hello(email)
sendEmail(name)
// error:
// Found: (repl.MdocSession.MdocApp1.email : repl.MdocSession.MdocApp1.Email.Type)
// Required: repl.MdocSession.MdocApp1.Name
// hello(email)
// ^^^^^
// error:
// Found: (repl.MdocSession.MdocApp1.name : repl.MdocSession.MdocApp1.Name.Type)
// Required: repl.MdocSession.MdocApp1.Email
// sendEmail(name)
// ^^^^
// error:
// Line is indented too far to the left, or a `}` is missing
// error:
// Line is indented too far to the left, or a `}` is missing
// error:
// Line is indented too far to the left, or a `}` is missing

diff --git a/docs/pureconfig/index.html b/docs/pureconfig/index.html index 7b32379..1238896 100644 --- a/docs/pureconfig/index.html +++ b/docs/pureconfig/index.html @@ -2,19 +2,19 @@ - + pureconfig module | Refined4s - - - + + + -

pureconfig module

Import

+

pureconfig module

Import

import refined4s.modules.pureconfig.derivation.types.all.given
import refined4s.modules.pureconfig.derivation.*

Use Drived Instances for Pre-defined Types

@@ -39,7 +39,7 @@

With deriving Method

If you want to have explicit ConfigReader and ConfigWriter type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.

NOTE

This works only when the actual type already has ConfigReader and ConfigWriter.

-
import refined4s.*
import refined4s.types.all.*
import refined4s.modules.pureconfig.derivation.*
import refined4s.modules.pureconfig.derivation.types.all.given

import com.typesafe.config.*
import pureconfig.generic.derivation.default.*
import pureconfig.*

import scala.jdk.CollectionConverters.*

final case class NewtypeApiConfig(api: NewtypeApiConfig.Api) derives ConfigReader
object NewtypeApiConfig {

final case class Api(
id: Api.Id,
baseUri: Api.NewtypeBaseUri,
endpointPath: Api.RefinedEndpointPath,
additionalId: Api.InlinedRefinedNewtypeId,
) derives ConfigReader
object Api {

type Id = Id.Type
object Id extends InlinedRefined[Long] {

override inline val inlinedExpectedValue = "a positive Long"

override inline def invalidReason(a: Long): String =
"It must be a positive Long"

override inline def predicate(a: Long): Boolean = a > 0L

override inline def inlinedPredicate(inline a: Long): Boolean = a > 0L

given configReaderId: ConfigReader[Id] = deriving[ConfigReader]
}

type NewtypeBaseUri = NewtypeBaseUri.Type
object NewtypeBaseUri extends Newtype[Uri] {
given configReaderNewtypeBaseUri: ConfigReader[NewtypeBaseUri] = deriving[ConfigReader]
}

type RefinedEndpointPath = RefinedEndpointPath.Type
object RefinedEndpointPath extends Refined[String] {
override inline def invalidReason(a: String): String =
"It must be a non-empty String"

override inline def predicate(a: String): Boolean = a != ""

given configReaderRefinedEndpointPath: ConfigReader[RefinedEndpointPath] = deriving[ConfigReader]
}

type InlinedRefinedNewtypeId = InlinedRefinedNewtypeId.Type
object InlinedRefinedNewtypeId extends Newtype[PosLong] {
given configReaderInlinedRefinedNewtypeId: ConfigReader[InlinedRefinedNewtypeId] = deriving[ConfigReader]
}
}

}

val confString =
raw"""api {
| id = 123
| base-uri = "https://localhost:8080"
| endpoint-path = "/v1/blah/blah"
| additional-id = 999
|}
|""".stripMargin
// confString: String = """api {
// id = 123
// base-uri = "https://localhost:8080"
// endpoint-path = "/v1/blah/blah"
// additional-id = 999
// }
// """

ConfigSource.string(confString).load[NewtypeApiConfig]
// res5: Either[ConfigReaderFailures, NewtypeApiConfig] = Right(
// value = NewtypeApiConfig(
// api = Api(
// id = 123L,
// baseUri = "https://localhost:8080",
// endpointPath = "/v1/blah/blah",
// additionalId = 999L
// )
// )
// )
diff --git a/docs/tapir/index.html b/docs/tapir/index.html index 8e66c0f..61e4cc1 100644 --- a/docs/tapir/index.html +++ b/docs/tapir/index.html @@ -2,19 +2,19 @@ - + tapir module | Refined4s - - - + + + -

tapir module

Import

+

tapir module

Import

import refined4s.modules.tapir.derivation.types.all.given
import refined4s.modules.tapir.derivation.*

Use Drived Instances for Pre-defined Types

@@ -24,9 +24,9 @@

info

Using refined4s.modules.tapir.derivation.types.all.given is required only when sttp.tapir.Schema is required for the pre-defined types.
So if you want your Newtype or Refined or InlinedRefined to have Schema instances,
you can use pre-defined traits for tapir or the deriving method instead.

-
import refined4s.*
import refined4s.types.all.*

import sttp.tapir.*

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
+
import refined4s.*
import refined4s.types.all.*

import sttp.tapir.*

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
// NOTE: You don't need code like this in your project as `Schema` is required by Tapir to generate API docs so just having the Schema type-class instances is good enough.

With derivation.types.all,

-
import refined4s.modules.tapir.derivation.types.all.given
import sttp.tapir.generic.auto.* // It's only for case classes. // It's only for case classes.

final case class Person(name: NonEmptyString)

validate(NonEmptyString("Tony Stark"))
// res1: List[ValidationError[_ >: Nothing <: Any]] = List()

val thor = Person(NonEmptyString("Thor Odinson"))
// thor: Person = Person(name = "Thor Odinson")
validate(thor)
// res2: List[ValidationError[_ >: Nothing <: Any]] = List()
+
import refined4s.modules.tapir.derivation.types.all.given
import sttp.tapir.generic.auto.* // It's only for case classes.

final case class Person(name: NonEmptyString)

validate(NonEmptyString("Tony Stark"))
// res1: List[ValidationError[_ >: Nothing <: Any]] = List()

val thor = Person(NonEmptyString("Thor Odinson"))
// thor: Person = Person(name = "Thor Odinson")
validate(thor)
// res2: List[ValidationError[_ >: Nothing <: Any]] = List()

With Explicit Pre-defined Tapir Support

There are the following pre-defined traits to support tapir's Schema.

    @@ -34,13 +34,13 @@

    NOTE

    This works only when the actual type already has Schema.

-
import refined4s.*
import refined4s.modules.tapir.derivation.*
import sttp.tapir.generic.auto.* // It's only for case classes. // It's only for case classes.

type Name = Name.Type
object Name extends Newtype[String] with TapirNewtypeSchema[String]

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] with TapirRefinedSchema[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""
}

import sttp.tapir.*

final case class Person(name: Name)

final case class Item(id: NotEmptyStr)

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
+
import refined4s.*
import refined4s.modules.tapir.derivation.*
import sttp.tapir.generic.auto.* // It's only for case classes.

type Name = Name.Type
object Name extends Newtype[String] with TapirNewtypeSchema[String]

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] with TapirRefinedSchema[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""
}

import sttp.tapir.*

final case class Person(name: Name)

final case class Item(id: NotEmptyStr)

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
// NOTE: You don't need code like this in your project as `Schema` is required by Tapir to generate API docs so just having the Schema type-class instances is good enough.
validate(Name("Tony Stark"))
// res4: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(NotEmptyStr("Thor Odinson"))
// res5: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Person(Name("Steve Rogers")))
// res6: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Item(NotEmptyStr("abc-999")))
// res7: List[ValidationError[_ >: Nothing <: Any]] = List()

With deriving Method

If you want to have explicit sttp.tapir.Schema type-class instances in your Newtype or Refined or InlinedRefined, you can use the deriving method.

NOTE

This works only when the actual type already has the Schema instance.

-
import cats.*

import refined4s.*
import sttp.tapir.generic.auto.* // It's only for case classes. // It's only for case classes.

import sttp.tapir.*

type Name = Name.Type
object Name extends Newtype[String] {
given schemaName: Schema[Name] = deriving[Schema]
}

type NotEmptyStr = NotEmptyStr.Type
object NotEmptyStr extends Refined[String] {
inline def invalidReason(a: String): String = "non-empty String"

inline def predicate(a: String): Boolean = a != ""

given schemaNotEmptyStr: Schema[NotEmptyStr] = deriving[Schema]
}

import sttp.tapir.*

final case class Person(name: Name)

final case class Item(id: NotEmptyStr)

def validate[A: Schema](a: A): List[ValidationError[?]] = summon[Schema[A]].applyValidation(a)
-
validate(Name("Tony Stark"))
// res9: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(NotEmptyStr("Thor Odinson"))
// res10: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Person(Name("Steve Rogers")))
// res11: List[ValidationError[_ >: Nothing <: Any]] = List()

validate(Item(NotEmptyStr("abc-999")))
// res12: List[ValidationError[_ >: Nothing <: Any]] = List()
diff --git a/index.html b/index.html index 0e1b280..7080a0a 100644 --- a/index.html +++ b/index.html @@ -2,19 +2,19 @@ - + Refined4s | Refined4s - - - + + + -
Project Logo

Refined4s

Newtypes and Refinement types for Scala 3

Newtypes

Newtypes

Refined4s provides an easy way to create newtypes for the existing types. So params like 
(Int, String, String, Int) can be
(Id, Name, Description, Count)

Refinement Types

Refinement Types

Refined4s also provides an easy way to create refinement types.

For Scala 3

Refined4s is developed to support newtypes and refinement types for Scala 3.