diff --git a/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerDefinition.scala b/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerDefinition.scala index c4b2108ae..19c0e9cb9 100644 --- a/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerDefinition.scala +++ b/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerDefinition.scala @@ -174,7 +174,8 @@ final class TransformerDefinition[From, To, Overrides <: TransformerOverrides, F /** Use `FromSubtype` in `From` as a source for `ToSubtype` in `To`. * * @see - * [[https://chimney.readthedocs.io/supported-transformations/#TODO]] for more details + * [[https://chimney.readthedocs.io/supported-transformations/#handling-a-specific-sealed-subtype-by-a-specific-target-subtype]] + * for more details * * @tparam FromSubtype * type of sealed/enum instance diff --git a/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerInto.scala b/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerInto.scala index 97167e0d2..b0e1bbd50 100644 --- a/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerInto.scala +++ b/chimney/src/main/scala-3/io/scalaland/chimney/dsl/TransformerInto.scala @@ -163,7 +163,8 @@ final class TransformerInto[From, To, Overrides <: TransformerOverrides, Flags < /** Use `FromSubtype` in `From` as a source for `ToSubtype` in `To`. * * @see - * [[https://chimney.readthedocs.io/supported-transformations/#TODO]] for more details + * [[https://chimney.readthedocs.io/supported-transformations/#handling-a-specific-sealed-subtype-by-a-specific-target-subtype]] + * for more details * * @tparam FromSubtype * type of sealed/enum instance diff --git a/chimney/src/main/scala/io/scalaland/chimney/integrations/DefaultValue.scala b/chimney/src/main/scala/io/scalaland/chimney/integrations/DefaultValue.scala index 8b2f814f7..ad453a708 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/integrations/DefaultValue.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/integrations/DefaultValue.scala @@ -3,7 +3,7 @@ package io.scalaland.chimney.integrations /** Tells Chimney how to provide default value of type `Value` if flag allows them but field does not define it. * * @see - * [[https://chimney.readthedocs.io/cookbook/#custom-default-values]] for more details TODO + * [[https://chimney.readthedocs.io/cookbook/#custom-default-values]] for more details * * @tparam Value * type of default value diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala index 5e4316a92..97c916f7c 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala @@ -116,7 +116,9 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { } ) case _ => - DerivationResult.assertionError("TODO") + // $COVERAGE-OFF$should never happen unless someone mess around with type-level representation + DerivationResult.assertionError(s"Unexpected path: $targetPath") + // $COVERAGE-ON$ }) } } diff --git a/docs/docs/cookbook.md b/docs/docs/cookbook.md index a6d56f531..c0fb0cb24 100644 --- a/docs/docs/cookbook.md +++ b/docs/docs/cookbook.md @@ -707,7 +707,7 @@ There are 2 ways in which Chimney could handle this issue: - using [default values](supported-transformations.md#allowing-fallback-to-the-constructors-default-values) - !!! example + !!! example "Globally enabled default values" ```scala domain @@ -715,6 +715,21 @@ There are 2 ways in which Chimney could handle this issue: .into[protobuf.Address] .enableDefaultValues .transform + + // can be set up for the whole scope with: + // implicit val cfg = TransformerConfiguration.default.enableDefaultValues + ``` + + !!! example "Default values scoped only to UnknownFieldSet" + + ```scala + domain + .Address("a", "b") + .into[protobuf.Address] + .enableDefaultValueOfType[scalapb.UnknownFieldSet] + .transform + // can be set up for the whole scope with: + // implicit val cfg = TransformerConfiguration.default.enableDefaultValueOfType[scalapb.UnknownFieldSet] ``` - manually [setting this one field](supported-transformations.md#wiring-the-constructors-parameter-to-a-provided-value)_ @@ -1319,6 +1334,36 @@ We can validate using the dedicated type class (`Validate`), while extraction is } ``` +## Custom default values + +If you are providing integration for a type which you do not control, and you'd like to let your users fall back +to default values when using Chimney, but the type does not define them - it might be still possible to provide them +with `io.scalaland.chimney.integrations.DefaultValue`. It could look like this: + +!!! example + + ```scala + //> using dep io.scalaland::chimney::{{ chimney_version() }} + + // Types which we cannot simply edit: come from external library, codegen, etc. + + case class MyType(int: Int) + case class Foo(a: Int) + case class Bar(a: Int, b: MyType) + + // Our integration: + implicit val defaultMyType: io.scalaland.chimney.integrations.DefaultValue[MyType] = () => MyType(0) + + // Remember that default values has to be enabled! + import io.scalaland.chimney.dsl._ + Foo(10).into[Bar].enableDefaultValues.transform // Bar(10, MyType(0)) + Foo(10).into[Bar].enableDefaultValueOfType[MyType].transform // Bar(10, MyType(0)) + ``` + +Keep in mind, that such provision works for every constructor which has an argument of such type not matched with source +value, so it's only safe to use when in the scope which sees such implicit all derivations would only need default value +of this type, rather than convert it from something else. + ## Custom optional types In case your library/domain defines custom Optional types, you can provide your own handling of such types through diff --git a/docs/docs/supported-transformations.md b/docs/docs/supported-transformations.md index 01c7fa8af..2a7f38a4b 100644 --- a/docs/docs/supported-transformations.md +++ b/docs/docs/supported-transformations.md @@ -1001,11 +1001,30 @@ If the flag was enabled in the implicit config it can be disabled with `.disable // Target // c: scala.Long - no accessor named c in source type Source // - // There are default values for c, the constructor argument/setter in Target. Consider using .enableDefaultValues. + // There are default values for c, the constructor argument/setter in Target. Consider using .enableDefaultValues or .enableDefaultValueForType. // // Consult https://chimney.readthedocs.io for usage examples. ``` +If enabling global values globally, seems too dangerous, you can also limit the scope of their usage, by enabling only +default values of one particular type: + +!!! example + + ```scala + //> using dep io.scalaland::chimney::{{ chimney_version() }} + import io.scalaland.chimney.dsl._ + + case class Source(a: String, b: Int) + case class Target(a: String, b: Int = 0, c: Long = 0L) + + Source("value", 128).into[Target].enableDefaultValueOfType[Long].transform + // val source = Source("value", 128) + // Target(source.a, source.b /* c is filled by the default value */) + Source("value", 128).intoPartial[Target].enableDefaultValueOfType[Long].transform + // val source = Source("value", 128) + // partial.Result.fromValue(Target(source.a, source.b /* c is filled by the default value */)) + ``` ### Allowing fallback to `None` as the constructor's argument @@ -1099,7 +1118,7 @@ If the flag was enabled in the implicit config it can be disabled with `.disable // Bar // b: scala.Option[java.lang.String] - no accessor named b in source type Foo // - // There are default values for b, the constructor argument/setter in Bar. Consider using .enableDefaultValues. + // There are default values for b, the constructor argument/setter in Bar. Consider using .enableDefaultValues or .enableDefaultValueForType. // // There are default optional values available for b, the constructor argument/setter in Bar. Consider using .enableOptionDefaultsToNone. //