ITADN

dynamic: DynamicValue round-trip fails for Schema.NonEmptySequence and Schema.NonEmptyMap

#1097Openhaskiindahouse 创建于 2026-05-10
H
haskiindahousecommented
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 条评论