Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite DynamicValue error handling to Validate #549

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .sbtopts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-J-Xms5120m
-J-Xmx5120m
-J-XX:MaxMetaspaceSize=1024m
-J-XX:MaxMetaspaceSize=2048m
-J-XX:MetaspaceSize=760m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ object CodecBenchmarks {
val statusProtobufEncoder: Status => Chunk[Byte] =
ProtobufCodec.protobufCodec[Status].encode

val statusProtobufDecoder: Chunk[Byte] => Either[DecodeError, Status] =
val statusProtobufDecoder: Chunk[Byte] => zio.prelude.Validation[DecodeError, Status] =
ProtobufCodec.protobufCodec[Status].decode

val statuses: Array[Status] = Array(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ProtobufBenchmarks {
byteChunkCodec.encode(bigByteChunk)

@Benchmark
def decodeLargeByteChunk(): Either[DecodeError, Chunk[Byte]] =
def decodeLargeByteChunk(): zio.prelude.Validation[DecodeError, Chunk[Byte]] =
byteChunkCodec.decode(encodedBigByteChunk)
}

Expand Down
18 changes: 9 additions & 9 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,11 @@ lazy val zioSchema = crossProject(JSPlatform, JVMPlatform)
.settings(buildInfoSettings("zio.schema"))
.settings(
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-streams" % zioVersion,
"dev.zio" %% "zio-prelude" % zioPreludeVersion,
"dev.zio" %% "zio-constraintless" % zioConstraintlessVersion
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-streams" % zioVersion,
"dev.zio" %% "zio-prelude" % zioPreludeVersion,
"dev.zio" %% "zio-constraintless" % zioConstraintlessVersion,
"org.scala-lang.modules" %% "scala-collection-compat" % scalaCollectionCompatVersion
)
)
.dependsOn(zioSchemaMacros)
Expand Down Expand Up @@ -245,11 +246,10 @@ lazy val zioSchemaBson = crossProject(JVMPlatform)
.settings(buildInfoSettings("zio.schema.bson"))
.settings(
libraryDependencies ++= Seq(
"org.mongodb" % "bson" % bsonVersion,
"dev.zio" %% "zio-bson" % zioBsonVersion,
"dev.zio" %% "zio" % zioVersion, // zio.Chunk
"dev.zio" %% "zio-test-magnolia" % zioVersion % Test, // TODO: implement DeriveDiff in zioSchemaZioTest
"org.scala-lang.modules" %% "scala-collection-compat" % scalaCollectionCompatVersion
"org.mongodb" % "bson" % bsonVersion,
"dev.zio" %% "zio-bson" % zioBsonVersion,
"dev.zio" %% "zio" % zioVersion, // zio.Chunk
"dev.zio" %% "zio-test-magnolia" % zioVersion % Test // TODO: implement DeriveDiff in zioSchemaZioTest
),
scalacOptions -= "-Xfatal-warnings" // cross-version imports
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package zio.schema

import zio.prelude.Validation
import zio.schema.Schema._
import zio.schema.SchemaGen.Json.schema
import zio.test._
Expand Down Expand Up @@ -35,7 +36,7 @@ object AccessorBuilderSpec extends ZIOSpecDefault {
},
test("transform") {
check(SchemaGen.anyPrimitive) { schema =>
val transform = schema.transformOrFail[Unit](_ => Left("error"), _ => Left("error"))
val transform = schema.transformOrFail[Unit](_ => Validation.fail("error"), _ => Validation.fail("error"))

val transformAccessor: Any = transform.makeAccessors(builder).asInstanceOf[Any]
val schemaAccessor: Any = schema.makeAccessors(builder).asInstanceOf[Any]
Expand Down
33 changes: 17 additions & 16 deletions tests/shared/src/test/scala-2/zio/schema/DynamicValueSpec.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zio.schema

import zio._
import zio.prelude.Validation
import zio.schema.Schema.Primitive
import zio.schema.SchemaGen._
import zio.test.Assertion._
Expand All @@ -14,75 +15,75 @@ object DynamicValueSpec extends ZIOSpecDefault {
suite("Primitives")(primitiveTests: _*),
test("round-trips Records") {
check(SchemaGen.anyRecordOfRecordsAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips Enumerations") {
check(SchemaGen.anyEnumerationAndValue) {
case (schema, a) =>
assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips Eithers") {
check(SchemaGen.anyEitherAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips Tuples") {
check(SchemaGen.anyTupleAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips Optionals") {
check(SchemaGen.anyOptionalAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips Transform") {
check(SchemaGen.anyTransformAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips CaseClass") {
check(SchemaGen.anyCaseClassAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips Enum") {
check(SchemaGen.anyEnumAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips any un-nested schema") {
check(SchemaGen.anyLeafAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips any nested schema") {
check(SchemaGen.anyTree(1).flatMap(s => DynamicValueGen.anyDynamicValueOfSchema(s).map(s -> _))) {
case (schema, dynamic) =>
assert(schema.fromDynamic(dynamic))(isRight)
assert(schema.fromDynamic(dynamic).toEither)(isRight)
}
},
test("round-trips recursive data types") {
check(SchemaGen.anyRecursiveTypeAndValue) {
case (schema, a) =>
assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips sequence") {
check(SchemaGen.anySequenceAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips set") {
check(SchemaGen.anySetAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
},
test("round-trips map") {
check(SchemaGen.anyMapAndValue) {
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
case (schema, a) => assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}
}
),
Expand All @@ -97,7 +98,7 @@ object DynamicValueSpec extends ZIOSpecDefault {
check(Json.genDeep) { json =>
val dyn = DynamicValue.fromSchemaAndValue(Json.schema, json)
val json2 = dyn.toTypedValue(Json.schema)
assertTrue(json2 == Right(json))
assertTrue(json2 == Validation.succeed(json))
}
} @@ TestAspect.size(250) @@ TestAspect.ignore
)
Expand All @@ -112,7 +113,7 @@ object DynamicValueSpec extends ZIOSpecDefault {

private def dynamicValueLaw[R, A](gen: Gen[R, A], schema: Schema[A]): URIO[R with TestConfig, TestResult] =
check(gen) { a =>
assert(schema.fromDynamic(schema.toDynamic(a)))(isRight(equalTo(a)))
assert(schema.fromDynamic(schema.toDynamic(a)).toEither)(isRight(equalTo(a)))
}

}
12 changes: 6 additions & 6 deletions tests/shared/src/test/scala-2/zio/schema/OrderingSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ object OrderingSpec extends ZIOSpecDefault {
} yield (None, Some(a))
)

def genAnyOrderedPairEither: Gen[Sized, SchemaAndPair[Either[_, _]]] =
def genAnyOrderedPairEither: Gen[Sized, SchemaAndPair[zio.prelude.Validation[_, _]]] =
for {
leftSchema <- anySchema
rightSchema <- anySchema
(l, r) <- genOrderedPairEither(leftSchema, rightSchema)
} yield (Schema.Either(leftSchema, rightSchema), l, r).asInstanceOf[SchemaAndPair[Either[_, _]]]
} yield (Schema.Either(leftSchema, rightSchema), l, r).asInstanceOf[SchemaAndPair[zio.prelude.Validation[_, _]]]

def genOrderedPairEither[A, B](
lSchema: Schema[A],
Expand All @@ -116,7 +116,7 @@ object OrderingSpec extends ZIOSpecDefault {
xSchema <- anySchema
ySchema <- anySchema
(l, r) <- genOrderedPairTuple(xSchema, ySchema)
} yield (Schema.Tuple2(xSchema, ySchema), l, r).asInstanceOf[SchemaAndPair[Either[_, _]]]
} yield (Schema.Tuple2(xSchema, ySchema), l, r).asInstanceOf[SchemaAndPair[zio.prelude.Validation[_, _]]]

def genOrderedPairTuple[A, B](
xSchema: Schema[A],
Expand Down Expand Up @@ -171,9 +171,9 @@ object OrderingSpec extends ZIOSpecDefault {
for {
(small, large) <- genOrderedPair(schema)
} yield (schema.transformOrFail({ (a: A) =>
Right(a)
zio.prelude.Validation.succeed(a)
}, { (a: A) =>
Right(a)
zio.prelude.Validation.succeed(a)
}), small, large)

def genOrderedPairDecodeTransform[A](
Expand All @@ -182,7 +182,7 @@ object OrderingSpec extends ZIOSpecDefault {
for {
error <- Gen.boolean
(small, large) <- genOrderedPair(schema)
encode = (a: A) => Right(schema.toDynamic(a))
encode = (a: A) => zio.prelude.Validation.succeed(schema.toDynamic(a))
decode = schema.fromDynamic(_)
smallEncoded = encode(small).toOption.get
smallEncodedOrError = if (error) DynamicValue.SomeValue(smallEncoded) else smallEncoded
Expand Down
8 changes: 4 additions & 4 deletions tests/shared/src/test/scala-2/zio/schema/PatchSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ object PatchSpec extends ZIOSpecDefault {
),
suite("not comparable")(
test("Left <-> Right") {
notComparable[Either[String, String]](_.isLeft, _.isRight)(_.isLeft)
notComparable[Either[String, String]](_.isLeft, _.isRight)(_.toEither.isLeft)
},
test("Separate enum cases") {
notComparable[Pet](_.isInstanceOf[Pet.Dog], _.isInstanceOf[Pet.Cat])(_.isLeft)
notComparable[Pet](_.isInstanceOf[Pet.Dog], _.isInstanceOf[Pet.Cat])(_.toEither.isLeft)
}
)
)
Expand All @@ -182,15 +182,15 @@ object PatchSpec extends ZIOSpecDefault {
val afterInvert = diff.invert.invert
val patched = schema.diff(l, r).patch(l)
val patchedAfterInvert = afterInvert.patch(l)
assert(patched)(isRight(equalTo(r))) && assert(patchedAfterInvert)(isRight(equalTo(r)))
assert(patched.toEither)(isRight(equalTo(r))) && assert(patchedAfterInvert.toEither)(isRight(equalTo(r)))
} else {
assertTrue(true)
}
}
}

private def notComparable[A](leftFilter: A => Boolean, rightFilter: A => Boolean)(
assertion: Either[String, A] => Boolean
assertion: zio.prelude.Validation[String, A] => Boolean
)(implicit schema: Schema[A]): URIO[Sized with TestConfig, TestResult] = {
val gen = DeriveGen.gen[A]

Expand Down
19 changes: 10 additions & 9 deletions tests/shared/src/test/scala-2/zio/schema/SchemaGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zio.schema
import scala.collection.immutable.ListMap

import zio.Chunk
import zio.prelude.Validation
import zio.test.{ Gen, Sized }

object SchemaGen {
Expand Down Expand Up @@ -104,15 +105,15 @@ object SchemaGen {
right <- anyPrimitive
} yield Schema.Either(left, right)

type EitherAndGen[A, B] = (Schema.Either[A, B], Gen[Sized, scala.util.Either[A, B]])
type EitherAndGen[A, B] = (Schema.Either[A, B], Gen[Sized, Either[A, B]])

val anyEitherAndGen: Gen[Sized, EitherAndGen[_, _]] =
for {
(leftSchema, leftGen) <- anyPrimitiveAndGen
(rightSchema, rightGen) <- anyPrimitiveAndGen
} yield (Schema.Either(leftSchema, rightSchema), Gen.either(leftGen, rightGen))

type EitherAndValue[A, B] = (Schema.Either[A, B], scala.util.Either[A, B])
type EitherAndValue[A, B] = (Schema.Either[A, B], Either[A, B])

val anyEitherAndValue: Gen[Sized, EitherAndValue[_, _]] =
for {
Expand Down Expand Up @@ -315,8 +316,8 @@ object SchemaGen {
private def transformSequence[A](schema: Schema[Chunk[A]]): SequenceTransform[A] =
Schema.Transform[Chunk[A], List[A], String](
schema,
chunk => Right(chunk.toList),
list => Right(Chunk.fromIterable(list)),
chunk => Validation.succeed(chunk.toList),
list => Validation.succeed(Chunk.fromIterable(list)),
Chunk.empty,
"transformSequence"
)
Expand Down Expand Up @@ -348,8 +349,8 @@ object SchemaGen {
def transformRecord[A](schema: Schema[ListMap[String, _]]): RecordTransform[A] =
Schema.Transform[ListMap[String, _], A, String](
schema,
_ => Left("Not implemented."),
_ => Left("Not implemented."),
_ => Validation.fail("Not implemented."),
_ => Validation.fail("Not implemented."),
Chunk.empty,
"transformRecord"
)
Expand Down Expand Up @@ -381,8 +382,8 @@ object SchemaGen {
def transformEnumeration[A](schema: Schema[Any]): EnumerationTransform[_] =
Schema.Transform[Any, A, String](
schema,
_ => Left("Not implemented."),
_ => Left("Not implemented."),
_ => Validation.fail("Not implemented."),
_ => Validation.fail("Not implemented."),
Chunk.empty,
"transformEnumeration"
)
Expand Down Expand Up @@ -594,7 +595,7 @@ object SchemaGen {
// anyEnumeration(anyTree(depth - 1)).map(toCaseSet).map(Schema.enumeration[Any, CaseSet.Aux[Any]](_))
)

type SchemaAndDerivedValue[A, B] = (Schema[A], Schema[B], Chunk[scala.util.Either[A, B]])
type SchemaAndDerivedValue[A, B] = (Schema[A], Schema[B], Chunk[zio.prelude.Validation[A, B]])

lazy val anyLeafAndValue: Gen[Sized, SchemaAndValue[_]] =
for {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package zio.schema

import zio._
import zio.prelude.Validation
import zio.schema.syntax._
import zio.test.Assertion._
import zio.test._
Expand Down Expand Up @@ -47,7 +48,7 @@ object SchemaMigrationSpec extends ZIOSpecDefault {

val actualMigration = original.migrate[Recursive3]

assert(actualMigration)(isRight(equalTo(expectedMigration)))
assert(actualMigration.toEither)(isRight(equalTo(expectedMigration)))
},
test("require optional field") {
assert(PetFood.DogFood(List("i"), Some("brand")))(migratesTo(BrandedPetFood.DogFood(List("i"), "brand")))
Expand All @@ -64,7 +65,7 @@ object SchemaMigrationSpec extends ZIOSpecDefault {
},
test("migrates to equivalent type") {
check(PetFood.gen) { from =>
PetFood.brandedEquivalent(from) match {
PetFood.brandedEquivalent(from).toEither match {
case Left(_) => assert(from)(cannotMigrateValue[PetFood, BrandedPetFood])
case Right(to) => assert(from)(migratesTo(to))
}
Expand Down Expand Up @@ -114,7 +115,7 @@ object SchemaMigrationSpec extends ZIOSpecDefault {
check(genA) { a =>
val roundTrip = a.migrate[B].flatMap(_.migrate[A])

assertTrue(roundTrip == Right(a))
assertTrue(roundTrip == zio.prelude.Validation.succeed(a))
}

case class Recursive1(level: Int, value: String, r: Option[Recursive1])
Expand Down Expand Up @@ -170,10 +171,10 @@ object SchemaMigrationSpec extends ZIOSpecDefault {
(Gen.listOf(Gen.string) <*> Gen.option(Gen.string)).map((CatFood.apply _).tupled)
}

def brandedEquivalent(p: PetFood): Either[String, BrandedPetFood] = p match {
case CatFood(ingredients, Some(brand)) => Right(BrandedPetFood.CatFood(ingredients, brand))
case DogFood(ingredients, Some(brand)) => Right(BrandedPetFood.DogFood(ingredients, brand))
case _ => Left("error")
def brandedEquivalent(p: PetFood): zio.prelude.Validation[String, BrandedPetFood] = p match {
case CatFood(ingredients, Some(brand)) => Validation.succeed(BrandedPetFood.CatFood(ingredients, brand))
case DogFood(ingredients, Some(brand)) => Validation.succeed(BrandedPetFood.DogFood(ingredients, brand))
case _ => Validation.fail("error")
}

implicit lazy val schema: Schema[PetFood] = DeriveSchema.gen
Expand Down
Loading