dynamic: DynamicValue round-trip fails for Schema.NonEmptySequence and Schema.NonEmptyMap
Same shape as the `Schema.Fallback` round-trip issue: the forward direction in `MutableSchemaBasedValueProcessor` turns `NonEmptyChunk` and `NonEmptyMap` into the regular `DynamicValue.Sequence` and `DynamicValue.Dictionary` shapes, but `DynamicValue.toTypedValueLazyError` only has cases for those `DynamicValue` shapes against `Schema.Sequence` / `Schema.MapSchema`, not against the non-empty variants. So the reverse direction always returns `Left(CastError)` for any `Schema.nonEmptyChunk[*]` / `Schema.nonEmptyMap[*, *]`.
Reproducer (scala-cli):
```scala
//> using scala 3.8.3
//> using dep dev.zio::zio-schema::1.8.5
//> using dep dev.zio::zio-schema-derivation::1.8.5
//> using dep dev.zio::zio-prelude::1.0.0-RC42
import zio.schema.*
import zio.{Chunk, NonEmptyChunk}
import zio.prelude.NonEmptyMap
@main def repro(): Unit =
val necSchema = Schema.nonEmptyChunk[Int]
val nec = NonEmptyChunk(1, 2, 3)
println(DynamicValue.fromSchemaAndValue(necSchema, nec).toTypedValue(necSchema))
// Left(Failed to cast Sequence(...) to schema NonEmptySequence(...))
val nemSchema = Schema.nonEmptyMap[String, Int]
val nem = NonEmptyMap("a" -> 1)
println(DynamicValue.fromSchemaAndValue(nemSchema, nem).toTypedValue(nemSchema))
// Left(Failed to cast Dictionary(...) to schema NonEmptyMap(...))
```
Source: https://github.com/zio/zio-schema/blob/f32240d525c45a702aaa40e9fb50f25011dc003a/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala — there's a case `(DynamicValue.Sequence, Schema.Sequence)` and one for `(DynamicValue.Dictionary, Schema.MapSchema)`, but `grep "NonEmpty"` inside `toTypedValueLazyError` finds nothing. Same root cause as the `Fallback` round-trip — the forward path picks the regular `DynamicValue` shape, the reverse path can't recognise it against the non-empty schema.
**Versions.** zio-schema 1.8.5, Scala 3.8.3.
**Suggested fix.** Add cases that re-validate non-emptiness on the way back:
```scala
case (DynamicValue.Sequence(values), schema: Schema.NonEmptySequence[col, t, _]) =>
values.foldLeft[Either[DecodeError, Chunk[t]]](Right(Chunk.empty)) {
case (e @ Left(_), _) => e
case (Right(vs), v) => v.toTypedValueLazyError(schema.elementSchema).map(vs :+ _)
}.flatMap { chunk =>
schema.fromChunkOption(chunk)
.toRight(DecodeError.MalformedField(schema, "Empty NonEmptySequence"))
}
case (DynamicValue.Dictionary(entries), schema: Schema.NonEmptyMap[k, v]) =>
entries.foldLeft[Either[DecodeError, Map[k, v]]](Right(Map.empty)) {
case (e @ Left(_), _) => e
case (Right(m), (dk, dv)) =>
for
key <- dk.toTypedValueLazyError(schema.keySchema)
value <- dv.toTypedValueLazyError(schema.valueSchema)
yield m + (key -> value)
}.flatMap { m =>
schema.fromChunkOption(Chunk.fromIterable(m))
.toRight(DecodeError.MalformedField(schema, "Empty NonEmptyMap"))
}
```
Happy to PR.
0 条评论