Skip to content

Releases: kevin-lee/refined4s

v0.11.0

04 Jan 02:25
Compare
Choose a tag to compare

0.11.0 - 2024-01-04

New Feature

  • [refined4s-core] Add MinValue and MaxValue to refined basic numeric types (#223)

    • Add Min trait
    • Add Max trait
    • Add MinMax trait

    Add MinMax to the following types to have MinValue and MaxValue

    • NegInt
    • NonNegInt
    • PosInt
    • NonPosInt
    • NegLong
    • NonNegLong
    • PosLong
    • NonPosLong
    • NegShort
    • NonNegShort
    • PosShort
    • NonPosShort
    • NegByte
    • NonNegByte
    • PosByte
    • NonPosByte
    • NegFloat
    • NonNegFloat
    • PosFloat
    • NonPosFloat
    • NegDouble
    • NonNegDouble
    • PosDouble
    • NonPosDouble

Internal Change

  • [refined4s-core] Move Numeric and InlinedNumeric from numeric trait to numeric object (#225)

v0.10.0

02 Jan 07:58
Compare
Choose a tag to compare

0.10.0 - 2024-01-02

New Feature

  • Release refined4s-extras-render module (#220)
  • Add refined4s-extras-render to support Render for refined4s (#215)
    refined4s.modules.extras.derivation.ExtrasRender
    refined4s.modules.extras.derivation.types.all.given
    refined4s.modules.extras.derivation.generic.auto.given
    e.g.)
    import extras.render.Render
    
    import refined4s.types.all.*
    import refined4s.modules.extras.derivation.types.all.given
    
    val name = NonEmptyString("Kevin")
    Render[NonEmptyString].render(name)
    // String = Kevin
    import extras.render.Render
    
    import refined4s.Newtype
    import refined4s.modules.extras.derivation.ExtrasRender
    
    type Name = Name.Type
    object Name extends Newtype[String], ExtrasRender[String]
    
    val name = Name("Kevin")
    Render[Name].render(name)
    // String = Kevin
    import extras.render.Render
    
    import refined4s.Newtype
    
    type Name = Name.Type
    object Name extends Newtype[String]
    
    import refined4s.modules.extras.derivation.generic.auto.given
    
    val name = Name("Kevin")
    Render[Name].render(name)
    // String = Kevin

v0.9.0

02 Jan 06:23
Compare
Choose a tag to compare

0.9.0 - 2024-01-02

NOTE:
refined4s-extras-render was not released by mistake, and it will be released in v0.10.0.

New Feature

  • Add refined4s-extras-render to support Render for refined4s (#215)
    refined4s.modules.extras.derivation.ExtrasRender
    refined4s.modules.extras.derivation.types.all.given
    refined4s.modules.extras.derivation.generic.auto.given
    e.g.)
    import extras.render.Render
    
    import refined4s.types.all.*
    import refined4s.modules.extras.derivation.types.all.given
    
    val name = NonEmptyString("Kevin")
    Render[NonEmptyString].render(name)
    // String = Kevin
    import extras.render.Render
    
    import refined4s.Newtype
    import refined4s.modules.extras.derivation.ExtrasRender
    
    type Name = Name.Type
    object Name extends Newtype[String], ExtrasRender[String]
    
    val name = Name("Kevin")
    Render[Name].render(name)
    // String = Kevin
    import extras.render.Render
    
    import refined4s.Newtype
    
    type Name = Name.Type
    object Name extends Newtype[String]
    
    import refined4s.modules.extras.derivation.generic.auto.given
    
    val name = Name("Kevin")
    Render[Name].render(name)
    // String = Kevin

v0.8.0

31 Dec 09:41
Compare
Choose a tag to compare

0.8.0 - 2023-12-31

Changes

  • [refined4s-core] Change NewtypeBase.unapply and RefinedBase.unapply to return Some[A] instead of Option[A] (#208)

    The reason for having Some[A] as the return type of the unapply methods can be found at scala/bug#12232. 😔

v0.7.0

30 Dec 05:03
Compare
Choose a tag to compare

0.7.0 - 2023-12-30

Changes

  • [refined4s-cats] Rename validateAs in refined4s.modules.cats.syntax to refinedNewtypeNec (#182)

  • [refined4s-core] Move toValue from refined4s.syntax to refined4s.NewtypeBase (#186)

    So with the given following code,

    import refined4s.*
    import refined4s.types.all.*
    
    type Name = Name.Type
    object Name extends Newtype[NonEmptyString]
    

    the following is possible without importing any syntax.

    val name = Name(NonEmptyString("Kevin"))
    name.toValue
    // String = "Kevin"

New Features

  • [refined4s-cats] Add refinedNewtypeNel in refined4s.modules.cats.syntax (#184)

    import refined4s.*
    import refined4s.types.all.*
    
    import refined4s.modules.cats.syntax.*
    
    type Name = Name.Type
    object Name extends Newtype[NonEmptyString]
    
    "Kevin".refinedNewtypeNel[Name]
    // EitherNel[String, Name] = Right(Name(NonEmptyString("Kevin")))
    
    "".refinedNewtypeNel[Name]
    // EitherNel[String, Name] = Left(NonEmptyList("Failed to create Name: Invalid value: []. It has to be a non-empty String but got \"\"))

  • [refined4s-cats] Add validateAs in refined4s.modules.cats.syntax to validate a value and return Validated (#188)

    import refined4s.*
    import refined4s.types.all.*
    
    import refined4s.modules.cats.syntax.*
    
    type Name = Name.Type
    object Name extends Newtype[NonEmptyString]
    
    "Kevin".validateAs[Name]
    // Validated[String, Name] = Valid(Name(NonEmptyString("Kevin")))
    
    "".validateAs[Name]
    // Validated[String, Name] = Invalid("Failed to create Name: Invalid value: []. It has to be a non-empty String but got \"\")

  • [refined4s-cats] Add validateNecAs in refined4s.modules.cats.syntax to validate a value and return ValidatedNec (#189)

    import refined4s.*
    import refined4s.types.all.*
    
    import refined4s.modules.cats.syntax.*
    
    type Name = Name.Type
    object Name extends Newtype[NonEmptyString]
    
    "Kevin".validateNecAs[Name]
    // ValidatedNec[String, Name] = Valid(Name(NonEmptyString("Kevin")))
    
    "".validateNecAs[Name]
    // ValidatedNec[String, Name] = Invalid(NonEmptyChain("Failed to create Name: Invalid value: []. It has to be a non-empty String but got \"\"))

  • [refined4s-cats] Add validateNelAs in refined4s.modules.cats.syntax to validate a value and return ValidatedNel (#190)

    import refined4s.*
    import refined4s.types.all.*
    
    import refined4s.modules.cats.syntax.*
    
    type Name = Name.Type
    object Name extends Newtype[NonEmptyString]
    
    "Kevin".validateNelAs[Name]
    // ValidatedNel[String, Name] = Valid(Name(NonEmptyString("Kevin")))
    
    "".validateNelAs[Name]
    // ValidatedNel[String, Name] = Invalid(NonEmptyList("Failed to create Name: Invalid value: []. It has to be a non-empty String but got \"\"))

  • [refined4s-cats] Add derivedOrder to have the instance of Order[A] derived from Coercible[A, B] and Order[B] (#194)

    Given

    import refined4s.*
    
    type MyNum = MyNum.Type
    object MyNum extends Newtype[Int]

    it can be

    import cats.*
    
    val n1 = MyNum(1)
    val n2 = MyNum(2)
    
    Order[MyNum].compare(n1, n2)
    // Int = -1

  • [refined4s-core] Add CanBeOrdered for providing Ordering and Conversion[Type, Ordered[Type]] (#196)

    import refined4s.*
    
    type MyNum = MyNum.Type
    object MyNum extends Newtype[Int]
    val input1 = MyNum(1)
    val input2 = MyNum(2)
    
    Ordering[MyNum].compare(input1, input2)
    // Int = -1
    
    (input1: Ordered[MyNum]).compare(input2)
    // Int = -1

  • [refined4s-core] Make NonEmptyString CanBeOrdered to have Ordering[NonEmptyString] and Conversion[NonEmptyString, Ordered[NonEmptyString]] (#198)

  • [refined4s-cats] Add CatsOrder (#203)
    import refined4s.*
    
    type MyNum = MyNum.Type
    object MyNum extends Newtype[Int], CatsOrder[Int]
    import cats.*
    val myNum1 = NyNum(1)
    val myNum2 = NyNum(2)
    
    Order[MyNum].compare(myNum1, myNum1)
    // Int = 0
    
    Order[MyNum].compare(myNum1, myNum2)
    // Int = -1
    
    Order[MyNum].compare(myNum2, myNum1)
    // Int = 1

Internal Changes

  • [refined4s-core] Replace Ordering and Conversion[Type, Ordered[Type]] for numeric types with CanBeOrdered (#199)

v0.6.0

28 Dec 05:41
Compare
Choose a tag to compare

0.6.0 - 2023-12-28

Changes

  • All modules: importing derivation.instances.given can cause an issue as it overrides all type-classes defined in the companion objects (#163)
    • [refined4s-cats] Add explicit Eq and Show for pre-defined types (#171)

      • Now it has refined4s.modules.cats.derivation.types.all for the all pre-defined types (e.g. NegInt, PosInt, NonEmptyString, etc.)
      • refined4s.modules.cats.derivation.instances => refined4s.modules.cats.derivation.generic.auto
      • refined4s.modules.cats.derivation.instances.contraCoercible is moved to refined4s.modules.cats.syntax
    • [refined4s-circe] Add explicit Encoder and Decoder for pre-defined types (#166)

    • [refined4s-pureconfig] Add explicit ConfigReader and ConfigWriter for pre-defined types (#172)

    • [refined4s-doobie] Add explicit Get and Put for pre-defined types (#173)


  • [refined4s-core] Keep only all object for pre-defined types and remove all the others (#168)

    So this will be the only import available for using pre-defined types

    import refined4s.types.all.*

    The following ones have been removed.

    import refined4s.types.numeric.*
    import refined4s.types.strings.*
    import refined4s.types.network.*

  • Rename derived type classes - some of them have a naming conflict issue (#165)

v0.5.0

23 Dec 09:52
Compare
Choose a tag to compare

0.5.0 - 2023-12-23

New Features

  • [refined4s-cats] Add contraCoercible to F[B] => F[A] with Contravariant[F] and Coercible[A, B] (#152)

    This is useful to derive type-class instances for Newtype, Refined and InlinedRefined from the type-class instances of the actual types.

    e.g.)

    import refined4s.modules.cats.derivation.instances.contraCoercible
    
    inline given eqDerived[A, B](using coercible: Coercible[A, B], eqB: Eq[B]): Eq[A] =
      contraCoercible(eqB)
    
    inline given showDerived[A, B](using coercible: Coercible[A, B], showB: Show[B]): Show[A] =
      contraCoercible(showB)

    where B is the actual type and A could be a newtype or a refined type.


Improvement

  • Add missing inline to invalidReason in the sub-types of InlinedNumeric (#146)

  • [refined4s-pureconfig] Add type name to the error message of PureconfigRefinedConfigReader and refined4s.modules.pureconfig.derivation.instances.derivedRefinedConfigReader (#150)

    So a message like this

    
    Invalid value found: -2373683071661092303 with error: Invalid value: [-2373683071661092303]. It must be a positive Long
    

    should be like this instead.

    The value -2373683071661092303 cannot be created as the expected type, mytypes.blah.Id.Type, due to the following error: Invalid value: [-2373683071661092303]. It must be a positive Long
    

  • [refined4s-doobie] Make type-classes in refined4s.modules.doobie.derivation.instances inline (#156)

  • [refined4s-core] Improve compile-time error message for inline apply method (#158)

    The old compile-time error for the constant value passed to the inline apply method may look like this.

    [error] 2780 |      NegBigInt(1)
    [error]      |      ^^^^^^^^^^^^
    [error]      |A literal string is expected as an argument to `compiletime.error`. Got "Invalid value: [BigInt.apply(1)]. ".+(
    [error]      |  {
    [error]      |    val a$proxy4: BigInt = BigInt.apply(1)
    [error]      |    "It must be a negative BigInt":String:String
    [error]      |  }:String
    [error]      |)
    [error] one error found
    

    It is not so readable, and it is hard to comprehend what is wrong with the input.

    After this release, it will be like

    [error] 2780 |      NegBigInt(1)
    [error]      |      ^^^^^^^^^^^^
    [error]      |      Invalid value: [BigInt.apply(1)]. It must be a negative BigInt
    [error] one error found
    

Internal Housekeeping

  • [refined4s-circe] Update refined4s.modules.circe.derivation.instances.derivedEncoder to use contraCoercible and make it inline (#154)

    The old code has the following issue if it's turned into an inline method.

    [error] 13 |    a => encoder(coercible(a))
    [error]    |    ^^^^^^^^^^^^^^^^^^^^^^^^^^
    [error]    |An inline given alias with a function value as right-hand side can significantly increase
    [error]    |generated code size. You should either drop the `inline` or rewrite the given with an
    [error]    |explicit `apply` method.
    

  • Rename Coercible methods and type parameters (#160)
    • wrap and unwrap suffixed with M: M to TC (type constructor)
    • wrap and unwrap suffixed with MOfM: MOfM to HKT (higher-kinded type)
    • M[*] to F[*]
    • M1[*] to F[*] and M2[*] to G[*] e.g.) M1[M2[A]] to F[G[A]]

v0.4.0

16 Dec 09:00
Compare
Choose a tag to compare

0.4.0 - 2023-12-16

New Features

  • Add refined4s-doobie-ce2 and refined4s-doobie-ce3 modules to support doobie (#123)
  • [refined4s-doobie] Add Gets and Put for Newtype, Refined and InlinedRefined with Coercible and RefinedCtor (#124)
  • [refined4s-doobie] Add DoobiePut, DoobieNewtypeGet, DoobieRefinedGet, DoobieNewtypeGetPut and DoobieRefinedGetPut to have circe Get and Put derived from the actual type for Newtype, Refined and InlinedRefined (#127)

v0.3.0

15 Dec 12:51
Compare
Choose a tag to compare

0.3.0 - 2023-12-15

Changes

  • [refined4s-cats] Replace Eq and Show instances for the existing refined types with the ones derived from the actual types using Coercible (#107)

New Features

  • Add refined4s-circe module to support circe (#101)

  • [refined4s-circe] Add Encoder and Decoders for Newtype, Refined and InlinedRefined with Coercible and RefinedCtor (#103)

  • [refined4s-circe] Add CirceEncoder, CirceNewtypeDecoder, CirceRefinedDecoder, CirceNewtypeCodec and CirceRefinedCodec to have circe Encoder and Decoder derived from the actual type for Newtype, Refined and InlinedRefined (#104)

    import refined4s.modules.circe.derivation.*
    type MyNewtype = MyNewtype.Type
    object MyNewtype extends Newtype[String] with CirceEncoder[String]
    
    type MyRefinedType = MyRefinedType.Type
    object MyRefinedType extends Refined[String] with CirceEncoder[String] {
      override inline def invalidReason(a: String): String =
        "It has to be a non-empty String but got \"" + a + "\""
    
      override inline def predicate(a: String): Boolean = a != ""
    }
    
    type MyRefinedNewtype = MyRefinedNewtype.Type
    object MyRefinedNewtype extends Newtype[MyRefinedType] with CirceEncoder[MyRefinedType]
    type MyNewtype = MyNewtype.Type
    object MyNewtype extends Newtype[String] with CirceNewtypeDecoder[String]
    
    type MyRefinedType = MyRefinedType.Type
    object MyRefinedType extends Refined[String] with CirceRefinedDecoder[String] {
      override inline def invalidReason(a: String): String =
        "It has to be a non-empty String but got \"" + a + "\""
    
      override inline def predicate(a: String): Boolean = a != ""
    }
    
    type MyRefinedNewtype = MyRefinedNewtype.Type
    object MyRefinedNewtype extends Newtype[MyRefinedType] with CirceNewtypeDecoder[MyRefinedType]
  • [refined4s-core] Add PortNumber, SystemPortNumber, NonSystemPortNumber, UserPortNumber and DynamicPortNumber (#110)

  • Add refined4s-pureconfig module to support pureconfig (#112)

  • [refined4s-pureconfig] Add ConfigReader and ConfigWriters for Newtype, Refined and InlinedRefined with Coercible and RefinedCtor (#113)

    import refined4s.modules.pureconfig.derivation.instances.given
  • [refined4s-pureconfig] Add PureconfigNewtypeConfigReader and PureconfigRefinedConfigReader to provider ConfigReader for Newtype, Refined and InlinedRefined (#116)

    type MyNewtype = MyNewtype.Type
    object MyNewtype extends Newtype[String] with PureconfigNewtypeConfigReader[String]
    
    type MyRefinedType = MyRefinedType.Type
    object MyRefinedType extends Refined[String] with PureconfigRefinedConfigReader[String] {
      override inline def invalidReason(a: String): String =
        "It has to be a non-empty String but got \"" + a + "\""
    
      override inline def predicate(a: String): Boolean = a != ""
    }
    
    type MyRefinedNewtype = MyRefinedNewtype.Type
    object MyRefinedNewtype extends Newtype[MyRefinedType] with PureconfigNewtypeConfigReader[MyRefinedType]
    
    type MyInlinedRefinedType = MyInlinedRefinedType.Type
    object MyInlinedRefinedType extends InlinedRefined[String] with PureconfigRefinedConfigReader[String] {
      override inline def invalidReason(a: String): String =
        "It has to be a non-empty String but got \"" + a + "\""
    
      override inline def predicate(a: String): Boolean = a != ""
    
      override inline def inlinedPredicate(inline a: String): Boolean = a != ""
    }
    
    type MyInlinedRefinedNewtype = MyInlinedRefinedNewtype.Type
    object MyInlinedRefinedNewtype extends Newtype[MyRefinedType] with PureconfigNewtypeConfigReader[MyRefinedType]
  • [refined4s-pureconfig] Add PureconfigConfigWriter to provider ConfigWriter for Newtype, Refined and InlinedRefined (#118)

v0.2.0

10 Dec 10:42
Compare
Choose a tag to compare

0.2.0 - 2023-12-10

Changes

  • Rename refined4s.cats to refined4s.modules.cats (#94)
    import refined4s.modules.cats.derivation.*
    import refined4s.modules.cats.syntax.*

New Features

  • Add Eq[A] and Show[A] instances for the existing refined types (#95)

    So with

    import refined4s.modules.cats.derivation.instances.given

    Eq and Show instances for the following types are available

    • NegInt
    • NonNegInt
    • PosInt
    • NonPosInt
    • NegLong
    • NonNegLong
    • PosLong
    • NonPosLong
    • NegShort
    • NonNegShort
    • PosShort
    • NonPosShort
    • NegByte
    • NonNegByte
    • PosByte
    • NonPosByte
    • NegFloat
    • NonNegFloat
    • PosFloat
    • NonPosFloat
    • NegDouble
    • NonNegDouble
    • PosDouble
    • NonPosDouble
    • NegBigInt
    • NonNegBigInt
    • PosBigInt
    • NonPosBigInt
    • NegBigDecimal
    • NonNegBigDecimal
    • PosBigDecimal
    • NonPosBigDecimal
    • NonEmptyString
    • Uri