@@ -111,6 +111,20 @@ object DynamoDBCodecDeriverSpec extends ZIOSpecDefault {
111111 case class WithDefaultField (name : String , rank : Int = 99 )
112112 object WithDefaultField { implicit val schema : Schema [WithDefaultField ] = Schema .derived }
113113
114+ // covers every primitive register type's default-value handling
115+ // (FieldInfo.defaultEqualsValue / setMissingValueOrDefault), not just Int/String
116+ case class WithPrimitiveDefaults (
117+ id : String ,
118+ longVal : Long = 100L ,
119+ boolVal : Boolean = true ,
120+ byteVal : Byte = 1 ,
121+ charVal : Char = 'x' ,
122+ shortVal : Short = 10 ,
123+ floatVal : Float = 1.5f ,
124+ doubleVal : Double = 2.5
125+ )
126+ object WithPrimitiveDefaults { implicit val schema : Schema [WithPrimitiveDefaults ] = Schema .derived }
127+
114128 case class WithMaybe (id : String , value : Maybe [String ])
115129 object WithMaybe { implicit val schema : Schema [WithMaybe ] = Schema .derived }
116130
@@ -222,6 +236,7 @@ object DynamoDBCodecDeriverSpec extends ZIOSpecDefault {
222236 encodeTransientSuite,
223237 transientDefaultValueSuite,
224238 defaultValueDecodeSuite,
239+ primitiveDefaultsSuite,
225240 emptyCollectionSuite,
226241 maybeSuite,
227242 sequenceSuite,
@@ -1104,6 +1119,44 @@ object DynamoDBCodecDeriverSpec extends ZIOSpecDefault {
11041119 }
11051120 )
11061121
1122+ // ---- default-value handling across every primitive register type --------
1123+ //
1124+ // The suites above only exercise Int/String defaults. FieldInfo dispatches
1125+ // on register type for both defaultEqualsValue (encode-side omission check)
1126+ // and setMissingValueOrDefault (decode-side fallback) with a case per
1127+ // primitive type, so cover Long/Boolean/Byte/Char/Short/Float/Double too.
1128+
1129+ private val primitiveDefaultsSuite = suite(" default-value handling for every primitive type" )(
1130+ test(" all primitive-default fields are omitted when equal to their defaults" ) {
1131+ val deriver = DynamoDBCodecDeriver .withTransientDefaultValue(transientDefaultValue = true )
1132+ val codec = WithPrimitiveDefaults .schema.deriving(deriver).derive
1133+ codec.encoder(WithPrimitiveDefaults (" a" )) match {
1134+ case m : AttributeValue .Map =>
1135+ val keys = m.value.keys.map(_.value).toSet
1136+ assertTrue(keys == Set (" id" ))
1137+ case _ => assertTrue(false )
1138+ }
1139+ },
1140+ test(" all primitive-default fields are written when not at their defaults" ) {
1141+ val deriver = DynamoDBCodecDeriver .withTransientDefaultValue(transientDefaultValue = true )
1142+ val codec = WithPrimitiveDefaults .schema.deriving(deriver).derive
1143+ val value = WithPrimitiveDefaults (" a" , 200L , false , 2 , 'y' , 20 , 9.5f , 8.5 )
1144+ codec.encoder(value) match {
1145+ case m : AttributeValue .Map =>
1146+ val keys = m.value.keys.map(_.value).toSet
1147+ assertTrue(
1148+ keys == Set (" id" , " longVal" , " boolVal" , " byteVal" , " charVal" , " shortVal" , " floatVal" , " doubleVal" )
1149+ )
1150+ case _ => assertTrue(false )
1151+ }
1152+ },
1153+ test(" decoding an item missing every primitive-default field uses each schema default" ) {
1154+ val codec = codecFor[WithPrimitiveDefaults ]
1155+ val stored = AttributeValue .Map (Map (AttributeValue .String (" id" ) -> AttributeValue .String (" a" )))
1156+ assertTrue(codec.decoder(stored) == Right (WithPrimitiveDefaults (" a" )))
1157+ }
1158+ )
1159+
11071160 // ---- emptyCollectionConstructor ----------------------------------------
11081161
11091162 private val collectionsCodec = codecFor[WithCollections ]
0 commit comments