Skip to content

Commit

Permalink
Handle non-empty schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
987Nabil committed Aug 14, 2024
1 parent 61f5fd6 commit 2740a59
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 30 deletions.
2 changes: 1 addition & 1 deletion project/BuildHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ object BuildHelper {
baseDirectory.value
)
},
nativeConfig ~= { _.withMultithreading(false) },
nativeConfig ~= { _.withMultithreading(false) }
)

def buildInfoSettings(packageName: String) = Seq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,14 @@ object AvroSchemaCodec extends AvroSchemaCodec {

private def toAvroSchema(schema: Schema[_]): scala.util.Either[String, SchemaAvro] = {
schema match {
case e: Enum[_] => toAvroEnum(e)
case record: Record[_] => toAvroRecord(record)
case map: Schema.Map[_, _] => toAvroMap(map)
case seq: Schema.Sequence[_, _, _] => toAvroSchema(seq.elementSchema).map(SchemaAvro.createArray)
case set: Schema.Set[_] => toAvroSchema(set.elementSchema).map(SchemaAvro.createArray)
case Transform(codec, _, _, _, _) => toAvroSchema(codec)
case e: Enum[_] => toAvroEnum(e)
case record: Record[_] => toAvroRecord(record)
case map: Schema.Map[_, _] => toAvroMap(map)
case map: Schema.NonEmptyMap[_, _] => toAvroMap(map)
case seq: Schema.Sequence[_, _, _] => toAvroSchema(seq.elementSchema).map(SchemaAvro.createArray)
case seq: Schema.NonEmptySequence[_, _, _] => toAvroSchema(seq.elementSchema).map(SchemaAvro.createArray)
case set: Schema.Set[_] => toAvroSchema(set.elementSchema).map(SchemaAvro.createArray)
case Transform(codec, _, _, _, _) => toAvroSchema(codec)
case Primitive(standardType, _) =>
standardType match {
case StandardType.UnitType => Right(SchemaAvro.create(SchemaAvro.Type.NULL))
Expand Down Expand Up @@ -624,6 +626,18 @@ object AvroSchemaCodec extends AvroSchemaCodec {
toAvroSchema(tupleSchema).map(SchemaAvro.createArray)
}

private[codec] def toAvroMap(map: NonEmptyMap[_, _]): scala.util.Either[String, SchemaAvro] =
map.keySchema match {
case p: Schema.Primitive[_] if p.standardType == StandardType.StringType =>
toAvroSchema(map.valueSchema).map(SchemaAvro.createMap)
case _ =>
val tupleSchema = Schema
.Tuple2(map.keySchema, map.valueSchema)
.annotate(AvroAnnotations.name("Tuple"))
.annotate(AvroAnnotations.namespace("scala"))
toAvroSchema(tupleSchema).map(SchemaAvro.createArray)
}

private[codec] def toAvroDecimal(schema: Schema[_]): scala.util.Either[String, SchemaAvro] = {
val scale = schema.annotations.collectFirst { case AvroAnnotations.scale(s) => s }
.getOrElse(AvroAnnotations.scale().scale)
Expand Down Expand Up @@ -820,7 +834,9 @@ object AvroSchemaCodec extends AvroSchemaCodec {
case c: Dynamic => Right(c)
case c: GenericRecord => Right(c)
case c: Map[_, _] => Right(c)
case c: NonEmptyMap[_, _] => Right(c)
case c: Sequence[_, _, _] => Right(c)
case c: NonEmptySequence[_, _, _] => Right(c)
case c: Set[_] => Right(c)
case c: Fail[_] => Right(c)
case c: Lazy[_] => Right(c)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1918,10 +1918,7 @@ object AssertionHelper {
def recordFields(assertion: Assertion[Iterable[Schema.Field[_, _]]]): Assertion[Schema.Record[_]] =
Assertion.assertionRec[Schema.Record[_], Chunk[Field[_, _]]]("hasRecordField")(
assertion
) {
case r: Schema.Record[_] => Some(r.fields)
case _ => None
}
)((r: Schema.Record[_]) => Some(r.fields))

def hasSequenceElementSchema[A](assertion: Assertion[Schema[A]]): Assertion[Schema.Sequence[_, A, _]] =
Assertion.hasField("schemaA", _.elementSchema, assertion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ object BsonSchemaCodecSpec extends ZIOSpecDefault {
implicit lazy val schema: Schema[Tree] = DeriveSchema.gen
implicit lazy val codec: BsonCodec[Tree] = BsonSchemaCodec.bsonCodec(schema)

private val genLeaf = Gen.int.map(Leaf)
private val genLeaf = Gen.int.map(Leaf.apply)

lazy val gen: Gen[Any, Tree] = Gen.sized { i =>
if (i >= 2) Gen.oneOf(genLeaf, Gen.suspend(gen.zipWith(gen)(Branch)).resize(i / 2))
if (i >= 2) Gen.oneOf(genLeaf, Gen.suspend(gen.zipWith(gen)(Branch.apply)).resize(i / 2))
else genLeaf
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,22 @@ private[schema] object CachedDeriver {
final case class Tuple2[A, B](leftKey: CacheKey[A], rightKey: CacheKey[B]) extends CacheKey[(A, B)]
final case class Set[A](element: CacheKey[A]) extends CacheKey[Set[A]]
final case class Map[K, V](key: CacheKey[K], valuew: CacheKey[V]) extends CacheKey[Map[K, V]]
final case class NonEmptyMap[K, V](key: CacheKey[K], valuew: CacheKey[V]) extends CacheKey[NonEmptyMap[K, V]]
final case class Misc[A](schema: Schema[A]) extends CacheKey[A]

def fromStandardType[A](st: StandardType[A]): CacheKey[A] = Primitive(st)

def fromSchema[A](schema: Schema[A]): CacheKey[A] =
schema match {
case e: Schema.Enum[_] => WithId(e.id)
case record: Schema.Record[_] => WithId(record.id)
case seq: Schema.Sequence[_, _, _] => WithIdentityObject(fromSchema(seq.elementSchema), seq.identity)
case set: Schema.Set[_] => Set(fromSchema(set.elementSchema)).asInstanceOf[CacheKey[A]]
case e: Schema.Enum[_] => WithId(e.id)
case record: Schema.Record[_] => WithId(record.id)
case seq: Schema.Sequence[_, _, _] => WithIdentityObject(fromSchema(seq.elementSchema), seq.identity)
case seq: Schema.NonEmptySequence[_, _, _] => WithIdentityObject(fromSchema(seq.elementSchema), seq.identity)
case set: Schema.Set[_] => Set(fromSchema(set.elementSchema)).asInstanceOf[CacheKey[A]]
case map: Schema.Map[_, _] =>
Map(fromSchema(map.keySchema), fromSchema(map.valueSchema)).asInstanceOf[CacheKey[A]]
case map: Schema.NonEmptyMap[_, _] =>
Map(fromSchema(map.keySchema), fromSchema(map.valueSchema)).asInstanceOf[CacheKey[A]]
case Schema.Transform(inner, _, _, _, identity) => WithIdentityObject(fromSchema(inner), identity)
case Schema.Primitive(standardType, _) => fromStandardType(standardType)
case optional: Schema.Optional[_] => Optional(fromSchema(optional.schema)).asInstanceOf[CacheKey[A]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ object JsonCodec {
//scalafmt: { maxColumn = 400, optIn.configStyleArguments = false }
private[codec] def schemaEncoder[A](schema: Schema[A], cfg: Config, discriminatorTuple: DiscriminatorTuple = Chunk.empty): ZJsonEncoder[A] =
schema match {
case Schema.Primitive(standardType, _) => primitiveCodec(standardType).encoder
case Schema.Sequence(schema, _, g, _, _) => ZJsonEncoder.chunk(schemaEncoder(schema, cfg, discriminatorTuple)).contramap(g)
case Schema.NonEmptySequence(schema, _, g, _, _) => ZJsonEncoder.chunk(schemaEncoder(schema, cfg, discriminatorTuple)).contramap(g)
case Schema.Map(ks, vs, _) => mapEncoder(ks, vs, discriminatorTuple, cfg)
case Schema.NonEmptyMap(ks, vs, _) => mapEncoder(ks, vs, discriminatorTuple, cfg).contramap[NonEmptyMap[Any, Any]](_.toMap.asInstanceOf[Map[Any, Any]]).asInstanceOf[ZJsonEncoder[A]]
case Schema.Primitive(standardType, _) => primitiveCodec(standardType).encoder
case Schema.Sequence(schema, _, g, _, _) => ZJsonEncoder.chunk(schemaEncoder(schema, cfg, discriminatorTuple)).contramap(g)
case Schema.NonEmptySequence(schema, _, g, _, _) => ZJsonEncoder.chunk(schemaEncoder(schema, cfg, discriminatorTuple)).contramap(g)
case Schema.Map(ks, vs, _) => mapEncoder(ks, vs, discriminatorTuple, cfg)
case Schema.NonEmptyMap(ks: Schema[kt], vs: Schema[vt], _) => mapEncoder(ks, vs, discriminatorTuple, cfg).contramap[NonEmptyMap[kt, vt]](_.toMap.asInstanceOf[Map[kt, vt]]).asInstanceOf[ZJsonEncoder[A]]
case Schema.Set(s, _) =>
ZJsonEncoder.chunk(schemaEncoder(s, cfg, discriminatorTuple)).contramap(m => Chunk.fromIterable(m))
case Schema.Transform(c, _, g, a, _) => transformEncoder(a.foldLeft(c)((s, a) => s.annotate(a)), g, cfg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,6 @@ object ProtobufCodec {
encodeKey(rightWireType, Some(2)) ++
rightDecoder.remainder
encodeKey(WireType.LengthDelimited(data.size), Some(seqIndex)) ++ data
case other =>
throw new IllegalStateException(s"Invalid state in processDictionary: $other")
}
}.flatten
val data = encodeKey(
Expand Down Expand Up @@ -371,7 +369,7 @@ object ProtobufCodec {
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
byteBuffer.putDouble(v)
encodeKey(WireType.Bit64, fieldNumber) ++ Chunk.fromArray(byteBuffer.array)
case (StandardType.BinaryType, bytes: Chunk[Byte]) =>
case (StandardType.BinaryType, bytes: Chunk[Byte] @unchecked) =>
encodeKey(WireType.LengthDelimited(bytes.length), fieldNumber) ++ bytes
case (StandardType.CharType, c: Char) =>
encodePrimitive(fieldNumber, StandardType.StringType, c.toString)
Expand Down
10 changes: 5 additions & 5 deletions zio-schema/shared/src/main/scala/zio/schema/Differ.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package zio.schema

import zio.prelude.NonEmptyMap

import java.math.{ BigInteger, MathContext }
import java.time.temporal.{ ChronoField, ChronoUnit }
import java.time.{
DayOfWeek,
Duration => JDuration,
Instant,
LocalDate,
LocalDateTime,
LocalTime,
Month => JMonth,
MonthDay,
OffsetDateTime,
OffsetTime,
Expand All @@ -18,13 +18,13 @@ import java.time.{
YearMonth,
ZoneId,
ZoneOffset,
Duration => JDuration,
Month => JMonth,
ZonedDateTime => JZonedDateTime
}
import java.util.{ Currency, UUID }

import scala.annotation.nowarn
import scala.collection.immutable.ListMap

import zio.schema.diff.Edit
import zio.{ Chunk, ChunkBuilder }

Expand Down Expand Up @@ -269,7 +269,7 @@ object Differ {
case s @ Schema.NonEmptySequence(schema, _, f, _, _) => fromSchema(schema).chunk.transform(f, s.fromChunk)
case Schema.Set(s, _) => set(s)
case Schema.Map(k, v, _) => map(k, v)
case s @ Schema.NonEmptyMap(k, v, _) => map(k, v).transform(_.toMap.asInstanceOf[Map[Any, Any]], s.fromMap)
case s @ Schema.NonEmptyMap(k: Schema[kt], v: Schema[vt], _) => map(k, v).transform[NonEmptyMap[kt, vt]](_.toMap.asInstanceOf[Map[kt, vt]], s.fromMap).asInstanceOf[Differ[A]]
case Schema.Either(leftSchema, rightSchema, _) => either(fromSchema(leftSchema), fromSchema(rightSchema))
case Schema.Fallback(leftSchema, rightSchema, _, _) => fallback(fromSchema(leftSchema), fromSchema(rightSchema))
case s @ Schema.Lazy(_) => fromSchema(s.schema)
Expand Down

0 comments on commit 2740a59

Please sign in to comment.