diff --git a/.sbtopts b/.sbtopts index ae2b88708..66610b278 100644 --- a/.sbtopts +++ b/.sbtopts @@ -1,4 +1,4 @@ -J-Xms5120m -J-Xmx5120m --J-XX:MaxMetaspaceSize=1024m +-J-XX:MaxMetaspaceSize=2048m -J-XX:MetaspaceSize=760m \ No newline at end of file diff --git a/benchmarks/src/main/scala/zio/schema/codec/CodecBenchmarks.scala b/benchmarks/src/main/scala/zio/schema/codec/CodecBenchmarks.scala index 334b0da7d..b894b19f3 100644 --- a/benchmarks/src/main/scala/zio/schema/codec/CodecBenchmarks.scala +++ b/benchmarks/src/main/scala/zio/schema/codec/CodecBenchmarks.scala @@ -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( diff --git a/benchmarks/src/main/scala/zio/schema/codec/ProtobufBenchmarks.scala b/benchmarks/src/main/scala/zio/schema/codec/ProtobufBenchmarks.scala index da14574f1..313b370fe 100644 --- a/benchmarks/src/main/scala/zio/schema/codec/ProtobufBenchmarks.scala +++ b/benchmarks/src/main/scala/zio/schema/codec/ProtobufBenchmarks.scala @@ -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) } diff --git a/build.sbt b/build.sbt index cb1db388f..49d790faa 100644 --- a/build.sbt +++ b/build.sbt @@ -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) @@ -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 ) diff --git a/tests/shared/src/test/scala-2/zio/schema/AccessorBuilderSpec.scala b/tests/shared/src/test/scala-2/zio/schema/AccessorBuilderSpec.scala index d2b467cf7..f8ae98ab7 100644 --- a/tests/shared/src/test/scala-2/zio/schema/AccessorBuilderSpec.scala +++ b/tests/shared/src/test/scala-2/zio/schema/AccessorBuilderSpec.scala @@ -1,5 +1,6 @@ package zio.schema +import zio.prelude.Validation import zio.schema.Schema._ import zio.schema.SchemaGen.Json.schema import zio.test._ @@ -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] diff --git a/tests/shared/src/test/scala-2/zio/schema/DynamicValueSpec.scala b/tests/shared/src/test/scala-2/zio/schema/DynamicValueSpec.scala index 26f91be2d..22346a0d2 100644 --- a/tests/shared/src/test/scala-2/zio/schema/DynamicValueSpec.scala +++ b/tests/shared/src/test/scala-2/zio/schema/DynamicValueSpec.scala @@ -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._ @@ -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))) } } ), @@ -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 ) @@ -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))) } } diff --git a/tests/shared/src/test/scala-2/zio/schema/OrderingSpec.scala b/tests/shared/src/test/scala-2/zio/schema/OrderingSpec.scala index 2e33499d3..c4d798238 100644 --- a/tests/shared/src/test/scala-2/zio/schema/OrderingSpec.scala +++ b/tests/shared/src/test/scala-2/zio/schema/OrderingSpec.scala @@ -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], @@ -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], @@ -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]( @@ -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 diff --git a/tests/shared/src/test/scala-2/zio/schema/PatchSpec.scala b/tests/shared/src/test/scala-2/zio/schema/PatchSpec.scala index f20285052..fdfff446b 100644 --- a/tests/shared/src/test/scala-2/zio/schema/PatchSpec.scala +++ b/tests/shared/src/test/scala-2/zio/schema/PatchSpec.scala @@ -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) } ) ) @@ -182,7 +182,7 @@ 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) } @@ -190,7 +190,7 @@ object PatchSpec extends ZIOSpecDefault { } 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] diff --git a/tests/shared/src/test/scala-2/zio/schema/SchemaGen.scala b/tests/shared/src/test/scala-2/zio/schema/SchemaGen.scala index d4519a3e3..139f8aba9 100644 --- a/tests/shared/src/test/scala-2/zio/schema/SchemaGen.scala +++ b/tests/shared/src/test/scala-2/zio/schema/SchemaGen.scala @@ -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 { @@ -104,7 +105,7 @@ 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 { @@ -112,7 +113,7 @@ object SchemaGen { (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 { @@ -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" ) @@ -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" ) @@ -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" ) @@ -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 { diff --git a/tests/shared/src/test/scala-2/zio/schema/SchemaMigrationSpec.scala b/tests/shared/src/test/scala-2/zio/schema/SchemaMigrationSpec.scala index 47d5fa66c..d6e70e33c 100644 --- a/tests/shared/src/test/scala-2/zio/schema/SchemaMigrationSpec.scala +++ b/tests/shared/src/test/scala-2/zio/schema/SchemaMigrationSpec.scala @@ -1,6 +1,7 @@ package zio.schema import zio._ +import zio.prelude.Validation import zio.schema.syntax._ import zio.test.Assertion._ import zio.test._ @@ -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"))) @@ -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)) } @@ -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]) @@ -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 diff --git a/tests/shared/src/test/scala/zio/schema/DefaultValueSpec.scala b/tests/shared/src/test/scala/zio/schema/DefaultValueSpec.scala index 1f28f6fb9..25783d033 100644 --- a/tests/shared/src/test/scala/zio/schema/DefaultValueSpec.scala +++ b/tests/shared/src/test/scala/zio/schema/DefaultValueSpec.scala @@ -1,10 +1,10 @@ package zio.schema -import zio.Chunk import zio.schema.CaseSet.caseOf import zio.schema.Schema.{ Lazy, Primitive } import zio.test.Assertion._ import zio.test.{ Spec, ZIOSpecDefault, assert } +import zio.{ Chunk, NonEmptyChunk } object DefaultValueSpec extends ZIOSpecDefault { // Record Tests @@ -37,108 +37,114 @@ object DefaultValueSpec extends ZIOSpecDefault { def spec: Spec[Environment, Any] = suite("Default Value Spec")( suite("Primitive")( test("UnitType default value") { - assert(Primitive(StandardType.UnitType).defaultValue)(isRight(equalTo(()))) + assert(Primitive(StandardType.UnitType).defaultValue.toEither)(isRight(equalTo(()))) }, test("StringType default value") { - assert(Primitive(StandardType.StringType).defaultValue)(isRight(equalTo(""))) + assert(Primitive(StandardType.StringType).defaultValue.toEither)(isRight(equalTo(""))) }, test("BoolType default value") { - assert(Primitive(StandardType.BoolType).defaultValue)(isRight(equalTo(false))) + assert(Primitive(StandardType.BoolType).defaultValue.toEither)(isRight(equalTo(false))) }, test("ShortType default value") { - assert(Primitive(StandardType.ShortType).defaultValue)(isRight(equalTo(0.asInstanceOf[Short]))) + assert(Primitive(StandardType.ShortType).defaultValue.toEither)(isRight(equalTo(0.asInstanceOf[Short]))) }, test("IntType default value") { - assert(Primitive(StandardType.IntType).defaultValue)(isRight(equalTo(0))) + assert(Primitive(StandardType.IntType).defaultValue.toEither)(isRight(equalTo(0))) }, test("LongType default value") { - assert(Primitive(StandardType.LongType).defaultValue)(isRight(equalTo(0.asInstanceOf[Long]))) + assert(Primitive(StandardType.LongType).defaultValue.toEither)(isRight(equalTo(0.asInstanceOf[Long]))) }, test("FloatType default value") { - assert(Primitive(StandardType.FloatType).defaultValue)(isRight(equalTo(0.0.asInstanceOf[Float]))) + assert(Primitive(StandardType.FloatType).defaultValue.toEither)(isRight(equalTo(0.0.asInstanceOf[Float]))) }, test("DoubleType default value") { - assert(Primitive(StandardType.DoubleType).defaultValue)(isRight(equalTo(0.0))) + assert(Primitive(StandardType.DoubleType).defaultValue.toEither)(isRight(equalTo(0.0))) }, test("BinaryType default value") { - assert(Primitive(StandardType.BinaryType).defaultValue)(isRight(equalTo(Chunk.empty))) + assert(Primitive(StandardType.BinaryType).defaultValue.toEither)(isRight(equalTo(Chunk.empty))) }, test("CharType default value") { - assert(Primitive(StandardType.CharType).defaultValue)(isRight(equalTo('\u0000'))) + assert(Primitive(StandardType.CharType).defaultValue.toEither)(isRight(equalTo('\u0000'))) }, test("BigDecimalType default value") { - assert(Primitive(StandardType.BigDecimalType).defaultValue)(isRight(equalTo(java.math.BigDecimal.ZERO))) + assert(Primitive(StandardType.BigDecimalType).defaultValue.toEither)( + isRight(equalTo(java.math.BigDecimal.ZERO)) + ) }, test("BigIntegerType default value") { - assert(Primitive(StandardType.BigIntegerType).defaultValue)(isRight(equalTo(java.math.BigInteger.ZERO))) + assert(Primitive(StandardType.BigIntegerType).defaultValue.toEither)( + isRight(equalTo(java.math.BigInteger.ZERO)) + ) }, test("DayOfWeekType default value") { - assert(Primitive(StandardType.DayOfWeekType).defaultValue)( + assert(Primitive(StandardType.DayOfWeekType).defaultValue.toEither)( isRight(equalTo(java.time.temporal.WeekFields.of(java.util.Locale.getDefault).getFirstDayOfWeek)) ) }, test("Month default value") { - assert(Primitive(StandardType.MonthType).defaultValue)(isRight(equalTo(java.time.Month.JANUARY))) + assert(Primitive(StandardType.MonthType).defaultValue.toEither)(isRight(equalTo(java.time.Month.JANUARY))) }, test("MonthDay default value") { - assert(Primitive(StandardType.MonthDayType).defaultValue)( + assert(Primitive(StandardType.MonthDayType).defaultValue.toEither)( isRight(equalTo(java.time.MonthDay.of(java.time.Month.JANUARY, 1))) ) }, test("Period default value") { - assert(Primitive(StandardType.PeriodType).defaultValue)(isRight(equalTo(java.time.Period.ZERO))) + assert(Primitive(StandardType.PeriodType).defaultValue.toEither)(isRight(equalTo(java.time.Period.ZERO))) }, test("Year default value") { - assert(Primitive(StandardType.YearType).defaultValue)( + assert(Primitive(StandardType.YearType).defaultValue.toEither)( isRight(equalTo(java.time.Year.now)) ) }, test("YearMonth default value") { - assert(Primitive(StandardType.YearMonthType).defaultValue)(isRight(equalTo(java.time.YearMonth.now))) + assert(Primitive(StandardType.YearMonthType).defaultValue.toEither)(isRight(equalTo(java.time.YearMonth.now))) }, test("ZoneId default value") { - assert(Primitive(StandardType.ZoneIdType).defaultValue)(isRight(equalTo(java.time.ZoneId.systemDefault))) + assert(Primitive(StandardType.ZoneIdType).defaultValue.toEither)( + isRight(equalTo(java.time.ZoneId.systemDefault)) + ) }, test("ZoneOffset default value") { - assert(Primitive(StandardType.ZoneOffsetType).defaultValue)(isRight(equalTo(java.time.ZoneOffset.UTC))) + assert(Primitive(StandardType.ZoneOffsetType).defaultValue.toEither)(isRight(equalTo(java.time.ZoneOffset.UTC))) }, test("Duration default value") { - assert(Primitive(StandardType.DurationType).defaultValue)( + assert(Primitive(StandardType.DurationType).defaultValue.toEither)( isRight(equalTo(java.time.Duration.ZERO)) ) }, test("Instant default value") { - assert(Primitive(StandardType.InstantType).defaultValue)( + assert(Primitive(StandardType.InstantType).defaultValue.toEither)( isRight(equalTo(java.time.Instant.EPOCH)) ) }, test("LocalDate default value") { - assert(Primitive(StandardType.LocalDateType).defaultValue)( + assert(Primitive(StandardType.LocalDateType).defaultValue.toEither)( isRight(isSubtype[java.time.LocalDate](anything)) ) }, test("LocalTime default value") { - assert(Primitive(StandardType.LocalTimeType).defaultValue)( + assert(Primitive(StandardType.LocalTimeType).defaultValue.toEither)( isRight(equalTo(java.time.LocalTime.MIDNIGHT)) ) }, test("LocalDateTime default value") { - assert(Primitive(StandardType.LocalDateTimeType).defaultValue)( + assert(Primitive(StandardType.LocalDateTimeType).defaultValue.toEither)( isRight(isSubtype[java.time.LocalDateTime](anything)) ) }, test("OffsetTime default value") { - assert(Primitive(StandardType.OffsetTimeType).defaultValue)( + assert(Primitive(StandardType.OffsetTimeType).defaultValue.toEither)( isRight(isSubtype[java.time.OffsetTime](anything)) ) }, test("OffsetDateTime default value") { - assert(Primitive(StandardType.OffsetDateTimeType).defaultValue)( + assert(Primitive(StandardType.OffsetDateTimeType).defaultValue.toEither)( isRight(isSubtype[java.time.OffsetDateTime](anything)) ) }, test("ZonedDateTime default value") { - assert(Primitive(StandardType.ZonedDateTimeType).defaultValue)( + assert(Primitive(StandardType.ZonedDateTimeType).defaultValue.toEither)( isRight(isSubtype[java.time.ZonedDateTime](anything)) ) } @@ -156,7 +162,7 @@ object DefaultValueSpec extends ZIOSpecDefault { ), UserId.apply ) - assert(schema.defaultValue)(isRight(equalTo(UserId("")))) + assert(schema.defaultValue.toEither)(isRight(equalTo(UserId("")))) }, test("recursive") { val expected: Schema[User] = @@ -191,15 +197,15 @@ object DefaultValueSpec extends ZIOSpecDefault { ), User.apply ) - assert(expected.defaultValue)(isRight(equalTo(User(UserId(""), "", 0)))) + assert(expected.defaultValue.toEither)(isRight(equalTo(User(UserId(""), "", 0)))) } ), suite("Sequence")( test("chunk") { - assert(Schema.chunk[Int].defaultValue)(isRight(equalTo(Chunk(0)))) + assert(Schema.chunk[Int].defaultValue.toEither)(isRight(equalTo(Chunk(0)))) }, test("list") { - assert(Schema.list[Int].defaultValue)(isRight(equalTo(List(0)))) + assert(Schema.list[Int].defaultValue.toEither)(isRight(equalTo(List(0)))) } ), suite("Enumeration")( @@ -211,38 +217,38 @@ object DefaultValueSpec extends ZIOSpecDefault { Any ]("myString")(_.asInstanceOf[String])(_.asInstanceOf[Any])(_.isInstanceOf[String]) ) - assert(schema.defaultValue)(isRight(equalTo(0))) + assert(schema.defaultValue.toEither)(isRight(equalTo(0))) } ), suite("Transform")( test("returns transformed default value") { val schema: Schema[String] = Schema.primitive(StandardType.IntType).transform[String](_.toString, _.toInt) - assert(schema.defaultValue)(isRight(equalTo("0"))) + assert(schema.defaultValue.toEither)(isRight(equalTo("0"))) } ), suite("Optional")( test("defaults to None") { val schema: Schema[Option[Int]] = Schema.option[Int] - assert(schema.defaultValue)(isRight(isNone)) + assert(schema.defaultValue.toEither)(isRight(isNone)) } ), suite("Fail")( test("defaults to the error message") { val schema: Schema[Nothing] = Schema.fail("failing") - assert(schema.defaultValue)(isLeft(equalTo("failing"))) + assert(schema.defaultValue.toEither)(isLeft(equalTo(NonEmptyChunk("failing")))) } ), suite("Tuple")( test("defaults to default value of tuple members") { val schema: Schema[(Int, String)] = Schema.tuple2(Schema.primitive(StandardType.IntType), Schema.primitive(StandardType.StringType)) - assert(schema.defaultValue)(isRight(equalTo((0, "")))) + assert(schema.defaultValue.toEither)(isRight(equalTo((0, "")))) } ), suite("Lazy")( test("calls the schema thunk") { val schema: Lazy[Int] = Schema.Lazy(() => Schema.primitive(StandardType.IntType)) - assert(schema.defaultValue)(isRight(equalTo(0))) + assert(schema.defaultValue.toEither)(isRight(equalTo(0))) } ), suite("Enum")( @@ -274,7 +280,7 @@ object DefaultValueSpec extends ZIOSpecDefault { (s: Status) => s.isInstanceOf[Pending.type] ) ) - assert(schema.defaultValue)(isRight(equalTo(Failed(0, "", None, "")))) + assert(schema.defaultValue.toEither)(isRight(equalTo(Failed(0, "", None, "")))) } ), suite("EitherSchema")( @@ -283,15 +289,15 @@ object DefaultValueSpec extends ZIOSpecDefault { Schema.primitive(StandardType.IntType), Schema.primitive(StandardType.StringType) ) - assert(eitherSchema.defaultValue)(isRight(isLeft(equalTo(0)))) + assert(eitherSchema.defaultValue.toEither)(isRight(isLeft(equalTo(0)))) }, test("left") { val leftSchema = Schema.either(Schema.primitive(StandardType.IntType), Schema.fail("Nothing")) - assert(leftSchema.defaultValue)(isRight(isLeft(equalTo(0)))) + assert(leftSchema.defaultValue.toEither)(isRight(isLeft(equalTo(0)))) }, test("right") { val rightSchema = Schema.either(Schema.fail("Nothing"), Schema.primitive(StandardType.StringType)) - assert(rightSchema.defaultValue)(isRight(isRight(equalTo("")))) + assert(rightSchema.defaultValue.toEither)(isRight(isRight(equalTo("")))) } ) ) diff --git a/tests/shared/src/test/scala/zio/schema/MigrationSpec.scala b/tests/shared/src/test/scala/zio/schema/MigrationSpec.scala index 15576083f..014c3f3fd 100644 --- a/tests/shared/src/test/scala/zio/schema/MigrationSpec.scala +++ b/tests/shared/src/test/scala/zio/schema/MigrationSpec.scala @@ -19,7 +19,8 @@ object MigrationSpec extends ZIOSpecDefault { assertTrue( Migration - .derive(from, to) == Right(Chunk(Migration.ChangeType(NodePath.root, StandardType.StringType))) + .derive(from, to) == zio.prelude.Validation + .succeed(Chunk(Migration.ChangeType(NodePath.root, StandardType.StringType))) ) }, test("optional") { @@ -29,7 +30,7 @@ object MigrationSpec extends ZIOSpecDefault { assertTrue( Migration - .derive(from, to) == Right(Chunk(Migration.Optional(NodePath.root))) + .derive(from, to) == zio.prelude.Validation.succeed(Chunk(Migration.Optional(NodePath.root))) ) }, test("require") { @@ -40,7 +41,7 @@ object MigrationSpec extends ZIOSpecDefault { assertTrue( Migration - .derive(from, to) == Right(Chunk(Migration.Require(NodePath.root))) + .derive(from, to) == zio.prelude.Validation.succeed(Chunk(Migration.Require(NodePath.root))) ) }, test("increment dimensions") { @@ -55,7 +56,8 @@ object MigrationSpec extends ZIOSpecDefault { assertTrue( Migration - .derive(from, to) == Right(Chunk(Migration.IncrementDimensions(NodePath.root, 1))) + .derive(from, to) == zio.prelude.Validation + .succeed(Chunk(Migration.IncrementDimensions(NodePath.root, 1))) ) }, test("decrement dimensions") { @@ -69,7 +71,8 @@ object MigrationSpec extends ZIOSpecDefault { assertTrue( Migration - .derive(from, to) == Right(Chunk(Migration.DecrementDimensions(NodePath.root, 1))) + .derive(from, to) == zio.prelude.Validation + .succeed(Chunk(Migration.DecrementDimensions(NodePath.root, 1))) ) } ), @@ -231,7 +234,7 @@ object MigrationSpec extends ZIOSpecDefault { val value: Pet2 = Pet2.Hamster("name") val dynamicValue = value.dynamic - assertTrue(Migration.DeleteNode(NodePath.root / "Hamster").migrate(dynamicValue).isLeft) + assertTrue(Migration.DeleteNode(NodePath.root / "Hamster").migrate(dynamicValue).toEither.isLeft) } ) ) @@ -286,12 +289,12 @@ object MigrationSpec extends ZIOSpecDefault { def transformsValueTo[A: Schema](value: A, expected: DynamicValue): Assertion[Migration] = Assertion.assertion("transformsValueTo") { transform => val transformed = transform.migrate(value.dynamic) - transformed == Right(expected) + transformed == zio.prelude.Validation.succeed(expected) } def failsToTransform[A: Schema](value: A): Assertion[Migration] = Assertion.assertion("failsToTransform") { transform => - transform.migrate(value.dynamic).isLeft + transform.migrate(value.dynamic).toEither.isLeft } case class Recursive1(v1: Int, v2: String, r: Option[Recursive1]) diff --git a/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala b/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala index fbecd6bf6..b1208011d 100644 --- a/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala +++ b/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala @@ -3,6 +3,7 @@ package zio.schema import scala.collection.immutable.ListMap import zio.Chunk +import zio.prelude.Validation import zio.schema.CaseSet._ import zio.test.Assertion._ import zio.test._ @@ -72,12 +73,12 @@ object SchemaSpec extends ZIOSpecDefault { ) ) - val f: Unit => Either[String, Int] = _ => Right(0) - val g: Int => Either[String, Unit] = _ => Right(()) - def schemaTransform: Schema[Int] = schemaUnit.transformOrFail[Int](f, g) + val f: Unit => Validation[String, Int] = _ => zio.prelude.Validation.succeed(0) + val g: Int => Validation[String, Unit] = _ => zio.prelude.Validation.succeed(()) + def schemaTransform: Schema[Int] = schemaUnit.transformOrFail[Int](f, g) - def tranformF(u: Unit): Either[String, Int] = Some(u).map(_ => 0).toRight("") - def tranformG(i: Int): Either[String, Unit] = Some(i).map(_ => ()).toRight("") - def schemaTransformMethod: Schema[Int] = schemaUnit.transformOrFail(tranformF, tranformG) + def tranformF(u: Unit): Validation[String, Int] = Validation.fromEither(Some(u).map(_ => 0).toRight("")) + def tranformG(i: Int): Validation[String, Unit] = Validation.fromEither(Some(i).map(_ => ()).toRight("")) + def schemaTransformMethod: Schema[Int] = schemaUnit.transformOrFail(tranformF, tranformG) } diff --git a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroCodec.scala b/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroCodec.scala index 3500669b7..c3e9c8d92 100644 --- a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroCodec.scala +++ b/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroCodec.scala @@ -7,11 +7,12 @@ import java.time.{ Duration, Month, MonthDay, Period, Year, YearMonth } import scala.annotation.StaticAnnotation import scala.collection.immutable.ListMap import scala.jdk.CollectionConverters._ -import scala.util.{ Right, Try } +import scala.util.Try import org.apache.avro.{ LogicalTypes, Schema => SchemaAvro } import zio.Chunk +import zio.prelude.Validation import zio.schema.CaseSet.Aux import zio.schema.Schema.{ Record, _ } import zio.schema._ @@ -20,47 +21,44 @@ import zio.schema.codec.AvroPropMarker._ import zio.schema.meta.MetaSchema trait AvroCodec { - def encode(schema: Schema[_]): scala.util.Either[String, String] + def encode(schema: Schema[_]): Validation[String, String] - def decode(bytes: Chunk[Byte]): scala.util.Either[String, Schema[_]] + def decode(bytes: Chunk[Byte]): Validation[String, Schema[_]] } object AvroCodec extends AvroCodec { - def encode(schema: Schema[_]): scala.util.Either[String, String] = + def encode(schema: Schema[_]): Validation[String, String] = toAvroSchema(schema).map(_.toString) - def encodeToApacheAvro(schema: Schema[_]): scala.util.Either[String, SchemaAvro] = + def encodeToApacheAvro(schema: Schema[_]): Validation[String, SchemaAvro] = toAvroSchema(schema) - def decode(bytes: Chunk[Byte]): scala.util.Either[String, Schema[_]] = { + def decode(bytes: Chunk[Byte]): Validation[String, Schema[_]] = { val avroSchemaParser = new SchemaAvro.Parser() - val avroSchema = Try { + val avroSchema = Validation( avroSchemaParser.parse(new String(bytes.toArray, StandardCharsets.UTF_8)) - }.fold( - e => Left(e.getMessage), - s => Right(s) - ) + ).mapError(_.getMessage) avroSchema.flatMap(toZioSchema) } - def decodeFromApacheAvro: SchemaAvro => scala.util.Either[String, Schema[_]] = toZioSchema + def decodeFromApacheAvro: SchemaAvro => Validation[String, Schema[_]] = toZioSchema - private def toZioSchema(avroSchema: SchemaAvro): scala.util.Either[String, Schema[_]] = + private def toZioSchema(avroSchema: SchemaAvro): Validation[String, Schema[_]] = for { // make sure to parse logical types with throwing exceptions enabled, // otherwise parsing errors on invalid logical types might be lost - _ <- Try { + _ <- Validation { LogicalTypes.fromSchema(avroSchema) - }.toEither.left.map(e => e.getMessage) + }.mapError(e => e.getMessage) result <- avroSchema.getType match { case SchemaAvro.Type.RECORD => RecordType.fromAvroRecord(avroSchema) match { - case Some(RecordType.Period) => Right(Schema.primitive(StandardType.PeriodType)) - case Some(RecordType.YearMonth) => Right(Schema.primitive(StandardType.YearMonthType)) + case Some(RecordType.Period) => Validation.succeed(Schema.primitive(StandardType.PeriodType)) + case Some(RecordType.YearMonth) => Validation.succeed(Schema.primitive(StandardType.YearMonthType)) case Some(RecordType.Tuple) => toZioTuple(avroSchema) - case Some(RecordType.MonthDay) => Right(Schema.primitive(StandardType.MonthDayType)) - case Some(RecordType.Duration) => Right(Schema.primitive(StandardType.DurationType)) + case Some(RecordType.MonthDay) => Validation.succeed(Schema.primitive(StandardType.MonthDayType)) + case Some(RecordType.Duration) => Validation.succeed(Schema.primitive(StandardType.DurationType)) case None => toZioRecord(avroSchema) } case SchemaAvro.Type.ENUM => toZioStringEnum(avroSchema) @@ -77,14 +75,14 @@ object AvroCodec extends AvroCodec { } case SchemaAvro.Type.FIXED => val fixed = if (avroSchema.getLogicalType == null) { - Right(Schema.primitive(StandardType.BinaryType)) + Validation.succeed(Schema.primitive(StandardType.BinaryType)) } else if (avroSchema.getLogicalType.isInstanceOf[LogicalTypes.Decimal]) { val size = avroSchema.getFixedSize toZioDecimal(avroSchema, DecimalType.Fixed(size)) } else { // TODO: Java implementation of Apache Avro does not support logical type Duration yet: // AVRO-2123 with PR https://github.com/apache/avro/pull/1263 - Left(s"Unsupported fixed logical type ${avroSchema.getLogicalType}") + Validation.fail(s"Unsupported fixed logical type ${avroSchema.getLogicalType}") } fixed.map(_.addAllAnnotations(buildZioAnnotations(avroSchema))) case SchemaAvro.Type.STRING => @@ -95,67 +93,67 @@ object AvroCodec extends AvroCodec { .map(_.dateTimeFormatter) .flatMap(_ => { stringType match { - case StringType.ZoneId => Right(Schema.primitive(StandardType.ZoneIdType)) + case StringType.ZoneId => Validation.succeed(Schema.primitive(StandardType.ZoneIdType)) case StringType.Instant => - Right( + Validation.succeed( Schema .primitive(StandardType.InstantType) .annotate(AvroAnnotations.formatToString) ) case StringType.LocalDate => - Right( + Validation.succeed( Schema .primitive(StandardType.LocalDateType) .annotate(AvroAnnotations.formatToString) ) case StringType.LocalTime => - Right( + Validation.succeed( Schema .primitive(StandardType.LocalTimeType) .annotate(AvroAnnotations.formatToString) ) case StringType.LocalDateTime => - Right( + Validation.succeed( Schema .primitive(StandardType.LocalDateTimeType) .annotate(AvroAnnotations.formatToString) ) case StringType.OffsetTime => - Right(Schema.primitive(StandardType.OffsetTimeType)) + Validation.succeed(Schema.primitive(StandardType.OffsetTimeType)) case StringType.OffsetDateTime => - Right(Schema.primitive(StandardType.OffsetDateTimeType)) + Validation.succeed(Schema.primitive(StandardType.OffsetDateTimeType)) case StringType.ZoneDateTime => - Right(Schema.primitive(StandardType.ZonedDateTimeType)) + Validation.succeed(Schema.primitive(StandardType.ZonedDateTimeType)) } }) case None => if (avroSchema.getLogicalType == null) { - Right(Schema.primitive(StandardType.StringType)) + Validation.succeed(Schema.primitive(StandardType.StringType)) } else if (avroSchema.getLogicalType.getName == LogicalTypes.uuid().getName) { - Right(Schema.primitive(StandardType.UUIDType)) + Validation.succeed(Schema.primitive(StandardType.UUIDType)) } else { - Left(s"Unsupported string logical type: ${avroSchema.getLogicalType.getName}") + Validation.fail(s"Unsupported string logical type: ${avroSchema.getLogicalType.getName}") } } case SchemaAvro.Type.BYTES => if (avroSchema.getLogicalType == null) { - Right(Schema.primitive(StandardType.BinaryType)) + Validation.succeed(Schema.primitive(StandardType.BinaryType)) } else if (avroSchema.getLogicalType.isInstanceOf[LogicalTypes.Decimal]) { toZioDecimal(avroSchema, DecimalType.Bytes) } else { - Left(s"Unsupported bytes logical type ${avroSchema.getLogicalType.getName}") + Validation.fail(s"Unsupported bytes logical type ${avroSchema.getLogicalType.getName}") } case SchemaAvro.Type.INT => IntType.fromAvroInt(avroSchema) match { - case Some(IntType.Char) => Right(Schema.primitive(StandardType.CharType)) - case Some(IntType.DayOfWeek) => Right(Schema.primitive(StandardType.DayOfWeekType)) - case Some(IntType.Year) => Right(Schema.primitive(StandardType.YearType)) - case Some(IntType.Short) => Right(Schema.primitive(StandardType.ShortType)) - case Some(IntType.Month) => Right(Schema.primitive(StandardType.MonthType)) - case Some(IntType.ZoneOffset) => Right(Schema.primitive(StandardType.ZoneOffsetType)) + case Some(IntType.Char) => Validation.succeed(Schema.primitive(StandardType.CharType)) + case Some(IntType.DayOfWeek) => Validation.succeed(Schema.primitive(StandardType.DayOfWeekType)) + case Some(IntType.Year) => Validation.succeed(Schema.primitive(StandardType.YearType)) + case Some(IntType.Short) => Validation.succeed(Schema.primitive(StandardType.ShortType)) + case Some(IntType.Month) => Validation.succeed(Schema.primitive(StandardType.MonthType)) + case Some(IntType.ZoneOffset) => Validation.succeed(Schema.primitive(StandardType.ZoneOffsetType)) case None => if (avroSchema.getLogicalType == null) { - Right(Schema.primitive(StandardType.IntType)) + Validation.succeed(Schema.primitive(StandardType.IntType)) } else avroSchema.getLogicalType match { case _: LogicalTypes.TimeMillis => @@ -168,12 +166,13 @@ object AvroCodec extends AvroCodec { formatter.map( _ => Schema.primitive(StandardType.LocalDateType) ) - case _ => Left(s"Unsupported int logical type ${avroSchema.getLogicalType.getName}") + case _ => + Validation.fail(s"Unsupported int logical type ${avroSchema.getLogicalType.getName}") } } case SchemaAvro.Type.LONG => if (avroSchema.getLogicalType == null) { - Right(Schema.primitive(StandardType.LongType)) + Validation.succeed(Schema.primitive(StandardType.LongType)) } else avroSchema.getLogicalType match { case _: LogicalTypes.TimeMicros => @@ -201,13 +200,13 @@ object AvroCodec extends AvroCodec { formatter.map( _ => Schema.primitive(StandardType.LocalDateTimeType) ) - case _ => Left(s"Unsupported long logical type ${avroSchema.getLogicalType.getName}") + case _ => Validation.fail(s"Unsupported long logical type ${avroSchema.getLogicalType.getName}") } - case SchemaAvro.Type.FLOAT => Right(Schema.primitive(StandardType.FloatType)) - case SchemaAvro.Type.DOUBLE => Right(Schema.primitive(StandardType.DoubleType)) - case SchemaAvro.Type.BOOLEAN => Right(Schema.primitive(StandardType.BoolType)) - case SchemaAvro.Type.NULL => Right(Schema.primitive(StandardType.UnitType)) - case null => Left(s"Unsupported type ${avroSchema.getType}") + case SchemaAvro.Type.FLOAT => Validation.succeed(Schema.primitive(StandardType.FloatType)) + case SchemaAvro.Type.DOUBLE => Validation.succeed(Schema.primitive(StandardType.DoubleType)) + case SchemaAvro.Type.BOOLEAN => Validation.succeed(Schema.primitive(StandardType.BoolType)) + case SchemaAvro.Type.NULL => Validation.succeed(Schema.primitive(StandardType.UnitType)) + case null => Validation.fail(s"Unsupported type ${avroSchema.getType}") } } yield result @@ -275,7 +274,7 @@ object AvroCodec extends AvroCodec { ) ) - private def toAvroSchema(schema: Schema[_]): scala.util.Either[String, SchemaAvro] = { + private def toAvroSchema(schema: Schema[_]): Validation[String, SchemaAvro] = { schema match { case e: Enum[_] => toAvroEnum(e) case record: Record[_] => toAvroRecord(record) @@ -285,45 +284,51 @@ object AvroCodec extends AvroCodec { case Transform(codec, _, _, _, _) => toAvroSchema(codec) case Primitive(standardType, _) => standardType match { - case StandardType.UnitType => Right(SchemaAvro.create(SchemaAvro.Type.NULL)) - case StandardType.StringType => Right(SchemaAvro.create(SchemaAvro.Type.STRING)) - case StandardType.BoolType => Right(SchemaAvro.create(SchemaAvro.Type.BOOLEAN)) + case StandardType.UnitType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.NULL)) + case StandardType.StringType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.STRING)) + case StandardType.BoolType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.BOOLEAN)) case StandardType.ShortType => - Right(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Short))) - case StandardType.ByteType => Right(SchemaAvro.create(SchemaAvro.Type.INT)) - case StandardType.IntType => Right(SchemaAvro.create(SchemaAvro.Type.INT)) - case StandardType.LongType => Right(SchemaAvro.create(SchemaAvro.Type.LONG)) - case StandardType.FloatType => Right(SchemaAvro.create(SchemaAvro.Type.FLOAT)) - case StandardType.DoubleType => Right(SchemaAvro.create(SchemaAvro.Type.DOUBLE)) - case StandardType.BinaryType => Right(toAvroBinary(schema)) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Short))) + case StandardType.ByteType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.INT)) + case StandardType.IntType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.INT)) + case StandardType.LongType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.LONG)) + case StandardType.FloatType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.FLOAT)) + case StandardType.DoubleType => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.DOUBLE)) + case StandardType.BinaryType => Validation.succeed(toAvroBinary(schema)) case StandardType.CharType => - Right(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Char))) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Char))) case StandardType.UUIDType => - Right(LogicalTypes.uuid().addToSchema(SchemaAvro.create(SchemaAvro.Type.STRING))) + Validation.succeed(LogicalTypes.uuid().addToSchema(SchemaAvro.create(SchemaAvro.Type.STRING))) case StandardType.BigDecimalType => toAvroDecimal(schema) case StandardType.BigIntegerType => toAvroDecimal(schema) case StandardType.DayOfWeekType => - Right(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.DayOfWeek))) + Validation.succeed( + SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.DayOfWeek)) + ) case StandardType.MonthType => - Right(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Month))) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Month))) case StandardType.YearType => - Right(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Year))) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.Year))) case StandardType.ZoneIdType => - Right(SchemaAvro.create(SchemaAvro.Type.STRING).addMarkerProp(StringDiscriminator(StringType.ZoneId))) + Validation.succeed( + SchemaAvro.create(SchemaAvro.Type.STRING).addMarkerProp(StringDiscriminator(StringType.ZoneId)) + ) case StandardType.ZoneOffsetType => - Right(SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.ZoneOffset))) + Validation.succeed( + SchemaAvro.create(SchemaAvro.Type.INT).addMarkerProp(IntDiscriminator(IntType.ZoneOffset)) + ) case StandardType.MonthDayType => //TODO 1 - //Right(SchemaAvro.create(monthDayStructure).addMarkerProp(RecordDiscriminator(RecordType.MonthDay))) - Right(SchemaAvro.create(SchemaAvro.Type.RECORD)) + //zio.prelude.Validation.succeed(SchemaAvro.create(monthDayStructure).addMarkerProp(RecordDiscriminator(RecordType.MonthDay))) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.RECORD)) case StandardType.PeriodType => //TODO 2 //toAvroSchema(periodStructure).map(_.addMarkerProp(RecordDiscriminator(RecordType.Period))) - Right(SchemaAvro.create(SchemaAvro.Type.RECORD)) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.RECORD)) case StandardType.YearMonthType => //TODO 3 //toAvroSchema(yearMonthStructure).map(_.addMarkerProp(RecordDiscriminator(RecordType.YearMonth))) - Right(SchemaAvro.create(SchemaAvro.Type.RECORD)) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.RECORD)) case StandardType.DurationType => // TODO: Java implementation of Apache Avro does not support logical type Duration yet: // AVRO-2123 with PR https://github.com/apache/avro/pull/1263 @@ -332,46 +337,46 @@ object AvroCodec extends AvroCodec { //DurationChronoUnit.fromTemporalUnit(temporalUnit).getOrElse(DurationChronoUnit.default) //toAvroSchema(durationStructure).map( // _.addMarkerProp(RecordDiscriminator(RecordType.Duration)).addMarkerProp(chronoUnitMarker)) - Right(SchemaAvro.create(SchemaAvro.Type.RECORD)) + Validation.succeed(SchemaAvro.create(SchemaAvro.Type.RECORD)) case StandardType.InstantType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.Instant)) ) case StandardType.LocalDateType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.LocalDate)) ) case StandardType.LocalTimeType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.LocalTime)) ) case StandardType.LocalDateTimeType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.LocalDateTime)) ) case StandardType.OffsetTimeType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.OffsetTime)) ) case StandardType.OffsetDateTimeType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.OffsetDateTime)) ) case StandardType.ZonedDateTimeType => - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.ZoneDateTime)) @@ -389,7 +394,7 @@ object AvroCodec extends AvroCodec { case schema => schema } } yield SchemaAvro.createUnion(SchemaAvro.create(SchemaAvro.Type.NULL), wrappedAvroSchema) - case Fail(message, _) => Left(message) + case Fail(message, _) => Validation.fail(message) case tuple: Tuple2[_, _] => toAvroSchema(tuple.toRecord).map( _.addMarkerProp(RecordDiscriminator(RecordType.Tuple)) @@ -403,8 +408,10 @@ object AvroCodec extends AvroCodec { leftSchema = if (l.getType == SchemaAvro.Type.UNION) wrapAvro(l, lname, UnionWrapper) else l rightSchema = if (r.getType == SchemaAvro.Type.UNION) wrapAvro(r, rname, UnionWrapper) else r _ <- if (leftSchema.getFullName == rightSchema.getFullName) - Left(s"Left and right schemas of either must have different fullnames: ${leftSchema.getFullName}") - else Right(()) + Validation.fail( + s"Left and right schemas of either must have different fullnames: ${leftSchema.getFullName}" + ) + else Validation.succeed(()) } yield SchemaAvro.createUnion(leftSchema, rightSchema) // Unions in Avro can not hold additional properties, so we need to wrap the union in a record @@ -430,9 +437,9 @@ object AvroCodec extends AvroCodec { private[codec] def toAvroInstant( formatter: DateTimeFormatter, annotations: Chunk[Any] - ): scala.util.Either[String, SchemaAvro] = + ): Validation[String, SchemaAvro] = if (hasFormatToStringAnnotation(annotations)) { - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.Instant)) @@ -442,33 +449,35 @@ object AvroCodec extends AvroCodec { val baseSchema = SchemaAvro.create(SchemaAvro.Type.LONG) getTimeprecisionType(annotations).getOrElse(TimePrecisionType.default) match { case TimePrecisionType.Millis => - Right(LogicalTypes.timestampMillis().addToSchema(baseSchema).addMarkerProp(Formatter(formatter))) + Validation.succeed(LogicalTypes.timestampMillis().addToSchema(baseSchema).addMarkerProp(Formatter(formatter))) case TimePrecisionType.Micros => - Right(LogicalTypes.timestampMicros().addToSchema(baseSchema).addMarkerProp(Formatter(formatter))) + Validation.succeed(LogicalTypes.timestampMicros().addToSchema(baseSchema).addMarkerProp(Formatter(formatter))) } } private[codec] def toAvroLocalDate( formatter: DateTimeFormatter, annotations: Chunk[Any] - ): scala.util.Either[String, SchemaAvro] = + ): Validation[String, SchemaAvro] = if (hasFormatToStringAnnotation(annotations)) { - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.LocalDate)) .addMarkerProp(Formatter(formatter)) ) } else { - Right(LogicalTypes.date().addToSchema(SchemaAvro.create(SchemaAvro.Type.INT)).addMarkerProp(Formatter(formatter))) + Validation.succeed( + LogicalTypes.date().addToSchema(SchemaAvro.create(SchemaAvro.Type.INT)).addMarkerProp(Formatter(formatter)) + ) } private[codec] def toAvroLocalTime( formatter: DateTimeFormatter, annotations: Chunk[Any] - ): scala.util.Either[String, SchemaAvro] = + ): Validation[String, SchemaAvro] = if (hasFormatToStringAnnotation(annotations)) { - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.LocalTime)) @@ -477,14 +486,14 @@ object AvroCodec extends AvroCodec { } else { getTimeprecisionType(annotations).getOrElse(TimePrecisionType.default) match { case TimePrecisionType.Millis => - Right( + Validation.succeed( LogicalTypes .timeMillis() .addToSchema(SchemaAvro.create(SchemaAvro.Type.INT)) .addMarkerProp(Formatter(formatter)) ) case TimePrecisionType.Micros => - Right( + Validation.succeed( LogicalTypes .timeMicros() .addToSchema(SchemaAvro.create(SchemaAvro.Type.LONG)) @@ -496,9 +505,9 @@ object AvroCodec extends AvroCodec { private[codec] def toAvroLocalDateTime( formatter: DateTimeFormatter, annotations: Chunk[Any] - ): scala.util.Either[String, SchemaAvro] = + ): Validation[String, SchemaAvro] = if (hasFormatToStringAnnotation(annotations)) { - Right( + Validation.succeed( SchemaAvro .create(SchemaAvro.Type.STRING) .addMarkerProp(StringDiscriminator(StringType.LocalDateTime)) @@ -508,9 +517,13 @@ object AvroCodec extends AvroCodec { val baseSchema = SchemaAvro.create(SchemaAvro.Type.LONG) getTimeprecisionType(annotations).getOrElse(TimePrecisionType.default) match { case TimePrecisionType.Millis => - Right(LogicalTypes.localTimestampMillis().addToSchema(baseSchema).addMarkerProp(Formatter(formatter))) + Validation.succeed( + LogicalTypes.localTimestampMillis().addToSchema(baseSchema).addMarkerProp(Formatter(formatter)) + ) case TimePrecisionType.Micros => - Right(LogicalTypes.localTimestampMicros().addToSchema(baseSchema).addMarkerProp(Formatter(formatter))) + Validation.succeed( + LogicalTypes.localTimestampMicros().addToSchema(baseSchema).addMarkerProp(Formatter(formatter)) + ) } } @@ -529,7 +542,7 @@ object AvroCodec extends AvroCodec { .addMarkerProp(marker) } - private[codec] def toAvroEnum(enu: Enum[_]): scala.util.Either[String, SchemaAvro] = { + private[codec] def toAvroEnum(enu: Enum[_]): Validation[String, SchemaAvro] = { val avroEnumAnnotationExists = hasAvroEnumAnnotation(enu.annotations) val isAvroEnumEquivalent = enu.cases.map(_.schema).forall { case (Transform(Primitive(standardType, _), _, _, _, _)) @@ -554,10 +567,12 @@ object AvroCodec extends AvroCodec { case (symbol, (Transform(Primitive(standardType, _), _, _, _, _), annotations)) if standardType == StandardType.UnitType => val name = getNameOption(annotations).getOrElse(symbol) - Right(SchemaAvro.createRecord(name, null, null, false, new java.util.ArrayList[SchemaAvro.Field])) + Validation + .succeed(SchemaAvro.createRecord(name, null, null, false, new java.util.ArrayList[SchemaAvro.Field])) case (symbol, (CaseClass0(_, _, _), annotations)) => val name = getNameOption(annotations).getOrElse(symbol) - Right(SchemaAvro.createRecord(name, null, null, false, new java.util.ArrayList[SchemaAvro.Field])) + Validation + .succeed(SchemaAvro.createRecord(name, null, null, false, new java.util.ArrayList[SchemaAvro.Field])) case (symbol, (schema, annotations)) => val name = getNameOption(annotations).getOrElse(symbol) val schemaWithName = addNameAnnotationIfMissing(schema, name) @@ -567,30 +582,22 @@ object AvroCodec extends AvroCodec { case schema => schema } } - cases.toList.map(_.merge).partition { - case _: String => true - case _ => false - } match { - case (Nil, right: List[org.apache.avro.Schema @unchecked]) => Right(SchemaAvro.createUnion(right.asJava)) - case (left, _) => Left(left.mkString("\n")) - } + Validation + .validateAll(cases.toList) + .map(c => SchemaAvro.createUnion(c.asJava)) } } private def extractAvroFields(record: Record[_]): List[org.apache.avro.Schema.Field] = - record.fields.map(toAvroRecordField).toList.map(_.merge).partition { - case _: String => true - case _ => false - } match { - case (Nil, right: List[org.apache.avro.Schema.Field @unchecked]) => right - case _ => null - } + Validation + .validateAll(record.fields.map(toAvroRecordField(_)).toList) + .getOrElse(null) - private[codec] def toAvroRecord(record: Record[_]): scala.util.Either[String, SchemaAvro] = + private[codec] def toAvroRecord(record: Record[_]): Validation[String, SchemaAvro] = for { name <- getName(record) namespaceOption <- getNamespace(record.annotations) - result <- Right( + result <- Validation.succeed( SchemaAvro.createRecord( name, getDoc(record.annotations).orNull, @@ -601,7 +608,7 @@ object AvroCodec extends AvroCodec { ) } yield result - private[codec] def toAvroMap(map: Map[_, _]): scala.util.Either[String, SchemaAvro] = + private[codec] def toAvroMap(map: Map[_, _]): Validation[String, SchemaAvro] = map.keySchema match { case p: Schema.Primitive[_] if p.standardType == StandardType.StringType => toAvroSchema(map.valueSchema).map(SchemaAvro.createMap) @@ -613,7 +620,7 @@ object AvroCodec extends AvroCodec { toAvroSchema(tupleSchema).map(SchemaAvro.createArray) } - private[codec] def toAvroDecimal(schema: Schema[_]): scala.util.Either[String, SchemaAvro] = { + private[codec] def toAvroDecimal(schema: Schema[_]): Validation[String, SchemaAvro] = { val scale = schema.annotations.collectFirst { case AvroAnnotations.scale(s) => s } .getOrElse(AvroAnnotations.scale().scale) val precision = schema match { @@ -632,7 +639,7 @@ object AvroCodec extends AvroCodec { doc = getDoc(schema.annotations).orNull result = SchemaAvro.createFixed(name, doc, namespaceOption.orNull, size) } yield result - case DecimalType.Bytes => Right(SchemaAvro.create(SchemaAvro.Type.BYTES)) + case DecimalType.Bytes => Validation.succeed(SchemaAvro.create(SchemaAvro.Type.BYTES)) } baseAvroType.map( LogicalTypes @@ -644,7 +651,7 @@ object AvroCodec extends AvroCodec { private[codec] def toErrorMessage(err: Throwable, at: AnyRef) = s"Error mapping to Apache Avro schema: $err at ${at.toString}" - private[codec] def toAvroRecordField[Z](value: Field[Z, _]): scala.util.Either[String, SchemaAvro.Field] = + private[codec] def toAvroRecordField[Z](value: Field[Z, _]): Validation[String, SchemaAvro.Field] = toAvroSchema(value.schema).map( schema => new SchemaAvro.Field( @@ -659,21 +666,21 @@ object AvroCodec extends AvroCodec { private[codec] def getFieldOrder(annotations: Chunk[Any]): Option[FieldOrderType] = annotations.collectFirst { case AvroAnnotations.fieldOrder(fieldOrderType) => fieldOrderType } - private[codec] def getName(schema: Schema[_]): scala.util.Either[String, String] = { + private[codec] def getName(schema: Schema[_]): Validation[String, String] = { val validNameRegex = raw"[A-Za-z_][A-Za-z0-9_]*".r schema.annotations.collectFirst { case AvroAnnotations.name(name) => name } match { case Some(s) => s match { - case validNameRegex() => Right(s) + case validNameRegex() => Validation.succeed(s) case _ => - Left(s"Invalid Avro name: $s") + Validation.fail(s"Invalid Avro name: $s") } case None => schema match { - case r: Record[_] => Right(r.id.name) - case e: Enum[_] => Right(e.id.name) - case _ => Right(s"hashed_${schema.ast.toString.hashCode().toString.replaceFirst("-", "n")}") + case r: Record[_] => Validation.succeed(r.id.name) + case e: Enum[_] => Validation.succeed(e.id.name) + case _ => Validation.succeed(s"hashed_${schema.ast.toString.hashCode().toString.replaceFirst("-", "n")}") // TODO: better way to generate a (maybe stable) name? } } @@ -688,16 +695,16 @@ object AvroCodec extends AvroCodec { private[codec] def getDefault(annotations: Chunk[Any]): Option[java.lang.Object] = annotations.collectFirst { case AvroAnnotations.default(javaDefaultObject) => javaDefaultObject } - private[codec] def getNamespace(annotations: Chunk[Any]): scala.util.Either[String, Option[String]] = { + private[codec] def getNamespace(annotations: Chunk[Any]): Validation[String, Option[String]] = { val validNamespaceRegex = raw"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*".r annotations.collectFirst { case AvroAnnotations.namespace(ns) => ns } match { case Some(s) => s match { - case validNamespaceRegex(_) => Right(Some(s)) - case _ => Left(s"Invalid Avro namespace: $s") + case validNamespaceRegex(_) => Validation.succeed(Some(s)) + case _ => Validation.fail(s"Invalid Avro namespace: $s") } - case None => Right(None) + case None => Validation.succeed(None) } } @@ -711,13 +718,13 @@ object AvroCodec extends AvroCodec { private[codec] def toZioDecimal( avroSchema: SchemaAvro, decimalType: DecimalType - ): scala.util.Either[String, Schema[_]] = { + ): Validation[String, Schema[_]] = { val decimalTypeAnnotation = AvroAnnotations.decimal(decimalType) val decimalLogicalType = avroSchema.getLogicalType.asInstanceOf[LogicalTypes.Decimal] val precision = decimalLogicalType.getPrecision val scale = decimalLogicalType.getScale if (precision - scale > 0) { - Right( + Validation.succeed( Schema .primitive(StandardType.BigDecimalType) .annotate(AvroAnnotations.scale(scale)) @@ -725,7 +732,7 @@ object AvroCodec extends AvroCodec { .annotate(decimalTypeAnnotation) ) } else { - Right( + Validation.succeed( Schema .primitive(StandardType.BigIntegerType) .annotate(AvroAnnotations.scale(scale)) @@ -734,7 +741,7 @@ object AvroCodec extends AvroCodec { } } - private[codec] def toZioEnumeration[A, Z](avroSchema: SchemaAvro): scala.util.Either[String, Schema[Z]] = { + private[codec] def toZioEnumeration[A, Z](avroSchema: SchemaAvro): Validation[String, Schema[Z]] = { val cases = avroSchema.getTypes.asScala .map(t => { val inner = @@ -753,24 +760,23 @@ object AvroCodec extends AvroCodec { ) ) }) - val caseSet = cases.toList.map(_.merge).partition { - case _: String => true - case _ => false - } match { - case (Nil, right: Seq[Case[_, _] @unchecked]) => - Try { - CaseSet(right: _*).asInstanceOf[CaseSet { type EnumType = Z }] - }.toEither.left.map(_.getMessage) - case (left, _) => Left(left.mkString("\n")) - } + + val caseSet = Validation + .validateAll(cases.toList) + .flatMap(cases => { + Validation( + CaseSet(cases: _*).asInstanceOf[CaseSet { type EnumType = Z }] + ).mapError(_.getMessage) + }) + caseSet.map(cs => Schema.enumeration(TypeId.parse(avroSchema.getName), cs)) } - private[codec] def toZioRecord(avroSchema: SchemaAvro): scala.util.Either[String, Schema[_]] = + private[codec] def toZioRecord(avroSchema: SchemaAvro): Validation[String, Schema[_]] = if (avroSchema.getObjectProp(UnionWrapper.propName) != null) { avroSchema.getFields.asScala.headOption match { case Some(value) => toZioSchema(value.schema()) - case None => Left("ZIO schema wrapped record must have a single field") + case None => Validation.fail("ZIO schema wrapped record must have a single field") } } else if (avroSchema.getObjectProp(EitherWrapper.propName) != null) { avroSchema.getFields.asScala.headOption match { @@ -778,47 +784,49 @@ object AvroCodec extends AvroCodec { toZioSchema(value.schema()).flatMap { case enu: Enum[_] => enu.cases.toList match { - case first :: second :: Nil => Right(Schema.either(first.schema, second.schema)) - case _ => Left("ZIO schema wrapped either must have exactly two cases") + case first :: second :: Nil => Validation.succeed(Schema.either(first.schema, second.schema)) + case _ => Validation.fail("ZIO schema wrapped either must have exactly two cases") } - case e: Schema.Either[_, _] => Right(e) - case c: CaseClass0[_] => Right(c) - case c: CaseClass1[_, _] => Right(c) - case c: CaseClass2[_, _, _] => Right(c) - case c: CaseClass3[_, _, _, _] => Right(c) - case c: CaseClass4[_, _, _, _, _] => Right(c) - case c: CaseClass5[_, _, _, _, _, _] => Right(c) - case c: CaseClass6[_, _, _, _, _, _, _] => Right(c) - case c: CaseClass7[_, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass8[_, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass9[_, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass10[_, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass11[_, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Right(c) - case c: Dynamic => Right(c) - case c: GenericRecord => Right(c) - case c: Map[_, _] => Right(c) - case c: Sequence[_, _, _] => Right(c) - case c: Set[_] => Right(c) - case c: Fail[_] => Right(c) - case c: Lazy[_] => Right(c) - case c: Optional[_] => Right(c) - case c: Primitive[_] => Right(c) - case c: Transform[_, _, _] => Right(c) - case c: Tuple2[_, _] => Right(c) + case e: Schema.Either[_, _] => Validation.succeed(e) + case c: CaseClass0[_] => Validation.succeed(c) + case c: CaseClass1[_, _] => Validation.succeed(c) + case c: CaseClass2[_, _, _] => Validation.succeed(c) + case c: CaseClass3[_, _, _, _] => Validation.succeed(c) + case c: CaseClass4[_, _, _, _, _] => Validation.succeed(c) + case c: CaseClass5[_, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass6[_, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass7[_, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass8[_, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass9[_, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass10[_, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass11[_, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => Validation.succeed(c) + case c: CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Validation.succeed(c) + case c: CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] => + Validation.succeed(c) + case c: Dynamic => Validation.succeed(c) + case c: GenericRecord => Validation.succeed(c) + case c: Map[_, _] => Validation.succeed(c) + case c: Sequence[_, _, _] => Validation.succeed(c) + case c: Set[_] => Validation.succeed(c) + case c: Fail[_] => Validation.succeed(c) + case c: Lazy[_] => Validation.succeed(c) + case c: Optional[_] => Validation.succeed(c) + case c: Primitive[_] => Validation.succeed(c) + case c: Transform[_, _, _] => Validation.succeed(c) + case c: Tuple2[_, _] => Validation.succeed(c) } - case None => Left("ZIO schema wrapped record must have a single field") + case None => Validation.fail("ZIO schema wrapped record must have a single field") } } else { val annotations = buildZioAnnotations(avroSchema) @@ -827,16 +835,10 @@ object AvroCodec extends AvroCodec { } } - private def extractZioFields[Z](avroSchema: SchemaAvro): scala.util.Either[String, List[Field[Z, _]]] = - avroSchema.getFields.asScala.map(toZioField).toList.map(_.merge).partition { - case _: String => true - case _ => false - } match { - case (Nil, right: List[Field[Z, _] @unchecked]) => Right(right) - case (left, _) => Left(left.mkString("\n")) - } + private def extractZioFields[Z](avroSchema: SchemaAvro): Validation[String, List[Field[Z, _]]] = + Validation.validateAll(avroSchema.getFields.asScala.map(toZioField).map(_.map(_.asInstanceOf[Field[Z, _]])).toList) - private[codec] def toZioField(field: SchemaAvro.Field): scala.util.Either[String, Field[ListMap[String, _], _]] = + private[codec] def toZioField(field: SchemaAvro.Field): Validation[String, Field[ListMap[String, _], _]] = toZioSchema(field.schema()) .map( (s: Schema[_]) => @@ -849,10 +851,12 @@ object AvroCodec extends AvroCodec { ) ) - private[codec] def toZioTuple(schema: SchemaAvro): scala.util.Either[String, Schema[_]] = + private[codec] def toZioTuple(schema: SchemaAvro): Validation[String, Schema[_]] = for { - _ <- scala.util.Either - .cond(schema.getFields.size() == 2, (), "Tuple must have exactly 2 fields:" + schema.toString(false)) + _ <- Validation.fromEither( + scala.Either + .cond(schema.getFields.size() == 2, (), "Tuple must have exactly 2 fields:" + schema.toString(false)) + ) _1 <- toZioSchema(schema.getFields.get(0).schema()) _2 <- toZioSchema(schema.getFields.get(1).schema()) } yield Schema.Tuple2(_1, _2, buildZioAnnotations(schema)) @@ -891,14 +895,14 @@ object AvroCodec extends AvroCodec { Chunk.fromIterable(annotations) } - private[codec] def toZioStringEnum(avroSchema: SchemaAvro): scala.util.Either[String, Schema[_]] = { + private[codec] def toZioStringEnum(avroSchema: SchemaAvro): Validation[String, Schema[_]] = { val cases = avroSchema.getEnumSymbols.asScala .map(s => Schema.Case[String, String](s, Schema[String], identity, identity, _.isInstanceOf[String])) .toSeq val caseSet = CaseSet[String](cases: _*).asInstanceOf[Aux[String]] val enumeration: Schema[String] = Schema.enumeration(TypeId.parse("org.apache.avro.Schema"), caseSet) - Right(enumeration.addAllAnnotations(buildZioAnnotations(avroSchema))) + Validation.succeed(enumeration.addAllAnnotations(buildZioAnnotations(avroSchema))) } private[codec] case object OptionUnion { diff --git a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroPropMarker.scala b/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroPropMarker.scala index 9217fcced..b23a83910 100644 --- a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroPropMarker.scala +++ b/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroPropMarker.scala @@ -4,10 +4,11 @@ import java.time.format.DateTimeFormatter import java.time.temporal.{ ChronoUnit, TemporalUnit } import scala.jdk.CollectionConverters._ -import scala.util.Try import org.apache.avro.{ LogicalType, LogicalTypes, Schema => SchemaAvro } +import zio.prelude.Validation + sealed trait AvroPropMarker { def propName: String def value: Any = true @@ -59,13 +60,19 @@ object AvroPropMarker { val propName = "zio.schema.codec.avro.dateTimeFormatter" val default: Formatter = Formatter(DateTimeFormatter.ISO_INSTANT) - def fromAvroStringOrDefault(avroSchema: SchemaAvro, stringType: StringType): Either[String, Formatter] = + def fromAvroStringOrDefault( + avroSchema: SchemaAvro, + stringType: StringType + ): zio.prelude.Validation[String, Formatter] = fromAvroString(avroSchema).map { case Some(value) => value case None => getDefaultByStringType(stringType) } - def fromAvroStringOrDefault(avroSchema: SchemaAvro, logicalType: LogicalType): Either[String, Formatter] = + def fromAvroStringOrDefault( + avroSchema: SchemaAvro, + logicalType: LogicalType + ): zio.prelude.Validation[String, Formatter] = fromAvroString(avroSchema).map { case Some(value) => value case None => getDefaultByLogicalType(logicalType) @@ -95,30 +102,30 @@ object AvroPropMarker { case StringType.ZoneDateTime => Formatter(DateTimeFormatter.ISO_ZONED_DATE_TIME) } - private def fromAvroString(avroSchema: SchemaAvro): Either[String, Option[Formatter]] = + private def fromAvroString(avroSchema: SchemaAvro): zio.prelude.Validation[String, Option[Formatter]] = avroSchema.getObjectProps.asScala.get(propName).collect { - case "ISO_LOCAL_DATE_TIME" => Right(Formatter(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) - case "ISO_DATE" => Right(Formatter(DateTimeFormatter.ISO_DATE)) - case "ISO_TIME" => Right(Formatter(DateTimeFormatter.ISO_TIME)) - case "ISO_LOCAL_TIME" => Right(Formatter(DateTimeFormatter.ISO_LOCAL_TIME)) - case "ISO_LOCAL_DATE" => Right(Formatter(DateTimeFormatter.ISO_LOCAL_DATE)) - case "ISO_OFFSET_DATE_TIME" => Right(Formatter(DateTimeFormatter.ISO_OFFSET_DATE_TIME)) - case "ISO_OFFSET_DATE" => Right(Formatter(DateTimeFormatter.ISO_OFFSET_DATE)) - case "ISO_OFFSET_TIME" => Right(Formatter(DateTimeFormatter.ISO_OFFSET_TIME)) - case "ISO_ZONED_DATE_TIME" => Right(Formatter(DateTimeFormatter.ISO_ZONED_DATE_TIME)) - case "ISO_ORDINAL_DATE" => Right(Formatter(DateTimeFormatter.ISO_ORDINAL_DATE)) - case "ISO_WEEK_DATE" => Right(Formatter(DateTimeFormatter.ISO_WEEK_DATE)) - case "ISO_INSTANT" => Right(Formatter(DateTimeFormatter.ISO_INSTANT)) - case "ISO_DATE_TIME" => Right(Formatter(DateTimeFormatter.ISO_DATE_TIME)) - case "RFC_1123_DATE_TIME" => Right(Formatter(DateTimeFormatter.RFC_1123_DATE_TIME)) - case "BASIC_ISO_DATE" => Right(Formatter(DateTimeFormatter.BASIC_ISO_DATE)) + case "ISO_LOCAL_DATE_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_LOCAL_DATE_TIME)) + case "ISO_DATE" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_DATE)) + case "ISO_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_TIME)) + case "ISO_LOCAL_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_LOCAL_TIME)) + case "ISO_LOCAL_DATE" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_LOCAL_DATE)) + case "ISO_OFFSET_DATE_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_OFFSET_DATE_TIME)) + case "ISO_OFFSET_DATE" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_OFFSET_DATE)) + case "ISO_OFFSET_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_OFFSET_TIME)) + case "ISO_ZONED_DATE_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_ZONED_DATE_TIME)) + case "ISO_ORDINAL_DATE" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_ORDINAL_DATE)) + case "ISO_WEEK_DATE" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_WEEK_DATE)) + case "ISO_INSTANT" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_INSTANT)) + case "ISO_DATE_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.ISO_DATE_TIME)) + case "RFC_1123_DATE_TIME" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.RFC_1123_DATE_TIME)) + case "BASIC_ISO_DATE" => zio.prelude.Validation.succeed(Formatter(DateTimeFormatter.BASIC_ISO_DATE)) case s: String => - Try { + Validation { Formatter(DateTimeFormatter.ofPattern(s)) - }.toEither.left.map(_.getMessage) + }.mapError(_.getMessage) } match { case Some(value) => value.map(Some(_)) - case None => Right(None) + case None => zio.prelude.Validation.succeed(None) } } diff --git a/zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala b/zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala index 3592028f2..a857f259d 100644 --- a/zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala +++ b/zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala @@ -47,7 +47,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val result = AvroCodec.encode(schema) val expected = """{"type":"enum","name":"MyEnum","symbols":["A","B","C"]}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("encodes sealed trait objects only as union of records when no avroEnum annotation is present") { @@ -56,7 +56,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """[{"type":"record","name":"A","fields":[]},{"type":"record","name":"B","fields":[]},{"type":"record","name":"MyC","fields":[]}]""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("encodes sealed trait objects only as enum when avroEnum annotation is present") { @@ -64,7 +64,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val result = AvroCodec.encode(schema) val expected = """{"type":"enum","name":"MyEnum","symbols":["A","B","MyC"]}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("ignores avroEnum annotation if ADT cannot be reduced to String symbols") { val schema = DeriveSchema.gen[SpecTestData.CaseObjectAndCaseClassAdt] @@ -72,7 +72,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """[{"type":"record","name":"A","fields":[]},{"type":"record","name":"B","fields":[]},{"type":"record","name":"MyC","fields":[]},{"type":"record","name":"D","fields":[{"name":"s","type":"string"}]}]""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("flatten nested unions with initialSchemaDerived derivation") { val schema = DeriveSchema.gen[SpecTestData.UnionWithNesting] @@ -80,7 +80,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """[{"type":"record","name":"A","fields":[]},{"type":"record","name":"B","fields":[]},{"type":"record","name":"MyC","fields":[]},{"type":"record","name":"D","fields":[{"name":"s","type":"string"}]}]""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("wraps nested unions") { val schemaA = DeriveSchema.gen[UnionWithNesting.Nested.A.type] @@ -137,7 +137,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val wrappedString = """[{"type":"record","name":"wrapper_Nested","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":[{"type":"record","name":"A","namespace":"","fields":[]},{"type":"record","name":"B","namespace":"","fields":[]}]}],"zio.schema.codec.avro.wrapper":true},{"type":"record","name":"C","fields":[]},{"type":"record","name":"D","fields":[{"name":"s","type":"string"}]}]""" - assert(result)(isRight(equalTo(wrappedString))) + assert(result.toEither)(isRight(equalTo(wrappedString))) } ), suite("record")( @@ -149,19 +149,19 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"hashed_1642816955","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" - assert(result1)(isRight(equalTo(expected))) && assert(result2)(isRight(equalTo(expected))) + assert(result1.toEither)(isRight(equalTo(expected))) && assert(result2.toEither)(isRight(equalTo(expected))) } @@ TestAspect.ignore, // TODO: FIX test("fail with left on invalid name") { val schema = DeriveSchema.gen[SpecTestData.Record].annotate(AvroAnnotations.name("0invalid")) val result = AvroCodec.encode(schema) - assert(result)(isLeft(containsString("""0invalid"""))) + assert(result.toEither.left.map(_.head))(isLeft(containsString("""0invalid"""))) }, test("pick up name from annotation") { val schema = DeriveSchema.gen[SpecTestData.NamedRecord] val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" @@ -173,7 +173,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = DeriveSchema.gen[SpecTestData.NamedFieldRecord] val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"record","name":"MyNamedFieldRecord","fields":[{"name":"myNamedField","type":"string"},{"name":"b","type":"boolean"}]}""" @@ -185,7 +185,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = DeriveSchema.gen[SpecTestData.NamedRecord].annotate(AvroAnnotations.doc("My doc")) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"record","name":"MyNamedRecord","doc":"My doc","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" @@ -198,7 +198,7 @@ object AvroCodecSpec extends ZIOSpecDefault { DeriveSchema.gen[SpecTestData.NamedRecord].annotate(AvroAnnotations.namespace("test.namespace")) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"record","name":"MyNamedRecord","namespace":"test.namespace","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" @@ -210,7 +210,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = DeriveSchema.gen[SpecTestData.NamedRecord].annotate(AvroAnnotations.namespace("0@-.invalid")) val result = AvroCodec.encode(schema) - assert(result)(isLeft(containsString("""0@-.invalid"""))) + assert(result.toEither.left.map(_.head))(isLeft(containsString("""0@-.invalid"""))) }, test("pick up error annotation") { val schema = DeriveSchema.gen[SpecTestData.NamedRecord].annotate(AvroAnnotations.error) @@ -218,7 +218,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"error","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("includes all fields") { val schema = DeriveSchema.gen[SpecTestData.NamedRecord] @@ -226,7 +226,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("includes nested record fields") { val schema = DeriveSchema.gen[SpecTestData.NestedRecord] @@ -234,7 +234,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"NestedRecord","fields":[{"name":"s","type":"string"},{"name":"nested","type":{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}}]}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) } ), suite("map")( @@ -244,7 +244,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Map(keySchema, valueSchema) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"map","values":"string"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"map","values":"string"}"""))) }, test("string keys and complex values") { val keySchema = Schema.primitive(StandardType.StringType) @@ -252,7 +252,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Map(keySchema, valueSchema) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"map","values":{"type":"record","name":"Simple","fields":[{"name":"s","type":"string"}]}}""" @@ -273,7 +273,7 @@ object AvroCodecSpec extends ZIOSpecDefault { ) val hasTupleField_2 = containsString("""{"name":"_2","type":"string"}""") - assert(result)(isRight(isArray && tupleItems && hasTupleField_1 && hasTupleField_2)) + assert(result.toEither)(isRight(isArray && tupleItems && hasTupleField_1 && hasTupleField_2)) }, test("complex keys and complex values") { val keySchema = DeriveSchema.gen[SpecTestData.SimpleRecord] @@ -290,7 +290,7 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"name":"_2","type":{"type":"record","name":"MyNamedRecord","namespace":"","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}}""" ) - assert(result)(isRight(isArray && tupleItems && hasTupleField_1 && hasTupleField_2)) + assert(result.toEither)(isRight(isArray && tupleItems && hasTupleField_1 && hasTupleField_2)) } ), suite("seq")( @@ -304,7 +304,7 @@ object AvroCodecSpec extends ZIOSpecDefault { ) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"array","items":"string"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"array","items":"string"}"""))) }, test("encodes complex types") { val valueSchema = DeriveSchema.gen[SpecTestData.NamedRecord] @@ -312,7 +312,7 @@ object AvroCodecSpec extends ZIOSpecDefault { .Sequence[Chunk[NamedRecord], NamedRecord, String](valueSchema, identity, identity, Chunk.empty, "Seq") val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"array","items":{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}}""" @@ -332,7 +332,7 @@ object AvroCodecSpec extends ZIOSpecDefault { ) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"array","items":"string"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"array","items":"string"}"""))) }, test("encodes complex types") { val valueSchema = DeriveSchema.gen[SpecTestData.NamedRecord] @@ -340,7 +340,7 @@ object AvroCodecSpec extends ZIOSpecDefault { .Sequence[Chunk[NamedRecord], NamedRecord, String](valueSchema, identity, identity, Chunk.empty, "Seq") val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"array","items":{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}}""" @@ -354,14 +354,14 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Optional(Schema.primitive(StandardType.StringType)) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""["null","string"]"""))) + assert(result.toEither)(isRight(equalTo("""["null","string"]"""))) }, test("encodes complex types") { val valueSchema = DeriveSchema.gen[SpecTestData.NamedRecord] val schema = Schema.Optional(valueSchema) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """["null",{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}]""" @@ -373,7 +373,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Optional(Schema.primitive(StandardType.UnitType)) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """["null",{"type":"record","name":"wrapper_hashed_3594628","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":"null"}],"zio.schema.codec.avro.wrapper":true}]""" @@ -386,7 +386,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Optional(nested) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """["null",{"type":"record","name":"wrapper_hashed_n813828848","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":["null","string"]}],"zio.schema.codec.avro.wrapper":true}]""" @@ -399,7 +399,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Optional(union) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """["null",{"type":"record","name":"wrapper_MyEnum","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":[{"type":"record","name":"A","namespace":"","fields":[]},{"type":"record","name":"B","namespace":"","fields":[]},{"type":"record","name":"MyC","namespace":"","fields":[]}]}],"zio.schema.codec.avro.wrapper":true}]""" @@ -413,7 +413,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Optional(either) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """["null",{"type":"record","name":"wrapper_hashed_n630422444","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":["string","int"]}],"zio.schema.codec.avro.either":true}]""" @@ -430,7 +430,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"wrapper_hashed_n630422444","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":["string","int"]}],"zio.schema.codec.avro.either":true}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("create a named union") { val schema = Schema @@ -440,7 +440,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"wrapper_MyEither","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":["string","int"]}],"zio.schema.codec.avro.either":true}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("encodes complex types") { val left = DeriveSchema.gen[SpecTestData.SimpleRecord] @@ -450,7 +450,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"wrapper_hashed_754352222","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":[{"type":"record","name":"Simple","namespace":"","fields":[{"name":"s","type":"string"}]},"string"]}],"zio.schema.codec.avro.either":true}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("fails with duplicate names") { val left = DeriveSchema.gen[SpecTestData.SimpleRecord] @@ -458,7 +458,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Either(left, right) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither.left.map(_.head))( isLeft(equalTo("""Left and right schemas of either must have different fullnames: Simple""")) ) }, @@ -468,7 +468,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Either(left, right) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"record","name":"wrapper_hashed_n465006219","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":[{"type":"record","name":"wrapper_hashed_n813828848","fields":[{"name":"value","type":["null","string"]}],"zio.schema.codec.avro.wrapper":true},"string"]}],"zio.schema.codec.avro.either":true}""" @@ -485,7 +485,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val expected = """{"type":"record","name":"wrapper_hashed_2071802344","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":[{"type":"record","name":"wrapper_hashed_n465006219","fields":[{"name":"value","type":[{"type":"record","name":"wrapper_hashed_n813828848","fields":[{"name":"value","type":["null","string"]}],"zio.schema.codec.avro.wrapper":true},"string"]}],"zio.schema.codec.avro.either":true},"string"]}],"zio.schema.codec.avro.either":true}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) } ), suite("tuple")( @@ -495,7 +495,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.Tuple2(left, right).annotate(AvroAnnotations.name("MyTuple")) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"record","name":"MyTuple","fields":[{"name":"_1","type":"string"},{"name":"_2","type":"string"}],"zio.schema.codec.recordType":"tuple"}""" @@ -513,7 +513,7 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"name":"_1","type":{"type":"record","name":"Simple","fields":[{"name":"s","type":"string"}]}}""" val field_2 = """{"name":"_2","type":{"type":"record","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}}""" - assert(result)(isRight(containsString(field_1) && containsString(field_2))) + assert(result.toEither)(isRight(containsString(field_1) && containsString(field_2))) }, test("encodes duplicate complex types by reference") { val left = DeriveSchema.gen[SpecTestData.SimpleRecord] @@ -524,7 +524,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val field_1 = """{"name":"_1","type":{"type":"record","name":"Simple","fields":[{"name":"s","type":"string"}]}}""" val field_2 = """{"name":"_2","type":"Simple"}""" - assert(result)(isRight(containsString(field_1) && containsString(field_2))) + assert(result.toEither)(isRight(containsString(field_1) && containsString(field_2))) } ), suite("primitives")( @@ -532,55 +532,55 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.primitive(StandardType.UnitType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"null\""))) + assert(result.toEither)(isRight(equalTo("\"null\""))) }, test("encodes StringType") { val schema = Schema.primitive(StandardType.StringType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"string\""))) + assert(result.toEither)(isRight(equalTo("\"string\""))) }, test("encodes BooleanType") { val schema = Schema.primitive(StandardType.BoolType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"boolean\""))) + assert(result.toEither)(isRight(equalTo("\"boolean\""))) }, test("encodes ShortType") { val schema = Schema.primitive(StandardType.ShortType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"short"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"short"}"""))) }, test("encodes IntType") { val schema = Schema.primitive(StandardType.IntType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"int\""))) + assert(result.toEither)(isRight(equalTo("\"int\""))) }, test("encodes LongType") { val schema = Schema.primitive(StandardType.LongType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"long\""))) + assert(result.toEither)(isRight(equalTo("\"long\""))) }, test("encodes FloatType") { val schema = Schema.primitive(StandardType.FloatType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"float\""))) + assert(result.toEither)(isRight(equalTo("\"float\""))) }, test("encodes DoubleType") { val schema = Schema.primitive(StandardType.DoubleType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"double\""))) + assert(result.toEither)(isRight(equalTo("\"double\""))) }, test("encodes BinaryType as bytes") { val schema = Schema.primitive(StandardType.BinaryType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"bytes\""))) + assert(result.toEither)(isRight(equalTo("\"bytes\""))) }, test("encodes BinaryType as fixed") { val size = 12 @@ -591,26 +591,28 @@ object AvroCodecSpec extends ZIOSpecDefault { val result = AvroCodec.encode(schema) val expected = """{"type":"fixed","name":"MyFixed","doc":"","size":12}""" - assert(result)(isRight(equalTo(expected))) + assert(result.toEither)(isRight(equalTo(expected))) }, test("encodes CharType") { val schema = Schema.primitive(StandardType.CharType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"char"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"char"}"""))) }, test("encodes UUIDType") { val schema = Schema.primitive(StandardType.UUIDType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"string","logicalType":"uuid"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"string","logicalType":"uuid"}"""))) }, test("encodes BigDecimalType as Bytes") { val schema = Schema.primitive(StandardType.BigDecimalType).annotate(AvroAnnotations.decimal(DecimalType.Bytes)) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":48,"scale":24}"""))) + assert(result.toEither)( + isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":48,"scale":24}""")) + ) }, test("encodes BigDecimalType as Bytes with scala and precision") { val schema = Schema @@ -620,14 +622,16 @@ object AvroCodecSpec extends ZIOSpecDefault { .annotate(AvroAnnotations.precision(20)) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":20,"scale":10}"""))) + assert(result.toEither)( + isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":20,"scale":10}""")) + ) }, test("encodes BigDecimalType as Fixed") { val schema = Schema.primitive(StandardType.BigDecimalType).annotate(AvroAnnotations.decimal(DecimalType.Fixed(21))) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"fixed","name":"Decimal_48_24","size":21,"logicalType":"decimal","precision":48,"scale":24}""" @@ -643,7 +647,7 @@ object AvroCodecSpec extends ZIOSpecDefault { .annotate(AvroAnnotations.precision(20)) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"fixed","name":"Decimal_20_10","size":9,"logicalType":"decimal","precision":20,"scale":10}""" @@ -656,7 +660,9 @@ object AvroCodecSpec extends ZIOSpecDefault { Schema.primitive(StandardType.BigIntegerType).annotate(AvroAnnotations.decimal(DecimalType.Bytes)) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":24,"scale":24}"""))) + assert(result.toEither)( + isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":24,"scale":24}""")) + ) }, test("encodes BigIntegerType as Bytes with scala and precision") { val schema = Schema @@ -666,14 +672,16 @@ object AvroCodecSpec extends ZIOSpecDefault { .annotate(AvroAnnotations.precision(20)) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":10,"scale":10}"""))) + assert(result.toEither)( + isRight(equalTo("""{"type":"bytes","logicalType":"decimal","precision":10,"scale":10}""")) + ) }, test("encodes BigIntegerType as Fixed") { val schema = Schema.primitive(StandardType.BigIntegerType).annotate(AvroAnnotations.decimal(DecimalType.Fixed(11))) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"fixed","name":"Decimal_24_24","size":11,"logicalType":"decimal","precision":24,"scale":24}""" @@ -689,7 +697,7 @@ object AvroCodecSpec extends ZIOSpecDefault { .annotate(AvroAnnotations.precision(20)) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"fixed","name":"Decimal_10_10","size":5,"logicalType":"decimal","precision":10,"scale":10}""" @@ -701,31 +709,31 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.primitive(StandardType.DayOfWeekType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"dayOfWeek"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"dayOfWeek"}"""))) }, test("encodes MonthType") { val schema = Schema.primitive(StandardType.MonthType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"month"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"month"}"""))) }, test("encodes YearType") { val schema = Schema.primitive(StandardType.YearType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"year"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"year"}"""))) }, test("encodes ZoneIdType") { val schema = Schema.primitive(StandardType.ZoneIdType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"string","zio.schema.codec.stringType":"zoneId"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"string","zio.schema.codec.stringType":"zoneId"}"""))) }, test("encodes ZoneOffsetType") { val schema = Schema.primitive(StandardType.ZoneOffsetType) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"zoneOffset"}"""))) + assert(result.toEither)(isRight(equalTo("""{"type":"int","zio.schema.codec.intType":"zoneOffset"}"""))) }, //TODO 1 //test("encodes MonthDayType") { @@ -783,7 +791,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.primitive(StandardType.InstantType).annotate(AvroAnnotations.formatToString) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"instant"}""" @@ -796,7 +804,7 @@ object AvroCodecSpec extends ZIOSpecDefault { Schema.primitive(StandardType.LocalDateType).annotate(AvroAnnotations.formatToString) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"localDate"}""" @@ -809,7 +817,7 @@ object AvroCodecSpec extends ZIOSpecDefault { Schema.primitive(StandardType.LocalTimeType).annotate(AvroAnnotations.formatToString) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"localTime"}""" @@ -822,7 +830,7 @@ object AvroCodecSpec extends ZIOSpecDefault { Schema.primitive(StandardType.LocalDateTimeType).annotate(AvroAnnotations.formatToString) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"localDateTime"}""" @@ -834,7 +842,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.primitive(StandardType.OffsetTimeType) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"offsetTime"}""" @@ -846,7 +854,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.primitive(StandardType.OffsetDateTimeType) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"offsetDateTime"}""" @@ -858,7 +866,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.primitive(StandardType.ZonedDateTimeType) val result = AvroCodec.encode(schema) - assert(result)( + assert(result.toEither)( isRight( equalTo( """{"type":"string","zio.schema.codec.stringType":"zoneDateTime"}""" @@ -871,13 +879,13 @@ object AvroCodecSpec extends ZIOSpecDefault { val schema = Schema.fail("I'm failing") val result = AvroCodec.encode(schema) - assert(result)(isLeft(equalTo("""I'm failing"""))) + assert(result.toEither.left.map(_.head))(isLeft(equalTo("""I'm failing"""))) }, test("lazy is handled properly") { val schema = Schema.Lazy(() => Schema.primitive(StandardType.StringType)) val result = AvroCodec.encode(schema) - assert(result)(isRight(equalTo("\"string\""))) + assert(result.toEither)(isRight(equalTo("\"string\""))) } ), /** @@ -890,7 +898,7 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"record","name":"TestRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema.map(_.ast))( + assert(schema.map(_.ast).toEither)( isRight( equalTo( Schema @@ -942,14 +950,14 @@ object AvroCodecSpec extends ZIOSpecDefault { ) ) - assert(schema.map(_.ast))(isRight(equalTo(expectedSchema.ast))) + assert(schema.map(_.ast).toEither)(isRight(equalTo(expectedSchema.ast))) }, test("unwrap a wrapped initialSchemaDerived") { val s = """{"type":"record","zio.schema.codec.avro.wrapper":true,"name":"wrapper_xyz","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":{"type":"record","name":"TestRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema.map(_.ast))( + assert(schema.map(_.ast).toEither)( isRight( equalTo( Schema @@ -978,21 +986,21 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"record","name":"Period","namespace":"zio.schema.codec.avro","fields":[{"name":"years","type":"int"},{"name":"months","type":"int"},{"name":"days","type":"int"}],"zio.schema.codec.recordType":"period"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.PeriodType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.PeriodType))) }, test("yearMonth record") { val s = """{"type":"record","name":"YearMonth","namespace":"zio.schema.codec.avro","fields":[{"name":"year","type":"int"},{"name":"month","type":"int"}],"zio.schema.codec.recordType":"yearMonth"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.YearMonthType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.YearMonthType))) }, test("tuple record successful") { val s = """{"type":"record","name":"Tuple","namespace":"zio.schema.codec.avro","fields":[{"name":"_1","type":"string"},{"name":"_2","type":"int"}],"zio.schema.codec.recordType":"tuple"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isTuple(isStandardType(StandardType.StringType), isStandardType(StandardType.IntType))) ) }, @@ -1001,70 +1009,70 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"record","name":"Tuple","namespace":"zio.schema.codec.avro","fields":[{"name":"_1","type":"string"},{"name":"_2","type":"int"},{"name":"_3","type":"int"}],"zio.schema.codec.recordType":"tuple"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isLeft) + assert(schema.toEither)(isLeft) }, test("monthDay record") { val s = """{"type":"record","name":"MonthDay","namespace":"zio.schema.codec.avro","fields":[{"name":"month","type":"int"},{"name":"day","type":"int"}],"zio.schema.codec.recordType":"monthDay"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.MonthDayType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.MonthDayType))) }, test("duration record without chrono unit annotation") { val s = """{"type":"record","name":"Duration","namespace":"zio.schema.codec.avro","fields":[{"name":"seconds","type":"long"},{"name":"nanos","type":"int"}],"zio.schema.codec.recordType":"duration"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.DurationType))) //(ChronoUnit.MILLIS)))) + assert(schema.toEither)(isRight(isStandardType(StandardType.DurationType))) //(ChronoUnit.MILLIS)))) }, test("duration record chrono unit annotation") { val s = """{"type":"record","name":"Duration","namespace":"zio.schema.codec.avro","fields":[{"name":"seconds","type":"long"},{"name":"nanos","type":"int"}],"zio.schema.codec.recordType":"duration","zio.schema.codec.avro.durationChronoUnit":"DAYS"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.DurationType))) //(ChronoUnit.DAYS)))) + assert(schema.toEither)(isRight(isStandardType(StandardType.DurationType))) //(ChronoUnit.DAYS)))) }, test("assign the name annotation") { val s = """{"type":"record","name":"TestRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasNameAnnotation(equalTo("TestRecord"))))) + assert(schema.toEither)(isRight(isRecord(hasNameAnnotation(equalTo("TestRecord"))))) }, test("assign the namespace annotation") { val s = """{"type":"record","name":"TestRecord","namespace":"MyTest","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasNamespaceAnnotation(equalTo("MyTest"))))) + assert(schema.toEither)(isRight(isRecord(hasNamespaceAnnotation(equalTo("MyTest"))))) }, test("not assign the namespace annotation if missing") { val s = """{"type":"record","name":"TestRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasNamespaceAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isRecord(hasNamespaceAnnotation(anything).negate))) }, zio.test.test("assign the doc annotation") { val s = """{"type":"record","name":"TestRecord","doc":"Very helpful documentation!","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasDocAnnotation(equalTo("Very helpful documentation!"))))) + assert(schema.toEither)(isRight(isRecord(hasDocAnnotation(equalTo("Very helpful documentation!"))))) }, test("not assign the doc annotation if missing") { val s = """{"type":"record","name":"TestRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasDocAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isRecord(hasDocAnnotation(anything).negate))) }, test("assign the aliases annotation") { val s = """{"type":"record","name":"TestRecord","aliases":["wow", "cool"],"fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isRecord(hasAliasesAnnotation(exists[String](equalTo("wow")) && exists(equalTo("cool"))))) ) }, @@ -1073,28 +1081,28 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"record","name":"TestRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasAliasesAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isRecord(hasAliasesAnnotation(anything).negate))) }, test("not assign the aliases annotation if empty") { val s = """{"type":"record","name":"TestRecord","aliases":[],"fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasAliasesAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isRecord(hasAliasesAnnotation(anything).negate))) }, zio.test.test("assign the error annotation") { val s = """{"type":"error","name":"MyNamedRecord","fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasErrorAnnotation))) + assert(schema.toEither)(isRight(isRecord(hasErrorAnnotation))) }, test("not assign the error annotation if not an error") { val s = """{"type":"record","name":"TestRecord","aliases":[],"fields":[{"name":"s","type":"string"},{"name":"b","type":"boolean"}]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isRecord(hasErrorAnnotation.negate))) + assert(schema.toEither)(isRight(isRecord(hasErrorAnnotation.negate))) } ), suite("fields")( @@ -1105,7 +1113,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val field1 = hasRecordField(hasLabel(equalTo("s")) && hasSchema(isStandardType(StandardType.StringType))) val field2 = hasRecordField(hasLabel(equalTo("b")) && hasSchema(isStandardType(StandardType.BoolType))) - assert(schema)(isRight(isRecord(field1 && field2))) + assert(schema.toEither)(isRight(isRecord(field1 && field2))) }, test("decodes the fields complex initialSchemaDerived") { val s = @@ -1116,7 +1124,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val field2 = hasRecordField(hasLabel(equalTo("b")) && hasSchema(isStandardType(StandardType.BoolType))) val complex = isRecord(field1 && field2) val field = hasRecordField(hasLabel(equalTo("complex")) && hasSchema(complex)) - assert(schema)(isRight(isRecord(field))) + assert(schema.toEither)(isRight(isRecord(field))) }, zio.test.test("assign the field name annotation") { val s = @@ -1125,7 +1133,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val field1 = hasRecordField(hasLabel(equalTo("s")) && hasNameAnnotation(equalTo("s"))) val field2 = hasRecordField(hasLabel(equalTo("b")) && hasNameAnnotation(equalTo("b"))) - assert(schema)(isRight(isRecord(field1 && field2))) + assert(schema.toEither)(isRight(isRecord(field1 && field2))) }, zio.test.test("assign the field doc annotation iff it exists") { val s = @@ -1134,7 +1142,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val field1 = hasRecordField(hasLabel(equalTo("s")) && hasDocAnnotation(equalTo("Very helpful doc!"))) val field2 = hasRecordField(hasLabel(equalTo("b")) && hasDocAnnotation(anything).negate) - assert(schema)(isRight(isRecord(field1 && field2))) + assert(schema.toEither)(isRight(isRecord(field1 && field2))) }, test("assign the field default annotation") { val s = @@ -1146,7 +1154,7 @@ object AvroCodecSpec extends ZIOSpecDefault { hasLabel(equalTo("complex")) && hasFieldDefaultAnnotation(asString(equalTo("""{s=defaultS, b=true}"""))) ) val field3 = hasRecordField(hasLabel(equalTo("b")) && hasFieldDefaultAnnotation(anything).negate) - assert(schema)(isRight(isRecord(field1 && field2 && field3))) + assert(schema.toEither)(isRight(isRecord(field1 && field2 && field3))) }, zio.test.test("assign the fieldOrder annotation") { val s = @@ -1159,7 +1167,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val field2 = hasRecordField( hasLabel(equalTo("b")) && hasFieldOrderAnnotation(equalTo(AvroAnnotations.FieldOrderType.Ascending)) ) - assert(schema)(isRight(isRecord(field1 && field2))) + assert(schema.toEither)(isRight(isRecord(field1 && field2))) }, zio.test.test("assign the field aliases annotation") { val s = @@ -1170,7 +1178,7 @@ object AvroCodecSpec extends ZIOSpecDefault { hasLabel(equalTo("s")) && hasAliasesAnnotation(Assertion.hasSameElements(Seq("wow", "cool"))) ) val field2 = hasRecordField(hasLabel(equalTo("b")) && hasAliasesAnnotation(anything).negate) - assert(schema)(isRight(isRecord(field1 && field2))) + assert(schema.toEither)(isRight(isRecord(field1 && field2))) } ), suite("enum")( @@ -1181,88 +1189,90 @@ object AvroCodecSpec extends ZIOSpecDefault { val symbolKeysAssetion = Assertion.hasKeys(hasSameElements(Seq("a", "b", "c"))) val enumStringTypeAssertion: Assertion[ListMap[String, (Schema[_], Chunk[Any])]] = Assertion.hasValues(forall(tuple2First(isStandardType(StandardType.StringType)))) - assert(schema)(isRight(isEnum(enumStructure(symbolKeysAssetion && enumStringTypeAssertion)))) + assert(schema.toEither)(isRight(isEnum(enumStructure(symbolKeysAssetion && enumStringTypeAssertion)))) }, test("assign the enum name annotation") { val s = """{"type":"enum","name":"TestEnum","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasNameAnnotation(equalTo("TestEnum"))))) + assert(schema.toEither)(isRight(isEnum(hasNameAnnotation(equalTo("TestEnum"))))) }, test("assign the enum namespace annotation") { val s = """{"type":"enum","name":"TestEnum","namespace":"MyTest","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasNamespaceAnnotation(equalTo("MyTest"))))) + assert(schema.toEither)(isRight(isEnum(hasNamespaceAnnotation(equalTo("MyTest"))))) }, test("not assign the enum namespace annotation if empty") { val s = """{"type":"enum","name":"TestEnum","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasNamespaceAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isEnum(hasNamespaceAnnotation(anything).negate))) }, test("assign the enum aliases annotation") { val s = """{"type":"enum","name":"TestEnum","aliases":["MyAlias", "MyAlias2"],"symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasAliasesAnnotation(hasSameElements(Seq("MyAlias", "MyAlias2")))))) + assert(schema.toEither)(isRight(isEnum(hasAliasesAnnotation(hasSameElements(Seq("MyAlias", "MyAlias2")))))) }, test("not assign the enum aliases annotation if empty") { val s = """{"type":"enum","name":"TestEnum","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasAliasesAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isEnum(hasAliasesAnnotation(anything).negate))) }, test("assign the enum doc annotation") { val s = """{"type":"enum","name":"TestEnum","doc":"Some very helpful documentation!","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasDocAnnotation(equalTo("Some very helpful documentation!"))))) + assert(schema.toEither)(isRight(isEnum(hasDocAnnotation(equalTo("Some very helpful documentation!"))))) }, test("not assign the enum doc annotation if empty") { val s = """{"type":"enum","name":"TestEnum","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasAliasesAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isEnum(hasAliasesAnnotation(anything).negate))) }, test("assign the enum default annotation") { val s = """{"type":"enum","name":"TestEnum","default":"a","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasDefaultAnnotation(equalTo("a"))))) + assert(schema.toEither)(isRight(isEnum(hasDefaultAnnotation(equalTo("a"))))) }, test("fail if enum default is not a symbol") { val s = """{"type":"enum","name":"TestEnum","default":"d","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isLeft(equalTo("The Enum Default: d is not in the enum symbol set: [a, b, c]"))) + assert(schema.toEither.left.map(_.head))( + isLeft(equalTo("The Enum Default: d is not in the enum symbol set: [a, b, c]")) + ) }, test("not assign the enum default annotation if empty") { val s = """{"type":"enum","name":"TestEnum","symbols":["a","b","c"]}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isEnum(hasDefaultAnnotation(anything).negate))) + assert(schema.toEither)(isRight(isEnum(hasDefaultAnnotation(anything).negate))) } ), test("decodes primitive array") { val s = """{"type":"array","items":{"type":"int"}}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isSequence(hasSequenceElementSchema(isStandardType(StandardType.IntType))))) + assert(schema.toEither)(isRight(isSequence(hasSequenceElementSchema(isStandardType(StandardType.IntType))))) }, test("decodes complex array") { val s = """{"type":"array","items":{"type":"record","name":"TestRecord","fields":[{"name":"f1","type":"int"},{"name":"f2","type":"string"}]}}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isSequence(hasSequenceElementSchema(isRecord(anything))))) + assert(schema.toEither)(isRight(isSequence(hasSequenceElementSchema(isRecord(anything))))) }, test("decodes map with string keys") { val s = """{"type":"map","values":{"type":"int"}}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight( isMap( hasMapKeys(isStandardType(StandardType.StringType)) && hasMapValues( @@ -1277,26 +1287,26 @@ object AvroCodecSpec extends ZIOSpecDefault { val s = """[{"type":"null"}, {"type":"int"}]""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isOption(hasOptionElementSchema(isStandardType(StandardType.IntType))))) + assert(schema.toEither)(isRight(isOption(hasOptionElementSchema(isStandardType(StandardType.IntType))))) }, test("option union with null on second position") { val s = """[{"type":"int"}, {"type":"null"}]""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isOption(hasOptionElementSchema(isStandardType(StandardType.IntType))))) + assert(schema.toEither)(isRight(isOption(hasOptionElementSchema(isStandardType(StandardType.IntType))))) }, test("not an option union with more than one element type") { val s = """[{"type":"null"}, {"type":"int"}, {"type":"string"}]""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isOption(anything).negate)) + assert(schema.toEither)(isRight(isOption(anything).negate)) }, test("nested either union") { val s = """{"type":"record","name":"wrapper_hashed_2071802344","namespace":"zio.schema.codec.avro","fields":[{"name":"value","type":[{"type":"record","name":"wrapper_hashed_n465006219","fields":[{"name":"value","type":[{"type":"record","name":"wrapper_hashed_n813828848","fields":[{"name":"value","type":["null","string"]}],"zio.schema.codec.avro.wrapper":true},"string"]}],"zio.schema.codec.avro.either":true},"string"]}],"zio.schema.codec.avro.either":true}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight( isEither( isEither(isOption(anything), isStandardType(StandardType.StringType)), @@ -1312,7 +1322,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val assertion1 = hasKey("null", tuple2First(isStandardType(StandardType.UnitType))) val sssertion2 = hasKey("int", tuple2First(isStandardType(StandardType.IntType))) val assertion3 = hasKey("string", tuple2First(isStandardType(StandardType.StringType))) - assert(schema)(isRight(isEnum(enumStructure(assertion1 && sssertion2 && assertion3)))) + assert(schema.toEither)(isRight(isEnum(enumStructure(assertion1 && sssertion2 && assertion3)))) }, test("correct case codec for case object of ADT") { val s = @@ -1322,7 +1332,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val assertionA = hasKey("A", tuple2First(isEmptyRecord)) val assertionB = hasKey("B", tuple2First(isEmptyRecord)) val assertionMyC = hasKey("MyC", tuple2First(isEmptyRecord)) - assert(schema)(isRight(isEnum(enumStructure(assertionA && assertionB && assertionMyC)))) + assert(schema.toEither)(isRight(isEnum(enumStructure(assertionA && assertionB && assertionMyC)))) }, test("correct case codec for case class of ADT") { val s = @@ -1335,7 +1345,7 @@ object AvroCodecSpec extends ZIOSpecDefault { ) val assertionB = hasKey("B", tuple2First(isEmptyRecord)) val assertionMyC = hasKey("MyC", tuple2First(isEmptyRecord)) - assert(schema)(isRight(isEnum(enumStructure(assertionA && assertionB && assertionMyC)))) + assert(schema.toEither)(isRight(isEnum(enumStructure(assertionA && assertionB && assertionMyC)))) }, test("unwrap nested union") { val s = @@ -1354,7 +1364,7 @@ object AvroCodecSpec extends ZIOSpecDefault { hasKey("zio.schema.codec.avro.wrapper_hashed_n465006219", tuple2First(nestedEnumAssertion)) val cEnumKey = hasKey("C", tuple2First(isEmptyRecord)) val dEnumKey = hasKey("D", tuple2First(isRecord(hasRecordField(hasLabel(equalTo("s")))))) - assert(schema)(isRight(isEnum(enumStructure(nestedEnumKey && cEnumKey && dEnumKey)))) + assert(schema.toEither)(isRight(isEnum(enumStructure(nestedEnumKey && cEnumKey && dEnumKey)))) } ), suite("fixed")( @@ -1370,7 +1380,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val hasPrecisionAnnotation: Assertion[Iterable[Any]] = exists(equalTo(AvroAnnotations.precision(11))) val hasAnnotationsAssertion = annotations(hasDecimalTypeAnnotation && hasScalaAnnotation && hasPrecisionAnnotation) - assert(schema)(isRight(isDecimalAssertion && hasAnnotationsAssertion)) + assert(schema.toEither)(isRight(isDecimalAssertion && hasAnnotationsAssertion)) }, test("logical type decimal as BigInteger") { val s = @@ -1385,21 +1395,23 @@ object AvroCodecSpec extends ZIOSpecDefault { exists(Assertion.isSubtype[AvroAnnotations.precision.type](anything)).negate val hasAnnotationsAssertion = annotations(hasDecimalTypeAnnotation && hasScalaAnnotation && doesNotHavePrecisionAnnotation) - assert(schema)(isRight(isBigIntegerType && hasAnnotationsAssertion)) + assert(schema.toEither)(isRight(isBigIntegerType && hasAnnotationsAssertion)) }, test("fail on invalid logical type") { val s = """{"type":"fixed","name":"Decimal_10_10","size":5,"logicalType":"decimal","precision":9,"scale":10}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isLeft(equalTo("Invalid decimal scale: 10 (greater than precision: 9)"))) + assert(schema.toEither.left.map(_.head))( + isLeft(equalTo("Invalid decimal scale: 10 (greater than precision: 9)")) + ) }, test("decode as binary") { val s = """{"type":"fixed","name":"Something","size":5}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) val hasNameAnnotation = annotations(exists(equalTo(AvroAnnotations.name("Something")))) - assert(schema)(isRight(isStandardType(StandardType.BinaryType) && hasNameAnnotation)) + assert(schema.toEither)(isRight(isStandardType(StandardType.BinaryType) && hasNameAnnotation)) } ), suite("string")( @@ -1407,20 +1419,20 @@ object AvroCodecSpec extends ZIOSpecDefault { val s = """{"type":"string","zio.schema.codec.stringType":"zoneId"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.ZoneIdType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.ZoneIdType))) }, test("decodes instant with formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"instant","zio.schema.codec.avro.dateTimeFormatter":"ISO_INSTANT"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decodes instant using default") { val s = """{"type":"string","zio.schema.codec.stringType":"instant"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decodes instant with formatter pattern") { val pattern = "yyyy MM dd" @@ -1428,7 +1440,7 @@ object AvroCodecSpec extends ZIOSpecDefault { s"""{"type":"string","zio.schema.codec.stringType":"instant","zio.schema.codec.avro.dateTimeFormatter":"$pattern"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decode DateTimeFormatter field fails on invalid formatter") { val pattern = "this is not a valid formatter pattern" @@ -1436,46 +1448,46 @@ object AvroCodecSpec extends ZIOSpecDefault { s"""{"type":"string","zio.schema.codec.stringType":"instant","zio.schema.codec.avro.dateTimeFormatter":"$pattern"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isLeft(equalTo("Unknown pattern letter: t"))) + assert(schema.toEither.left.map(_.head))(isLeft(equalTo("Unknown pattern letter: t"))) }, test("decodes localDate with formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"localDate","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateType))) }, test("decodes localDate with default formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"localDate"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateType))) }, test("decodes localTime with formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"localTime","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalTimeType))) }, test("decodes localTime with default formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"localTime"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalTimeType))) }, test("decodes localDateTime with formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"localDateTime","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateTimeType))) }, test("decodes localDateTime with default formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"localDateTime"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isStandardType(StandardType.LocalDateTimeType)) ) }, @@ -1484,13 +1496,13 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"string","zio.schema.codec.stringType":"zoneDateTime","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.ZonedDateTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.ZonedDateTimeType))) }, test("decodes zonedDateTime with default formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"zoneDateTime"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isStandardType(StandardType.ZonedDateTimeType)) ) }, @@ -1499,26 +1511,26 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"string","zio.schema.codec.stringType":"offsetTime","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.OffsetTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.OffsetTimeType))) }, test("decodes offsetTime with default formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"offsetTime"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.OffsetTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.OffsetTimeType))) }, test("decodes offsetDateTime with formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"offsetDateTime","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.OffsetDateTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.OffsetDateTimeType))) }, test("decodes offsetDateTime with default formatter") { val s = """{"type":"string","zio.schema.codec.stringType":"offsetDateTime"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isStandardType(StandardType.OffsetDateTimeType)) ) }, @@ -1526,13 +1538,13 @@ object AvroCodecSpec extends ZIOSpecDefault { val s = """{"type":"string","logicalType":"uuid"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.UUIDType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.UUIDType))) }, test("decodes primitive type string") { val s = """{"type":"string"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.StringType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.StringType))) } ), suite("bytes")( @@ -1547,7 +1559,7 @@ object AvroCodecSpec extends ZIOSpecDefault { val hasPrecisionAnnotation: Assertion[Iterable[Any]] = exists(equalTo(AvroAnnotations.precision(20))) val hasAnnotationsAssertion = annotations(hasDecimalTypeAnnotation && hasScalaAnnotation && hasPrecisionAnnotation) - assert(schema)(isRight(isDecimalAssertion && hasAnnotationsAssertion)) + assert(schema.toEither)(isRight(isDecimalAssertion && hasAnnotationsAssertion)) }, test("logical type decimal as BigInteger") { val s = """{"type":"bytes","logicalType":"decimal","precision":20,"scale":20}""" @@ -1558,13 +1570,13 @@ object AvroCodecSpec extends ZIOSpecDefault { exists(equalTo(AvroAnnotations.decimal(DecimalType.Bytes))) val hasScalaAnnotation: Assertion[Iterable[Any]] = exists(equalTo(AvroAnnotations.scale(20))) val hasAnnotationsAssertion = annotations(hasDecimalTypeAnnotation && hasScalaAnnotation) - assert(schema)(isRight(isBigIntegerAssertion && hasAnnotationsAssertion)) + assert(schema.toEither)(isRight(isBigIntegerAssertion && hasAnnotationsAssertion)) }, test("decode as binary") { val s = """{"type":"bytes"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.BinaryType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.BinaryType))) } ), suite("int")( @@ -1572,69 +1584,69 @@ object AvroCodecSpec extends ZIOSpecDefault { val s = """{"type":"int","zio.schema.codec.intType":"char"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.CharType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.CharType))) }, test("decodes dayOfWeek") { val s = """{"type":"int","zio.schema.codec.intType":"dayOfWeek"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.DayOfWeekType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.DayOfWeekType))) }, test("decodes Year") { val s = """{"type":"int","zio.schema.codec.intType":"year"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.YearType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.YearType))) }, test("decodes short") { val s = """{"type":"int","zio.schema.codec.intType":"short"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.ShortType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.ShortType))) }, test("decodes month") { val s = """{"type":"int","zio.schema.codec.intType":"month"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.MonthType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.MonthType))) }, test("decodes zoneOffset") { val s = """{"type":"int","zio.schema.codec.intType":"zoneOffset"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.ZoneOffsetType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.ZoneOffsetType))) }, test("decodes int") { val s = """{"type":"int"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.IntType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.IntType))) }, test("decodes logical type timemillis") { val s = """{"type":"int","logicalType":"time-millis","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalTimeType))) }, test("decodes logical type timemillis with default formatter") { val s = """{"type":"int","logicalType":"time-millis"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalTimeType))) }, test("decodes logical type date") { val s = """{"type":"int","logicalType":"date"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateType))) }, test("decodes logical type date with default formatter") { val s = """{"type":"int","logicalType":"date"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateType))) } ), suite("long")( @@ -1642,59 +1654,59 @@ object AvroCodecSpec extends ZIOSpecDefault { val s = """{"type":"long"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LongType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LongType))) }, test("decodes logical type timeMicros") { val s = """{"type":"long","logicalType":"time-micros","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalTimeType))) }, test("decodes logical type timeMicros with default formatter") { val s = """{"type":"long","logicalType":"time-micros"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalTimeType))) }, test("decodes logical type timestampMillis") { val s = """{"type":"long","logicalType":"timestamp-millis","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decodes logical type timestampMillis with default formatter") { val s = """{"type":"long","logicalType":"timestamp-millis"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decodes logical type timestampMicros") { val s = """{"type":"long","logicalType":"timestamp-micros","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decodes logical type timestampMicros with default formatter") { val s = """{"type":"long","logicalType":"timestamp-micros"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.InstantType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.InstantType))) }, test("decodes logical type LocalTimestamp millis") { val s = """{"type":"long","logicalType":"local-timestamp-millis","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateTimeType))) }, test("decodes logical type LocalTimestamp millis with default formatter") { val s = """{"type":"long","logicalType":"local-timestamp-millis"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isStandardType(StandardType.LocalDateTimeType)) ) }, @@ -1703,13 +1715,13 @@ object AvroCodecSpec extends ZIOSpecDefault { """{"type":"long","logicalType":"local-timestamp-micros","zio.schema.codec.avro.dateTimeFormatter":"ISO_ORDINAL_DATE"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.LocalDateTimeType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.LocalDateTimeType))) }, test("decodes logical type LocalTimestamp micros with default formatter") { val s = """{"type":"long","logicalType":"local-timestamp-micros"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)( + assert(schema.toEither)( isRight(isStandardType(StandardType.LocalDateTimeType)) ) } @@ -1718,25 +1730,25 @@ object AvroCodecSpec extends ZIOSpecDefault { val s = """{"type":"float"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.FloatType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.FloatType))) }, test("double") { val s = """{"type":"double"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.DoubleType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.DoubleType))) }, test("boolean") { val s = """{"type":"boolean"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.BoolType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.BoolType))) }, test("null") { val s = """{"type":"null"}""" val schema = AvroCodec.decode(Chunk.fromArray(s.getBytes())) - assert(schema)(isRight(isStandardType(StandardType.UnitType))) + assert(schema.toEither)(isRight(isStandardType(StandardType.UnitType))) } ), test("encode/decode full adt test") { @@ -1748,7 +1760,7 @@ object AvroCodecSpec extends ZIOSpecDefault { //_ <- AvroCodec.encode(decoded) TODO: this fails } yield decoded - assert(decoded)(isRight(hasField("ast", _.ast, equalTo(initialSchemaDerived.ast)))) + assert(decoded.toEither)(isRight(hasField("ast", _.ast, equalTo(initialSchemaDerived.ast)))) } @@ TestAspect.ignore // TODO: FIX ) } @@ -2031,7 +2043,7 @@ object SpecTestData { // case class IterablesComplex(list: List[InnerRecord], map: Map[InnerRecord, Enum]) extends TopLevelUnion } - case class InnerRecord(s: String, union: Option[scala.util.Either[String, Int]]) + case class InnerRecord(s: String, union: Option[scala.Either[String, Int]]) sealed trait Union case class NestedUnion(inner: InnerUnion) extends Union diff --git a/zio-schema-bson/shared/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala b/zio-schema-bson/shared/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala index 4e57c31fe..32e8d7e37 100644 --- a/zio-schema-bson/shared/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala +++ b/zio-schema-bson/shared/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala @@ -25,6 +25,7 @@ import zio.bson.{ bsonHint, bsonNoExtraFields } +import zio.prelude.{ Validation, ZValidation } import zio.schema.annotation.{ caseName, caseNameAliases, @@ -507,20 +508,21 @@ object BsonSchemaCodec { } } - private def transformEncoder[A, B](schema: Schema[A], g: B => Either[String, A]): BsonEncoder[B] = + private def transformEncoder[A, B](schema: Schema[A], g: B => Validation[String, A]): BsonEncoder[B] = new BsonEncoder[B] { private lazy val innerEncoder = schemaEncoder(schema) override def encode(writer: BsonWriter, b: B, ctx: BsonEncoder.EncoderContext): Unit = g(b) match { - case Left(_) => () - case Right(a) => innerEncoder.encode(writer, a, ctx) + case ZValidation.Failure(_, _) => () + case ZValidation.Success(_, value) => innerEncoder.encode(writer, value, ctx) } override def toBsonValue(b: B): BsonValue = g(b) match { - case Left(_) => BsonNull.VALUE - case Right(a) => innerEncoder.toBsonValue(a) + case ZValidation.Failure(_, _) => BsonNull.VALUE + case ZValidation.Success(_, value) => innerEncoder.toBsonValue(value) + } } @@ -689,7 +691,7 @@ object BsonSchemaCodec { case Schema.Primitive(standardType, _) => primitiveCodec(standardType).decoder case Schema.Optional(codec, _) => BsonDecoder.option(schemaDecoder(codec)) case Schema.Tuple2(left, right, _) => tuple2Decoder(schemaDecoder(left), schemaDecoder(right)) - case Schema.Transform(codec, f, _, _, _) => schemaDecoder(codec).mapOrFail(f) + case Schema.Transform(codec, f, _, _, _) => schemaDecoder(codec).mapOrFail(g => f(g).toEither.left.map(_.head)) case Schema.Sequence(codec, f, _, _, _) => chunkDecoder(schemaDecoder(codec)).map(f) case Schema.Map(ks, vs, _) => mapDecoder(ks, vs) case Schema.Set(s, _) => chunkDecoder(schemaDecoder(s)).map(entries => entries.toSet) @@ -1174,8 +1176,8 @@ object BsonSchemaCodec { Unsafe.unsafe { implicit u => caseClassSchema.construct(Chunk.fromArray(ps)) match { - case Left(err) => throw BsonDecoder.Error(trace, s"Failed to construct case class: $err") - case Right(value) => value + case ZValidation.Failure(_, err) => throw BsonDecoder.Error(trace, s"Failed to construct case class: $err") + case ZValidation.Success(_, value) => value } } } @@ -1216,8 +1218,8 @@ object BsonSchemaCodec { Unsafe.unsafe { implicit u => caseClassSchema.construct(Chunk.fromArray(ps)) match { - case Left(err) => throw BsonDecoder.Error(trace, s"Failed to construct case class: $err") - case Right(value) => value + case ZValidation.Failure(_, errors) => throw BsonDecoder.Error(trace, s"Failed to construct case class: $errors") + case ZValidation.Success(_, value) => value } } } diff --git a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/Derive.scala b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/Derive.scala index fcdc372e4..a165db514 100644 --- a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/Derive.scala +++ b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/Derive.scala @@ -22,7 +22,7 @@ object Derive { val setTpe = c.typeOf[Set[_]] val vectorTpe = c.typeOf[Vector[_]] val chunkTpe = c.typeOf[Chunk[_]] - val eitherTpe = c.typeOf[Either[_, _]] + val eitherTpe = c.typeOf[scala.Either[_, _]] val tuple2Tpe = c.typeOf[Tuple2[_, _]] val tuple3Tpe = c.typeOf[Tuple3[_, _, _]] val tuple4Tpe = c.typeOf[Tuple4[_, _, _, _]] diff --git a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala index c1ddb7714..4b32b3333 100644 --- a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala +++ b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala @@ -259,7 +259,7 @@ object DeriveSchema { } } }.filter(_ != EmptyTree) - .map(_.foldLeft[c.universe.Tree](q"_root_.zio.schema.validation.Validation.succeed") { + .map(_.foldLeft[c.universe.Tree](q"_root_.zio.schema.validation.SchemaValidation.succeed") { case (acc, t) => q"$acc && $t" }) }.getOrElse(Nil) @@ -299,13 +299,13 @@ object DeriveSchema { } """ } - q"""(m: scala.collection.immutable.ListMap[String, _]) => try { Right($tpeCompanion.apply(..$casts)) } catch { case e: Throwable => Left(e.getMessage) }""" + q"""(m: scala.collection.immutable.ListMap[String, _]) => try { zio.prelude.Validation.succeed($tpeCompanion.apply(..$casts)) } catch { case e: Throwable => zio.prelude.Validation.fail(e.getMessage) }""" } val toMap = { val tuples = fieldAccessors.map { fieldName => q"(${fieldName.toString},b.$fieldName)" } - q"""(b: $tpe) => Right(scala.collection.immutable.ListMap.apply(..$tuples))""" + q"""(b: $tpe) => zio.prelude.Validation.succeed(scala.collection.immutable.ListMap.apply(..$tuples))""" } val applyArgs = diff --git a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/Derive.scala b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/Derive.scala index c33c8cdcf..f84cfc5e0 100644 --- a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/Derive.scala +++ b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/Derive.scala @@ -88,9 +88,9 @@ private case class DeriveInstance()(using val ctx: Quotes) extends ReflectionUti lazyVals[F[A]](selfRef, seqSchemaRef -> '{Schema.force($schema).asInstanceOf[Schema.Sequence[List[a], a, _]]}, selfRef -> '{$deriver.deriveSequence[List, a]($seqSchemaRefExpr, $elemInstance, ${summoned})} - ) + ) case '[scala.util.Either[a, b]] => - val (schemaRef, schemaRefExpr) = createSchemaRef[scala.util.Either[a, b], Schema.Either[a, b]](stack) + val (schemaRef, schemaRefExpr) = createSchemaRef[scala.util.Either[a, b], Schema.Either[a, b]](stack) val summoned = summonOptionalIfNotTop[F, scala.util.Either[a, b]](top) val instanceA = deriveInstance[F, a](deriver, '{$schemaRefExpr.left}, stack) diff --git a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala index 4e67fd317..ce0adc59b 100644 --- a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala +++ b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala @@ -1,600 +1,600 @@ -package zio.schema - -import scala.quoted._ -import scala.deriving.Mirror -import scala.compiletime.{erasedValue, summonInline, constValueTuple} -import scala.collection.immutable.ListMap -import Schema._ - -import zio.schema.annotation.fieldName - -extension (s: Schema.type) transparent inline def derived[A] = DeriveSchema.gen[A] - -object DeriveSchema { - - transparent inline def gen[T]: Schema[T] = ${ deriveSchema[T] } - - private def deriveSchema[T: Type](using Quotes): Expr[Schema[T]] = - DeriveSchema().deriveSchema[T](top = true) -} - -private case class DeriveSchema()(using val ctx: Quotes) extends ReflectionUtils(ctx) { - import ctx.reflect._ - - case class Frame(ref: Term, tpe: TypeRepr) - case class Stack(frames: List[Frame]) { - def find(tpe: TypeRepr): Option[Term] = frames.find(_.tpe =:= tpe).map(_.ref) - - def push(ref: Term, tpe: TypeRepr): Stack = Stack(Frame(ref, tpe) :: frames) - - def pop: Stack = Stack(frames.tail) - - def size = frames.size - - override def toString = - frames.map(f => s"${f.ref.show} : ${f.tpe.show}").mkString("Stack(", ", ", ")") - } - - object Stack { - val empty: Stack = Stack(Nil) - } - - var depth = 0 - - def deriveSchema[T: Type](stack: Stack = Stack.empty, top: Boolean = false)(using Quotes): Expr[Schema[T]] = { - depth += 1 - if (depth > 1024) - throw new Exception("Schema derivation exceeded") - - val typeRepr = TypeRepr.of[T] - val result = stack.find(typeRepr) match { - case Some(ref) => - '{ Schema.defer(${ref.asExprOf[Schema[T]]}) } - case None => - typeRepr.asType match { - case '[List[a]] => - val schema = deriveSchema[a](stack) - '{ Schema.list(Schema.defer(${schema})) }.asExprOf[Schema[T]] - case '[scala.util.Either[a, b]] => - val schemaA = deriveSchema[a](stack) - val schemaB = deriveSchema[b](stack) - '{ Schema.either(Schema.defer(${schemaA}), Schema.defer(${schemaB})) }.asExprOf[Schema[T]] - case '[Option[a]] => - val schema = deriveSchema[a](stack) - // throw new Error(s"OPITOS ${schema.show}") - '{ Schema.option(Schema.defer($schema)) }.asExprOf[Schema[T]] - case '[scala.collection.Set[a]] => - val schema = deriveSchema[a](stack) - '{ Schema.set(Schema.defer(${schema})) }.asExprOf[Schema[T]] - case '[Vector[a]] => - val schema = deriveSchema[a](stack) - '{ Schema.vector(Schema.defer(${schema})) }.asExprOf[Schema[T]] - case '[scala.collection.Map[a, b]] => - val schemaA = deriveSchema[a](stack) - val schemaB = deriveSchema[b](stack) - '{ Schema.map(Schema.defer(${schemaA}), Schema.defer(${schemaB})) }.asExprOf[Schema[T]] - case '[zio.Chunk[a]] => - val schema = deriveSchema[a](stack) - '{ Schema.chunk(Schema.defer(${schema})) }.asExprOf[Schema[T]] - case _ => - val summoned = if (!top) Expr.summon[Schema[T]] else None - summoned match { - case Some(schema) => - // println(s"FOR TYPE ${typeRepr.show}") - // println(s"STACK ${stack.find(typeRepr)}") - // println(s"Found schema ${schema.show}") - schema - case _ => - Mirror(typeRepr) match { - case Some(mirror) => - mirror.mirrorType match { - case MirrorType.Sum => - deriveEnum[T](mirror, stack) - case MirrorType.Product => - deriveCaseClass[T](mirror, stack, top) - } - case None => - val sym = typeRepr.typeSymbol - if (sym.isClassDef && sym.flags.is(Flags.Module)) { - deriveCaseObject[T](stack, top) - } - else { - report.errorAndAbort(s"Deriving schema for ${typeRepr.show} is not supported") - } - } - } - } - } - - //println() - //println() - //println(s"RESULT ${typeRepr.show}") - //println(s"------") - //println(s"RESULT ${result.show}") - - result - } - - def deriveCaseObject[T: Type](stack: Stack, top: Boolean)(using Quotes) = { - val selfRefSymbol = Symbol.newVal(Symbol.spliceOwner, s"derivedSchema${stack.size}", TypeRepr.of[Schema[T]], Flags.Lazy, Symbol.noSymbol) - val selfRef = Ref(selfRefSymbol) - - val typeInfo = '{TypeId.parse(${Expr(TypeRepr.of[T].show)})} - val annotationExprs = TypeRepr.of[T].typeSymbol.annotations.filter (filterAnnotation).map (_.asExpr) - val annotations = '{zio.Chunk.fromIterable (${Expr.ofSeq (annotationExprs)})} - - val constructor = '{() => ${Ref(TypeRepr.of[T].typeSymbol.companionModule).asExprOf[T]}} - val ctor = typeRprOf[T](0).typeSymbol.companionModule - val args = List(typeInfo, constructor, annotations) - - val applied = Apply( - TypeApply( - Select.unique(Ref(ctor), "apply"), - List(TypeRepr.of[T].asType match { - case '[tt] => TypeTree.of[tt] - })), - args.map(_.asTerm) - ) - - val lazyValDef = ValDef(selfRefSymbol, Some(applied.changeOwner(selfRefSymbol))) - - applied.asExpr match { - case '{ type tt <: Schema[T]; $ex : `tt` } => - '{ - ${Block( - List(lazyValDef), - selfRef - ).asExpr}.asInstanceOf[tt] - } - } - } - - def deriveCaseClass[T: Type](mirror: Mirror, stack: Stack, top: Boolean)(using Quotes) = { - val selfRefSymbol = Symbol.newVal(Symbol.spliceOwner, s"derivedSchema${stack.size}", TypeRepr.of[Schema[T]], Flags.Lazy, Symbol.noSymbol) - val selfRef = Ref(selfRefSymbol) - val newStack = stack.push(selfRef, TypeRepr.of[T]) - - val labels = mirror.labels.toList - val types = mirror.types.toList - val typesAndLabels = types.zip(labels) - - val paramAnns = fromConstructor(TypeRepr.of[T].typeSymbol) - val constructor = caseClassConstructor[T](mirror).asExpr - - val annotationExprs = TypeRepr.of[T].typeSymbol.annotations.filter(filterAnnotation).map(_.asExpr) - val annotations = '{ zio.Chunk.fromIterable(${Expr.ofSeq(annotationExprs)}) } - val typeInfo = '{TypeId.parse(${Expr(TypeRepr.of[T].show)})} - - val applied = if (labels.length <= 22) { - - val typeArgs = - (types.appended(TypeRepr.of[T])).map { tpe => - tpe.asType match - case '[tt] => TypeTree.of[tt] - } - - val ctor = typeRprOf[T](labels.length).typeSymbol.companionModule - val typeAppliedCtor = TypeApply( - Select.unique(Ref(ctor), "apply"), - typeArgs - ) - - val fieldsAndFieldTypes = typesAndLabels.map { case (tpe, label) => deriveField[T](tpe, label, paramAnns.getOrElse(label, List.empty), newStack) } - val (fields, fieldTypes) = fieldsAndFieldTypes.unzip - val args = List(typeInfo) ++ fields ++ Seq(constructor) ++ Seq(annotations) - val terms = Expr.ofTupleFromSeq(args) - - if (labels.length > 0) { - val caseClassWithFieldsTpe = caseClassWithFieldsType(labels.length) - val appliedCaseClassWithFieldsTpe = caseClassWithFieldsTpe.appliedTo( - fieldTypes ++ types ++ List(TypeRepr.of[T]) - ) - - Select.unique(Apply( - typeAppliedCtor, - args.map(_.asTerm) - ), "asInstanceOf").appliedToType(appliedCaseClassWithFieldsTpe) - } else { - Apply( - typeAppliedCtor, - args.map(_.asTerm) - ) - } - } else { - val fieldsAndFieldTypes = typesAndLabels.map { case (tpe, label) => deriveGenericField[T](tpe, label, paramAnns.getOrElse(label, List.empty), newStack) } - val fields = fieldsAndFieldTypes.map(_._1) - val genericRecord = '{GenericRecord($typeInfo, FieldSet.fromFields(${Varargs(fields)} : _*), $annotations)} - - val s = TypeRepr.of[T].typeSymbol.declaredFields - - def casts(m: Expr[ListMap[String, _]])(using Quotes) = - typesAndLabels.map { case (tpe, label) => - val interestingField = s.find (_.name == label) - val fieldType = interestingField match { - case Some(interestingField) => - val ct = tpe.memberType (interestingField) - ct.asType - case None => - tpe.asType - } - fieldType match { case '[t] => - '{ try ${m}.apply(${Expr(label)}).asInstanceOf[t] - catch { - case _: ClassCastException => throw new RuntimeException("Field " + ${Expr(label)} + " has invalid type") - case _: Throwable => throw new RuntimeException("Field " + ${Expr(label)} + " is missing") - } - }.asTerm - } - } - - def appliedConstructor(m: Expr[ListMap[String, _]])(using Quotes) = { - Apply(Select.unique(Ref(TypeRepr.of[T].typeSymbol.companionModule), "apply"), casts(m)).asExprOf[T] - } - - val fromMap = '{ (m: ListMap[String, _]) => - try { Right(${appliedConstructor('m)}) } catch { - case e: Throwable => Left(e.getMessage) - }} - - def tuples(b: Expr[T])(using Quotes) = - typesAndLabels.map { case (tpe, label) => - val interestingField = s.find (_.name == label) - val fieldType = interestingField match { - case Some(interestingField) => - val ct = tpe.memberType (interestingField) - ct.asType - case None => - tpe.asType - } - fieldType match { case '[t] => - '{(${Expr(label)}, ${Select.unique(b.asTerm, label).asExprOf[t]})} - } - } - val toMap = '{(b: T) => Right(ListMap.apply(${Varargs(tuples('b))} :_*)) } - - '{${genericRecord.asExprOf[GenericRecord]}.transformOrFail[T]($fromMap, $toMap)}.asTerm - } - - val lazyValDef = ValDef(selfRefSymbol, Some(applied.changeOwner(selfRefSymbol))) - - applied.asExpr match { - case '{ type tt <: Schema[T]; $ex : `tt` } => - '{ - ${Block( - List(lazyValDef), - selfRef - ).asExpr}.asInstanceOf[tt] - } - } - } - - - private def fromDeclarations(from: Symbol): List[(String, List[Expr[Any]])] = - from.declaredFields.map { - field => - field.name -> field.annotations.filter(filterAnnotation).map(_.asExpr) - } - - private def fromConstructor(from: Symbol): scala.collection.Map[String, List[Expr[Any]]] = - from.primaryConstructor.paramSymss.flatten.map { field => - field.name -> field.annotations - .filter(filterAnnotation) - .map(_.asExpr.asInstanceOf[Expr[Any]]) - }.toMap - - def deriveEnum[T: Type](mirror: Mirror, stack: Stack)(using Quotes) = { - val selfRefSymbol = Symbol.newVal(Symbol.spliceOwner, s"derivedSchema${stack.size}", TypeRepr.of[Schema[T]], Flags.Lazy, Symbol.noSymbol) - val selfRef = Ref(selfRefSymbol) - val newStack = stack.push(selfRef, TypeRepr.of[T]) - - val labels = mirror.labels.toList - val types = mirror.types.toList - val typesAndLabels = types.zip(labels) - - val cases = typesAndLabels.map { case (tpe, label) => deriveCase[T](tpe, label, newStack) } - - val annotationExprs = TypeRepr.of[T].typeSymbol.annotations.filter(filterAnnotation).map(_.asExpr) - val annotations = '{ zio.Chunk.fromIterable(${Expr.ofSeq(annotationExprs)}) } - - val typeInfo = '{TypeId.parse(${Expr(TypeRepr.of[T].show)})} - - val applied = if (cases.length <= 22) { - val args = List(typeInfo) ++ cases :+ annotations - val terms = Expr.ofTupleFromSeq(args) - val ctor = TypeRepr.of[Enum2[_, _, _]].typeSymbol.primaryConstructor - - val typeArgs = - (types.appended(TypeRepr.of[T])).map { tpe => - tpe.asType match - case '[tt] => TypeTree.of[tt] - } - - val typeTree = enumTypeTree[T](labels.length) - - Apply( - TypeApply( - Select(New(typeTree), ctor), - typeArgs - ), - args.map(_.asTerm) - ) - } else { - '{EnumN($typeInfo, CaseSet(${Varargs(cases)}: _*).asInstanceOf[CaseSet.Aux[T]], $annotations) }.asTerm - } - - val lazyValDef = ValDef(selfRefSymbol, Some(applied.changeOwner(selfRefSymbol))) - - applied.asExpr match { - case '{ type tt <: Schema[T]; $ex : `tt` } => - '{ - ${Block( - List(lazyValDef), - selfRef - ).asExpr}.asInstanceOf[tt] - } - } - } - - - // Derive Field for a CaseClass - def deriveField[T: Type](repr: TypeRepr, name: String, anns: List[Expr[Any]], stack: Stack)(using Quotes) = { - import zio.schema.validation.Validation - import zio.schema.annotation.validate - - val tpe = TypeRepr.of[T] - val s = tpe.typeSymbol.declaredFields - val interestingField = s.find (_.name == name) - - val fieldType = interestingField match { - case Some(interestingField) => - val ct = tpe.memberType (interestingField) - ct.asType - case None => - repr.asType - } - fieldType match { case '[t] => - val schema = deriveSchema[t](stack) - val validations = anns.collect { - case ann if ann.isExprOf[validate[t]] => ann.asExprOf[validate[t]] - } - val validator: Expr[Validation[t]] = validations.foldLeft[Expr[Validation[t]]]('{Validation.succeed}){ - case (acc, expr) => '{ - $acc && ${expr}.validation - } - } - - val typeParams = TypeRepr.of[T].dealias match - case AppliedType (t, params) => params - case _ => Nil - - val get = '{ (t: T) => ${Select.unique('t.asTerm, name).asExprOf[t]} } - val set = '{ (ts: T, v: t) => ${Select.overloaded('ts.asTerm, "copy", typeParams, List(NamedArg(name, 'v.asTerm))).asExprOf[T]} } - val chunk = '{ zio.Chunk.fromIterable(${ Expr.ofSeq(anns.reverse) }) } - - if (anns.nonEmpty) { - val (newName, newNameValue) = anns.collectFirst { - case ann if ann.isExprOf[fieldName] => - val fieldNameAnn = ann.asExprOf[fieldName] - ('{${fieldNameAnn}.name}, extractFieldNameValue(fieldNameAnn)) - }.getOrElse((Expr(name), name)) - - val f = '{ Field($newName, $schema, $chunk, $validator, $get, $set)} - addFieldName(newNameValue)(f) // TODO: we need to pass the evaluated annotation value instead of name - } else { - val f = '{ Field(${Expr(name)}, $schema, $chunk, $validator, $get, $set) } - addFieldName(name)(f) - } - } - } - -// Derive Field for a GenericRecord - def deriveGenericField[T: Type](repr: TypeRepr, name: String, anns: List[Expr[Any]], stack: Stack)(using Quotes) = { - import zio.schema.validation.Validation - import zio.schema.annotation.validate - - val tpe = TypeRepr.of[T] - val s = tpe.typeSymbol.declaredFields - val interestingField = s.find (_.name == name) - - val fieldType = interestingField match { - case Some(interestingField) => - val ct = tpe.memberType (interestingField) - ct.asType - case None => - repr.asType - } - fieldType match { case '[t] => - val schema = deriveSchema[t](stack) - val validations = anns.collect { - case ann if ann.isExprOf[validate[t]] => ann.asExprOf[validate[t]] - } - val validator: Expr[Validation[t]] = validations.foldLeft[Expr[Validation[t]]]('{Validation.succeed}){ - case (acc, expr) => '{ - $acc && ${expr}.validation - } - } - - val typeParams = TypeRepr.of[T].dealias match - case AppliedType (t, params) => params - case _ => Nil - - val get = '{ (t: ListMap[String, _]) => t.apply(${Expr(name)}).asInstanceOf[t] } - val set = '{ (ts: ListMap[String, _], v: t) => ts.updated(${Expr(name)}, v) } - val chunk = '{ zio.Chunk.fromIterable(${ Expr.ofSeq(anns.reverse) }) } - - if (anns.nonEmpty) { - val newName = anns.collectFirst { - case ann if ann.isExprOf[fieldName] => '{${ann.asExprOf[fieldName]}.name} - }.getOrElse(Expr(name)) - - val f = '{ Field($newName, $schema, $chunk, $validator, $get, $set) } - addFieldName(name)(f) // TODO: we need to pass the evaluated annotation value instead of name - } else { - val f = '{ Field(${Expr(name)}, $schema, $chunk, $validator, $get, $set) } - addFieldName(name)(f) - } - } - } - - def addFieldName[R: Type, T: Type, F <: Field[R, T]: Type](name: String)(f: Expr[F])(using Quotes) = { - val withFieldName = TypeRepr.of[Field.WithFieldName] - val r = TypeRepr.of[R] - val t = TypeRepr.of[T] - val nameT = ConstantType(StringConstant(name)) - val fieldWithName = withFieldName.appliedTo(List(r, nameT, t)) - (Select.unique(f.asTerm, "asInstanceOf").appliedToType(fieldWithName).asExprOf[F], nameT) - } - - - // sealed case class Case[A, Z](id: String, codec: Schema[A], unsafeDeconstruct: Z => A, annotations: Chunk[Any] = Chunk.empty) { - def deriveCase[T: Type](repr: TypeRepr, label: String, stack: Stack)(using Quotes) = { - repr.asType match { case '[t] => - val schema = deriveSchema[t](stack) - val stringExpr = Expr(label) - - val annotationExprs = TypeRepr.of[t].typeSymbol.annotations.filter(filterAnnotation).map(_.asExpr) - val annotations = '{ zio.Chunk.fromIterable(${Expr.ofSeq(annotationExprs)}) } - - val unsafeDeconstruct = '{ - (z: T) => z.asInstanceOf[t] - } - val construct = '{ - (a: t) => a.asInstanceOf[T] - } - - val isCase = '{ (z: T) => z.isInstanceOf[t @unchecked] } - - '{ Case(${Expr(label)}, $schema, $unsafeDeconstruct, $construct, $isCase, $annotations) } - } - } - - - def caseClassConstructor[T: Type](mirror: Mirror) = { - val product = Expr.summon[scala.deriving.Mirror.ProductOf[T]].get - val methodType = MethodType(mirror.labels.toList)(_ => mirror.types.toList, _ => TypeRepr.of[T]) - Lambda(Symbol.spliceOwner, methodType, { (sym, reprs) => - val tupled = Expr.ofTupleFromSeq(reprs.map(_.asExpr)) - Select.overloaded(product.asTerm, "fromProduct", List.empty, List(tupled.asTerm)) - }) - } - - private def filterAnnotation(a: Term): Boolean = - a.tpe.typeSymbol.maybeOwner.isNoSymbol || - a.tpe.typeSymbol.owner.fullName != "scala.annotation.internal" - - def extractFieldNameValue(attribute: Expr[fieldName]): String = - attribute.asTerm match { - // Apply(Select(New(Ident(fieldName)),),List(Literal(Constant(renamed)))) - case Apply(_, List(Literal(StringConstant(name)))) => - name - } - - def caseClassTypeTree[T: Type](arity: Int): TypeTree = - arity match { - case 0 => TypeTree.of[CaseClass0[T]] - case 1 => TypeTree.of[CaseClass1[_, T]] - case 2 => TypeTree.of[CaseClass2[_, _, T]] - case 3 => TypeTree.of[CaseClass3[_, _, _, T]] - case 4 => TypeTree.of[CaseClass4[_, _, _, _, T]] - case 5 => TypeTree.of[CaseClass5[_, _, _, _, _, T]] - case 6 => TypeTree.of[CaseClass6[_, _, _, _, _, _, T]] - case 7 => TypeTree.of[CaseClass7[_, _, _, _, _, _, _, T]] - case 8 => TypeTree.of[CaseClass8[_, _, _, _, _, _, _, _, T]] - case 9 => TypeTree.of[CaseClass9[_, _, _, _, _, _, _, _, _, T]] - case 10 => TypeTree.of[CaseClass10[_, _, _, _, _, _, _, _, _, _, T]] - case 11 => TypeTree.of[CaseClass11[_, _, _, _, _, _, _, _, _, _, _, T]] - case 12 => TypeTree.of[CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, T]] - case 13 => TypeTree.of[CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 14 => TypeTree.of[CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 15 => TypeTree.of[CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 16 => TypeTree.of[CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 17 => TypeTree.of[CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 18 => TypeTree.of[CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 19 => TypeTree.of[CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 20 => TypeTree.of[CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 21 => TypeTree.of[CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 22 => TypeTree.of[CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - } - - def typeRprOf[T: Type](arity: Int): TypeRepr = - arity match { - case 0 => TypeRepr.of[CaseClass0[T]] - case 1 => TypeRepr.of[CaseClass1[_, T]] - case 2 => TypeRepr.of[CaseClass2[_, _, T]] - case 3 => TypeRepr.of[CaseClass3[_, _, _, T]] - case 4 => TypeRepr.of[CaseClass4[_, _, _, _, T]] - case 5 => TypeRepr.of[CaseClass5[_, _, _, _, _, T]] - case 6 => TypeRepr.of[CaseClass6[_, _, _, _, _, _, T]] - case 7 => TypeRepr.of[CaseClass7[_, _, _, _, _, _, _, T]] - case 8 => TypeRepr.of[CaseClass8[_, _, _, _, _, _, _, _, T]] - case 9 => TypeRepr.of[CaseClass9[_, _, _, _, _, _, _, _, _, T]] - case 10 => TypeRepr.of[CaseClass10[_, _, _, _, _, _, _, _, _, _, T]] - case 11 => TypeRepr.of[CaseClass11[_, _, _, _, _, _, _, _, _, _, _, T]] - case 12 => TypeRepr.of[CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, T]] - case 13 => TypeRepr.of[CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 14 => TypeRepr.of[CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 15 => TypeRepr.of[CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 16 => TypeRepr.of[CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 17 => TypeRepr.of[CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 18 => TypeRepr.of[CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 19 => TypeRepr.of[CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 20 => TypeRepr.of[CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 21 => TypeRepr.of[CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 22 => TypeRepr.of[CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - } - - def caseClassWithFieldsType(arity: Int): TypeRepr = - arity match { - case 1 => TypeRepr.of[CaseClass1.WithFields] - case 2 => TypeRepr.of[CaseClass2.WithFields] - case 3 => TypeRepr.of[CaseClass3.WithFields] - case 4 => TypeRepr.of[CaseClass4.WithFields] - case 5 => TypeRepr.of[CaseClass5.WithFields] - case 6 => TypeRepr.of[CaseClass6.WithFields] - case 7 => TypeRepr.of[CaseClass7.WithFields] - case 8 => TypeRepr.of[CaseClass8.WithFields] - case 9 => TypeRepr.of[CaseClass9.WithFields] - case 10 => TypeRepr.of[CaseClass10.WithFields] - case 11 => TypeRepr.of[CaseClass11.WithFields] - case 12 => TypeRepr.of[CaseClass12.WithFields] - case 13 => TypeRepr.of[CaseClass13.WithFields] - case 14 => TypeRepr.of[CaseClass14.WithFields] - case 15 => TypeRepr.of[CaseClass15.WithFields] - case 16 => TypeRepr.of[CaseClass16.WithFields] - case 17 => TypeRepr.of[CaseClass17.WithFields] - case 18 => TypeRepr.of[CaseClass18.WithFields] - case 19 => TypeRepr.of[CaseClass19.WithFields] - case 20 => TypeRepr.of[CaseClass20.WithFields] - case 21 => TypeRepr.of[CaseClass21.WithFields] - case 22 => TypeRepr.of[CaseClass22.WithFields] - } - - def enumTypeTree[T: Type](arity: Int): TypeTree = - arity match { - case 0 => TypeTree.of[CaseClass0[T]] - case 1 => TypeTree.of[Enum1[_, T]] - case 2 => TypeTree.of[Enum2[_, _, T]] - case 3 => TypeTree.of[Enum3[_, _, _, T]] - case 4 => TypeTree.of[Enum4[_, _, _, _, T]] - case 5 => TypeTree.of[Enum5[_, _, _, _, _, T]] - case 6 => TypeTree.of[Enum6[_, _, _, _, _, _, T]] - case 7 => TypeTree.of[Enum7[_, _, _, _, _, _, _, T]] - case 8 => TypeTree.of[Enum8[_, _, _, _, _, _, _, _, T]] - case 9 => TypeTree.of[Enum9[_, _, _, _, _, _, _, _, _, T]] - case 10 => TypeTree.of[Enum10[_, _, _, _, _, _, _, _, _, _, T]] - case 11 => TypeTree.of[Enum11[_, _, _, _, _, _, _, _, _, _, _, T]] - case 12 => TypeTree.of[Enum12[_, _, _, _, _, _, _, _, _, _, _, _, T]] - case 13 => TypeTree.of[Enum13[_, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 14 => TypeTree.of[Enum14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 15 => TypeTree.of[Enum15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 16 => TypeTree.of[Enum16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 17 => TypeTree.of[Enum17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 18 => TypeTree.of[Enum18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 19 => TypeTree.of[Enum19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 20 => TypeTree.of[Enum20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 21 => TypeTree.of[Enum21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - case 22 => TypeTree.of[Enum22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] - } - -} - +package zio.schema + +import scala.quoted._ +import scala.deriving.Mirror +import scala.compiletime.{erasedValue, summonInline, constValueTuple} +import scala.collection.immutable.ListMap +import Schema._ + +import zio.schema.annotation.fieldName + +extension (s: Schema.type) transparent inline def derived[A] = DeriveSchema.gen[A] + +object DeriveSchema { + + transparent inline def gen[T]: Schema[T] = ${ deriveSchema[T] } + + private def deriveSchema[T: Type](using Quotes): Expr[Schema[T]] = + DeriveSchema().deriveSchema[T](top = true) +} + +private case class DeriveSchema()(using val ctx: Quotes) extends ReflectionUtils(ctx) { + import ctx.reflect._ + + case class Frame(ref: Term, tpe: TypeRepr) + case class Stack(frames: List[Frame]) { + def find(tpe: TypeRepr): Option[Term] = frames.find(_.tpe =:= tpe).map(_.ref) + + def push(ref: Term, tpe: TypeRepr): Stack = Stack(Frame(ref, tpe) :: frames) + + def pop: Stack = Stack(frames.tail) + + def size = frames.size + + override def toString = + frames.map(f => s"${f.ref.show} : ${f.tpe.show}").mkString("Stack(", ", ", ")") + } + + object Stack { + val empty: Stack = Stack(Nil) + } + + var depth = 0 + + def deriveSchema[T: Type](stack: Stack = Stack.empty, top: Boolean = false)(using Quotes): Expr[Schema[T]] = { + depth += 1 + if (depth > 1024) + throw new Exception("Schema derivation exceeded") + + val typeRepr = TypeRepr.of[T] + val result = stack.find(typeRepr) match { + case Some(ref) => + '{ Schema.defer(${ref.asExprOf[Schema[T]]}) } + case None => + typeRepr.asType match { + case '[List[a]] => + val schema = deriveSchema[a](stack) + '{ Schema.list(Schema.defer(${schema})) }.asExprOf[Schema[T]] + case '[zio.prelude.Validation[a, b]] => + val schemaA = deriveSchema[a](stack) + val schemaB = deriveSchema[b](stack) + '{ Schema.either(Schema.defer(${schemaA}), Schema.defer(${schemaB})) }.asExprOf[Schema[T]] + case '[Option[a]] => + val schema = deriveSchema[a](stack) + // throw new Error(s"OPITOS ${schema.show}") + '{ Schema.option(Schema.defer($schema)) }.asExprOf[Schema[T]] + case '[scala.collection.Set[a]] => + val schema = deriveSchema[a](stack) + '{ Schema.set(Schema.defer(${schema})) }.asExprOf[Schema[T]] + case '[Vector[a]] => + val schema = deriveSchema[a](stack) + '{ Schema.vector(Schema.defer(${schema})) }.asExprOf[Schema[T]] + case '[scala.collection.Map[a, b]] => + val schemaA = deriveSchema[a](stack) + val schemaB = deriveSchema[b](stack) + '{ Schema.map(Schema.defer(${schemaA}), Schema.defer(${schemaB})) }.asExprOf[Schema[T]] + case '[zio.Chunk[a]] => + val schema = deriveSchema[a](stack) + '{ Schema.chunk(Schema.defer(${schema})) }.asExprOf[Schema[T]] + case _ => + val summoned = if (!top) Expr.summon[Schema[T]] else None + summoned match { + case Some(schema) => + // println(s"FOR TYPE ${typeRepr.show}") + // println(s"STACK ${stack.find(typeRepr)}") + // println(s"Found schema ${schema.show}") + schema + case _ => + Mirror(typeRepr) match { + case Some(mirror) => + mirror.mirrorType match { + case MirrorType.Sum => + deriveEnum[T](mirror, stack) + case MirrorType.Product => + deriveCaseClass[T](mirror, stack, top) + } + case None => + val sym = typeRepr.typeSymbol + if (sym.isClassDef && sym.flags.is(Flags.Module)) { + deriveCaseObject[T](stack, top) + } + else { + report.errorAndAbort(s"Deriving schema for ${typeRepr.show} is not supported") + } + } + } + } + } + + //println() + //println() + //println(s"RESULT ${typeRepr.show}") + //println(s"------") + //println(s"RESULT ${result.show}") + + result + } + + def deriveCaseObject[T: Type](stack: Stack, top: Boolean)(using Quotes) = { + val selfRefSymbol = Symbol.newVal(Symbol.spliceOwner, s"derivedSchema${stack.size}", TypeRepr.of[Schema[T]], Flags.Lazy, Symbol.noSymbol) + val selfRef = Ref(selfRefSymbol) + + val typeInfo = '{TypeId.parse(${Expr(TypeRepr.of[T].show)})} + val annotationExprs = TypeRepr.of[T].typeSymbol.annotations.filter (filterAnnotation).map (_.asExpr) + val annotations = '{zio.Chunk.fromIterable (${Expr.ofSeq (annotationExprs)})} + + val constructor = '{() => ${Ref(TypeRepr.of[T].typeSymbol.companionModule).asExprOf[T]}} + val ctor = typeRprOf[T](0).typeSymbol.companionModule + val args = List(typeInfo, constructor, annotations) + + val applied = Apply( + TypeApply( + Select.unique(Ref(ctor), "apply"), + List(TypeRepr.of[T].asType match { + case '[tt] => TypeTree.of[tt] + })), + args.map(_.asTerm) + ) + + val lazyValDef = ValDef(selfRefSymbol, Some(applied.changeOwner(selfRefSymbol))) + + applied.asExpr match { + case '{ type tt <: Schema[T]; $ex : `tt` } => + '{ + ${Block( + List(lazyValDef), + selfRef + ).asExpr}.asInstanceOf[tt] + } + } + } + + def deriveCaseClass[T: Type](mirror: Mirror, stack: Stack, top: Boolean)(using Quotes) = { + val selfRefSymbol = Symbol.newVal(Symbol.spliceOwner, s"derivedSchema${stack.size}", TypeRepr.of[Schema[T]], Flags.Lazy, Symbol.noSymbol) + val selfRef = Ref(selfRefSymbol) + val newStack = stack.push(selfRef, TypeRepr.of[T]) + + val labels = mirror.labels.toList + val types = mirror.types.toList + val typesAndLabels = types.zip(labels) + + val paramAnns = fromConstructor(TypeRepr.of[T].typeSymbol) + val constructor = caseClassConstructor[T](mirror).asExpr + + val annotationExprs = TypeRepr.of[T].typeSymbol.annotations.filter(filterAnnotation).map(_.asExpr) + val annotations = '{ zio.Chunk.fromIterable(${Expr.ofSeq(annotationExprs)}) } + val typeInfo = '{TypeId.parse(${Expr(TypeRepr.of[T].show)})} + + val applied = if (labels.length <= 22) { + + val typeArgs = + (types.appended(TypeRepr.of[T])).map { tpe => + tpe.asType match + case '[tt] => TypeTree.of[tt] + } + + val ctor = typeRprOf[T](labels.length).typeSymbol.companionModule + val typeAppliedCtor = TypeApply( + Select.unique(Ref(ctor), "apply"), + typeArgs + ) + + val fieldsAndFieldTypes = typesAndLabels.map { case (tpe, label) => deriveField[T](tpe, label, paramAnns.getOrElse(label, List.empty), newStack) } + val (fields, fieldTypes) = fieldsAndFieldTypes.unzip + val args = List(typeInfo) ++ fields ++ Seq(constructor) ++ Seq(annotations) + val terms = Expr.ofTupleFromSeq(args) + + if (labels.length > 0) { + val caseClassWithFieldsTpe = caseClassWithFieldsType(labels.length) + val appliedCaseClassWithFieldsTpe = caseClassWithFieldsTpe.appliedTo( + fieldTypes ++ types ++ List(TypeRepr.of[T]) + ) + + Select.unique(Apply( + typeAppliedCtor, + args.map(_.asTerm) + ), "asInstanceOf").appliedToType(appliedCaseClassWithFieldsTpe) + } else { + Apply( + typeAppliedCtor, + args.map(_.asTerm) + ) + } + } else { + val fieldsAndFieldTypes = typesAndLabels.map { case (tpe, label) => deriveGenericField[T](tpe, label, paramAnns.getOrElse(label, List.empty), newStack) } + val fields = fieldsAndFieldTypes.map(_._1) + val genericRecord = '{GenericRecord($typeInfo, FieldSet.fromFields(${Varargs(fields)} : _*), $annotations)} + + val s = TypeRepr.of[T].typeSymbol.declaredFields + + def casts(m: Expr[ListMap[String, _]])(using Quotes) = + typesAndLabels.map { case (tpe, label) => + val interestingField = s.find (_.name == label) + val fieldType = interestingField match { + case Some(interestingField) => + val ct = tpe.memberType (interestingField) + ct.asType + case None => + tpe.asType + } + fieldType match { case '[t] => + '{ try ${m}.apply(${Expr(label)}).asInstanceOf[t] + catch { + case _: ClassCastException => throw new RuntimeException("Field " + ${Expr(label)} + " has invalid type") + case _: Throwable => throw new RuntimeException("Field " + ${Expr(label)} + " is missing") + } + }.asTerm + } + } + + def appliedConstructor(m: Expr[ListMap[String, _]])(using Quotes) = { + Apply(Select.unique(Ref(TypeRepr.of[T].typeSymbol.companionModule), "apply"), casts(m)).asExprOf[T] + } + + val fromMap = '{ (m: ListMap[String, _]) => + try { zio.prelude.Validation.succeed(${appliedConstructor('m)}) } catch { + case e: Throwable => zio.prelude.Validation.fail(e.getMessage) + }} + + def tuples(b: Expr[T])(using Quotes) = + typesAndLabels.map { case (tpe, label) => + val interestingField = s.find (_.name == label) + val fieldType = interestingField match { + case Some(interestingField) => + val ct = tpe.memberType (interestingField) + ct.asType + case None => + tpe.asType + } + fieldType match { case '[t] => + '{(${Expr(label)}, ${Select.unique(b.asTerm, label).asExprOf[t]})} + } + } + val toMap = '{(b: T) => zio.prelude.Validation.succeed(ListMap.apply(${Varargs(tuples('b))} :_*)) } + + '{${genericRecord.asExprOf[GenericRecord]}.transformOrFail[T]($fromMap, $toMap)}.asTerm + } + + val lazyValDef = ValDef(selfRefSymbol, Some(applied.changeOwner(selfRefSymbol))) + + applied.asExpr match { + case '{ type tt <: Schema[T]; $ex : `tt` } => + '{ + ${Block( + List(lazyValDef), + selfRef + ).asExpr}.asInstanceOf[tt] + } + } + } + + + private def fromDeclarations(from: Symbol): List[(String, List[Expr[Any]])] = + from.declaredFields.map { + field => + field.name -> field.annotations.filter(filterAnnotation).map(_.asExpr) + } + + private def fromConstructor(from: Symbol): scala.collection.Map[String, List[Expr[Any]]] = + from.primaryConstructor.paramSymss.flatten.map { field => + field.name -> field.annotations + .filter(filterAnnotation) + .map(_.asExpr.asInstanceOf[Expr[Any]]) + }.toMap + + def deriveEnum[T: Type](mirror: Mirror, stack: Stack)(using Quotes) = { + val selfRefSymbol = Symbol.newVal(Symbol.spliceOwner, s"derivedSchema${stack.size}", TypeRepr.of[Schema[T]], Flags.Lazy, Symbol.noSymbol) + val selfRef = Ref(selfRefSymbol) + val newStack = stack.push(selfRef, TypeRepr.of[T]) + + val labels = mirror.labels.toList + val types = mirror.types.toList + val typesAndLabels = types.zip(labels) + + val cases = typesAndLabels.map { case (tpe, label) => deriveCase[T](tpe, label, newStack) } + + val annotationExprs = TypeRepr.of[T].typeSymbol.annotations.filter(filterAnnotation).map(_.asExpr) + val annotations = '{ zio.Chunk.fromIterable(${Expr.ofSeq(annotationExprs)}) } + + val typeInfo = '{TypeId.parse(${Expr(TypeRepr.of[T].show)})} + + val applied = if (cases.length <= 22) { + val args = List(typeInfo) ++ cases :+ annotations + val terms = Expr.ofTupleFromSeq(args) + val ctor = TypeRepr.of[Enum2[_, _, _]].typeSymbol.primaryConstructor + + val typeArgs = + (types.appended(TypeRepr.of[T])).map { tpe => + tpe.asType match + case '[tt] => TypeTree.of[tt] + } + + val typeTree = enumTypeTree[T](labels.length) + + Apply( + TypeApply( + Select(New(typeTree), ctor), + typeArgs + ), + args.map(_.asTerm) + ) + } else { + '{EnumN($typeInfo, CaseSet(${Varargs(cases)}: _*).asInstanceOf[CaseSet.Aux[T]], $annotations) }.asTerm + } + + val lazyValDef = ValDef(selfRefSymbol, Some(applied.changeOwner(selfRefSymbol))) + + applied.asExpr match { + case '{ type tt <: Schema[T]; $ex : `tt` } => + '{ + ${Block( + List(lazyValDef), + selfRef + ).asExpr}.asInstanceOf[tt] + } + } + } + + + // Derive Field for a CaseClass + def deriveField[T: Type](repr: TypeRepr, name: String, anns: List[Expr[Any]], stack: Stack)(using Quotes) = { + import zio.schema.validation.SchemaValidation + import zio.schema.annotation.validate + + val tpe = TypeRepr.of[T] + val s = tpe.typeSymbol.declaredFields + val interestingField = s.find (_.name == name) + + val fieldType = interestingField match { + case Some(interestingField) => + val ct = tpe.memberType (interestingField) + ct.asType + case None => + repr.asType + } + fieldType match { case '[t] => + val schema = deriveSchema[t](stack) + val validations = anns.collect { + case ann if ann.isExprOf[validate[t]] => ann.asExprOf[validate[t]] + } + val validator: Expr[SchemaValidation[t]] = validations.foldLeft[Expr[SchemaValidation[t]]]('{SchemaValidation.succeed}){ + case (acc, expr) => '{ + $acc && ${expr}.validation + } + } + + val typeParams = TypeRepr.of[T].dealias match + case AppliedType (t, params) => params + case _ => Nil + + val get = '{ (t: T) => ${Select.unique('t.asTerm, name).asExprOf[t]} } + val set = '{ (ts: T, v: t) => ${Select.overloaded('ts.asTerm, "copy", typeParams, List(NamedArg(name, 'v.asTerm))).asExprOf[T]} } + val chunk = '{ zio.Chunk.fromIterable(${ Expr.ofSeq(anns.reverse) }) } + + if (anns.nonEmpty) { + val (newName, newNameValue) = anns.collectFirst { + case ann if ann.isExprOf[fieldName] => + val fieldNameAnn = ann.asExprOf[fieldName] + ('{${fieldNameAnn}.name}, extractFieldNameValue(fieldNameAnn)) + }.getOrElse((Expr(name), name)) + + val f = '{ Field($newName, $schema, $chunk, $validator, $get, $set)} + addFieldName(newNameValue)(f) // TODO: we need to pass the evaluated annotation value instead of name + } else { + val f = '{ Field(${Expr(name)}, $schema, $chunk, $validator, $get, $set) } + addFieldName(name)(f) + } + } + } + +// Derive Field for a GenericRecord + def deriveGenericField[T: Type](repr: TypeRepr, name: String, anns: List[Expr[Any]], stack: Stack)(using Quotes) = { + import zio.schema.validation.SchemaValidation + import zio.schema.annotation.validate + + val tpe = TypeRepr.of[T] + val s = tpe.typeSymbol.declaredFields + val interestingField = s.find (_.name == name) + + val fieldType = interestingField match { + case Some(interestingField) => + val ct = tpe.memberType (interestingField) + ct.asType + case None => + repr.asType + } + fieldType match { case '[t] => + val schema = deriveSchema[t](stack) + val validations = anns.collect { + case ann if ann.isExprOf[validate[t]] => ann.asExprOf[validate[t]] + } + val validator: Expr[SchemaValidation[t]] = validations.foldLeft[Expr[SchemaValidation[t]]]('{SchemaValidation.succeed}){ + case (acc, expr) => '{ + $acc && ${expr}.validation + } + } + + val typeParams = TypeRepr.of[T].dealias match + case AppliedType (t, params) => params + case _ => Nil + + val get = '{ (t: ListMap[String, _]) => t.apply(${Expr(name)}).asInstanceOf[t] } + val set = '{ (ts: ListMap[String, _], v: t) => ts.updated(${Expr(name)}, v) } + val chunk = '{ zio.Chunk.fromIterable(${ Expr.ofSeq(anns.reverse) }) } + + if (anns.nonEmpty) { + val newName = anns.collectFirst { + case ann if ann.isExprOf[fieldName] => '{${ann.asExprOf[fieldName]}.name} + }.getOrElse(Expr(name)) + + val f = '{ Field($newName, $schema, $chunk, $validator, $get, $set) } + addFieldName(name)(f) // TODO: we need to pass the evaluated annotation value instead of name + } else { + val f = '{ Field(${Expr(name)}, $schema, $chunk, $validator, $get, $set) } + addFieldName(name)(f) + } + } + } + + def addFieldName[R: Type, T: Type, F <: Field[R, T]: Type](name: String)(f: Expr[F])(using Quotes) = { + val withFieldName = TypeRepr.of[Field.WithFieldName] + val r = TypeRepr.of[R] + val t = TypeRepr.of[T] + val nameT = ConstantType(StringConstant(name)) + val fieldWithName = withFieldName.appliedTo(List(r, nameT, t)) + (Select.unique(f.asTerm, "asInstanceOf").appliedToType(fieldWithName).asExprOf[F], nameT) + } + + + // sealed case class Case[A, Z](id: String, codec: Schema[A], unsafeDeconstruct: Z => A, annotations: Chunk[Any] = Chunk.empty) { + def deriveCase[T: Type](repr: TypeRepr, label: String, stack: Stack)(using Quotes) = { + repr.asType match { case '[t] => + val schema = deriveSchema[t](stack) + val stringExpr = Expr(label) + + val annotationExprs = TypeRepr.of[t].typeSymbol.annotations.filter(filterAnnotation).map(_.asExpr) + val annotations = '{ zio.Chunk.fromIterable(${Expr.ofSeq(annotationExprs)}) } + + val unsafeDeconstruct = '{ + (z: T) => z.asInstanceOf[t] + } + val construct = '{ + (a: t) => a.asInstanceOf[T] + } + + val isCase = '{ (z: T) => z.isInstanceOf[t @unchecked] } + + '{ Case(${Expr(label)}, $schema, $unsafeDeconstruct, $construct, $isCase, $annotations) } + } + } + + + def caseClassConstructor[T: Type](mirror: Mirror) = { + val product = Expr.summon[scala.deriving.Mirror.ProductOf[T]].get + val methodType = MethodType(mirror.labels.toList)(_ => mirror.types.toList, _ => TypeRepr.of[T]) + Lambda(Symbol.spliceOwner, methodType, { (sym, reprs) => + val tupled = Expr.ofTupleFromSeq(reprs.map(_.asExpr)) + Select.overloaded(product.asTerm, "fromProduct", List.empty, List(tupled.asTerm)) + }) + } + + private def filterAnnotation(a: Term): Boolean = + a.tpe.typeSymbol.maybeOwner.isNoSymbol || + a.tpe.typeSymbol.owner.fullName != "scala.annotation.internal" + + def extractFieldNameValue(attribute: Expr[fieldName]): String = + attribute.asTerm match { + // Apply(Select(New(Ident(fieldName)),),List(Literal(Constant(renamed)))) + case Apply(_, List(Literal(StringConstant(name)))) => + name + } + + def caseClassTypeTree[T: Type](arity: Int): TypeTree = + arity match { + case 0 => TypeTree.of[CaseClass0[T]] + case 1 => TypeTree.of[CaseClass1[_, T]] + case 2 => TypeTree.of[CaseClass2[_, _, T]] + case 3 => TypeTree.of[CaseClass3[_, _, _, T]] + case 4 => TypeTree.of[CaseClass4[_, _, _, _, T]] + case 5 => TypeTree.of[CaseClass5[_, _, _, _, _, T]] + case 6 => TypeTree.of[CaseClass6[_, _, _, _, _, _, T]] + case 7 => TypeTree.of[CaseClass7[_, _, _, _, _, _, _, T]] + case 8 => TypeTree.of[CaseClass8[_, _, _, _, _, _, _, _, T]] + case 9 => TypeTree.of[CaseClass9[_, _, _, _, _, _, _, _, _, T]] + case 10 => TypeTree.of[CaseClass10[_, _, _, _, _, _, _, _, _, _, T]] + case 11 => TypeTree.of[CaseClass11[_, _, _, _, _, _, _, _, _, _, _, T]] + case 12 => TypeTree.of[CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, T]] + case 13 => TypeTree.of[CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 14 => TypeTree.of[CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 15 => TypeTree.of[CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 16 => TypeTree.of[CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 17 => TypeTree.of[CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 18 => TypeTree.of[CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 19 => TypeTree.of[CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 20 => TypeTree.of[CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 21 => TypeTree.of[CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 22 => TypeTree.of[CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + } + + def typeRprOf[T: Type](arity: Int): TypeRepr = + arity match { + case 0 => TypeRepr.of[CaseClass0[T]] + case 1 => TypeRepr.of[CaseClass1[_, T]] + case 2 => TypeRepr.of[CaseClass2[_, _, T]] + case 3 => TypeRepr.of[CaseClass3[_, _, _, T]] + case 4 => TypeRepr.of[CaseClass4[_, _, _, _, T]] + case 5 => TypeRepr.of[CaseClass5[_, _, _, _, _, T]] + case 6 => TypeRepr.of[CaseClass6[_, _, _, _, _, _, T]] + case 7 => TypeRepr.of[CaseClass7[_, _, _, _, _, _, _, T]] + case 8 => TypeRepr.of[CaseClass8[_, _, _, _, _, _, _, _, T]] + case 9 => TypeRepr.of[CaseClass9[_, _, _, _, _, _, _, _, _, T]] + case 10 => TypeRepr.of[CaseClass10[_, _, _, _, _, _, _, _, _, _, T]] + case 11 => TypeRepr.of[CaseClass11[_, _, _, _, _, _, _, _, _, _, _, T]] + case 12 => TypeRepr.of[CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, T]] + case 13 => TypeRepr.of[CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 14 => TypeRepr.of[CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 15 => TypeRepr.of[CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 16 => TypeRepr.of[CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 17 => TypeRepr.of[CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 18 => TypeRepr.of[CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 19 => TypeRepr.of[CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 20 => TypeRepr.of[CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 21 => TypeRepr.of[CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 22 => TypeRepr.of[CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + } + + def caseClassWithFieldsType(arity: Int): TypeRepr = + arity match { + case 1 => TypeRepr.of[CaseClass1.WithFields] + case 2 => TypeRepr.of[CaseClass2.WithFields] + case 3 => TypeRepr.of[CaseClass3.WithFields] + case 4 => TypeRepr.of[CaseClass4.WithFields] + case 5 => TypeRepr.of[CaseClass5.WithFields] + case 6 => TypeRepr.of[CaseClass6.WithFields] + case 7 => TypeRepr.of[CaseClass7.WithFields] + case 8 => TypeRepr.of[CaseClass8.WithFields] + case 9 => TypeRepr.of[CaseClass9.WithFields] + case 10 => TypeRepr.of[CaseClass10.WithFields] + case 11 => TypeRepr.of[CaseClass11.WithFields] + case 12 => TypeRepr.of[CaseClass12.WithFields] + case 13 => TypeRepr.of[CaseClass13.WithFields] + case 14 => TypeRepr.of[CaseClass14.WithFields] + case 15 => TypeRepr.of[CaseClass15.WithFields] + case 16 => TypeRepr.of[CaseClass16.WithFields] + case 17 => TypeRepr.of[CaseClass17.WithFields] + case 18 => TypeRepr.of[CaseClass18.WithFields] + case 19 => TypeRepr.of[CaseClass19.WithFields] + case 20 => TypeRepr.of[CaseClass20.WithFields] + case 21 => TypeRepr.of[CaseClass21.WithFields] + case 22 => TypeRepr.of[CaseClass22.WithFields] + } + + def enumTypeTree[T: Type](arity: Int): TypeTree = + arity match { + case 0 => TypeTree.of[CaseClass0[T]] + case 1 => TypeTree.of[Enum1[_, T]] + case 2 => TypeTree.of[Enum2[_, _, T]] + case 3 => TypeTree.of[Enum3[_, _, _, T]] + case 4 => TypeTree.of[Enum4[_, _, _, _, T]] + case 5 => TypeTree.of[Enum5[_, _, _, _, _, T]] + case 6 => TypeTree.of[Enum6[_, _, _, _, _, _, T]] + case 7 => TypeTree.of[Enum7[_, _, _, _, _, _, _, T]] + case 8 => TypeTree.of[Enum8[_, _, _, _, _, _, _, _, T]] + case 9 => TypeTree.of[Enum9[_, _, _, _, _, _, _, _, _, T]] + case 10 => TypeTree.of[Enum10[_, _, _, _, _, _, _, _, _, _, T]] + case 11 => TypeTree.of[Enum11[_, _, _, _, _, _, _, _, _, _, _, T]] + case 12 => TypeTree.of[Enum12[_, _, _, _, _, _, _, _, _, _, _, _, T]] + case 13 => TypeTree.of[Enum13[_, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 14 => TypeTree.of[Enum14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 15 => TypeTree.of[Enum15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 16 => TypeTree.of[Enum16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 17 => TypeTree.of[Enum17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 18 => TypeTree.of[Enum18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 19 => TypeTree.of[Enum19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 20 => TypeTree.of[Enum20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 21 => TypeTree.of[Enum21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + case 22 => TypeTree.of[Enum22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, T]] + } + +} + diff --git a/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSchemaSpec.scala b/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSchemaSpec.scala index dd37ad614..0421fc248 100644 --- a/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSchemaSpec.scala +++ b/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSchemaSpec.scala @@ -376,12 +376,12 @@ object DeriveSchemaSpec extends ZIOSpecDefault with VersionSpecificDeriveSchemaS val a = DependsOnA(Some(DependsOnB(None))) val a0 = Schema[DependsOnA].fromDynamic(Schema[DependsOnA].toDynamic(a)) assert(Schema[DependsOnA])(anything) - assert(a0)(isRight(equalTo(a))) + assert(a0.toEither)(isRight(equalTo(a))) val b = DependsOnB(Some(DependsOnA(None))) val b0 = Schema[DependsOnB].fromDynamic(Schema[DependsOnB].toDynamic(b)) assert(Schema[DependsOnB])(anything) - assert(b0)(isRight(equalTo(b))) + assert(b0.toEither)(isRight(equalTo(b))) }, test("correctly derives recursive Enum with type parameters") { val derived: Schema[Tree[Recursive]] = DeriveSchema.gen[Tree[Recursive]] diff --git a/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala b/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala index 20b004a44..352062601 100644 --- a/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala +++ b/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala @@ -223,7 +223,7 @@ object DeriveSpec extends ZIOSpecDefault with VersionSpecificDeriveSpec { implicit val schema: Schema[Record5] = DeriveSchema.gen[Record5] } - case class Record6(map: Map[String, Record1], either: Either[String, Record2]) + case class Record6(map: Map[String, Record1], either: scala.Either[String, Record2]) object Record6 { implicit val schema: Schema[Record6] = DeriveSchema.gen[Record6] diff --git a/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala b/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaSchemaValidationSpec.scala similarity index 52% rename from zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala rename to zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaSchemaValidationSpec.scala index 4173f3de2..6b880aaf6 100644 --- a/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala +++ b/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaSchemaValidationSpec.scala @@ -3,14 +3,14 @@ package zio.schema import zio._ import zio.schema.Schema._ import zio.schema.annotation.validate -import zio.schema.validation.{ Validation, ValidationError } +import zio.schema.validation.{ SchemaValidation, SchemaValidationError } import zio.test._ -object SchemaValidationSpec extends ZIOSpecDefault { +object SchemaSchemaValidationSpec extends ZIOSpecDefault { import Assertion._ final case class ExampleData( - either: scala.util.Either[Person, Person] = Right(goodData), + either: scala.Either[Person, Person] = Right(goodData), option: Option[Person] = None, list: List[Person] = goodData :: Nil, tuple: scala.Tuple2[Person, Person] = (goodData, goodData), @@ -29,76 +29,76 @@ object SchemaValidationSpec extends ZIOSpecDefault { final case class Wrapper(person: Person) implicit val schema - : CaseClass6[scala.util.Either[Person, Person], Option[Person], List[Person], (Person, Person), Wrapper, EnumData, ExampleData] = + : CaseClass6[scala.Either[Person, Person], Option[Person], List[Person], (Person, Person), Wrapper, EnumData, ExampleData] = DeriveSchema.gen[ExampleData] val badData: Person = Person("foo", 123123123) val goodData: Person = Person("foo", 100) - final case class Person(name: String, @validate(Validation.between(0, 120)) age: Int) + final case class Person(name: String, @validate(SchemaValidation.between(0, 120)) age: Int) // val schemaCaseClass2: Schema.CaseClass2[String, Int, Person] = DeriveSchema.gen[Person] val schemaPerson: CaseClass2[String, Int, Person] = DeriveSchema.gen[Person] - final case class Grade(@validate(Validation.greaterThan(0)) value: Int) + final case class Grade(@validate(SchemaValidation.greaterThan(0)) value: Int) // val schemaCaseClass1: Schema.CaseClass1[Int, Grade] = DeriveSchema.gen[Grade] val schemaGrade: CaseClass1[Int, Grade] = DeriveSchema.gen[Grade] override def spec: Spec[Environment, Any] = suite("Schema Validation Spec")( test("Invalid CaseClass1 creation") { - val grade = Grade(-50) - implicit val gradeSchema: Schema[Grade] = schemaGrade - val validated: Chunk[ValidationError] = Schema.validate(grade) + val grade = Grade(-50) + implicit val gradeSchema: Schema[Grade] = schemaGrade + val validated: Chunk[SchemaValidationError] = Schema.validate(grade) - val expected: Chunk[ValidationError] = - Chunk(ValidationError.GreaterThan(-50, 0)) + val expected: Chunk[SchemaValidationError] = + Chunk(SchemaValidationError.GreaterThan(-50, 0)) assert(validated)(Assertion.hasSameElements(expected)) }, test("Valid CaseClass1 creation") { - val grade = Grade(97) - implicit val gradeSchema: Schema[Grade] = schemaGrade - val validated: Chunk[ValidationError] = Schema.validate(grade) + val grade = Grade(97) + implicit val gradeSchema: Schema[Grade] = schemaGrade + val validated: Chunk[SchemaValidationError] = Schema.validate(grade) - val expected: Chunk[ValidationError] = Chunk.empty + val expected: Chunk[SchemaValidationError] = Chunk.empty assert(validated)(equalTo(expected)) }, test("Invalid CaseClass2 creation") { - val person = Person("Michelle", 200) - implicit val personSchema: Schema[Person] = schemaPerson - val validated: Chunk[ValidationError] = Schema.validate(person) + val person = Person("Michelle", 200) + implicit val personSchema: Schema[Person] = schemaPerson + val validated: Chunk[SchemaValidationError] = Schema.validate(person) - val expected: Chunk[ValidationError] = - Chunk(ValidationError.LessThan(200, 120), ValidationError.EqualTo(200, 120)) + val expected: Chunk[SchemaValidationError] = + Chunk(SchemaValidationError.LessThan(200, 120), SchemaValidationError.EqualTo(200, 120)) assert(validated)(Assertion.hasSameElements(expected)) }, test("Valid CaseClass2 creation") { - val person = Person("Michelle", 20) - implicit val personSchema: Schema[Person] = schemaPerson - val validated: Chunk[ValidationError] = Schema.validate(person) + val person = Person("Michelle", 20) + implicit val personSchema: Schema[Person] = schemaPerson + val validated: Chunk[SchemaValidationError] = Schema.validate(person) - val expected: Chunk[ValidationError] = Chunk.empty + val expected: Chunk[SchemaValidationError] = Chunk.empty assert(validated)(Assertion.hasSameElements(expected)) }, test("Example Data, no ValidationErrors") { val exampleData = ExampleData() - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk.empty + val expected: Chunk[SchemaValidationError] = Chunk.empty assert(validated)(hasSameElements(expected)) }, test("Example Data, Left ValidationError") { val exampleData = ExampleData(either = Left(badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -106,11 +106,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, Right ValidationError") { val exampleData = ExampleData(either = Right(badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -118,20 +118,20 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, Option value without ValidationError") { val exampleData = ExampleData(option = Some(goodData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk.empty + val expected: Chunk[SchemaValidationError] = Chunk.empty assert(validated)(Assertion.hasSameElements(expected)) }, test("Example Data, Option value with ValidationError") { val exampleData = ExampleData(option = Some(badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -139,11 +139,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, single element List with ValidationError") { val exampleData = ExampleData(list = badData :: Nil) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -151,11 +151,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, multi element List with ValidationError") { val exampleData = ExampleData(list = goodData :: goodData :: badData :: Nil) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -163,11 +163,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, Tuple with ValidationError on first element") { val exampleData = ExampleData(tuple = (badData, goodData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -175,11 +175,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, Tuple with ValidationError on second element") { val exampleData = ExampleData(tuple = (goodData, badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -187,11 +187,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, Wrapper class wrapping class with ValidationError") { val exampleData = ExampleData(wrapper = Wrapper(badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -199,11 +199,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, first Enum with ValidationError") { val exampleData = ExampleData(enumData = EnumData.Case1(badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -211,11 +211,11 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Example Data, second Enum with ValidationError") { val exampleData = ExampleData(enumData = EnumData.Case2(badData)) - val validated: Chunk[ValidationError] = Schema.validate(exampleData) + val validated: Chunk[SchemaValidationError] = Schema.validate(exampleData) - val expected: Chunk[ValidationError] = Chunk( - ValidationError.LessThan(123123123, 120), - ValidationError.EqualTo(123123123, 120) + val expected: Chunk[SchemaValidationError] = Chunk( + SchemaValidationError.LessThan(123123123, 120), + SchemaValidationError.EqualTo(123123123, 120) ) assert(validated)(Assertion.hasSameElements(expected)) @@ -240,7 +240,7 @@ object SchemaValidationSpec extends ZIOSpecDefault { test("Validator successfully extracts from validation annotation") { val validation = schemaPerson.field2.validation - assertTrue(validation.validate(45).isRight) && assertTrue(validation.validate(-20).isLeft) + assertTrue(validation.validate(45).toEither.isRight) && assertTrue(validation.validate(-20).toEither.isLeft) } ) } diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala deleted file mode 100644 index 7a9b2188a..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example1/Example1.scala +++ /dev/null @@ -1,244 +0,0 @@ -package dev.zio.schema.example.example1 - -import zio._ -import zio.schema.{ DeriveSchema, Schema, TypeId } -import zio.stream.ZPipeline - -/** - * Example 1 of ZIO-Schema: - * - * In this example we define our basic Domain Model. - * Then we'll show how to manually construct a Schema for the given domain model - * and how to derive one using macros. - * - * We'll then use the Schema to transform instances of our classes (Person) to/from JSON and Protobuf. - */ - -object Domain { - sealed trait PaymentMethod - - final case class Person(name: String, age: Int) - - final case class Customer(person: Person, paymentMethod: PaymentMethod) - - object PaymentMethod { - final case class CreditCard(number: String, expirationMonth: Int, expirationYear: Int) extends PaymentMethod - final case class WireTransfer(accountNumber: String, bankCode: String) extends PaymentMethod - } -} - -import dev.zio.schema.example.example1.Domain._ - -object ManualConstruction { - import Domain.PaymentMethod._ - import zio.schema.Schema._ - - val schemaPerson: Schema[Person] = Schema.CaseClass2[String, Int, Person]( - TypeId.parse("dev.zio.schema.example.example1.Domain.Person"), - field01 = - Schema.Field[Person, String]("name", Schema.primitive[String], get0 = _.name, set0 = (p, v) => p.copy(name = v)), - field02 = Schema.Field[Person, Int]("age", Schema.primitive[Int], get0 = _.age, set0 = (p, v) => p.copy(age = v)), - construct0 = (name, age) => Person(name, age) - ) - - val schemaPaymentMethodWireTransfer: Schema[WireTransfer] = Schema.CaseClass2[String, String, WireTransfer]( - TypeId.parse("dev.zio.schema.example.example1.Domain.PaymentMethod.WireTransfer"), - field01 = Schema.Field[WireTransfer, String]( - "accountNumber", - Schema.primitive[String], - get0 = _.accountNumber, - set0 = (p, v) => p.copy(accountNumber = v) - ), - field02 = Schema.Field[WireTransfer, String]( - "bankCode", - Schema.primitive[String], - get0 = _.bankCode, - set0 = (p, v) => p.copy(bankCode = v) - ), - construct0 = (number, bankCode) => PaymentMethod.WireTransfer(number, bankCode) - ) - - val schemaPaymentMethodCreditCard: Schema[CreditCard] = Schema.CaseClass3[String, Int, Int, CreditCard]( - TypeId.parse("dev.zio.schema.example.example1.Domain.PaymentMethod.CreditCard"), - field01 = Schema.Field[CreditCard, String]( - "number", - Schema.primitive[String], - get0 = _.number, - set0 = (p, v) => p.copy(number = v) - ), - field02 = Schema.Field[CreditCard, Int]( - "expirationMonth", - Schema.primitive[Int], - get0 = _.expirationMonth, - set0 = (p, v) => p.copy(expirationMonth = v) - ), - field03 = Schema.Field[CreditCard, Int]( - "expirationYear", - Schema.primitive[Int], - get0 = _.expirationYear, - set0 = (p, v) => p.copy(expirationYear = v) - ), - construct0 = - (number, expirationMonth, expirationYear) => PaymentMethod.CreditCard(number, expirationMonth, expirationYear) - ) - - val schemaPaymentMethod: Schema[PaymentMethod] = - Schema.Enum2[PaymentMethod.CreditCard, PaymentMethod.WireTransfer, PaymentMethod]( - id = TypeId.parse("dev.zio.schema.example.example1.Domain.PaymentMethod"), - case1 = Case[PaymentMethod, PaymentMethod.CreditCard]( - id = "CreditCard", - schema = schemaPaymentMethodCreditCard, - unsafeDeconstruct = pm => pm.asInstanceOf[PaymentMethod.CreditCard], - construct = pc => pc.asInstanceOf[PaymentMethod], - isCase = _.isInstanceOf[PaymentMethod.CreditCard], - annotations = Chunk.empty - ), - case2 = Case[PaymentMethod, PaymentMethod.WireTransfer]( - id = "WireTransfer", - schema = schemaPaymentMethodWireTransfer, - unsafeDeconstruct = pm => pm.asInstanceOf[PaymentMethod.WireTransfer], - construct = pc => pc.asInstanceOf[PaymentMethod], - isCase = _.isInstanceOf[PaymentMethod.WireTransfer], - annotations = Chunk.empty - ), - annotations = Chunk.empty - ) - - val schemaCustomer: Schema[Customer] = Schema.CaseClass2[Person, PaymentMethod, Customer]( - TypeId.parse("dev.zio.schema.example.example1.Domain.Customer"), - field01 = - Schema.Field[Customer, Person]("person", schemaPerson, get0 = _.person, set0 = (p, v) => p.copy(person = v)), - field02 = Schema.Field[Customer, PaymentMethod]( - "paymentMethod", - schemaPaymentMethod, - get0 = _.paymentMethod, - set0 = (p, v) => p.copy(paymentMethod = v) - ), - construct0 = (person, paymentMethod) => Customer(person, paymentMethod) - ) - - val schemaPersonDictionary: Schema[scala.collection.immutable.Map[String, Person]] = - Schema.map( - Schema.primitive[String], - Schema[Person](schemaPerson) - ) - -} - -object MacroConstruction { - - implicit val schemaPerson: Schema[Person] = DeriveSchema.gen[Person] - - val schemaPaymentMethod: Schema[PaymentMethod] = DeriveSchema.gen[PaymentMethod] - - val schemaCustomer: Schema[Customer] = DeriveSchema.gen[Customer] - - val schemaPersonDictionaryFromMacro: Schema[scala.collection.immutable.Map[String, Person]] = - DeriveSchema.gen[Map[String, Person]] - -} - -object JsonSample extends zio.ZIOAppDefault { - import ManualConstruction._ - import zio.schema.codec.JsonCodec - import zio.stream.ZStream - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - person = Person("Michelle", 32) - personToJsonTransducer = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson).streamEncoder - _ <- ZStream(person) - .via(personToJsonTransducer) - .via(ZPipeline.utf8Decode) - .foreach(ZIO.debug(_)) - } yield ExitCode.success -} - -object ProtobufExample extends ZIOAppDefault { - import ManualConstruction._ - import zio.schema.codec.ProtobufCodec - import zio.stream.ZStream - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - _ <- ZIO.debug("protobuf roundtrip") - person = Person("Michelle", 32) - - personToProto = ProtobufCodec.protobufCodec[Person](schemaPerson).streamEncoder - protoToPerson = ProtobufCodec.protobufCodec[Person](schemaPerson).streamDecoder - - newPerson <- ZStream(person) - .via(personToProto) - .via(protoToPerson) - .runHead - .some - .catchAll(error => ZIO.debug(error)) - _ <- ZIO.debug("is old person the new person? " + (person == newPerson).toString) - _ <- ZIO.debug("old person: " + person) - _ <- ZIO.debug("new person: " + newPerson) - } yield ExitCode.success -} - -object CombiningExample extends ZIOAppDefault { - import ManualConstruction._ - import zio.schema.codec.{ JsonCodec, ProtobufCodec } - import zio.stream.ZStream - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - _ <- ZIO.debug("combining roundtrip") - person = Person("Michelle", 32) - - personToJson = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson).streamEncoder - jsonToPerson = JsonCodec.schemaBasedBinaryCodec[Person](schemaPerson).streamDecoder - - personToProto = ProtobufCodec.protobufCodec[Person](schemaPerson).streamEncoder - protoToPerson = ProtobufCodec.protobufCodec[Person](schemaPerson).streamDecoder - - newPerson <- ZStream(person) - .tap(v => ZIO.debug("input object is: " + v)) - .via(personToJson) - .via(jsonToPerson) - .tap(v => ZIO.debug("object after json roundtrip: " + v)) - .via(personToProto) - .via(protoToPerson) - .tap(v => ZIO.debug("person after protobuf roundtrip: " + v)) - .runHead - .some - .catchAll(error => ZIO.debug(error)) - _ <- ZIO.debug("is old person the new person? " + (person == newPerson).toString) - _ <- ZIO.debug("old person: " + person) - _ <- ZIO.debug("new person: " + newPerson) - } yield ExitCode.success -} - -object DictionaryExample extends ZIOAppDefault { - - import MacroConstruction._ - import zio.schema.codec.JsonCodec - import zio.stream.ZStream - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - person = Person("Mike", 32) - dictionary = Map("m" -> person) - dictionaryToJson = JsonCodec - .schemaBasedBinaryCodec[scala.collection.immutable.Map[String, Person]](schemaPersonDictionaryFromMacro) - .streamEncoder - jsonToDictionary = JsonCodec - .schemaBasedBinaryCodec[scala.collection.immutable.Map[String, Person]](schemaPersonDictionaryFromMacro) - .streamDecoder - newPersonDictionary <- ZStream(dictionary) - .via(dictionaryToJson) - .via(jsonToDictionary) - .runHead - .some - .catchAll(error => ZIO.debug(error)) - _ <- ZIO.debug("is old dictionary the new dictionary? " + (dictionary == newPersonDictionary).toString) - _ <- ZIO.debug("old dictionary: " + dictionary) - _ <- ZIO.debug("new dictionary: " + newPersonDictionary) - } yield ExitCode.success -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala deleted file mode 100644 index 3bc56004e..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example2/Example2.scala +++ /dev/null @@ -1,225 +0,0 @@ -package dev.zio.schema.example.example2 - -import zio._ -import zio.schema.Schema._ -import zio.schema.{ Schema, TypeId } -import zio.stream.ZPipeline - -/** - * Example 2 of ZIO-Schema - * - * In this example, we pull the definition of our schema into the companion objects of our types. - * This will help us in the future to avoid having to write the same code over and over again. - * - * Again we'll also show that the moved schema can still be used to transform an object from/to JSON and Protobuf. - */ - -object Domain { - sealed trait PaymentMethod - - final case class Person(name: String, age: Int) - - object Person { - - val name: Field[Person, String] = - Schema.Field[Person, String]("name", Schema.primitive[String], get0 = _.name, set0 = (p, v) => p.copy(name = v)) - - val age: Field[Person, Int] = - Schema.Field[Person, Int]("age", Schema.primitive[Int], get0 = _.age, set0 = (p, v) => p.copy(age = v)) - - val schema: Schema[Person] = Schema.CaseClass2[String, Int, Person]( - TypeId.parse("dev.zio.schema.example.example2.Domain.Person"), - field01 = name, - field02 = age, - construct0 = (name, age) => Person(name, age) - ) - } - - object PaymentMethod { - final case class CreditCard(number: String, expirationMonth: Int, expirationYear: Int) extends PaymentMethod - - object CreditCard { - - val number: Field[CreditCard, String] = - Schema.Field[CreditCard, String]( - "number", - Schema.primitive[String], - get0 = _.number, - set0 = (p, v) => p.copy(number = v) - ) - - val expirationMonth: Field[CreditCard, Int] = - Schema.Field[CreditCard, Int]( - "expirationMonth", - Schema.primitive[Int], - get0 = _.expirationMonth, - set0 = (p, v) => p.copy(expirationMonth = v) - ) - - val expirationYear: Field[CreditCard, Int] = - Schema.Field[CreditCard, Int]( - "expirationYear", - Schema.primitive[Int], - get0 = _.expirationYear, - set0 = (p, v) => p.copy(expirationYear = v) - ) - implicit val schema: Schema[CreditCard] = Schema.CaseClass3[String, Int, Int, CreditCard]( - TypeId.parse("dev.zio.schema.example.example2.Domain.PaymentMethod.CreditCard"), - field01 = number, - field02 = expirationMonth, - field03 = expirationYear, - construct0 = - (number, expirationMonth, expirationYear) => PaymentMethod.CreditCard(number, expirationMonth, expirationYear) - ) - } - - final case class WireTransfer(accountNumber: String, bankCode: String) extends PaymentMethod - - object WireTransfer { - - val accountNumber: Field[WireTransfer, String] = - Schema.Field[WireTransfer, String]( - "accountNumber", - Schema.primitive[String], - get0 = _.accountNumber, - set0 = (p, v) => p.copy(accountNumber = v) - ) - - val bankCode: Field[WireTransfer, String] = - Schema.Field[WireTransfer, String]( - "bankCode", - Schema.primitive[String], - get0 = _.bankCode, - set0 = (p, v) => p.copy(bankCode = v) - ) - - implicit val schema: Schema[WireTransfer] = Schema.CaseClass2[String, String, WireTransfer]( - TypeId.parse("dev.zio.schema.example.example2.Domain.PaymentMethod.WireTransfer"), - field01 = accountNumber, - field02 = bankCode, - construct0 = (number, bankCode) => PaymentMethod.WireTransfer(number, bankCode) - ) - } - - val schemaPaymentMethod: Schema[PaymentMethod] = Schema.Enum2[CreditCard, WireTransfer, PaymentMethod]( - id = TypeId.parse("dev.zio.schema.example.example2.Domain.PaymentMethod"), - case1 = Case[PaymentMethod, CreditCard]( - id = "CreditCard", - schema = CreditCard.schema, - unsafeDeconstruct = pm => pm.asInstanceOf[PaymentMethod.CreditCard], - construct = pc => pc.asInstanceOf[PaymentMethod], - isCase = _.isInstanceOf[PaymentMethod.CreditCard], - annotations = Chunk.empty - ), - case2 = Case[PaymentMethod, WireTransfer]( - id = "WireTransfer", - schema = WireTransfer.schema, - unsafeDeconstruct = pm => pm.asInstanceOf[PaymentMethod.WireTransfer], - construct = pc => pc.asInstanceOf[PaymentMethod], - isCase = _.isInstanceOf[PaymentMethod.WireTransfer], - annotations = Chunk.empty - ), - annotations = Chunk.empty - ) - - } - - final case class Customer(person: Person, paymentMethod: PaymentMethod) - - object Customer { - - val person: Field[Customer, Person] = - Schema.Field[Customer, Person]("person", Person.schema, get0 = _.person, set0 = (p, v) => p.copy(person = v)) - - val paymentMethod: Field[Customer, PaymentMethod] = - Schema.Field[Customer, PaymentMethod]( - "paymentMethod", - PaymentMethod.schemaPaymentMethod, - get0 = _.paymentMethod, - set0 = (p, v) => p.copy(paymentMethod = v) - ) - - implicit val schema: Schema[Customer] = Schema.CaseClass2[Person, PaymentMethod, Customer]( - TypeId.parse("dev.zio.schema.example.example2.Domain.Customer"), - field01 = Customer.person, - field02 = Customer.paymentMethod, - construct0 = (person, paymentMethod) => Customer(person, paymentMethod) - ) - } -} - -import dev.zio.schema.example.example2.Domain._ - -object JsonSample extends zio.ZIOAppDefault { - import zio.schema.codec.JsonCodec - import zio.stream.ZStream - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - person = Person("Michelle", 32) - personToJsonPipeline = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).streamEncoder - _ <- ZStream(person) - .via(personToJsonPipeline) - .via(ZPipeline.utf8Decode) - .foreach(f => ZIO.debug(f)) - } yield ExitCode.success -} - -object ProtobufExample extends ZIOAppDefault { - import zio.schema.codec.ProtobufCodec - import zio.stream.ZStream - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - _ <- ZIO.debug("protobuf roundtrip") - person = Person("Michelle", 32) - - personToProto = ProtobufCodec.protobufCodec[Person](Person.schema).streamEncoder - protoToPerson = ProtobufCodec.protobufCodec[Person](Person.schema).streamDecoder - - newPerson <- ZStream(person) - .via(personToProto) - .via(protoToPerson) - .runHead - .some - .catchAll(error => ZIO.debug(error)) - _ <- ZIO.debug("is old person the new person? " + (person == newPerson).toString) - _ <- ZIO.debug("old person: " + person) - _ <- ZIO.debug("new person: " + newPerson) - } yield ExitCode.success -} - -object CombiningExample extends zio.ZIOAppDefault { - import zio.schema.codec.{ JsonCodec, ProtobufCodec } - import zio.stream.ZStream - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.unit - _ <- ZIO.debug("combining roundtrip") - person = Person("Michelle", 32) - - personToJson = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).streamEncoder - jsonToPerson = JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).streamDecoder - - personToProto = ProtobufCodec.protobufCodec[Person](Person.schema).streamEncoder - protoToPerson = ProtobufCodec.protobufCodec[Person](Person.schema).streamDecoder - - newPerson <- ZStream(person) - .tap(v => ZIO.debug("input object is: " + v)) - .via(personToJson) - .via(jsonToPerson) - .tap(v => ZIO.debug("object after json roundtrip: " + v)) - .via(personToProto) - .via(protoToPerson) - .tap(v => ZIO.debug("person after protobuf roundtrip: " + v)) - .runHead - .some - .catchAll(error => ZIO.debug(error)) - _ <- ZIO.debug("is old person the new person? " + (person == newPerson).toString) - _ <- ZIO.debug("old person: " + person) - _ <- ZIO.debug("new person: " + newPerson) - } yield ExitCode.success -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala deleted file mode 100644 index 127fb89ce..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example3/Example3.scala +++ /dev/null @@ -1,88 +0,0 @@ -package dev.zio.schema.example.example3 - -import zio._ -import zio.schema.Schema._ -import zio.schema._ - -/** - * Example3: - * In this example we'll take a look on how to use ZIO-Schema to - * transform a PersonDTO (e.g. from a REST API) into a Person (e.g. for a database) in a single step. - * - * To do this, we'll transform the Schema of the PersonDTO into a Schema of the Person. - **/ -private[example3] object Domain { - final case class Person(name: String, age: Int) - - object Person { - - val name: Field[Person, String] = - Field[Person, String]("name", primitive[String], get0 = _.name, set0 = (p, v) => p.copy(name = v)) - - val age: Field[Person, Int] = - Field[Person, Int]("age", primitive[Int], get0 = _.age, set0 = (p, v) => p.copy(age = v)) - - val schema: Schema[Person] = CaseClass2[String, Int, Person]( - TypeId.parse("dev.zio.example.example3.Domain.Person"), - field01 = name, - field02 = age, - construct0 = (name, age) => Person(name, age) - ) - } - - final case class PersonDTO(firstname: String, lastname: String, years: Int) - - object PersonDTO { - - val firstname: Field[PersonDTO, String] = - Field("firstname", primitive[String], get0 = _.firstname, set0 = (p, v) => p.copy(firstname = v)) - - val lastname: Field[PersonDTO, String] = - Field("lastname", primitive[String], get0 = _.lastname, set0 = (p, v) => p.copy(lastname = v)) - - val years: Field[PersonDTO, Int] = - Field("years", primitive[Int], get0 = _.years, set0 = (p, v) => p.copy(years = v)) - - val schema: Schema[PersonDTO] = CaseClass3[String, String, Int, PersonDTO]( - TypeId.parse("dev.zio.example.example3.Domain.PersonDTO"), - field01 = firstname, - field02 = lastname, - field03 = years, - construct0 = (fn, ln, y) => PersonDTO(fn, ln, y) - ) - } - -} - -object Example3 extends ZIOAppDefault { - import dev.zio.schema.example.example3.Domain._ - import zio.schema.codec.JsonCodec - - val personTransformation: Schema[Person] = PersonDTO.schema.transform[Person]( - (dto: PersonDTO) => Person(dto.firstname + " " + dto.lastname, dto.years), - (person: Person) => { - val name = person.name.split(" ").toSeq - PersonDTO(name.head, name.tail.mkString(" "), person.age) - } - ) - - override val run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { - _ <- ZIO.unit - json = """{"firstname":"John","lastname":"Doe","years":42}""" - chunks = Chunk.fromArray(json.getBytes) - _ <- ZIO.debug("input JSON : " + json) - - // get objects from JSON - personDTO <- ZIO.fromEither(JsonCodec.schemaBasedBinaryCodec[PersonDTO](PersonDTO.schema).decode(chunks)) - person <- ZIO.fromEither(JsonCodec.schemaBasedBinaryCodec[Person](personTransformation).decode(chunks)) - _ <- ZIO.debug("PersonDTO : " + personDTO) - _ <- ZIO.debug("Person : " + person) - - // get JSON from Objects - personJson = new String(JsonCodec.schemaBasedBinaryCodec[Person](Person.schema).encode(person).toArray) - personDTOJson = new String(JsonCodec.schemaBasedBinaryCodec[Person](personTransformation).encode(person).toArray) - _ <- ZIO.debug("Person JSON: " + personJson) - _ <- ZIO.debug("PersonDTO JSON: " + personDTOJson) - - } yield () -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example4/Example4Transformation.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example4/Example4Transformation.scala deleted file mode 100644 index 60978b234..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example4/Example4Transformation.scala +++ /dev/null @@ -1,136 +0,0 @@ -package dev.zio.schema.example.example4 - -import zio._ -import zio.schema._ -import zio.schema.meta._ - -/** - * Example 4: In this Example, we use ZIO-Schema to migrate objects from one representation to another. - * This is a very common use case in proper designed applications where we have to migrate between - * different representations depending on the layer, e.g. - * transforming a Request-DTO to a Domain-DTO to a Database-DTO. - **/ -private[example4] object Domain { - final case class WebPerson(name: String, age: Int) - - object WebPerson { - - val name: Schema.Field[WebPerson, String] = - Schema - .Field[WebPerson, String]("name", Schema.primitive[String], get0 = _.name, set0 = (p, v) => p.copy(name = v)) - - val age: Schema.Field[WebPerson, Int] = - Schema.Field[WebPerson, Int]("age", Schema.primitive[Int], get0 = _.age, set0 = (p, v) => p.copy(age = v)) - - val schema: Schema[WebPerson] = Schema.CaseClass2[String, Int, WebPerson]( - TypeId.parse("dev.zio.schema.example.example4.Domain.WebPerson"), - field01 = name, - field02 = age, - construct0 = (name, age) => WebPerson(name, age) - ) - } - - final case class DomainPerson(firstname: String, lastname: String, years: Int) - - object DomainPerson { - - val firstname: Schema.Field[DomainPerson, String] = - Schema.Field("firstname", Schema.primitive[String], get0 = _.firstname, set0 = (p, v) => p.copy(firstname = v)) - - val lastname: Schema.Field[DomainPerson, String] = - Schema.Field("lastname", Schema.primitive[String], get0 = _.lastname, set0 = (p, v) => p.copy(lastname = v)) - - val years: Schema.Field[DomainPerson, Int] = - Schema.Field("years", Schema.primitive[Int], get0 = _.years, set0 = (p, v) => p.copy(years = v)) - - val schema: Schema[DomainPerson] = Schema.CaseClass3[String, String, Int, DomainPerson]( - TypeId.parse("dev.zio.schema.example.example4.Domain.DomainPerson"), - field01 = firstname, - field02 = lastname, - field03 = years, - construct0 = (fn, ln, y) => DomainPerson(fn, ln, y) - ) - } - -} - -// TODO - not working: -// Here I try to convert between WebPerson and DomainPerson using the `transform` method on `Schema` -object Example4Transformation extends ZIOAppDefault { - - import Domain._ - - val webPerson: WebPerson = WebPerson("Mike Moe", 32) - - val personTransformation: Schema[DomainPerson] = WebPerson.schema.transform[DomainPerson]( - (person: WebPerson) => { - val name = person.name.split(" ").toSeq - DomainPerson(name.head, name.tail.mkString(" "), person.age) - }, - (dto: DomainPerson) => WebPerson(dto.firstname + " " + dto.lastname, dto.years) - ) - - val domainPerson: Either[String, DomainPerson] = - WebPerson.schema.migrate(personTransformation).flatMap(f => f(webPerson)) - - override def run: UIO[Unit] = ZIO.debug(domainPerson) -} - -// TODO - not working!: -// Here I try to convert between WebPerson and DomainPerson -// using the roundtrip with dynamic and SchemaAst migrations. -object Example4Ast extends zio.ZIOAppDefault { - - import Domain._ - - val webPerson: WebPerson = WebPerson("Mike Moe", 32) - - val dyn: Either[String, DynamicValue] = WebPerson.schema - .toDynamic(webPerson) - .transform( - Chunk( - Migration.AddNode(NodePath.root / "lastname", MetaSchema.fromSchema(DomainPerson.lastname.schema)) -// Migration.Relabel(NodePath.root / "years", Migration.LabelTransformation("age")) // does not compile, LabelTransformation - ) - ) - //.flatMap(dv => DomainPerson.schema.fromDynamic(dv)) - - override def run: UIO[Unit] = ZIO.debug(dyn) -} - -object Example4Ast2 extends zio.ZIOAppDefault { - import Domain._ - - val webPerson: WebPerson = WebPerson("Mike Moe", 32) - - val personTransformation: Schema[DomainPerson] = WebPerson.schema.transform[DomainPerson]( - (person: WebPerson) => { - val name = person.name.split(" ").toSeq - DomainPerson(name.head, name.tail.mkString(" "), person.age) - }, - (dto: DomainPerson) => WebPerson(dto.firstname + " " + dto.lastname, dto.years) - ) - val webPersonAst: MetaSchema = MetaSchema.fromSchema(WebPerson.schema) - val domainPersonAst: MetaSchema = MetaSchema.fromSchema(DomainPerson.schema) - val migrationAst: MetaSchema = MetaSchema.fromSchema(personTransformation) - - val migrationWebPersonAstToMigrationAst: Either[String, Chunk[Migration]] = - Migration.derive(webPersonAst, migrationAst) - - val migrationWebPersonAstToDomainPersonAst: Either[String, Chunk[Migration]] = - Migration.derive(webPersonAst, domainPersonAst) - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = - for { - _ <- ZIO.debug(webPersonAst) - _ <- ZIO.debug(domainPersonAst) - _ <- ZIO.debug(migrationAst) - _ <- ZIO.debug("migrationWebPersonAstToMigrationAst" + migrationWebPersonAstToMigrationAst) - _ <- ZIO.debug("migrationWebPersonAstToDomainPersonAst" + migrationWebPersonAstToDomainPersonAst) - x = WebPerson.schema.migrate(personTransformation).flatMap(f => f(webPerson)) - _ <- ZIO.debug(x) // Left(Failed to cast Record(ListMap(name -> Primitive(Mike Moe,string), age -> Primitive(32,int))) to schema Transform(CaseClass2(Field(name,Primitive(string)),Field(age,Primitive(int))))) - - domainPerson = WebPerson.schema.migrate(DomainPerson.schema).flatMap(f => f(webPerson)) - _ <- ZIO.debug(domainPerson) // Left(Cannot add node at path firstname: No default value is available) - } yield () -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example5/Example5_Diffing.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example5/Example5_Diffing.scala deleted file mode 100644 index 05c1839cd..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example5/Example5_Diffing.scala +++ /dev/null @@ -1,63 +0,0 @@ -package dev.zio.schema.example.example5 - -import zio._ -import zio.schema.Schema._ -import zio.schema._ - -/** - * Example 5: In this example, we use ZIO-Schema to detect changes in our objects. - * - */ -private[example5] object Domain { - final case class Person(name: String, age: Int) - - object Person { - - val name: Field[Person, String] = - Field[Person, String]("name", primitive[String], get0 = _.name, set0 = (p, v) => p.copy(name = v)) - - val age: Field[Person, Int] = - Field[Person, Int]("age", primitive[Int], get0 = _.age, set0 = (p, v) => p.copy(age = v)) - - val schema: Schema[Person] = CaseClass2[String, Int, Person]( - TypeId.parse("dev.zio.schema.example.example5.Domain.Person"), - field01 = name, - field02 = age, - construct0 = (name, age) => Person(name, age) - ) - } - - final case class PersonDTO(firstname: String, lastname: String, years: Int) - - object PersonDTO { - - val firstname: Field[PersonDTO, String] = - Field("firstname", primitive[String], get0 = _.firstname, set0 = (p, v) => p.copy(firstname = v)) - - val lastname: Field[PersonDTO, String] = - Field("lastname", primitive[String], get0 = _.lastname, set0 = (p, v) => p.copy(lastname = v)) - - val years: Field[PersonDTO, Int] = - Field("years", primitive[Int], get0 = _.years, set0 = (p, v) => p.copy(years = v)) - - val schema: Schema[PersonDTO] = CaseClass3[String, String, Int, PersonDTO]( - TypeId.parse("dev.zio.schema.example.example5.Domain.PersonDTO"), - field01 = firstname, - field02 = lastname, - field03 = years, - construct0 = (fn, ln, y) => PersonDTO(fn, ln, y) - ) - } - -} - -object Example5_Diffing extends ZIOAppDefault { - - import Domain._ - - val personDTO: PersonDTO = PersonDTO("Mike", "Moe", 32) - - val diff: Patch[PersonDTO] = PersonDTO.schema.diff(personDTO, personDTO.copy(lastname = "Max")) - - override val run: UIO[Unit] = ZIO.debug(diff) -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example6/Example6_ReifiedOptics.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example6/Example6_ReifiedOptics.scala deleted file mode 100644 index 7d1d0e383..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example6/Example6_ReifiedOptics.scala +++ /dev/null @@ -1,127 +0,0 @@ -package dev.zio.schema.example.example6 - -import zio._ -import zio.schema.Schema._ -import zio.schema._ -import zio.schema.optics.ZioOpticsBuilder - -private[example6] object Domain { - final case class User(name: String, age: Int) - final case class Address(street: String, city: String, state: String) - final case class UserAddress(user: User, address: Address) - final case class Company(boss: User, employees: List[UserAddress]) - - implicit val userSchema: Schema.CaseClass2[String, Int, User] = Schema.CaseClass2[String, Int, User]( - TypeId.parse("dev.zio.schema.example.example6.Domain.User"), - field01 = Field("name", Schema.primitive[String], get0 = _.name, set0 = (p, v) => p.copy(name = v)), - field02 = Field("age", Schema.primitive[Int], get0 = _.age, set0 = (p, v) => p.copy(age = v)), - construct0 = (name, years) => User(name, years) - ) - - implicit val addressSchema: CaseClass3[String, String, String, Address] = - Schema.CaseClass3[String, String, String, Address]( - TypeId.parse("dev.zio.schema.example.example6.Domain.Address"), - field01 = Field("street", Schema.primitive[String], get0 = _.street, set0 = (p, v) => p.copy(street = v)), - field02 = Field("city", Schema.primitive[String], get0 = _.city, set0 = (p, v) => p.copy(city = v)), - field03 = Field("state", Schema.primitive[String], get0 = _.state, set0 = (p, v) => p.copy(state = v)), - construct0 = (street, city, state) => Address(street, city, state) - ) - - implicit val userAddressSchema: CaseClass2[User, Address, UserAddress] = - Schema.CaseClass2[User, Address, UserAddress]( - TypeId.parse("dev.zio.schema.example.example6.Domain.UserAddress"), - field01 = Field("user", userSchema, get0 = _.user, set0 = (p, v) => p.copy(user = v)), - field02 = Field("address", addressSchema, get0 = _.address, set0 = (p, v) => p.copy(address = v)), - construct0 = (user, address) => UserAddress(user, address) - ) - - implicit val companySchema: CaseClass2[User, List[UserAddress], Company] = - Schema.CaseClass2[User, List[UserAddress], Company]( - TypeId.parse("dev.zio.schema.example.example6.Domain.Company"), - field01 = Field("boss", userSchema, get0 = _.boss, set0 = (p, v) => p.copy(boss = v)), - field02 = - Field("employees", Schema.list(userAddressSchema), get0 = _.employees, set0 = (p, v) => p.copy(employees = v)), - construct0 = (boss, employees) => Company(boss, employees) - ) - -} - -object Example6_ReifiedOptics extends ZIOAppDefault { - import Domain._ - - val lensTest1: ZIO[Any, Nothing, Unit] = for { - _ <- ZIO.debug("lens test 1") - user = User("Dominik", 35) - userAccessors = userSchema.makeAccessors(ZioOpticsBuilder) - lensName = userAccessors._1 - lensAge = userAccessors._2 - changedUser = lensName.zip(lensAge).setOptic(("Mike", 32))(user) - _ <- ZIO.debug(user) - _ <- ZIO.debug(changedUser) - } yield () - - val lensTest2: ZIO[Any, Nothing, Unit] = for { - _ <- ZIO.debug("lens test 2") - user = User("Dominik", 35) - address = Address("Street", "City", "State") - userAddress = UserAddress(user, address) - userAddressAccessors = userAddressSchema.makeAccessors(ZioOpticsBuilder) - //userAccessors = userSchema.makeAccessors(ZioOpticsBuilder) - addressAccessors = addressSchema.makeAccessors(ZioOpticsBuilder) - - changedUserAddress = (userAddressAccessors._2 >>> addressAccessors._3).setOptic("New State")(userAddress) - _ <- ZIO.debug(userAddress) - _ <- ZIO.debug(changedUserAddress) - } yield () - - val traversalTest1: ZIO[Any, Nothing, Unit] = for { - _ <- ZIO.debug("\n\n\n\n") - _ <- ZIO.debug("traversal test 1.. trying to add a employee to a company") - company = Company(boss = User("Dominik", 36), List.empty[UserAddress]) - _ <- ZIO.debug("old company : " + company) - (_, employeesLens) = companySchema.makeAccessors(ZioOpticsBuilder) - - employeeSchema = companySchema.field2.schema.asInstanceOf[Sequence[List[UserAddress], UserAddress, _]] - employeesTraversal = ZioOpticsBuilder - .makeTraversal[List[UserAddress], UserAddress](employeeSchema, userAddressSchema) - - // not working approach - updatedCompany = (employeesLens >>> employeesTraversal).update(company)( - emps => emps ++ Chunk(UserAddress(User("joe", 22), Address("s1", "s2", "s3"))) - ) - _ <- ZIO.debug("updated company : " + updatedCompany) - - // working approach - updatedCompany2 = employeesLens.update(company)( - emps => emps ++ List(UserAddress(User("joe", 22), Address("s1", "s2", "s3"))) - ) - _ <- ZIO.debug("updated company2: " + updatedCompany2) - } yield () - - override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = (lensTest1 *> lensTest2 *> traversalTest1) -} - -/** - * Example by adam that shows pure usage of optics without any schema or derivation - */ -object Example6_PureOptics extends scala.App { - import zio.optics._ - - final case class User(name: String) - final case class Employee(name: String) - - final case class Company(boss: User, employees: List[Employee]) - - val company: Company = Company(User("boss"), List(Employee("employee1"))) - println("company with 1 employee : " + company) - - val employees: Lens[Company, List[Employee]] = - Lens( - company => Right(company.employees), - employees => company => Right(company.copy(employees = employees)) - ) - - val employee: Employee = Employee("employee2") - - println("company with 2 employees: " + employees.update(company)(employees => employee :: employees)) -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example7/Problem.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example7/Problem.scala deleted file mode 100644 index 9548d3e46..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example7/Problem.scala +++ /dev/null @@ -1,213 +0,0 @@ -package dev.zio.schema.example.example7 - -import scala.collection.immutable.ListMap -import scala.util.Try - -import zio.schema._ -import zio.{ Chunk, Unsafe } - -/** This exercise is based on John DeGoes' Spartan training on ZIO-Schema from 2021-11-04 - */ -private[example7] object Problem { - - final case class Person(name: String, age: Int) - - object Person { - implicit val schema: Schema[Person] = DeriveSchema.gen[Person] - } - final case class Profile(location: String, address: String) - - object Profile { - implicit val schema: Schema[Profile] = DeriveSchema.gen[Profile] - } - // sample url1: /foo/?name=john&age=42#foo - // sample url2: /foo/?name=john&age=42&location=london&address=baker%20street - - def decodePersonFromQueryParams(params: Map[String, List[String]]): scala.util.Either[String, Person] = - for { - name <- params.get("name").toRight("name parameter is missing") - age <- params.get("age").toRight("age parameter is missing") - } yield Person(name.head, age.head.toInt) - - def decodeProfileFromQueryParams(params: Map[String, List[String]]): scala.util.Either[String, Profile] = - for { - location <- params.get("location").toRight("location parameter is missing") - address <- params.get("address").toRight("address parameter is missing") - } yield Profile(location.head, address.head) - - object Approach1 extends scala.App { - - // this will be a "quick and dirty" solution, that can be accomplished in a few minutes. - // not suitable for _extremely high performance_ applications - // probably suitable for the normal business application with medium performance requirements - def decode[A]( - params: Map[String, List[String]] - )(implicit schema: Schema[A]): scala.util.Either[String, A] = - toDV(params) - .map(_.toTypedValue(schema)) - .collectFirst { - case Right(v) => - v - } - .toRight("some error") - - // parse each element into String and if possible Int representations. We basically create all - // possible solutions here. The Set[DynamicValue] removes duplicates. - def toDV(params: Map[String, List[String]]): Set[DynamicValue] = { - import DynamicValue._ - params - .foldLeft[Set[ListMap[String, DynamicValue]]](Set(ListMap())) { - case (set, (key, values)) => - set.flatMap { acc => - values match { - case Nil => Set(acc.updated(key, Singleton(()))) - case x :: Nil => - val strInterpretation = - Set(acc.updated(key, Primitive[String](x, StandardType.StringType))) - val intInterpretation = Try(x.toInt).toOption match { - case Some(value) => - Set(acc.updated(key, Primitive[Int](value, StandardType.IntType))) - case None => Set() - } - strInterpretation ++ intInterpretation - case xs => - Set( - acc.updated( - key, - DynamicValue.Sequence( - Chunk.fromIterable(xs).map(Primitive[String](_, StandardType.StringType)) - ) - ) - ) - } - } - } - .map(v => DynamicValue.Record(TypeId.Structural, v)) - } - - val p: scala.util.Either[String, Person] = decode[Person](Map("name" -> List("John"), "age" -> List("42"))) - - println(p) - } - - object Approach2 extends scala.App { - import Schema._ - type QueryParams = scala.collection.immutable.Map[String, List[String]] - - // this will be a sophisticated solution for a high performance library like ZIO - def decodeFromQueryParams[A]( - params: QueryParams - )(implicit schema: Schema[A], decoder: QueryParams => scala.util.Either[String, A]): scala.util.Either[String, A] = - decoder(params) - - def buildDecoder[A](implicit schemaA: Schema[A]): QueryParams => scala.util.Either[String, A] = { - - def compile[B](key: Option[String], schemaB: Schema[B]): QueryParams => scala.util.Either[String, B] = - schemaB match { - case transform: Transform[a, B, _] => - import transform.{ f, schema } - val func: QueryParams => scala.util.Either[String, Any] = compile(key, schema) - (params: QueryParams) => func(params).flatMap(v => f(v.asInstanceOf[a])) - case Primitive(standardType, _) => - key match { - case None => - val error = Left(s"Cannot extract a primitive out of a query string") - Function.const(error) - case Some(key) => - standardType match { - case StandardType.StringType => - val f: QueryParams => scala.util.Either[String, B] = (qp: QueryParams) => - qp.get(key) match { - case Some(value :: _) => Right[String, B](value.asInstanceOf[B]) - case _ => Left(s"Cannot extract a primitive string out of nothing") - } - f - case StandardType.IntType => - val f: QueryParams => scala.util.Either[String, B] = (qp: QueryParams) => - qp.get(key) match { - case Some(value :: _) => - Try(value.toInt).toOption.toRight(s"cannot create an integer out of $value") - case _ => Left(s"Cannot extract a primitive string out of nothing") - } - f - case _ => - val error = Left(s"Expected String or Int but found $standardType") - Function.const(error) - } - } - - case cc: CaseClass1[a, B] => - val f = compile[a](Some(cc.field.name), cc.field.schema) - (qp: QueryParams) => f(qp).map(v => cc.defaultConstruct(v)) - - case cc: CaseClass2[a, b, B] => - val f1 = compile[a](Some(cc.field1.name), cc.field1.schema) - val f2 = compile[b](Some(cc.field2.name), cc.field2.schema) - - (qp: QueryParams) => - for { - v1 <- f1(qp) - v2 <- f2(qp) - } yield cc.construct(v1, v2) - - case cc: CaseClass3[a, b, c, B] => - val f1 = compile[a](Some(cc.field1.name), cc.field1.schema) - val f2 = compile[b](Some(cc.field2.name), cc.field2.schema) - val f3 = compile[c](Some(cc.field3.name), cc.field3.schema) - - (qp: QueryParams) => - for { - v1 <- f1(qp) - v2 <- f2(qp) - v3 <- f3(qp) - } yield cc.construct(v1, v2, v3) - - // And so on to arity 23.. - - case record: Record[B] => - Unsafe.unsafe { implicit unsafe => (qp: QueryParams) => - { - record.fields.map { - case Schema.Field(label, schema, _, _, _, _) => - compile(Some(label), schema)(qp) - }.foldRight[scala.util.Either[String, Chunk[Any]]](Right(Chunk.empty)) { - case (Right(nextValue), Right(values)) => Right(values :+ nextValue) - case (Left(err), _) => Left(err) - case (_, Left(err)) => Left(err) - } - .flatMap(record.construct) - } - } - - case Fail(message, _) => Function.const(Left(message)) - //case enumer: Enum[_] => ??? - //case Optional(codec) => ??? - //case Tuple(left, right) => ??? - //case EitherSchema(left, right) => ??? - case lzy @ Lazy(_) => - // lazy val to make sure its only compiled on first usage and not instantly recursing - lazy val compiled = compile(key, lzy.schema) - (qp: QueryParams) => compiled(qp) - case _ => - val err = Left(s"Decoding from query parameters is not supported for $schemaB") - Function.const(err) - } - - compile(None, schemaA) - } - - implicit val personDecoder: QueryParams => scala.util.Either[String, Person] = buildDecoder[Person] - - println("approach 2") - - private val data = scala.collection.immutable.Map("name" -> List("John"), "age" -> List("42")) - - println(decodeFromQueryParams[Person](data)) - } -} - -object Runner extends scala.App { - - Problem.Approach1.main(Array.empty) - Problem.Approach2.main(Array.empty) -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Decoder.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Decoder.scala deleted file mode 100644 index f5136969b..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Decoder.scala +++ /dev/null @@ -1,47 +0,0 @@ -package dev.zio.schema.example.example8 - -import scala.collection.immutable.ListMap - -import zio.Chunk -import zio.prelude._ -import zio.schema._ - -trait Decoder[+A] { - def decode(in: Json): Either[String, A] -} - -object Decoder { - - def deriveDecoder[A](implicit schema: Schema[A]): Decoder[A] = - in => - for { - dv <- jsonToDynamicValue(in) - a <- schema.fromDynamic(dv) - } yield a - - private def jsonToDynamicValue(in: Json): Either[String, DynamicValue] = - in match { - case Json.JStr(s) => - Right(DynamicValue.Primitive(s, StandardType.StringType)) - - case Json.JNum(d) => - Right(DynamicValue.Primitive(d, StandardType.DoubleType)) - - case Json.JBool(b) => - Right(DynamicValue.Primitive(b, StandardType.BoolType)) - - case Json.JArr(as) => - as.forEach(jsonToDynamicValue) - .map(list => DynamicValue.Sequence(Chunk.fromIterable(list))) - - case Json.JObj(map) => - map.map { - case (k, v) => k -> jsonToDynamicValue(v) - }.foldRight[Either[String, DynamicValue]](Right(DynamicValue.Record(TypeId.Structural, ListMap.empty))) { - case ((key, Right(value)), Right(DynamicValue.Record(_, values))) => - Right(DynamicValue.Record(TypeId.parse(key), values + (key -> value))) - case ((_, Left(err)), _) => Left(err) - case (_, Left(err)) => Left(err) - } - } -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Encoder.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Encoder.scala deleted file mode 100644 index 3ab79f3c7..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Encoder.scala +++ /dev/null @@ -1,38 +0,0 @@ -package dev.zio.schema.example.example8 - -import zio.schema.{ DynamicValue, Schema, StandardType } - -trait Encoder[A] { - def encode(in: A): Json -} - -object Encoder { - - def deriveEncoder[A](implicit schema: Schema[A]): Encoder[A] = { (in: A) => - toJson(schema.toDynamic(in)) - } - - private def toJson(in: DynamicValue): Json = - in match { - case p: DynamicValue.Primitive[a] => - p.standardType match { - case StandardType.StringType => - Json.JStr(p.value) - - case StandardType.DoubleType | StandardType.IntType | StandardType.LongType => - Json.JNum(p.value) - - case StandardType.BoolType => - Json.JBool(p.value) - - case _ => - Json.JStr(p.value.toString) - } - - case DynamicValue.Sequence(chunk) => - Json.JArr(chunk.map(toJson).toList) - - case DynamicValue.Record(_, values) => - Json.JObj(values.map { case (k, v) => (k, toJson(v)) }) - } -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Json.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Json.scala deleted file mode 100644 index 89c3d86fd..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Json.scala +++ /dev/null @@ -1,11 +0,0 @@ -package dev.zio.schema.example.example8 - -sealed trait Json - -object Json { - final case class JStr(s: String) extends Json - final case class JNum(d: Double) extends Json - final case class JBool(b: Boolean) extends Json - final case class JArr(as: List[Json]) extends Json - final case class JObj(map: Map[String, Json]) extends Json -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Usage.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Usage.scala deleted file mode 100644 index 2f5adb185..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example8/Usage.scala +++ /dev/null @@ -1,30 +0,0 @@ -package dev.zio.schema.example.example8 - -import zio.schema.{ DeriveSchema, Schema } - -final case class Person(name: String, age: Double) - -object Person { - implicit val schemaPerson: Schema[Person] = DeriveSchema.gen[Person] -} - -object Usage extends App { - val p: Person = Person("cal", 30) - - val pJson: Json = Encoder.deriveEncoder[Person].encode(p) - val sameP: Either[String, Person] = Decoder.deriveDecoder[Person].decode(pJson) - println(sameP == Right(p)) - - println { - Decoder - .deriveDecoder[Person] - .decode( - Json.JObj( - Map( - "name" -> Json.JStr("cal"), - "age" -> Json.JNum(30) - ) - ) - ) - } -} diff --git a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example9/Patching.scala b/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example9/Patching.scala deleted file mode 100644 index daab0b2dc..000000000 --- a/zio-schema-examples/shared/src/main/scala/dev/zio/schema/example/example9/Patching.scala +++ /dev/null @@ -1,26 +0,0 @@ -package dev.zio.schema.example.example9 - -import zio.schema.{ DeriveSchema, Patch, Schema } - -object Patching extends App { - - final case class Person(name: String, age: Int) - - object Person { - implicit lazy val schema: Schema[Person] = DeriveSchema.gen - } - - private val person1 = Person("Gabriel", 45) - private val person2 = Person("Gabi", 54) - - import Person._ - - private val patch: Patch[Person] = schema.diff(person1, person2) - private val inverted: Patch[Person] = patch.invert - - private val result1: Either[String, Person] = patch.patch(person1) - private val result2: Either[String, Person] = result1.flatMap(inverted.patch) - - assert(result2 == Right(person1)) - -} diff --git a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala index 8c22480fa..51c274865 100644 --- a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala +++ b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala @@ -16,6 +16,7 @@ import zio.json.{ JsonFieldDecoder, JsonFieldEncoder } +import zio.prelude.Validation import zio.schema._ import zio.schema.annotation._ import zio.schema.codec.DecodeError.ReadError @@ -27,13 +28,15 @@ object JsonCodec { implicit def zioJsonBinaryCodec[A](implicit jsonCodec: ZJsonCodec[A]): BinaryCodec[A] = new BinaryCodec[A] { - override def decode(whole: Chunk[Byte]): Either[DecodeError, A] = - jsonCodec - .decodeJson( - new String(whole.toArray, JsonEncoder.CHARSET) + override def decode(whole: Chunk[Byte]): Validation[DecodeError, A] = + Validation + .fromEither( + jsonCodec + .decodeJson( + new String(whole.toArray, JsonEncoder.CHARSET) + ) ) - .left - .map(failure => DecodeError.ReadError(Cause.empty, failure)) + .mapError(failure => DecodeError.ReadError(Cause.empty, failure)) override def streamDecoder: ZPipeline[Any, DecodeError, Byte, A] = ZPipeline.fromChannel( @@ -60,7 +63,7 @@ object JsonCodec { implicit def schemaBasedBinaryCodec[A](implicit schema: Schema[A]): BinaryCodec[A] = new BinaryCodec[A] { - override def decode(whole: Chunk[Byte]): Either[DecodeError, A] = + override def decode(whole: Chunk[Byte]): Validation[DecodeError, A] = JsonDecoder.decode( schema, new String(whole.toArray, JsonEncoder.CHARSET) @@ -75,7 +78,7 @@ object JsonCodec { case (_, fragments) => fragments.mkString } >>> ZPipeline.mapZIO { (s: String) => - ZIO.fromEither(JsonDecoder.decode(schema, s)) + JsonDecoder.decode(schema, s).toZIO } override def encode(value: A): Chunk[Byte] = @@ -360,20 +363,20 @@ object JsonCodec { } } - private def transformEncoder[A, B](schema: Schema[A], g: B => Either[String, A]): ZJsonEncoder[B] = + private def transformEncoder[A, B](schema: Schema[A], g: B => Validation[String, A]): ZJsonEncoder[B] = new ZJsonEncoder[B] { private lazy val innerEncoder = schemaEncoder(schema) override def unsafeEncode(b: B, indent: Option[Int], out: Write): Unit = g(b) match { - case Left(_) => () - case Right(a) => innerEncoder.unsafeEncode(a, indent, out) + case Validation.Failure(_, _) => () + case Validation.Success(_, a) => innerEncoder.unsafeEncode(a, indent, out) } override def isNothing(b: B): Boolean = g(b) match { - case Left(_) => false - case Right(a) => innerEncoder.isNothing(a) + case Validation.Failure(_, _) => false + case Validation.Success(_, a) => innerEncoder.isNothing(a) } } @@ -474,10 +477,10 @@ object JsonCodec { import Codecs._ import ProductDecoder._ - final def decode[A](schema: Schema[A], json: String): Either[DecodeError, A] = + final def decode[A](schema: Schema[A], json: String): Validation[DecodeError, A] = schemaDecoder(schema).decodeJson(json) match { - case Left(value) => Left(ReadError(Cause.empty, value)) - case Right(value) => Right(value) + case Left(value) => Validation.fail(ReadError(Cause.empty, value)) + case Right(value) => Validation.succeed(value) } def x[A](dec: ZJsonDecoder[A]): Unit = dec match { @@ -489,7 +492,7 @@ object JsonCodec { case Schema.Primitive(standardType, _) => primitiveCodec(standardType).decoder case Schema.Optional(codec, _) => ZJsonDecoder.option(schemaDecoder(codec, hasDiscriminator)) case Schema.Tuple2(left, right, _) => ZJsonDecoder.tuple2(schemaDecoder(left, hasDiscriminator), schemaDecoder(right, hasDiscriminator)) - case Schema.Transform(codec, f, _, _, _) => schemaDecoder(codec, hasDiscriminator).mapOrFail(f) + case Schema.Transform(codec, f, _, _, _) => schemaDecoder(codec, hasDiscriminator).mapOrFail(g => f(g).toEither.left.map(_.head)) case Schema.Sequence(codec, f, _, _, _) => ZJsonDecoder.chunk(schemaDecoder(codec, hasDiscriminator)).map(f) case Schema.Map(ks, vs, _) => mapDecoder(ks, vs, hasDiscriminator) case Schema.Set(s, _) => ZJsonDecoder.chunk(schemaDecoder(s, hasDiscriminator)).map(entries => entries.toSet) diff --git a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala index d35adb72d..4f8730053 100644 --- a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala +++ b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala @@ -8,6 +8,7 @@ import zio.Console._ import zio._ import zio.json.JsonDecoder.JsonError import zio.json.{ DeriveJsonEncoder, JsonEncoder } +import zio.prelude.Validation import zio.schema.CaseSet._ import zio.schema._ import zio.schema.annotation._ @@ -275,7 +276,7 @@ object JsonCodecSpec extends ZIOSpecDefault { val errorMessage = "I'm sorry Dave, I can't do that" val schema: Schema[Int] = Schema .Primitive(StandardType.StringType) - .transformOrFail[Int](_ => Left(errorMessage), i => Right(i.toString)) + .transformOrFail[Int](_ => Validation.fail(errorMessage), i => Validation.succeed(i.toString)) check(Gen.int(Int.MinValue, Int.MaxValue)) { int => assertDecodesToError( schema, @@ -534,9 +535,9 @@ object JsonCodecSpec extends ZIOSpecDefault { ) ) { case (schema, value) => - assertEncodesThenDecodes[scala.util.Either[Map[Any, Any], Map[Any, Any]]]( - schema.asInstanceOf[Schema[scala.util.Either[Map[Any, Any], Map[Any, Any]]]], - value.asInstanceOf[scala.util.Either[Map[Any, Any], Map[Any, Any]]] + assertEncodesThenDecodes[scala.Either[Map[Any, Any], Map[Any, Any]]]( + schema.asInstanceOf[Schema[scala.Either[Map[Any, Any], Map[Any, Any]]]], + value.asInstanceOf[scala.Either[Map[Any, Any], Map[Any, Any]]] ) } }, @@ -552,9 +553,9 @@ object JsonCodecSpec extends ZIOSpecDefault { ) ) { case (schema, value) => - assertEncodesThenDecodes[scala.util.Either[Set[Any], Set[Any]]]( - schema.asInstanceOf[Schema[scala.util.Either[Set[Any], Set[Any]]]], - value.asInstanceOf[scala.util.Either[Set[Any], Set[Any]]] + assertEncodesThenDecodes[scala.Either[Set[Any], Set[Any]]]( + schema.asInstanceOf[Schema[scala.Either[Set[Any], Set[Any]]]], + value.asInstanceOf[scala.Either[Set[Any], Set[Any]]] ) } }, diff --git a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackCodec.scala b/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackCodec.scala index ceb7faf68..3290317da 100644 --- a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackCodec.scala +++ b/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackCodec.scala @@ -3,10 +3,11 @@ package zio.schema.codec import java.math.{ BigInteger, MathContext } import java.time._ +import zio.prelude.Validation import zio.schema.codec.DecodeError.ReadError import zio.schema.{ Schema, StandardType } import zio.stream.ZPipeline -import zio.{ Cause, Chunk, ZIO } +import zio.{ Cause, Chunk } object MessagePackCodec { implicit def messagePackCodec[A](implicit schema: Schema[A]): BinaryCodec[A] = @@ -14,9 +15,9 @@ object MessagePackCodec { override def encode(a: A): Chunk[Byte] = new MessagePackEncoder().encode(schema, a) - override def decode(bytes: Chunk[Byte]): Either[DecodeError, A] = + override def decode(bytes: Chunk[Byte]): Validation[DecodeError, A] = if (bytes.isEmpty) - Left(ReadError(Cause.empty, "No bytes to decode")) + Validation.fail(ReadError(Cause.empty, "No bytes to decode")) else decodeChunk(bytes) @@ -29,16 +30,12 @@ object MessagePackCodec { override def streamDecoder: ZPipeline[Any, DecodeError, Byte, A] = ZPipeline.mapChunksZIO { chunk => - ZIO.fromEither( - decodeChunk(chunk).map(Chunk(_)) - ) + decodeChunk(chunk).map(Chunk(_)).toZIO } private def decodeChunk(chunk: Chunk[Byte]) = new MessagePackDecoder(chunk) .decode(schema) - .left - .map(identity) } //TODO those are duplicates from ThriftCodec diff --git a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackDecoder.scala b/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackDecoder.scala index 821baf4b6..6cb6447c1 100644 --- a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackDecoder.scala +++ b/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackDecoder.scala @@ -10,6 +10,7 @@ import scala.util.{ Failure, Success, Try } import org.msgpack.core.{ MessagePack, MessageUnpacker } +import zio.prelude.Validation import zio.schema.codec.DecodeError.MalformedFieldWithPath import zio.schema.codec.MessagePackDecoder._ import zio.schema.{ DynamicValue, Schema, StandardType } @@ -105,8 +106,8 @@ private[codec] class MessagePackDecoder(bytes: Chunk[Byte]) { case _ => fail(path, s"Unknown schema ${schema.getClass.getName}") } - private def decodeTransform[A, B](path: Path, schema: Schema[B], f: B => scala.util.Either[String, A]): Result[A] = - decodeValue(path, schema).flatMap(a => f(a).left.map(msg => MalformedFieldWithPath(path, msg))) + private def decodeTransform[A, B](path: Path, schema: Schema[B], f: B => Validation[String, A]): Result[A] = + decodeValue(path, schema).flatMap(a => f(a).mapError(msg => MalformedFieldWithPath(path, msg))) private def decodeRecord[Z](path: Path, fields: Seq[Schema.Field[Z, _]]): Result[ListMap[String, _]] = decodeStructure(path, fields.map(f => f.name -> f.schema).toMap) @@ -122,8 +123,8 @@ private[codec] class MessagePackDecoder(bytes: Chunk[Byte]) { fields.get(fieldName) match { case Some(fieldSchema) => decodeValue(actualPath, fieldSchema) match { - case Left(err) => Left(err) - case Right(value) => + case f @ Validation.Failure(_, _) => f + case Validation.Success(_, value) => if (index == fields.size) { succeed(m.updated(fieldName, value)) } else { @@ -151,10 +152,10 @@ private[codec] class MessagePackDecoder(bytes: Chunk[Byte]) { def decodeElements(n: Int, m: scala.collection.mutable.Map[K, V]): Result[scala.collection.immutable.Map[K, V]] = if (n > 0) { (decodeValue(path, schema.keySchema), decodeValue(path, schema.valueSchema)) match { - case (Right(key), Right(value)) => decodeElements(n - 1, m += ((key, value))) + case (Validation.Success(_, key), Validation.Success(_, value)) => decodeElements(n - 1, m += ((key, value))) case (l, r) => - val key = l.fold(_.message, _.toString) - val value = r.fold(_.message, _.toString) + val key = l.fold(_.map(_.message).toString(), _.toString) + val value = r.fold(_.map(_.message).toString(), _.toString) fail(path, s"Error decoding Map element (key: $key; value: $value)") } } else { @@ -172,8 +173,8 @@ private[codec] class MessagePackDecoder(bytes: Chunk[Byte]) { def decodeElements(n: Int, cb: ChunkBuilder[A]): Result[Chunk[A]] = if (n > 0) { decodeValue(path, elementSchema) match { - case Right(elem) => decodeElements(n - 1, cb += elem) - case Left(err) => Left(err) + case Validation.Success(_, elem) => decodeElements(n - 1, cb += elem) + case failure @ Validation.Failure(_, _) => failure } } else { succeed(cb.result()) @@ -217,7 +218,7 @@ private[codec] class MessagePackDecoder(bytes: Chunk[Byte]) { } yield new java.math.BigDecimal(unscaled, scale, ctx) opt match { - case Some(value) => Right(value) + case Some(value) => Validation.succeed(value) case None => fail(path, s"Invalid big decimal record $data") } } @@ -614,11 +615,11 @@ private[codec] class MessagePackDecoder(bytes: Chunk[Byte]) { object MessagePackDecoder { type Path = Chunk[String] - type Result[A] = scala.util.Either[DecodeError, A] + type Result[A] = Validation[DecodeError, A] private def succeed[A](a: => A): Result[A] = - Right(a) + Validation.succeed(a) private def fail(path: Path, failure: String): Result[Nothing] = - Left(MalformedFieldWithPath(path, failure)) + Validation.fail(MalformedFieldWithPath(path, failure)) } diff --git a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackEncoder.scala b/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackEncoder.scala index ca267d2fc..a14713d59 100644 --- a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackEncoder.scala +++ b/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackEncoder.scala @@ -23,16 +23,16 @@ private[codec] class MessagePackEncoder { //scalafmt: { maxColumn = 400, optIn.configStyleArguments = false } private def encodeValue[A](schema: Schema[A], value: A): Unit = (schema, value) match { - case (Schema.GenericRecord(_, structure, _), v: Map[String, _]) => encodeRecord(structure.toChunk, v) - case (Schema.Sequence(element, _, g, _, _), v) => encodeSequence(element, g(v)) - case (mapSchema: Schema.Map[_, _], map: Map[_, _]) => encodeMap(mapSchema.asInstanceOf[Schema.Map[Any, Any]], map.asInstanceOf[scala.collection.immutable.Map[Any, Any]]) - case (setSchema: Schema.Set[_], set: Set[_]) => encodeSet(setSchema.asInstanceOf[Schema.Set[Any]].elementSchema, set.asInstanceOf[scala.collection.immutable.Set[Any]]) - case (Schema.Transform(schema, _, g, _, _), _) => g(value).foreach(encodeValue(schema, _)) - case (Schema.Primitive(standardType, _), v) => encodePrimitive(standardType, v) - case (Schema.Tuple2(left, right, _), v @ (_, _)) => encodeTuple(left, right, v) - case (optSchema: Schema.Optional[_], v: Option[_]) => encodeOptional(optSchema.asInstanceOf[Schema.Optional[Any]].schema, v.asInstanceOf[Option[Any]]) - case (eitherSchema: Schema.Either[_, _], v: scala.util.Either[_, _]) => encodeEither(eitherSchema.asInstanceOf[Schema.Either[Any, Any]].left, eitherSchema.asInstanceOf[Schema.Either[Any, Any]].right, v.asInstanceOf[scala.util.Either[Any, Any]]) - case (lzy @ Schema.Lazy(_), v) => encodeValue(lzy.schema, v) + case (Schema.GenericRecord(_, structure, _), v: Map[String, _]) => encodeRecord(structure.toChunk, v) + case (Schema.Sequence(element, _, g, _, _), v) => encodeSequence(element, g(v)) + case (mapSchema: Schema.Map[_, _], map: Map[_, _]) => encodeMap(mapSchema.asInstanceOf[Schema.Map[Any, Any]], map.asInstanceOf[scala.collection.immutable.Map[Any, Any]]) + case (setSchema: Schema.Set[_], set: Set[_]) => encodeSet(setSchema.asInstanceOf[Schema.Set[Any]].elementSchema, set.asInstanceOf[scala.collection.immutable.Set[Any]]) + case (Schema.Transform(schema, _, g, _, _), _) => g(value).map(v => encodeValue(schema, v)): Unit + case (Schema.Primitive(standardType, _), v) => encodePrimitive(standardType, v) + case (Schema.Tuple2(left, right, _), v @ (_, _)) => encodeTuple(left, right, v) + case (optSchema: Schema.Optional[_], v: Option[_]) => encodeOptional(optSchema.asInstanceOf[Schema.Optional[Any]].schema, v.asInstanceOf[Option[Any]]) + case (eitherSchema: Schema.Either[_, _], v: Either[_, _]) => encodeEither(eitherSchema.asInstanceOf[Schema.Either[Any, Any]].left, eitherSchema.asInstanceOf[Schema.Either[Any, Any]].right, v.asInstanceOf[scala.Either[Any, Any]]) + case (lzy @ Schema.Lazy(_), v) => encodeValue(lzy.schema, v) // case (Schema.Meta(ast, _), _) => encodeValue(fieldNumber, Schema[MetaSchema], ast) case (Schema.CaseClass0(_, _, _), _) => encodePrimitive(StandardType.UnitType, ()) case (Schema.CaseClass1(_, f, _, _), v) => encodeCaseClass(v, f) @@ -128,7 +128,7 @@ private[codec] class MessagePackEncoder { } } - private def encodeEither[A, B](left: Schema[A], right: Schema[B], either: scala.util.Either[A, B]): Unit = { + private def encodeEither[A, B](left: Schema[A], right: Schema[B], either: Either[A, B]): Unit = { packer.packMapHeader(1) either match { case Left(value) => diff --git a/zio-schema-msg-pack/shared/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala b/zio-schema-msg-pack/shared/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala index dd3886b42..7263e8945 100644 --- a/zio-schema-msg-pack/shared/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala +++ b/zio-schema-msg-pack/shared/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala @@ -989,7 +989,7 @@ object MessagePackCodecSpec extends ZIOSpecDefault { //NS == non streaming variant of decode def decodeNS[A](schema: Schema[A], hex: String): ZIO[Any, DecodeError, A] = - ZIO.succeed(MessagePackCodec.messagePackCodec(schema).decode(fromHex(hex))).absolve[DecodeError, A] + MessagePackCodec.messagePackCodec(schema).decode(fromHex(hex)).toZIO def encodeAndDecode[A](schema: Schema[A], input: A): ZIO[Any, DecodeError, Chunk[A]] = ZStream @@ -1006,20 +1006,26 @@ object MessagePackCodecSpec extends ZIOSpecDefault { .run(ZSink.collectAll) //NS == non streaming variant of encodeAndDecode - def encodeAndDecodeNS[A](schema: Schema[A], input: A, print: Boolean = false): ZIO[Any, DecodeError, A] = + def encodeAndDecodeNS[A]( + schema: Schema[A], + input: A, + print: Boolean = false + ): ZIO[Any, DecodeError, A] = ZIO .succeed(input) .tap(value => Console.printLine(s"Input Value: $value").when(print).ignore) .map(a => MessagePackCodec.messagePackCodec(schema).encode(a)) .tap(encoded => Console.printLine(s"\nEncoded Bytes:\n${toHex(encoded)}").when(print).ignore) - .map(ch => MessagePackCodec.messagePackCodec(schema).decode(ch)) - .absolve + .flatMap(ch => MessagePackCodec.messagePackCodec(schema).decode(ch).toZIO) - def encodeAndDecodeNS[A](encodeSchema: Schema[A], decodeSchema: Schema[A], input: A): ZIO[Any, DecodeError, A] = + def encodeAndDecodeNS[A]( + encodeSchema: Schema[A], + decodeSchema: Schema[A], + input: A + ): ZIO[Any, DecodeError, A] = ZIO .succeed(input) .map(a => MessagePackCodec.messagePackCodec(encodeSchema).encode(a)) - .map(ch => MessagePackCodec.messagePackCodec(decodeSchema).decode(ch)) - .absolve + .flatMap(ch => MessagePackCodec.messagePackCodec(decodeSchema).decode(ch).toZIO) } diff --git a/zio-schema-optics/shared/src/main/scala/zio/schema/optics/ZioOpticsBuilder.scala b/zio-schema-optics/shared/src/main/scala/zio/schema/optics/ZioOpticsBuilder.scala index 6da76d0d8..03bb3fcfa 100644 --- a/zio-schema-optics/shared/src/main/scala/zio/schema/optics/ZioOpticsBuilder.scala +++ b/zio-schema-optics/shared/src/main/scala/zio/schema/optics/ZioOpticsBuilder.scala @@ -68,8 +68,8 @@ object ZioOpticsBuilder extends AccessorBuilder { values .get(term.name) .map { dynamicField => - term.schema.fromDynamic(dynamicField) match { - case Left(error) => Left(OpticFailure(error) -> whole) + term.schema.fromDynamic(dynamicField).toEither match { + case Left(error) => Left(OpticFailure(error.toString()) -> whole) case Right(value) => Right(value) } } @@ -85,8 +85,8 @@ object ZioOpticsBuilder extends AccessorBuilder { product.toDynamic(whole) match { case DynamicValue.Record(name, values) => val updated = spliceRecord(values, term.name, term.name -> term.schema.toDynamic(piece)) - product.fromDynamic(DynamicValue.Record(name, updated)) match { - case Left(error) => Left(OpticFailure(error) -> whole) + product.fromDynamic(DynamicValue.Record(name, updated)).toEither match { + case Left(error) => Left(OpticFailure(error.toString()) -> whole) case Right(value) => Right(value) } case _ => Left(OpticFailure(s"Unexpected dynamic value for whole") -> whole) diff --git a/zio-schema-protobuf/shared/src/main/scala/zio/schema/codec/ProtobufCodec.scala b/zio-schema-protobuf/shared/src/main/scala/zio/schema/codec/ProtobufCodec.scala index 01a25f7fd..b1decd2ee 100644 --- a/zio-schema-protobuf/shared/src/main/scala/zio/schema/codec/ProtobufCodec.scala +++ b/zio-schema-protobuf/shared/src/main/scala/zio/schema/codec/ProtobufCodec.scala @@ -9,22 +9,25 @@ import java.util.UUID import scala.collection.immutable.ListMap import scala.util.control.NonFatal +import zio.prelude.Validation import zio.schema.MutableSchemaBasedValueBuilder.CreateValueFromSchemaError import zio.schema._ import zio.schema.codec.DecodeError.{ ExtraFields, MalformedField, MissingField } import zio.schema.codec.ProtobufCodec.Protobuf.WireType.LengthDelimited import zio.stream.ZPipeline -import zio.{ Cause, Chunk, ChunkBuilder, Unsafe, ZIO } +import zio.{ Cause, Chunk, ChunkBuilder, Unsafe } object ProtobufCodec { implicit def protobufCodec[A](implicit schema: Schema[A]): BinaryCodec[A] = new BinaryCodec[A] { - override def decode(whole: Chunk[Byte]): Either[DecodeError, A] = + override def decode(whole: Chunk[Byte]): zio.prelude.Validation[DecodeError, A] = new Decoder(whole).decode(schema) override def streamDecoder: ZPipeline[Any, DecodeError, Byte, A] = - ZPipeline.mapChunksZIO(chunk => ZIO.fromEither(new Decoder(chunk).decode(schema).map(Chunk(_)))) + ZPipeline.mapChunksZIO( + chunk => new Decoder(chunk).decode(schema).map(Chunk(_)).toZIO + ) override def encode(value: A): Chunk[Byte] = Encoder.process(schema, value) @@ -493,18 +496,16 @@ object ProtobufCodec { private val state: DecoderState = new DecoderState(chunk, 0) - def decode[A](schema: Schema[A]): scala.util.Either[DecodeError, A] = - try { - Right(create(schema).asInstanceOf[A]) - } catch { + def decode[A](schema: Schema[A]): zio.prelude.Validation[DecodeError, A] = + Validation(create(schema).asInstanceOf[A]).mapError { case CreateValueFromSchemaError(_, cause) => cause match { - case error: DecodeError => Left(error) + case error: DecodeError => error case _ => - Left(DecodeError.ReadError(Cause.fail(cause), cause.getMessage)) + DecodeError.ReadError(Cause.fail(cause), cause.getMessage) } case NonFatal(err) => - Left(DecodeError.ReadError(Cause.fail(err), err.getMessage)) + DecodeError.ReadError(Cause.fail(err), err.getMessage) } private def createTypedPrimitive[A](context: DecoderContext, standardType: StandardType[A]): A = @@ -623,10 +624,10 @@ object ProtobufCodec { values: Chunk[(Int, Any)] ): Any = Unsafe.unsafe { implicit u => - record.construct(values.map(_._2)) match { - case Right(result) => result - case Left(message) => throw DecodeError.ReadError(Cause.empty, message) - } + //TODO: Maybe combine exceptions? + record + .construct(values.map(_._2)) + .fold(message => throw DecodeError.ReadError(Cause.empty, message.toString()), a => a) } override protected def startCreatingEnum( @@ -875,13 +876,11 @@ object ProtobufCodec { override protected def transform( context: DecoderContext, value: Any, - f: Any => Either[String, Any], + f: Any => zio.prelude.Validation[String, Any], schema: Schema[_] ): Any = - f(value) match { - case Left(value) => throw MalformedField(schema, value) - case Right(value) => value - } + //TODO: Maybe combine exceptions? + f(value).fold(v => throw MalformedField(schema, v.toString()), a => a) override protected def fail(context: DecoderContext, message: String): Any = throw DecodeError.ReadError(Cause.empty, message) diff --git a/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala b/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala index b15dc82ad..e5d6e294c 100644 --- a/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala +++ b/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala @@ -8,6 +8,7 @@ import scala.util.Try import zio.Console._ import zio._ +import zio.prelude.Validation import zio.schema.CaseSet._ import zio.schema.meta.MetaSchema import zio.schema.{ CaseSet, DeriveSchema, DynamicValue, DynamicValueGen, Schema, SchemaGen, StandardType, TypeId } @@ -585,7 +586,7 @@ object ProtobufCodecSpec extends ZIOSpecDefault { test("sequence of tuples") { for { ed <- encodeAndDecodeNS2(Schema[List[(String, Int)]], List("foo" -> 1, "bar" -> 2)) - } yield assertTrue(ed == Right(List("foo" -> 1, "bar" -> 2))) + } yield assertTrue(ed == zio.prelude.Validation.succeed(List("foo" -> 1, "bar" -> 2))) }, test("sequence of products") { val richSequence = SequenceOfProduct( @@ -1044,7 +1045,7 @@ object ProtobufCodecSpec extends ZIOSpecDefault { //NS == non streaming variant of decode def decodeNS[A](schema: Schema[A], hex: String): ZIO[Any, DecodeError, A] = - ZIO.succeed(ProtobufCodec.protobufCodec(schema).decode(fromHex(hex))).absolve[DecodeError, A] + ProtobufCodec.protobufCodec(schema).decode(fromHex(hex)).toZIO def encodeAndDecode[A](schema: Schema[A], input: A): ZIO[Any, DecodeError, Chunk[A]] = ProtobufCodec @@ -1054,7 +1055,7 @@ object ProtobufCodecSpec extends ZIOSpecDefault { .apply(ZStream.succeed(input)) .run(ZSink.collectAll) - def encodeAndDecode2[A](schema: Schema[A], input: A): ZIO[Any, Any, scala.util.Either[DecodeError, Chunk[A]]] = + def encodeAndDecode2[A](schema: Schema[A], input: A): ZIO[Any, Any, scala.Either[DecodeError, Chunk[A]]] = ProtobufCodec .protobufCodec(schema) .streamEncoder @@ -1083,13 +1084,13 @@ object ProtobufCodecSpec extends ZIOSpecDefault { .map(a => ProtobufCodec.protobufCodec(schema).encode(a)) .tap(encoded => printLine(s"\nEncoded Bytes (${encoded.size}):\n${toHex(encoded)}").when(print).ignore) .map(ch => ProtobufCodec.protobufCodec(schema).decode(ch)) - .absolve + .flatMap(_.toZIO) def encodeAndDecodeNS2[A]( schema: Schema[A], input: A, print: Boolean = false - ): ZIO[Any, DecodeError, scala.util.Either[DecodeError, A]] = + ): ZIO[Any, DecodeError, Validation[DecodeError, A]] = ZIO .succeed(input) .tap(value => printLine(s"Input Value: $value").when(print).ignore) @@ -1097,7 +1098,8 @@ object ProtobufCodecSpec extends ZIOSpecDefault { .tap(encoded => printLine(s"\nEncoded Bytes:\n${toHex(encoded)}").when(print).ignore) .map(ch => ProtobufCodec.protobufCodec(schema).decode(ch)) .tapSome { - case Left(err) => printLine(s"Failed to encode and decode value $input\nError = $err").orDie + case prelude.Validation.Failure(_, err) => + printLine(s"Failed to encode and decode value $input\nError = $err").orDie } def encodeAndDecodeNS[A](encodeSchema: Schema[A], decodeSchema: Schema[A], input: A): ZIO[Any, DecodeError, A] = @@ -1105,6 +1107,6 @@ object ProtobufCodecSpec extends ZIOSpecDefault { .succeed(input) .map(a => ProtobufCodec.protobufCodec(encodeSchema).encode(a)) .map(ch => ProtobufCodec.protobufCodec(decodeSchema).decode(ch)) - .absolve + .flatMap(_.toZIO) } diff --git a/zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ThriftCodec.scala b/zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ThriftCodec.scala index 411b5c558..43d0d9f07 100644 --- a/zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ThriftCodec.scala +++ b/zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ThriftCodec.scala @@ -4,34 +4,33 @@ import java.nio.ByteBuffer import java.time._ import java.util.UUID -import scala.annotation.{ nowarn, tailrec } +import scala.annotation.tailrec import scala.collection.immutable.ListMap import scala.util.control.NonFatal import org.apache.thrift.protocol._ +import zio.prelude.Validation import zio.schema.MutableSchemaBasedValueBuilder.CreateValueFromSchemaError import zio.schema._ import zio.schema.annotation.{ fieldDefaultValue, optionalField, transientField } import zio.schema.codec.DecodeError.{ EmptyContent, MalformedFieldWithPath, ReadError, ReadErrorWithPath } import zio.stream.ZPipeline -import zio.{ Cause, Chunk, Unsafe, ZIO } +import zio.{ Cause, Chunk, NonEmptyChunk, Unsafe } object ThriftCodec { implicit def thriftCodec[A](implicit schema: Schema[A]): BinaryCodec[A] = new BinaryCodec[A] { - override def decode(whole: Chunk[Byte]): Either[DecodeError, A] = + override def decode(whole: Chunk[Byte]): Validation[DecodeError, A] = if (whole.isEmpty) - Left(EmptyContent("No bytes to decode")) + Validation.fail(EmptyContent("No bytes to decode")) else decodeChunk(whole) override def streamDecoder: ZPipeline[Any, DecodeError, Byte, A] = ZPipeline.mapChunksZIO { chunk => - ZIO.fromEither( - decodeChunk(chunk).map(Chunk(_)) - ) + decodeChunk(chunk).map(Chunk(_)).toZIO } override def encode(value: A): Chunk[Byte] = @@ -44,29 +43,27 @@ object ThriftCodec { } } - private def decodeChunk(chunk: Chunk[Byte]): Either[DecodeError, A] = + private def decodeChunk(chunk: Chunk[Byte]): Validation[DecodeError, A] = if (chunk.isEmpty) - Left(EmptyContent("No bytes to decode")) + Validation.fail(EmptyContent("No bytes to decode")) else { - try { - Right( + zio.prelude + .Validation( new Decoder(chunk) .create(schema) .asInstanceOf[A] ) - } catch { - case error: CreateValueFromSchemaError[DecoderContext] => - error.cause match { - case error: DecodeError => Left(error) - case _ => - Left( + .mapError { + case error: CreateValueFromSchemaError[DecoderContext] => + error.cause match { + case error: DecodeError => error + case _ => ReadErrorWithPath(error.context.path, Cause.fail(error.cause), error.cause.getMessage) - ) - } - case NonFatal(err) => - Left(ReadError(Cause.fail(err), err.getMessage)) - } - }: @nowarn + } + case NonFatal(err) => + ReadError(Cause.fail(err), err.getMessage) + } + } } class Encoder extends MutableSchemaBasedValueProcessor[Unit, Encoder.Context] { @@ -625,17 +622,11 @@ object ThriftCodec { } } Unsafe.unsafe { implicit u => - record.construct(allValues) match { - case Left(message) => fail(context, message) - case Right(value) => value - } + record.construct(allValues).fold(message => fail(context, message), a => a) } } else { Unsafe.unsafe { implicit u => - record.construct(Chunk.empty) match { - case Left(message) => fail(context, message) - case Right(value) => value - } + record.construct(Chunk.empty).fold(message => fail(context, message), a => a) } } @@ -778,7 +769,7 @@ object ThriftCodec { readField.id match { case 1 => Left(context.copy(path = context.path :+ "either:left")) case 2 => Right(context.copy(path = context.path :+ "either:right")) - case _ => fail(context, "Failed to decode either.").asInstanceOf[Either[DecoderContext, DecoderContext]] + case _ => fail(context, "Failed to decode either.").asInstanceOf[Nothing] } } @@ -818,17 +809,17 @@ object ThriftCodec { override protected def transform( context: DecoderContext, value: Any, - f: Any => Either[String, Any], + f: Any => Validation[String, Any], schema: Schema[_] ): Any = - f(value) match { - case Left(value) => fail(context, value) - case Right(value) => value - } + f(value).fold(v => fail(context, v), a => a) - override protected def fail(context: DecoderContext, message: String): Any = + override protected def fail(context: DecoderContext, message: String): Nothing = throw MalformedFieldWithPath(context.path, message) + protected def fail(context: DecoderContext, message: NonEmptyChunk[String]): Nothing = + throw MalformedFieldWithPath(context.path, message.mkString) + override protected val initialContext: DecoderContext = DecoderContext(Chunk.empty, None) private def emptyValue[A](schema: Schema[A]): Option[A] = schema match { diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala b/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala index 67c4cd9f5..b2aed6222 100644 --- a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala +++ b/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala @@ -1132,7 +1132,7 @@ object ThriftCodecSpec extends ZIOSpecDefault { //NS == non streaming variant of decode def decodeNS[A](schema: Schema[A], hex: String): ZIO[Any, DecodeError, A] = - ZIO.succeed(ThriftCodec.thriftCodec(schema).decode(fromHex(hex))).absolve[DecodeError, A] + ThriftCodec.thriftCodec(schema).decode(fromHex(hex)).toZIO def encodeAndDecode[A](schema: Schema[A], input: A): ZIO[Any, DecodeError, Chunk[A]] = ZStream @@ -1149,20 +1149,28 @@ object ThriftCodecSpec extends ZIOSpecDefault { .run(ZSink.collectAll) //NS == non streaming variant of encodeAndDecode - def encodeAndDecodeNS[A](schema: Schema[A], input: A, print: Boolean = false): ZIO[Any, DecodeError, A] = + def encodeAndDecodeNS[A]( + schema: Schema[A], + input: A, + print: Boolean = false + ): ZIO[Any, DecodeError, A] = ZIO .succeed(input) .tap(value => Console.printLine(s"Input Value: $value").when(print).ignore) .map(a => ThriftCodec.thriftCodec(schema).encode(a)) .tap(encoded => Console.printLine(s"\nEncoded Bytes:\n${toHex(encoded)}").when(print).ignore) .map(ch => ThriftCodec.thriftCodec(schema).decode(ch)) - .absolve + .flatMap(_.toZIO) - def encodeAndDecodeNS[A](encodeSchema: Schema[A], decodeSchema: Schema[A], input: A): ZIO[Any, DecodeError, A] = + def encodeAndDecodeNS[A]( + encodeSchema: Schema[A], + decodeSchema: Schema[A], + input: A + ): ZIO[Any, DecodeError, A] = ZIO .succeed(input) .map(a => ThriftCodec.thriftCodec(encodeSchema).encode(a)) .map(ch => ThriftCodec.thriftCodec(decodeSchema).decode(ch)) - .absolve + .flatMap(_.toZIO) } diff --git a/zio-schema-zio-test/shared/src/main/scala/zio/schema/DeriveGen.scala b/zio-schema-zio-test/shared/src/main/scala/zio/schema/DeriveGen.scala index c2cf96731..b4c5cc03e 100644 --- a/zio-schema-zio-test/shared/src/main/scala/zio/schema/DeriveGen.scala +++ b/zio-schema-zio-test/shared/src/main/scala/zio/schema/DeriveGen.scala @@ -529,7 +529,7 @@ object DeriveGen { private def genTuple[A, B](tuple: Schema.Tuple2[A, B]): Gen[Sized, (A, B)] = gen(tuple.left).zip(gen(tuple.right)) - private def genEither[A, B](either: Schema.Either[A, B]): Gen[Sized, scala.util.Either[A, B]] = + private def genEither[A, B](either: Schema.Either[A, B]): Gen[Sized, scala.Either[A, B]] = Gen.either(gen(either.left), gen(either.right)) private def genLazy[A](lazySchema: Schema.Lazy[A]): Gen[Sized, A] = diff --git a/zio-schema-zio-test/shared/src/test/scala/zio/schema/TestData.scala b/zio-schema-zio-test/shared/src/test/scala/zio/schema/TestData.scala index 49de74a50..2f62202c0 100644 --- a/zio-schema-zio-test/shared/src/test/scala/zio/schema/TestData.scala +++ b/zio-schema-zio-test/shared/src/test/scala/zio/schema/TestData.scala @@ -1,6 +1,7 @@ package zio.schema import zio.Chunk +import zio.prelude.Validation object TestData { @@ -55,7 +56,8 @@ object TestData { val optionalSchema: Schema[Option[Int]] = Schema.Optional(intSchema) val transformSchema: Schema[String] = - intSchema.transformOrFail[String]((int: Int) => Right(int.toString), (_: String) => Left("error")) + intSchema + .transformOrFail[String]((int: Int) => Validation.succeed(int.toString), (_: String) => Validation.fail("error")) val failSchema: Schema[Unit] = Schema.Fail[Unit]("failed") val lazySchema: Schema[Int] = Schema.Lazy(() => intSchema) diff --git a/zio-schema/shared/src/main/scala/zio/schema/Differ.scala b/zio-schema/shared/src/main/scala/zio/schema/Differ.scala index 4f4dee67f..bfc389903 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/Differ.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/Differ.scala @@ -25,6 +25,7 @@ import java.util.UUID import scala.annotation.nowarn import scala.collection.immutable.ListMap +import zio.prelude.Validation import zio.schema.diff.Edit import zio.{ Chunk, ChunkBuilder } @@ -41,14 +42,15 @@ trait Differ[A] { self => def transform[B](f: B => A, g: A => B): Differ[B] = (thisValue: B, thatValue: B) => - Patch.Transform(self(f(thisValue), f(thatValue)), g.andThen(Right(_)), f.andThen(Right(_))) + Patch.Transform(self(f(thisValue), f(thatValue)), g.andThen(Validation.succeed), f.andThen(Validation.succeed)) - def transformOrFail[B](f: B => Either[String, A], g: A => Either[String, B]): Differ[B] = + def transformOrFail[B](f: B => Validation[String, A], g: A => Validation[String, B]): Differ[B] = (thisValue: B, thatValue: B) => - f(thisValue) -> f(thatValue) match { - case (Right(l), Right(r)) => Patch.Transform(self(l, r), g, f) - case _ => Patch.notComparable - } + (for { + l <- f(thisValue) + r <- f(thatValue) + } yield Patch.Transform(self(l, r), g, f)) + .getOrElse(Patch.notComparable) def chunk: Differ[Chunk[A]] = Differ.LCSDiff[A] @@ -56,8 +58,8 @@ trait Differ[A] { self => case (Some(l), Some(r)) => Patch.Transform[A, Option[A]]( self(l, r), - (a: A) => Right(Some(a)), - (a: Option[A]) => a.map(Right(_)).getOrElse(Left("Patch cannot be applied to None value")) + (a: A) => Validation.succeed(Some(a)), + (a: Option[A]) => Validation.fromOptionWith("Patch cannot be applied to None value")(a) ) case (Some(_), None) => Patch.Total(None) case (None, Some(r)) => Patch.Total(Some(r)) @@ -225,20 +227,13 @@ object Differ { case Schema.Primitive(StandardType.BigIntegerType, _) => bigInt case Schema.Primitive(StandardType.StringType, _) => string case Schema.Primitive(StandardType.UUIDType, _) => - string.transformOrFail[UUID]( - (uuid: UUID) => Right(uuid.toString), - (s: String) => - try { - Right(UUID.fromString(s)) - } catch { case e: Throwable => Left(s"$s is not a valid UUID: ${e.getMessage}") } - ) + string.transformOrFail[UUID]((uuid: UUID) => Validation.succeed(uuid.toString), (s: String) => Validation(UUID.fromString(s)).mapError(e => s"$s is not a valid UUID: ${e.getMessage}")) case Schema.Primitive(StandardType.ZoneIdType, _) => string.transformOrFail[ZoneId]( - (zoneId: ZoneId) => Right(zoneId.getId), + (zoneId: ZoneId) => Validation.succeed(zoneId.getId), (s: String) => - try { - Right(ZoneId.of(s)) - } catch { case e: Throwable => Left(s"$s is not a valid ZoneId: ${e.getMessage}") } + Validation(ZoneId.of(s)) + .mapError(e => s"$s is not a valid ZoneId: ${e.getMessage}") ) case Schema.Primitive(StandardType.DayOfWeekType, _) => dayOfWeek case Schema.Primitive(StandardType.PeriodType, _) => period @@ -529,8 +524,8 @@ object Differ { left(thisA, thatA) <*> right(thisB, thatB) } - def either[A, B](left: Differ[A], right: Differ[B]): Differ[Either[A, B]] = - instancePartial[Either[A, B]] { + def either[A, B](left: Differ[A], right: Differ[B]): Differ[scala.Either[A, B]] = + instancePartial[scala.Either[A, B]] { case (Left(l), Left(r)) => Patch.EitherDiff(Left(left(l, r))) case (Right(l), Right(r)) => Patch.EitherDiff(Right(right(l, r))) } diff --git a/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala b/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala index eae9bb983..ad45a0525 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala @@ -6,6 +6,7 @@ import java.util.UUID import scala.collection.immutable.ListMap +import zio.prelude.Validation import zio.schema.codec.DecodeError import zio.schema.meta.{ MetaSchema, Migration } import zio.{ Cause, Chunk, Unsafe } @@ -13,39 +14,42 @@ import zio.{ Cause, Chunk, Unsafe } sealed trait DynamicValue { self => - def transform(transforms: Chunk[Migration]): Either[String, DynamicValue] = - transforms.foldRight[Either[String, DynamicValue]](Right(self)) { - case (transform, Right(value)) => transform.migrate(value) - case (_, error @ Left(_)) => error + def transform(transforms: Chunk[Migration]): zio.prelude.Validation[String, DynamicValue] = + transforms.foldRight[zio.prelude.Validation[String, DynamicValue]](zio.prelude.Validation.succeed(self)) { + case (transform, result) => result.flatMap(transform.migrate) } - def toTypedValue[A](implicit schema: Schema[A]): Either[String, A] = - toTypedValueLazyError.left.map(_.message) + def toTypedValue[A](implicit schema: Schema[A]): Validation[String, A] = + toTypedValueLazyError.mapError(_.toString) - def toValue[A](implicit schema: Schema[A]): Either[DecodeError, A] = toTypedValueLazyError + def toValue[A](implicit schema: Schema[A]): Validation[DecodeError, A] = toTypedValueLazyError def toTypedValueOption[A](implicit schema: Schema[A]): Option[A] = toTypedValueLazyError.toOption - private def toTypedValueLazyError[A](implicit schema: Schema[A]): Either[DecodeError, A] = + private def toTypedValueLazyError[A](implicit schema: Schema[A]): Validation[DecodeError, A] = (self, schema) match { case (DynamicValue.Primitive(value, p), Schema.Primitive(p2, _)) if p == p2 => - Right(value.asInstanceOf[A]) + Validation.succeed(value.asInstanceOf[A]) case (DynamicValue.Record(_, values), Schema.GenericRecord(_, structure, _)) => - DynamicValue.decodeStructure(values, structure.toChunk).asInstanceOf[Either[DecodeError, A]] + DynamicValue.decodeStructure(values, structure.toChunk).asInstanceOf[Validation[DecodeError, A]] case (DynamicValue.Record(_, values), s: Schema.Record[A]) => DynamicValue .decodeStructure(values, s.fields) .map(m => Chunk.fromIterable(m.values)) - .flatMap(values => s.construct(values)(Unsafe.unsafe).left.map(err => DecodeError.MalformedField(s, err))) + .flatMap( + values => + s.construct(values)(Unsafe.unsafe) + .mapError(err => DecodeError.MalformedField(s, err)) + ) case (DynamicValue.Enumeration(_, (key, value)), s: Schema.Enum[A]) => s.caseOf(key) match { case Some(caseValue) => - value.toTypedValueLazyError(caseValue.schema).asInstanceOf[Either[DecodeError, A]] - case None => Left(DecodeError.MissingCase(key, s)) + value.toTypedValueLazyError(caseValue.schema).asInstanceOf[Validation[DecodeError, A]] + case None => Validation.fail(DecodeError.MissingCase(key, s)) } case (DynamicValue.LeftValue(value), Schema.Either(schema1, _, _)) => @@ -57,66 +61,59 @@ sealed trait DynamicValue { case (DynamicValue.Tuple(leftValue, rightValue), Schema.Tuple2(leftSchema, rightSchema, _)) => val typedLeft = leftValue.toTypedValueLazyError(leftSchema) val typedRight = rightValue.toTypedValueLazyError(rightSchema) - (typedLeft, typedRight) match { - case (Left(e1), Left(e2)) => - Left(DecodeError.And(e1, e2)) - case (_, Left(e)) => Left(e) - case (Left(e), _) => Left(e) - case (Right(a), Right(b)) => Right(a -> b) - } + Validation + .validate(typedLeft, typedRight) case (DynamicValue.Sequence(values), schema: Schema.Sequence[col, t, _]) => - values - .foldLeft[Either[DecodeError, Chunk[t]]](Right[DecodeError, Chunk[t]](Chunk.empty)) { - case (err @ Left(_), _) => err - case (Right(values), value) => - value.toTypedValueLazyError(schema.elementSchema).map(values :+ _) - } + Validation + .validateAll( + values.map(_.toTypedValueLazyError(schema.elementSchema)) + ) .map(schema.fromChunk) case (DynamicValue.SetValue(values), schema: Schema.Set[t]) => - values.foldLeft[Either[DecodeError, Set[t]]](Right[DecodeError, Set[t]](Set.empty)) { - case (err @ Left(_), _) => err - case (Right(values), value) => - value.toTypedValueLazyError(schema.elementSchema).map(values + _) - } + Validation + .validateAll( + values.map(_.toTypedValueLazyError(schema.elementSchema)) + ) case (DynamicValue.SomeValue(value), Schema.Optional(schema: Schema[_], _)) => value.toTypedValueLazyError(schema).map(Some(_)) case (DynamicValue.NoneValue, Schema.Optional(_, _)) => - Right(None) + Validation.succeed(None) case (value, Schema.Transform(schema, f, _, _, _)) => value .toTypedValueLazyError(schema) - .flatMap(value => f(value).left.map(err => DecodeError.MalformedField(schema, err))) + .flatMap(value => f(value).mapError(err => DecodeError.MalformedField(schema, err))) case (DynamicValue.Dictionary(entries), schema: Schema.Map[k, v]) => - entries.foldLeft[Either[DecodeError, Map[k, v]]](Right[DecodeError, Map[k, v]](Map.empty)) { - case (err @ Left(_), _) => err - case (Right(map), entry) => { - for { - key <- entry._1.toTypedValueLazyError(schema.keySchema) - value <- entry._2.toTypedValueLazyError(schema.valueSchema) - } yield map ++ Map(key -> value) - } - } + Validation + .validateAll( + entries.map { entry => + for { + key <- entry._1.toTypedValueLazyError(schema.keySchema) + value <- entry._2.toTypedValueLazyError(schema.valueSchema) + } yield key -> value + } + ) + .map(_.toMap) case (_, l @ Schema.Lazy(_)) => toTypedValueLazyError(l.schema) case (DynamicValue.Error(message), _) => - Left(DecodeError.ReadError(Cause.empty, message)) + Validation.fail(DecodeError.ReadError(Cause.empty, message)) case (DynamicValue.Tuple(dyn, DynamicValue.DynamicAst(ast)), _) => val valueSchema = ast.toSchema.asInstanceOf[Schema[Any]] dyn.toTypedValueLazyError(valueSchema).map(a => (a -> valueSchema).asInstanceOf[A]) - case (dyn, Schema.Dynamic(_)) => Right(dyn) + case (dyn, Schema.Dynamic(_)) => Validation.succeed(dyn) case _ => - Left(DecodeError.CastError(self, schema)) + Validation.fail(DecodeError.CastError(self, schema)) } } @@ -183,18 +180,20 @@ object DynamicValue { def decodeStructure( values: ListMap[String, DynamicValue], structure: Chunk[Schema.Field[_, _]] - ): Either[DecodeError, ListMap[String, _]] = { - val keys = values.keySet - keys.foldLeft[Either[DecodeError, ListMap[String, Any]]](Right(ListMap.empty)) { - case (Right(record), key) => - (structure.find(_.name == key), values.get(key)) match { - case (Some(field), Some(value)) => - value.toTypedValueLazyError(field.schema).map(value => (record + (key -> value))) - case _ => - Left(DecodeError.IncompatibleShape(values, structure)) - } - case (Left(err), _) => Left(err) - } + ): Validation[DecodeError, ListMap[String, _]] = { + val keys = values.keys.toSeq + Validation + .validateAll( + keys.map(key => { + (structure.find(_.name == key), values.get(key)) match { + case (Some(field), Some(value)) => + value.toTypedValueLazyError(field.schema).map(value => (key -> value)) + case _ => + Validation.fail(DecodeError.IncompatibleShape(values, structure)) + } + }) + ) + .map(seq => ListMap.from(seq)) } final case class Record(id: TypeId, values: ListMap[String, DynamicValue]) extends DynamicValue diff --git a/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueBuilder.scala b/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueBuilder.scala index 4a49f6b1a..b8b3ac7bb 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueBuilder.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueBuilder.scala @@ -2,6 +2,7 @@ package zio.schema import scala.util.control.NonFatal +import zio.prelude.Validation import zio.schema.MutableSchemaBasedValueBuilder.CreateValueFromSchemaError import zio.{ Chunk, ChunkBuilder } @@ -123,10 +124,17 @@ trait MutableSchemaBasedValueBuilder[Target, Context] { * this method is responsible for gathering enough information to decide whether the created value will * be a Left or a Right. The result value represents this, and for each case allows specifying a context * that will be used to create the inner value. */ - protected def startCreatingEither(context: Context, schema: Schema.Either[_, _]): Either[Context, Context] + protected def startCreatingEither( + context: Context, + schema: Schema.Either[_, _] + ): Either[Context, Context] /** Create the either value from an inner value */ - protected def createEither(context: Context, schema: Schema.Either[_, _], value: Either[Target, Target]): Target + protected def createEither( + context: Context, + schema: Schema.Either[_, _], + value: Either[Target, Target] + ): Target /** The next value to be created is a tuple with the given schema. The returned context is used to * construct the first element of the tuple. */ @@ -147,7 +155,12 @@ trait MutableSchemaBasedValueBuilder[Target, Context] { /** Transforms a value with the given function that can fail. Making this customizable allows encoding the failure * in Target. */ - protected def transform(context: Context, value: Target, f: Any => Either[String, Any], schema: Schema[_]): Target + protected def transform( + context: Context, + value: Target, + f: Any => Validation[String, Any], + schema: Schema[_] + ): Target /** Fail the builder with the given message */ protected def fail(context: Context, message: String): Target @@ -663,7 +676,9 @@ trait MutableSchemaBasedValueBuilder[Target, Context] { case s @ Schema.Transform(schema, f, _, _, _) => currentSchema = schema push { result => - finishWith(transform(currentContext, result, f.asInstanceOf[Any => Either[String, Any]], s)) + finishWith( + transform(currentContext, result, f.asInstanceOf[Any => Validation[String, Any]], s) + ) } case s @ Schema.CaseClass0(_, _, _) => @@ -1111,7 +1126,10 @@ trait SimpleMutableSchemaBasedValueBuilder[Target] extends MutableSchemaBasedVal protected def createOptional(schema: Schema.Optional[_], value: Option[Target]): Target - override protected def startCreatingEither(context: Unit, schema: Schema.Either[_, _]): Either[Unit, Unit] = + override protected def startCreatingEither( + context: Unit, + schema: Schema.Either[_, _] + ): Either[Unit, Unit] = startCreatingEither(schema) protected def startCreatingEither(schema: Schema.Either[_, _]): Either[Unit, Unit] @@ -1147,12 +1165,12 @@ trait SimpleMutableSchemaBasedValueBuilder[Target] extends MutableSchemaBasedVal override protected def transform( context: Unit, value: Target, - f: Any => Either[String, Any], + f: Any => Validation[String, Any], schema: Schema[_] ): Target = transform(value, f, schema) - protected def transform(value: Target, f: Any => Either[String, Any], schema: Schema[_]): Target + protected def transform(value: Target, f: Any => Validation[String, Any], schema: Schema[_]): Target override protected def fail(context: Unit, message: String): Target = fail(message) diff --git a/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueProcessor.scala b/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueProcessor.scala index c044608f4..d68667556 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueProcessor.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/MutableSchemaBasedValueProcessor.scala @@ -59,7 +59,11 @@ trait MutableSchemaBasedValueProcessor[Target, Context] { @nowarn protected def startProcessingEither(context: Context, schema: Schema.Either[_, _]): Unit = {} /** Process an either value using its already processed left or right value */ - protected def processEither(context: Context, schema: Schema.Either[_, _], value: Either[Target, Target]): Target + protected def processEither( + context: Context, + schema: Schema.Either[_, _], + value: Either[Target, Target] + ): Target /** Called before processing an option value */ @nowarn protected def startProcessingOption(context: Context, schema: Schema.Optional[_]): Unit = {} @@ -868,13 +872,13 @@ trait MutableSchemaBasedValueProcessor[Target, Context] { } case Schema.Transform(schema, _, g, _, _) => - g.asInstanceOf[Any => Either[String, Any]](currentValue) match { - case Left(message) => - finishWith(fail(currentContext, message)) - case Right(a) => + g.asInstanceOf[Any => zio.prelude.Validation[String, Any]](currentValue) + .fold({ errors => + finishWith(fail(currentContext, errors.toString())) + }, { a => currentValue = a currentSchema = schema - } + }) case s @ Schema.CaseClass0(_, _, _) => fields(s, currentValue) @@ -1347,7 +1351,10 @@ trait SimpleMutableSchemaBasedValueProcessor[Target] extends MutableSchemaBasedV protected def processSet(schema: Schema.Set[_], value: Set[Target]): Target - protected def processEither(schema: Schema.Either[_, _], value: Either[Target, Target]): Target + protected def processEither( + schema: Schema.Either[_, _], + value: Either[Target, Target] + ): Target protected def processOption(schema: Schema.Optional[_], value: Option[Target]): Target diff --git a/zio-schema/shared/src/main/scala/zio/schema/Patch.scala b/zio-schema/shared/src/main/scala/zio/schema/Patch.scala index 5d5e7e70b..2ace2593a 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/Patch.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/Patch.scala @@ -24,6 +24,7 @@ import scala.annotation.tailrec import scala.collection.immutable.ListMap import zio.Chunk +import zio.prelude.Validation import zio.schema.diff.Edit import zio.schema.meta.Migration @@ -36,7 +37,7 @@ sealed trait Patch[A] { self => def zip[B](that: Patch[B]): Patch[(A, B)] = Patch.Tuple(self, that) - def patch(a: A): Either[String, A] + def patch(a: A): Validation[String, A] def invert: Patch[A] @@ -54,48 +55,48 @@ object Patch { def notComparable[A]: NotComparable[A] = NotComparable() final case class Identical[A]() extends Patch[A] { - override def patch(a: A): Either[String, A] = Right(a) - override def isIdentical: Boolean = true + override def patch(a: A): Validation[String, A] = Validation.succeed(a) + override def isIdentical: Boolean = true override def invert: Patch[A] = this } final case class Bool(xor: Boolean) extends Patch[Boolean] { - override def patch(a: Boolean): Either[String, Boolean] = Right(a ^ xor) + override def patch(a: Boolean): Validation[String, Boolean] = Validation.succeed(a ^ xor) override def invert: Patch[Boolean] = this } final case class Number[A](distance: A)(implicit ev: Numeric[A]) extends Patch[A] { - override def patch(input: A): Either[String, A] = - Right(ev.minus(input, distance)) + override def patch(input: A): Validation[String, A] = + Validation.succeed(ev.minus(input, distance)) override def invert: Patch[A] = Number(ev.negate(distance)) } final case class BigInt(distance: BigInteger) extends Patch[BigInteger] { - override def patch(input: BigInteger): Either[String, BigInteger] = - Right(input.subtract(distance)) + override def patch(input: BigInteger): Validation[String, BigInteger] = + Validation.succeed(input.subtract(distance)) override def invert: Patch[BigInteger] = BigInt(distance.negate()) } final case class BigDecimal(distance: java.math.BigDecimal, precision: Int) extends Patch[java.math.BigDecimal] { - override def patch(input: java.math.BigDecimal): Either[String, java.math.BigDecimal] = { + override def patch(input: java.math.BigDecimal): Validation[String, java.math.BigDecimal] = { val mc = new MathContext(precision) - Right(input.round(mc).subtract(distance, mc)) + Validation.succeed(input.round(mc).subtract(distance, mc)) } override def invert: Patch[java.math.BigDecimal] = BigDecimal(distance.negate(), precision) } final case class Temporal[A](distances: List[Long], tpe: StandardType[A]) extends Patch[A] { self => - override def patch(a: A): Either[String, A] = + override def patch(a: A): Validation[String, A] = (tpe, distances) match { case (_: StandardType.YearType.type, distance :: Nil) => - Right(Year.of(a.asInstanceOf[Year].getValue - distance.toInt).asInstanceOf[A]) + Validation.succeed(Year.of(a.asInstanceOf[Year].getValue - distance.toInt).asInstanceOf[A]) case (_: StandardType.YearMonthType.type, distance :: Nil) => - Right( + Validation.succeed( YearMonth .now() .`with`( @@ -105,17 +106,17 @@ object Patch { .asInstanceOf[A] ) case (_: StandardType.ZonedDateTimeType.type, distance :: Nil) => - Right(LocalDate.ofEpochDay(a.asInstanceOf[LocalDate].toEpochDay - distance).asInstanceOf[A]) + Validation.succeed(LocalDate.ofEpochDay(a.asInstanceOf[LocalDate].toEpochDay - distance).asInstanceOf[A]) case (_: StandardType.InstantType.type, dist1 :: dist2 :: Nil) => - Right( + Validation.succeed( Instant .ofEpochSecond(a.asInstanceOf[Instant].getEpochSecond - dist1, a.asInstanceOf[Instant].getNano() - dist2) .asInstanceOf[A] ) case (_: StandardType.LocalTimeType.type, distance :: Nil) => - Right(LocalTime.ofNanoOfDay(a.asInstanceOf[LocalTime].toNanoOfDay - distance).asInstanceOf[A]) + Validation.succeed(LocalTime.ofNanoOfDay(a.asInstanceOf[LocalTime].toNanoOfDay - distance).asInstanceOf[A]) case (_: StandardType.LocalDateTimeType.type, dist1 :: dist2 :: Nil) => - Right { + Validation.succeed { LocalDateTime .of( LocalDate.ofEpochDay(a.asInstanceOf[LocalDateTime].toLocalDate.toEpochDay - dist1), @@ -124,7 +125,7 @@ object Patch { .asInstanceOf[A] } case (_: StandardType.OffsetTimeType.type, dist1 :: dist2 :: Nil) => - Right { + Validation.succeed { OffsetTime .of( LocalTime.ofNanoOfDay(a.asInstanceOf[OffsetTime].toLocalTime.toNanoOfDay - dist1), @@ -133,7 +134,7 @@ object Patch { .asInstanceOf[A] } case (_: StandardType.OffsetDateTimeType.type, dist1 :: dist2 :: dist3 :: Nil) => - Right { + Validation.succeed { OffsetDateTime .of( LocalDate.ofEpochDay(a.asInstanceOf[OffsetDateTime].toLocalDate.toEpochDay - dist1), @@ -143,45 +144,41 @@ object Patch { .asInstanceOf[A] } case (_: StandardType.PeriodType.type, dayAdjustment :: monthAdjustment :: yearAdjustment :: Nil) => - try { - Right( - Period - .of( - a.asInstanceOf[Period].getYears - yearAdjustment.toInt, - a.asInstanceOf[Period].getMonths - monthAdjustment.toInt, - a.asInstanceOf[Period].getDays - dayAdjustment.toInt - ) - .asInstanceOf[A] - ) - } catch { case _: Throwable => Left(s"Invalid java.time.Period diff $self") } + Validation( + Period + .of( + a.asInstanceOf[Period].getYears - yearAdjustment.toInt, + a.asInstanceOf[Period].getMonths - monthAdjustment.toInt, + a.asInstanceOf[Period].getDays - dayAdjustment.toInt + ) + .asInstanceOf[A] + ).mapError(_ => s"Invalid java.time.Period diff $self") case (_: StandardType.ZoneOffsetType.type, distance :: Nil) => - try { - Right( - ZoneOffset.ofTotalSeconds(a.asInstanceOf[ZoneOffset].getTotalSeconds + distance.toInt).asInstanceOf[A] - ) - } catch { case t: Throwable => Left(s"Patched offset is invalid: ${t.getMessage}") } + Validation( + ZoneOffset.ofTotalSeconds(a.asInstanceOf[ZoneOffset].getTotalSeconds + distance.toInt).asInstanceOf[A] + ).mapError(e => s"Patched offset is invalid: ${e.getMessage}") case (_: StandardType.DayOfWeekType.type, distance :: Nil) => - Right(a.asInstanceOf[DayOfWeek].plus(distance).asInstanceOf[A]) + Validation.succeed(a.asInstanceOf[DayOfWeek].plus(distance).asInstanceOf[A]) case (_: StandardType.MonthType.type, distance :: Nil) => - Right(a.asInstanceOf[java.time.Month].plus(distance).asInstanceOf[A]) + Validation.succeed(a.asInstanceOf[java.time.Month].plus(distance).asInstanceOf[A]) case (_: StandardType.DurationType.type, dist1 :: dist2 :: Nil) => - Right( + Validation.succeed( JDuration .ofSeconds(a.asInstanceOf[JDuration].getSeconds - dist1, a.asInstanceOf[JDuration].getNano() - dist2) .asInstanceOf[A] ) // // TODO need to deal with leap year differences case (_: StandardType.MonthDayType.type, regDiff :: _ :: Nil) => - Right( - MonthDay.from(ChronoUnit.DAYS.addTo(a.asInstanceOf[MonthDay].atYear(2001), regDiff.toLong)).asInstanceOf[A] + Validation.succeed( + MonthDay.from(ChronoUnit.DAYS.addTo(a.asInstanceOf[MonthDay].atYear(2001), regDiff)).asInstanceOf[A] ) case (_: StandardType.LocalDateType.type, dist :: Nil) => - Right( + Validation.succeed( LocalDate .ofEpochDay(a.asInstanceOf[LocalDate].toEpochDay - dist) .asInstanceOf[A] ) - case (s, _) => Left(s"Cannot apply temporal diff to value with type $s") + case (s, _) => Validation.fail(s"Cannot apply temporal diff to value with type $s") } override def invert: Patch[A] = Temporal(distances.map(-_), tpe) @@ -189,18 +186,15 @@ object Patch { final case class ZonedDateTime(localDateTimeDiff: Patch[java.time.LocalDateTime], zoneIdDiff: Patch[String]) extends Patch[java.time.ZonedDateTime] { - override def patch(input: JZonedDateTime): scala.Either[String, JZonedDateTime] = + override def patch(input: JZonedDateTime): Validation[String, JZonedDateTime] = for { patchedLocalDateTime <- localDateTimeDiff.patch(input.toLocalDateTime) patchedZoneId <- zoneIdDiff.patch(input.getZone.getId) - patched <- try { - Right(JZonedDateTime.of(patchedLocalDateTime, ZoneId.of(patchedZoneId))) - } catch { - case e: Throwable => - Left( + patched <- Validation(JZonedDateTime.of(patchedLocalDateTime, ZoneId.of(patchedZoneId))) + .mapError( + e => s"Patched ZonedDateTime is not valid. Patched values $patchedLocalDateTime, $patchedZoneId. Error=${e.getMessage}" - ) - } + ) } yield patched override def invert: Patch[JZonedDateTime] = ZonedDateTime(localDateTimeDiff.invert, zoneIdDiff.invert) @@ -209,7 +203,7 @@ object Patch { final case class Tuple[A, B](leftDifference: Patch[A], rightDifference: Patch[B]) extends Patch[(A, B)] { override def isIdentical: Boolean = leftDifference.isIdentical && rightDifference.isIdentical - override def patch(input: (A, B)): Either[String, (A, B)] = + override def patch(input: (A, B)): Validation[String, (A, B)] = for { l <- leftDifference.patch(input._1) r <- rightDifference.patch(input._2) @@ -219,20 +213,20 @@ object Patch { } final case class LCS[A](edits: Chunk[Edit[A]]) extends Patch[Chunk[A]] { - override def patch(as: Chunk[A]): Either[String, Chunk[A]] = { + override def patch(as: Chunk[A]): Validation[String, Chunk[A]] = { import zio.schema.diff.{ Edit => ZEdit } @tailrec - def calc(in: List[A], edits: List[Edit[A]], result: List[A]): Either[String, Chunk[A]] = (in, edits) match { - case (_ :: _, Nil) => Left(s"Incorrect Patch - no instructions for these items: ${in.mkString}.") - case (h :: _, ZEdit.Delete(s) :: _) if s != h => Left(s"Cannot Delete $s - current letter is $h.") - case (Nil, ZEdit.Delete(s) :: _) => Left(s"Cannot Delete $s - no items left to delete.") + def calc(in: List[A], edits: List[Edit[A]], result: List[A]): Validation[String, Chunk[A]] = (in, edits) match { + case (_ :: _, Nil) => Validation.fail(s"Incorrect Patch - no instructions for these items: ${in.mkString}.") + case (h :: _, ZEdit.Delete(s) :: _) if s != h => Validation.fail(s"Cannot Delete $s - current letter is $h.") + case (Nil, ZEdit.Delete(s) :: _) => Validation.fail(s"Cannot Delete $s - no items left to delete.") case (_ :: t, ZEdit.Delete(_) :: tail) => calc(t, tail, result) - case (h :: _, ZEdit.Keep(s) :: _) if s != h => Left(s"Cannot Keep $s - current letter is $h.") - case (Nil, ZEdit.Keep(s) :: _) => Left(s"Cannot Keep $s - no items left to keep.") + case (h :: _, ZEdit.Keep(s) :: _) if s != h => Validation.fail(s"Cannot Keep $s - current letter is $h.") + case (Nil, ZEdit.Keep(s) :: _) => Validation.fail(s"Cannot Keep $s - no items left to keep.") case (h :: t, ZEdit.Keep(_) :: tail) => calc(t, tail, result :+ h) case (in, ZEdit.Insert(s) :: tail) => calc(in, tail, result :+ s) - case (Nil, Nil) => Right(Chunk.fromIterable(result)) + case (Nil, Nil) => Validation.succeed(Chunk.fromIterable(result)) } calc(as.toList, edits.toList, Nil) @@ -242,8 +236,8 @@ object Patch { } final case class Total[A](value: A) extends Patch[A] { - override def patch(input: A): Either[String, A] = Right(value) - override def invert: Patch[A] = Total(value) + override def patch(input: A): Validation[String, A] = Validation.succeed(value) + override def invert: Patch[A] = Total(value) } final case class EitherDiff[A, B](diff: Either[Patch[A], Patch[B]]) extends Patch[Either[A, B]] { @@ -251,14 +245,15 @@ object Patch { override def isComparable: Boolean = diff.fold(_.isComparable, _.isComparable) - override def patch(input: Either[A, B]): Either[String, Either[A, B]] = (input, diff) match { - case (Left(_), Right(_)) => Left(s"Cannot apply a right diff to a left value") - case (Right(_), Left(_)) => Left(s"Cannot apply a left diff to a right value") - case (Left(in), Left(diff)) => - diff.patch(in).map(Left(_)) - case (Right(in), Right(diff)) => - diff.patch(in).map(Right(_)) - } + override def patch(input: Either[A, B]): Validation[String, Either[A, B]] = + (input, diff) match { + case (Left(_), Right(_)) => Validation.fail(s"Cannot apply a right diff to a left value") + case (Right(_), Left(_)) => Validation.fail(s"Cannot apply a left diff to a right value") + case (Left(in), Left(diff)) => + diff.patch(in).map(e => Left(e)) + case (Right(in), Right(diff)) => + diff.patch(in).map(e => Right(e)) + } override def invert: Patch[Either[A, B]] = diff match { case Left(value) => EitherDiff(Left(value.invert)) @@ -266,13 +261,13 @@ object Patch { } } - final case class Transform[A, B](patch: Patch[A], f: A => Either[String, B], g: B => Either[String, A]) + final case class Transform[A, B](patch: Patch[A], f: A => Validation[String, B], g: B => Validation[String, A]) extends Patch[B] { override def isIdentical: Boolean = patch.isIdentical override def isComparable: Boolean = patch.isComparable - override def patch(input: B): Either[String, B] = + override def patch(input: B): Validation[String, B] = for { a <- g(input) a1 <- patch.patch(a) @@ -283,11 +278,11 @@ object Patch { } /** - * Represents diff between incomparable values. For instance Left(1) and Right("a") + * Represents diff between incomparable values. For instance Left(1) and zio.prelude.Validation.succeed("a") */ final case class NotComparable[A]() extends Patch[A] { - override def patch(input: A): Either[String, A] = - Left(s"Non-comparable diff cannot be applied") + override def patch(input: A): Validation[String, A] = + Validation.fail(s"Non-comparable diff cannot be applied") override def isComparable: Boolean = false @@ -297,7 +292,8 @@ object Patch { final case class SchemaMigration(migrations: Chunk[Migration]) extends Patch[Schema[_]] { self => //TODO Probably need to implement this - override def patch(input: Schema[_]): Either[String, Schema[_]] = Left(s"Schema migrations cannot be applied") + override def patch(input: Schema[_]): Validation[String, Schema[_]] = + Validation.fail(s"Schema migrations cannot be applied") def orIdentical: Patch[Schema[_]] = if (migrations.isEmpty) Patch.identical @@ -316,33 +312,30 @@ object Patch { override def isComparable: Boolean = differences.forall(_._2.isComparable) - override def patch(input: R): Either[String, R] = { + override def patch(input: R): Validation[String, R] = { val structure = schema.fields val patchedDynamicValue = schema.toDynamic(input) match { - case DynamicValue.Record(name, values) => { - differences - .foldLeft[Either[String, ListMap[String, DynamicValue]]](Right(values)) { - case (Right(record), (key, diff)) => - (structure.find(_.name == key).map(_.schema), values.get(key)) match { - case (Some(schema: Schema[b]), Some(oldValue)) => - val oldVal = oldValue.toTypedValue(schema) - oldVal - .flatMap(v => diff.asInstanceOf[Patch[Any]].patch(v)) - .map(v => schema.asInstanceOf[Schema[Any]].toDynamic(v)) match { - case Left(error) => Left(error) - case Right(newValue) => Right(record + (key -> newValue)) - } - case _ => - Left(s"Values=$values and structure=$structure have incompatible shape.") - } - case (Left(string), _) => Left(string) - } - .map(r => (name, r)) - - } + case DynamicValue.Record(name, values) => + Validation + .validateAll( + differences.map { + case (key, diff) => + (structure.find(_.name == key).map(_.schema), values.get(key)) match { + case (Some(schema: Schema[b]), Some(oldValue)) => + val oldVal = oldValue.toTypedValue(schema) + oldVal + .flatMap(v => diff.asInstanceOf[Patch[Any]].patch(v)) + .map(v => schema.asInstanceOf[Schema[Any]].toDynamic(v)) + .map(newValue => key -> newValue) + case _ => + Validation.fail(s"Values=$values and structure=$structure have incompatible shape.") + } + } + ) + .map(r => (name, ListMap.from(r))) - case dv => Left(s"Failed to apply record diff. Unexpected dynamic value for record: $dv") + case dv => Validation.fail(s"Failed to apply record diff. Unexpected dynamic value for record: $dv") } patchedDynamicValue.flatMap { newValues => diff --git a/zio-schema/shared/src/main/scala/zio/schema/Schema.scala b/zio-schema/shared/src/main/scala/zio/schema/Schema.scala index 26eb6c168..7bf5f05d6 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/Schema.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/Schema.scala @@ -6,6 +6,7 @@ import java.time.temporal.ChronoUnit import scala.annotation.tailrec import scala.collection.immutable.ListMap +import zio.prelude.Validation import zio.schema.internal.SourceLocation import zio.schema.meta._ import zio.schema.validation._ @@ -48,12 +49,12 @@ sealed trait Schema[A] { /** * A symbolic operator for [[orElseEither]]. */ - def <+>[B](that: Schema[B]): Schema[scala.util.Either[A, B]] = self.orElseEither(that) + def <+>[B](that: Schema[B]): Schema[Either[A, B]] = self.orElseEither(that) /** * The default value for a `Schema` of type `A`. */ - def defaultValue: scala.util.Either[String, A] + def defaultValue: Validation[String, A] /** * Chunk of annotations for this schema @@ -73,7 +74,7 @@ sealed trait Schema[A] { * This can be used to e.g convert between a case class and it's * "generic" representation as a ListMap[String,_] */ - def coerce[B](newSchema: Schema[B]): Either[String, Schema[B]] = + def coerce[B](newSchema: Schema[B]): Validation[String, Schema[B]] = for { f <- self.migrate(newSchema) g <- newSchema.migrate(self) @@ -89,9 +90,9 @@ sealed trait Schema[A] { /** * Patch value with a Patch. */ - def patch(oldValue: A, diff: Patch[A]): scala.util.Either[String, A] = diff.patch(oldValue) + def patch(oldValue: A, diff: Patch[A]): Validation[String, A] = diff.patch(oldValue) - def fromDynamic(value: DynamicValue): scala.util.Either[String, A] = + def fromDynamic(value: DynamicValue): Validation[String, A] = value.toTypedValue(self) def makeAccessors(b: AccessorBuilder): Accessors[b.Lens, b.Prism, b.Traversal] @@ -99,7 +100,7 @@ sealed trait Schema[A] { /** * Generate a homomorphism from A to B iff A and B are homomorphic */ - def migrate[B](newSchema: Schema[B]): Either[String, A => scala.util.Either[String, B]] = + def migrate[B](newSchema: Schema[B]): Validation[String, A => Validation[String, B]] = Migration.derive(MetaSchema.fromSchema(self), MetaSchema.fromSchema(newSchema)).map { transforms => (a: A) => self.toDynamic(a).transform(transforms).flatMap(newSchema.fromDynamic) } @@ -125,7 +126,7 @@ sealed trait Schema[A] { .asInstanceOf[Schema[Schema[_]]] .transformOrFail( s => s.coerce(self), - s => Right(s.ast.toSchema) + s => zio.prelude.Validation.succeed(s.ast.toSchema) ) def toDynamic(value: A): DynamicValue = @@ -136,18 +137,24 @@ sealed trait Schema[A] { * between `A` and `B`, without possibility of failure. */ def transform[B](f: A => B, g: B => A)(implicit loc: SourceLocation): Schema[B] = - Schema.Transform[A, B, SourceLocation](self, a => Right(f(a)), b => Right(g(b)), annotations, loc) + Schema.Transform[A, B, SourceLocation]( + self, + a => Validation.succeed(f(a)), + b => Validation.succeed(g(b)), + annotations, + loc + ) /** * Transforms this `Schema[A]` into a `Schema[B]`, by supplying two functions that can transform * between `A` and `B` (possibly failing in some cases). */ - def transformOrFail[B](f: A => scala.util.Either[String, B], g: B => scala.util.Either[String, A])( + def transformOrFail[B](f: A => Validation[String, B], g: B => Validation[String, A])( implicit loc: SourceLocation ): Schema[B] = Schema.Transform[A, B, SourceLocation](self, f, g, annotations, loc) - def validate(value: A)(implicit schema: Schema[A]): Chunk[ValidationError] = Schema.validate[A](value) + def validate(value: A)(implicit schema: Schema[A]): Chunk[SchemaValidationError] = Schema.validate[A](value) /** * Returns a new schema that combines this schema and the specified schema together, modeling @@ -187,16 +194,17 @@ object Schema extends SchemaEquality { def singleton[A](instance: A): Schema[A] = Schema[Unit].transform(_ => instance, _ => ()) - def validate[A](value: A)(implicit schema: Schema[A]): Chunk[ValidationError] = { - def loop[A](value: A, schema: Schema[A]): Chunk[ValidationError] = + def validate[A](value: A)(implicit schema: Schema[A]): Chunk[SchemaValidationError] = { + def loop[A](value: A, schema: Schema[A]): Chunk[SchemaValidationError] = schema match { case Sequence(schema, _, toChunk, _, _) => toChunk(value).flatMap(value => loop(value, schema)) case Transform(schema, _, g, _, _) => - g(value) match { - case Right(value) => loop(value, schema) - case Left(error) => Chunk(ValidationError.Generic(error)) - } + g(value) + .mapError(SchemaValidationError.Generic) + .map(value => loop(value, schema)) + .fold(a => a.toChunk, a => a) + case Primitive(_, _) => Chunk.empty case optional @ Optional(schema, _) => value.asInstanceOf[Option[optional.OptionalType]] match { @@ -224,17 +232,17 @@ object Schema extends SchemaEquality { } record.fields .zip(fieldValues) - .foldLeft[Chunk[ValidationError]](Chunk.empty) { + .foldLeft[Chunk[SchemaValidationError]](Chunk.empty) { case (acc, (field, fieldValue)) => - val validation = field.validation.asInstanceOf[Validation[Any]] - validation.validate(fieldValue).swap.getOrElse(Chunk.empty) ++ acc ++ loop( + val validation = field.validation.asInstanceOf[SchemaValidation[Any]] + validation.validate(fieldValue).toEither.swap.map(_.toChunk).getOrElse(Chunk.empty) ++ acc ++ loop( fieldValue, field.schema.asInstanceOf[Schema[Any]] ) } .reverse case either @ Schema.Either(left, right, _) => - value.asInstanceOf[scala.util.Either[either.LeftType, either.RightType]] match { + value.asInstanceOf[scala.Either[either.LeftType, either.RightType]] match { case Left(value) => loop(value, left) case Right(value) => loop(value, right) } @@ -250,35 +258,35 @@ object Schema extends SchemaEquality { implicit val chronoUnit: Schema[ChronoUnit] = Schema[String].transformOrFail( { - case "SECONDS" => Right(ChronoUnit.SECONDS) - case "CENTURIES" => Right(ChronoUnit.CENTURIES) - case "DAYS" => Right(ChronoUnit.DAYS) - case "DECADES" => Right(ChronoUnit.DECADES) - case "FOREVER" => Right(ChronoUnit.FOREVER) - case "HOURS" => Right(ChronoUnit.HOURS) - case "MICROS" => Right(ChronoUnit.MICROS) - case "MILLIS" => Right(ChronoUnit.MILLIS) - case "MINUTES" => Right(ChronoUnit.MINUTES) - case "MONTHS" => Right(ChronoUnit.MONTHS) - case "NANOS" => Right(ChronoUnit.NANOS) - case "WEEKS" => Right(ChronoUnit.WEEKS) - case "YEARS" => Right(ChronoUnit.YEARS) - case _ => Left("Failed") + case "SECONDS" => zio.prelude.Validation.succeed(ChronoUnit.SECONDS) + case "CENTURIES" => zio.prelude.Validation.succeed(ChronoUnit.CENTURIES) + case "DAYS" => zio.prelude.Validation.succeed(ChronoUnit.DAYS) + case "DECADES" => zio.prelude.Validation.succeed(ChronoUnit.DECADES) + case "FOREVER" => zio.prelude.Validation.succeed(ChronoUnit.FOREVER) + case "HOURS" => zio.prelude.Validation.succeed(ChronoUnit.HOURS) + case "MICROS" => zio.prelude.Validation.succeed(ChronoUnit.MICROS) + case "MILLIS" => zio.prelude.Validation.succeed(ChronoUnit.MILLIS) + case "MINUTES" => zio.prelude.Validation.succeed(ChronoUnit.MINUTES) + case "MONTHS" => zio.prelude.Validation.succeed(ChronoUnit.MONTHS) + case "NANOS" => zio.prelude.Validation.succeed(ChronoUnit.NANOS) + case "WEEKS" => zio.prelude.Validation.succeed(ChronoUnit.WEEKS) + case "YEARS" => zio.prelude.Validation.succeed(ChronoUnit.YEARS) + case _ => Validation.fail("Failed") }, { - case ChronoUnit.SECONDS => Right("SECONDS") - case ChronoUnit.CENTURIES => Right("CENTURIES") - case ChronoUnit.DAYS => Right("DAYS") - case ChronoUnit.DECADES => Right("DECADES") - case ChronoUnit.FOREVER => Right("FOREVER") - case ChronoUnit.HOURS => Right("HOURS") - case ChronoUnit.MICROS => Right("MICROS") - case ChronoUnit.MILLIS => Right("MILLIS") - case ChronoUnit.MINUTES => Right("MINUTES") - case ChronoUnit.MONTHS => Right("MONTHS") - case ChronoUnit.NANOS => Right("NANOS") - case ChronoUnit.WEEKS => Right("WEEKS") - case ChronoUnit.YEARS => Right("YEARS") - case _ => Left("Failed") + case ChronoUnit.SECONDS => zio.prelude.Validation.succeed("SECONDS") + case ChronoUnit.CENTURIES => zio.prelude.Validation.succeed("CENTURIES") + case ChronoUnit.DAYS => zio.prelude.Validation.succeed("DAYS") + case ChronoUnit.DECADES => zio.prelude.Validation.succeed("DECADES") + case ChronoUnit.FOREVER => zio.prelude.Validation.succeed("FOREVER") + case ChronoUnit.HOURS => zio.prelude.Validation.succeed("HOURS") + case ChronoUnit.MICROS => zio.prelude.Validation.succeed("MICROS") + case ChronoUnit.MILLIS => zio.prelude.Validation.succeed("MILLIS") + case ChronoUnit.MINUTES => zio.prelude.Validation.succeed("MINUTES") + case ChronoUnit.MONTHS => zio.prelude.Validation.succeed("MONTHS") + case ChronoUnit.NANOS => zio.prelude.Validation.succeed("NANOS") + case ChronoUnit.WEEKS => zio.prelude.Validation.succeed("WEEKS") + case ChronoUnit.YEARS => zio.prelude.Validation.succeed("YEARS") + case _ => Validation.fail("Failed") } ) @@ -317,9 +325,9 @@ object Schema extends SchemaEquality { Schema[String].transformOrFail( string => try { - Right(new URL(string)) - } catch { case _: Exception => Left(s"Invalid URL: $string") }, - url => Right(url.toString) + zio.prelude.Validation.succeed(new URL(string)) + } catch { case _: Exception => Validation.fail(s"Invalid URL: $string") }, + url => zio.prelude.Validation.succeed(url.toString) ) implicit def schemaSchema[A]: Schema[Schema[A]] = Schema[MetaSchema].transform( @@ -331,18 +339,20 @@ object Schema extends SchemaEquality { Schema[String].transformOrFail( string => try { - Right(new URI(string)) - } catch { case _: Exception => Left(s"Invalid URI: $string") }, - uri => Right(uri.toString) + zio.prelude.Validation.succeed(new URI(string)) + } catch { case _: Exception => Validation.fail(s"Invalid URI: $string") }, + uri => zio.prelude.Validation.succeed(uri.toString) ) implicit def standardSchema[A]: Schema[StandardType[A]] = Schema[String].transformOrFail[StandardType[A]]( string => - StandardType - .fromString(string) - .asInstanceOf[Option[StandardType[A]]] - .toRight(s"Invalid StandardType tag ${string}"), - standardType => Right(standardType.tag) + Validation.fromEither( + StandardType + .fromString(string) + .asInstanceOf[Option[StandardType[A]]] + .toRight(s"Invalid StandardType tag ${string}") + ), + standardType => Validation.succeed(standardType.tag) ) sealed trait Enum[Z] extends Schema[Z] { @@ -365,7 +375,7 @@ object Schema extends SchemaEquality { def name: Field def schema: Schema[A] def annotations: Chunk[Any] - def validation: Validation[A] + def validation: SchemaValidation[A] def get: R => A def set: (R, A) => R @@ -382,23 +392,25 @@ object Schema extends SchemaEquality { name0: String, schema0: Schema[A], annotations0: Chunk[Any] = Chunk.empty, - validation0: Validation[A] = Validation.succeed[A], + validation0: SchemaValidation[A] = SchemaValidation.succeed[A], get0: R => A, set0: (R, A) => R ): Field[R, A] = new Field[R, A] { override type Field = name0.type - def name: Field = name0.asInstanceOf[Field] - def schema: Schema[A] = schema0 - def annotations: Chunk[Any] = annotations0 - def validation: Validation[A] = validation0 - def get: R => A = get0 - def set: (R, A) => R = set0 + def name: Field = name0.asInstanceOf[Field] + def schema: Schema[A] = schema0 + def annotations: Chunk[Any] = annotations0 + def validation: SchemaValidation[A] = validation0 + def get: R => A = get0 + def set: (R, A) => R = set0 } - def unapply[R, A](field: Field[R, A]): Some[(String, Schema[A], Chunk[Any], Validation[A], R => A, (R, A) => R)] = - Some[(String, Schema[A], Chunk[Any], Validation[A], R => A, (R, A) => R)]( + def unapply[R, A]( + field: Field[R, A] + ): Some[(String, Schema[A], Chunk[Any], SchemaValidation[A], R => A, (R, A) => R)] = + Some[(String, Schema[A], Chunk[Any], SchemaValidation[A], R => A, (R, A) => R)]( (field.name, field.schema, field.annotations, field.validation, field.get, field.set) ) } @@ -411,21 +423,19 @@ object Schema extends SchemaEquality { def fields: Chunk[Field[R, _]] - def construct(fieldValues: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, R] + def construct(fieldValues: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, R] def deconstruct(value: R)(implicit unsafe: Unsafe): Chunk[Any] def id: TypeId - def defaultValue: scala.util.Either[String, R] = + def defaultValue: Validation[String, R] = Unsafe.unsafe { implicit unsafe => - self.fields - .map(_.schema.defaultValue) - .foldLeft[scala.util.Either[String, Chunk[R]]](Right(Chunk.empty)) { - case (e @ Left(_), _) => e - case (_, Left(e)) => Left[String, Chunk[R]](e) - case (Right(values), Right(value)) => Right[String, Chunk[R]](values :+ value.asInstanceOf[R]) - } + zio.prelude.Validation + .validateAll( + self.fields + .map(_.schema.defaultValue) + ) .flatMap(self.construct) } } @@ -444,7 +454,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Sequence[Col, Elem, I] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Col] = + override def defaultValue: Validation[String, Col] = elementSchema.defaultValue.map(fromChunk.compose(Chunk(_))) override def makeAccessors(b: AccessorBuilder): b.Traversal[Col, Elem] = b.makeTraversal(self, elementSchema) @@ -455,14 +465,14 @@ object Schema extends SchemaEquality { final case class Transform[A, B, I]( schema: Schema[A], - f: A => scala.util.Either[String, B], - g: B => scala.util.Either[String, A], + f: A => Validation[String, B], + g: B => Validation[String, A], annotations: Chunk[Any], identity: I ) extends Schema[B] { override type Accessors[Lens[_, _, _], Prism[_, _, _], Traversal[_, _]] = schema.Accessors[Lens, Prism, Traversal] - def defaultValue: scala.util.Either[String, B] = schema.defaultValue.flatMap(f) + def defaultValue: Validation[String, B] = schema.defaultValue.flatMap(f) override def makeAccessors(b: AccessorBuilder): schema.Accessors[b.Lens, b.Prism, b.Traversal] = schema.makeAccessors(b) @@ -474,8 +484,8 @@ object Schema extends SchemaEquality { .fromSchema(schema) .asInstanceOf[Schema[Schema[_]]] .transformOrFail( - s => s.coerce(schema).flatMap(s1 => Right(s1.transformOrFail(f, g))), - s => Right(s.transformOrFail(g, f).ast.toSchema) + s => s.coerce(schema).flatMap(s1 => zio.prelude.Validation.succeed(s1.transformOrFail(f, g))), + s => zio.prelude.Validation.succeed(s.transformOrFail(g, f).ast.toSchema) ) override def toString: String = s"Transform($schema, $identity)" @@ -488,7 +498,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Primitive[A] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, A] = standardType.defaultValue + override def defaultValue: Validation[String, A] = standardType.defaultValue override def makeAccessors(b: AccessorBuilder): Unit = () } @@ -529,7 +539,7 @@ object Schema extends SchemaEquality { Chunk.empty ) - def defaultValue: scala.util.Either[String, Option[A]] = Right(None) + def defaultValue: Validation[String, Option[A]] = zio.prelude.Validation.succeed(None) override def makeAccessors( b: AccessorBuilder @@ -543,7 +553,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Fail[A] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, A] = Left(message) + override def defaultValue: Validation[String, A] = Validation.fail(message) override def makeAccessors(b: AccessorBuilder): Unit = () } @@ -567,7 +577,7 @@ object Schema extends SchemaEquality { annotations ) - override def defaultValue: scala.util.Either[String, (A, B)] = + override def defaultValue: Validation[String, (A, B)] = left.defaultValue.flatMap(a => right.defaultValue.map(b => (a, b))) override def makeAccessors(b: AccessorBuilder): (b.Lens[first.type, (A, B), A], b.Lens[second.type, (A, B), B]) = @@ -617,15 +627,11 @@ object Schema extends SchemaEquality { Chunk.empty ) - override def defaultValue: scala.util.Either[String, scala.util.Either[A, B]] = - left.defaultValue match { - case Right(a) => Right(Left(a)) - case _ => - right.defaultValue match { - case Right(b) => Right(Right(b)) - case _ => Left("unable to extract default value for Either") - } - } + override def defaultValue: Validation[String, scala.util.Either[A, B]] = + left.defaultValue + .map(Left(_)) + .orElse(right.defaultValue.map(Right(_))) + .mapError(e => s"unable to extract default value for Either: ${e}") override def makeAccessors( b: AccessorBuilder @@ -644,7 +650,7 @@ object Schema extends SchemaEquality { lazy val schema: Schema[A] = schema0() - def defaultValue: scala.util.Either[String, A] = schema.defaultValue + def defaultValue: Validation[String, A] = schema.defaultValue override def makeAccessors(b: AccessorBuilder): schema.Accessors[b.Lens, b.Prism, b.Traversal] = schema.makeAccessors(b) @@ -665,7 +671,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Map[K, V] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, scala.collection.immutable.Map[K, V]] = + override def defaultValue: Validation[String, scala.collection.immutable.Map[K, V]] = keySchema.defaultValue.flatMap( defaultKey => valueSchema.defaultValue.map(defaultValue => scala.collection.immutable.Map(defaultKey -> defaultValue)) @@ -686,7 +692,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Set[A] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, scala.collection.immutable.Set[A]] = + override def defaultValue: Validation[String, scala.collection.immutable.Set[A]] = elementSchema.defaultValue.map(scala.collection.immutable.Set(_)) override def makeAccessors(b: AccessorBuilder): b.Traversal[scala.collection.immutable.Set[A], A] = @@ -701,8 +707,8 @@ object Schema extends SchemaEquality { /** * The default value for a `Schema` of type `A`. */ - override def defaultValue: scala.util.Either[String, DynamicValue] = - Right(DynamicValue.NoneValue) + override def defaultValue: Validation[String, DynamicValue] = + zio.prelude.Validation.succeed(DynamicValue.NoneValue) /** * Returns a new schema that with `annotation` @@ -738,7 +744,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum1[A, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): b.Prism[case1.id.type, Z, A] = b.makePrism(self, case1) @@ -758,7 +764,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum2[A1, A2, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): (b.Prism[case1.id.type, Z, A1], b.Prism[case2.id.type, Z, A2]) = (b.makePrism(self, case1), b.makePrism(self, case2)) @@ -779,7 +785,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum3[A1, A2, A3, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors( b: AccessorBuilder @@ -808,7 +814,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum4[A1, A2, A3, A4, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -842,7 +848,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum5[A1, A2, A3, A4, A5, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors( b: AccessorBuilder @@ -888,7 +894,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum6[A1, A2, A3, A4, A5, A6, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors( b: AccessorBuilder @@ -938,7 +944,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum7[A1, A2, A3, A4, A5, A6, A7, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -990,7 +996,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum8[A1, A2, A3, A4, A5, A6, A7, A8, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1045,7 +1051,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum9[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1104,7 +1110,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1180,7 +1186,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1262,7 +1268,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1361,7 +1367,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1466,7 +1472,7 @@ object Schema extends SchemaEquality { override def annotate(annotation: Any): Enum14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1579,7 +1585,7 @@ object Schema extends SchemaEquality { ): Enum15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1698,7 +1704,7 @@ object Schema extends SchemaEquality { ): Enum16[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1823,7 +1829,7 @@ object Schema extends SchemaEquality { ): Enum17[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -1954,7 +1960,7 @@ object Schema extends SchemaEquality { ): Enum18[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -2091,7 +2097,7 @@ object Schema extends SchemaEquality { ): Enum19[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -2234,7 +2240,7 @@ object Schema extends SchemaEquality { ): Enum20[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors(b: AccessorBuilder): ( b.Prism[case1.id.type, Z, A1], @@ -2383,7 +2389,7 @@ object Schema extends SchemaEquality { ): Enum21[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors( b: AccessorBuilder @@ -2540,7 +2546,7 @@ object Schema extends SchemaEquality { ): Enum22[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, Z] = copy(annotations = annotations :+ annotation) - override def defaultValue: scala.util.Either[String, Z] = case1.schema.defaultValue.map(case1.construct) + override def defaultValue: Validation[String, Z] = case1.schema.defaultValue.map(case1.construct) override def makeAccessors( b: AccessorBuilder @@ -2629,11 +2635,11 @@ object Schema extends SchemaEquality { override def cases: Chunk[Case[Z, _]] = Chunk(caseSet.toSeq: _*) - def defaultValue: scala.util.Either[String, Z] = + def defaultValue: Validation[String, Z] = if (caseSet.toSeq.isEmpty) - Left("cannot access default value for enum with no members") + Validation.fail("cannot access default value for enum with no members") else - caseSet.toSeq.head.schema.defaultValue.asInstanceOf[scala.util.Either[String, Z]] + caseSet.toSeq.head.schema.defaultValue.asInstanceOf[Validation[String, Z]] override def makeAccessors(b: AccessorBuilder): caseSet.Accessors[Z, b.Lens, b.Prism, b.Traversal] = caseSet.makeAccessors(self, b) @@ -3311,11 +3317,13 @@ object Schema extends SchemaEquality { override def fields: Chunk[Schema.Field[ListMap[String, _], _]] = fieldSet.toChunk - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, ListMap[String, _]] = + override def construct( + values: Chunk[Any] + )(implicit unsafe: Unsafe): Validation[String, ListMap[String, _]] = if (values.size == fields.size) - Right(ListMap(fields.map(_.name).zip(values): _*)) + zio.prelude.Validation.succeed(ListMap(fields.map(_.name).zip(values): _*)) else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(values: ListMap[String, _])(implicit unsafe: Unsafe): Chunk[Any] = Chunk.fromIterable(fields.map(f => values(f.name))) @@ -3340,14 +3348,14 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk.empty - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.isEmpty) try { - Right(defaultConstruct()) + zio.prelude.Validation.succeed(defaultConstruct()) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk(value) @@ -3391,14 +3399,14 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 1) try { - Right(defaultConstruct(values(0).asInstanceOf[A])) + zio.prelude.Validation.succeed(defaultConstruct(values(0).asInstanceOf[A])) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk(field.get(value)) override def toString: String = s"CaseClass1(${fields.mkString(",")})" @@ -3458,14 +3466,14 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 2) try { - Right(construct(values(0).asInstanceOf[A1], values(1).asInstanceOf[A2])) + zio.prelude.Validation.succeed(construct(values(0).asInstanceOf[A1], values(1).asInstanceOf[A2])) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk(field1.get(value), field2.get(value)) @@ -3538,14 +3546,15 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 3) try { - Right(construct(values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], values(2).asInstanceOf[A3])) + zio.prelude.Validation + .succeed(construct(values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], values(2).asInstanceOf[A3])) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk(field1.get(value), field2.get(value), field3.get(value)) @@ -3633,10 +3642,10 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3, field4) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 4) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -3645,9 +3654,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk(field1.get(value), field2.get(value), field3.get(value), field4.get(value)) @@ -3753,10 +3762,10 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3, field4, field5) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 5) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -3766,9 +3775,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -3906,10 +3915,10 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3, field4, field5, field6) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 6) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -3920,9 +3929,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -4079,10 +4088,10 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3, field4, field5, field6, field7) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 7) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -4094,9 +4103,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -4285,10 +4294,10 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3, field4, field5, field6, field7, field8) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 8) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -4301,9 +4310,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -4508,10 +4517,10 @@ object Schema extends SchemaEquality { override def fields: Chunk[Field[Z, _]] = Chunk(field1, field2, field3, field4, field5, field6, field7, field8, field9) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 9) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -4525,9 +4534,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -4769,10 +4778,10 @@ object Schema extends SchemaEquality { field10 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 10) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -4787,9 +4796,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -5052,10 +5061,10 @@ object Schema extends SchemaEquality { field11 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 11) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -5071,9 +5080,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -5354,10 +5363,10 @@ object Schema extends SchemaEquality { field12 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 12) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -5374,9 +5383,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -5675,10 +5684,10 @@ object Schema extends SchemaEquality { field13 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 13) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -5696,9 +5705,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -6015,10 +6024,10 @@ object Schema extends SchemaEquality { field14 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 14) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -6037,9 +6046,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -6375,10 +6384,10 @@ object Schema extends SchemaEquality { field15 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 15) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -6398,9 +6407,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -6756,10 +6765,10 @@ object Schema extends SchemaEquality { field16 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 16) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -6780,9 +6789,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -7156,10 +7165,10 @@ object Schema extends SchemaEquality { field17 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 17) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -7181,9 +7190,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -7575,10 +7584,10 @@ object Schema extends SchemaEquality { field18 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 18) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -7601,9 +7610,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -8015,10 +8024,10 @@ object Schema extends SchemaEquality { field19 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 19) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -8042,9 +8051,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -8474,10 +8483,10 @@ object Schema extends SchemaEquality { field20 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 20) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -8502,9 +8511,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -8973,10 +8982,10 @@ object Schema extends SchemaEquality { field21 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 21) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -9002,9 +9011,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), @@ -9538,10 +9547,10 @@ object Schema extends SchemaEquality { field22 ) - override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): scala.util.Either[String, Z] = + override def construct(values: Chunk[Any])(implicit unsafe: Unsafe): Validation[String, Z] = if (values.size == 22) try { - Right( + zio.prelude.Validation.succeed( construct( values(0).asInstanceOf[A1], values(1).asInstanceOf[A2], @@ -9568,9 +9577,9 @@ object Schema extends SchemaEquality { ) ) } catch { - case _: Throwable => Left("invalid type in values") + case e: Throwable => Validation.fail(s"invalid type in values: [$e]") } else - Left(s"wrong number of values for $fields") + Validation.fail(s"wrong number of values for $fields") override def deconstruct(value: Z)(implicit unsafe: Unsafe): Chunk[Any] = Chunk( field1.get(value), diff --git a/zio-schema/shared/src/main/scala/zio/schema/StandardType.scala b/zio-schema/shared/src/main/scala/zio/schema/StandardType.scala index 8be43c8a4..10e7b06f9 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/StandardType.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/StandardType.scala @@ -5,16 +5,17 @@ import java.time import java.time._ import zio.Chunk +import zio.prelude.Validation sealed trait StandardType[A] extends Ordering[A] { self => def tag: String - def defaultValue: Either[String, A] + def defaultValue: zio.prelude.Validation[String, A] override def toString: String = tag /** * Converts a DynamicValue into a primitive type. */ - def toTypedPrimitive(value: DynamicValue): Either[String, A] = + def toTypedPrimitive(value: DynamicValue): Validation[String, A] = value.toTypedValue(Schema.primitive[A](self)) } @@ -90,63 +91,66 @@ object StandardType { def apply[A](implicit standardType: StandardType[A]): StandardType[A] = standardType implicit object UnitType extends StandardType[Unit] { - override def tag: String = Tags.UNIT - override def compare(x: Unit, y: Unit): Int = 0 - override def defaultValue: Either[String, Unit] = Right(()) + override def tag: String = Tags.UNIT + override def compare(x: Unit, y: Unit): Int = 0 + override def defaultValue: zio.prelude.Validation[String, Unit] = zio.prelude.Validation.succeed(()) } implicit object StringType extends StandardType[String] { - override def tag: String = Tags.STRING - override def compare(x: String, y: String): Int = x.compareTo(y) - override def defaultValue: Either[String, String] = Right("") + override def tag: String = Tags.STRING + override def compare(x: String, y: String): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, String] = zio.prelude.Validation.succeed("") } implicit object BoolType extends StandardType[Boolean] { - override def tag: String = Tags.BOOL - override def compare(x: Boolean, y: Boolean): Int = x.compareTo(y) - override def defaultValue: Either[String, Boolean] = Right(false) + override def tag: String = Tags.BOOL + override def compare(x: Boolean, y: Boolean): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Boolean] = zio.prelude.Validation.succeed(false) } implicit object ByteType extends StandardType[Byte] { - override def tag: String = Tags.BYTE - override def compare(x: Byte, y: Byte): Int = x.compareTo(y) - override def defaultValue: Either[String, Byte] = Right(0.toByte) + override def tag: String = Tags.BYTE + override def compare(x: Byte, y: Byte): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Byte] = zio.prelude.Validation.succeed(0.toByte) } implicit object ShortType extends StandardType[Short] { - override def tag: String = Tags.SHORT - override def compare(x: Short, y: Short): Int = x.compareTo(y) - override def defaultValue: Either[String, Short] = Right(0.asInstanceOf[Short]) + override def tag: String = Tags.SHORT + override def compare(x: Short, y: Short): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Short] = + zio.prelude.Validation.succeed(0.asInstanceOf[Short]) } implicit object IntType extends StandardType[Int] { - override def tag: String = Tags.INT - override def compare(x: Int, y: Int): Int = x.compareTo(y) - override def defaultValue: Either[String, Int] = Right(0) + override def tag: String = Tags.INT + override def compare(x: Int, y: Int): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Int] = zio.prelude.Validation.succeed(0) } implicit object LongType extends StandardType[Long] { - override def tag: String = Tags.LONG - override def compare(x: Long, y: Long): Int = x.compareTo(y) - override def defaultValue: Either[String, Long] = Right(0.asInstanceOf[Long]) + override def tag: String = Tags.LONG + override def compare(x: Long, y: Long): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Long] = + zio.prelude.Validation.succeed(0.asInstanceOf[Long]) } implicit object FloatType extends StandardType[Float] { - override def tag: String = Tags.FLOAT - override def compare(x: Float, y: Float): Int = x.compareTo(y) - override def defaultValue: Either[String, Float] = Right(0.0.asInstanceOf[Float]) + override def tag: String = Tags.FLOAT + override def compare(x: Float, y: Float): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Float] = + zio.prelude.Validation.succeed(0.0.asInstanceOf[Float]) } implicit object DoubleType extends StandardType[Double] { - override def tag: String = Tags.DOUBLE - override def compare(x: Double, y: Double): Int = x.compareTo(y) - override def defaultValue: Either[String, Double] = Right(0.0) + override def tag: String = Tags.DOUBLE + override def compare(x: Double, y: Double): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, Double] = zio.prelude.Validation.succeed(0.0) } implicit object BinaryType extends StandardType[Chunk[Byte]] { - override def tag: String = Tags.BINARY - override def compare(x: Chunk[Byte], y: Chunk[Byte]): Int = x.sum.compare(y.sum) - override def defaultValue: Either[String, Chunk[Byte]] = Right(Chunk.empty) + override def tag: String = Tags.BINARY + override def compare(x: Chunk[Byte], y: Chunk[Byte]): Int = x.sum.compare(y.sum) + override def defaultValue: zio.prelude.Validation[String, Chunk[Byte]] = zio.prelude.Validation.succeed(Chunk.empty) } implicit object CharType extends StandardType[Char] { @@ -154,46 +158,50 @@ object StandardType { override def compare(x: Char, y: Char): Int = x.compareTo(y) // The NUL Unicode character is used as the default value for // `StandardType[Char]` because the empty Char '' does not compile - override def defaultValue: Either[String, Char] = Right('\u0000') + override def defaultValue: zio.prelude.Validation[String, Char] = zio.prelude.Validation.succeed('\u0000') } implicit object UUIDType extends StandardType[java.util.UUID] { override def tag: String = Tags.UUID override def compare(x: java.util.UUID, y: java.util.UUID): Int = x.compareTo(y) - override def defaultValue: Either[String, java.util.UUID] = Right(java.util.UUID.randomUUID()) + override def defaultValue: zio.prelude.Validation[String, java.util.UUID] = + zio.prelude.Validation.succeed(java.util.UUID.randomUUID()) } implicit object BigDecimalType extends StandardType[java.math.BigDecimal] { override def tag: String = Tags.BIG_DECIMAL override def compare(x: java.math.BigDecimal, y: java.math.BigDecimal): Int = x.compareTo(y) - override def defaultValue: Either[String, java.math.BigDecimal] = Right(java.math.BigDecimal.ZERO) + override def defaultValue: zio.prelude.Validation[String, java.math.BigDecimal] = + zio.prelude.Validation.succeed(java.math.BigDecimal.ZERO) } implicit object BigIntegerType extends StandardType[java.math.BigInteger] { - override def tag: String = Tags.BIG_INTEGER - override def compare(x: BigInteger, y: BigInteger): Int = x.compareTo(y) - override def defaultValue: Either[String, java.math.BigInteger] = Right(java.math.BigInteger.ZERO) + override def tag: String = Tags.BIG_INTEGER + override def compare(x: BigInteger, y: BigInteger): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, java.math.BigInteger] = + zio.prelude.Validation.succeed(java.math.BigInteger.ZERO) } //java.time specific types implicit object DayOfWeekType extends StandardType[DayOfWeek] { override def tag: String = Tags.DAY_OF_WEEK override def compare(x: DayOfWeek, y: DayOfWeek): Int = x.getValue.compareTo(y.getValue) - override def defaultValue: Either[String, DayOfWeek] = - Right(java.time.temporal.WeekFields.of(java.util.Locale.getDefault).getFirstDayOfWeek) + override def defaultValue: zio.prelude.Validation[String, DayOfWeek] = + zio.prelude.Validation.succeed(java.time.temporal.WeekFields.of(java.util.Locale.getDefault).getFirstDayOfWeek) } implicit object MonthType extends StandardType[java.time.Month] { - override def tag: String = Tags.MONTH - override def compare(x: Month, y: Month): Int = x.getValue.compareTo(y.getValue) - override def defaultValue: Either[String, java.time.Month] = Right(java.time.Month.JANUARY) + override def tag: String = Tags.MONTH + override def compare(x: Month, y: Month): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: zio.prelude.Validation[String, java.time.Month] = + Validation.succeed(java.time.Month.JANUARY) } implicit object MonthDayType extends StandardType[java.time.MonthDay] { override def tag: String = Tags.MONTH_DAY override def compare(x: MonthDay, y: MonthDay): Int = x.compareTo(y) - override def defaultValue: Either[String, java.time.MonthDay] = - Right(java.time.MonthDay.of(java.time.Month.JANUARY, 1)) + override def defaultValue: zio.prelude.Validation[String, java.time.MonthDay] = + zio.prelude.Validation.succeed(java.time.MonthDay.of(java.time.Month.JANUARY, 1)) } implicit object PeriodType extends StandardType[java.time.Period] { @@ -202,43 +210,50 @@ object StandardType { val startDate = time.LocalDate.of(0, 1, 1) startDate.plus(x).compareTo(startDate.plus(y)) } - override def defaultValue: Either[String, java.time.Period] = Right(java.time.Period.ZERO) + override def defaultValue: zio.prelude.Validation[String, java.time.Period] = + zio.prelude.Validation.succeed(java.time.Period.ZERO) } implicit object YearType extends StandardType[java.time.Year] { - override def tag: String = Tags.YEAR - override def compare(x: Year, y: Year): Int = x.getValue.compareTo(y.getValue) - override def defaultValue: Either[String, java.time.Year] = Right(java.time.Year.now) + override def tag: String = Tags.YEAR + override def compare(x: Year, y: Year): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: zio.prelude.Validation[String, java.time.Year] = + zio.prelude.Validation.succeed(java.time.Year.now) } implicit object YearMonthType extends StandardType[java.time.YearMonth] { - override def tag: String = Tags.YEAR_MONTH - override def compare(x: YearMonth, y: YearMonth): Int = x.compareTo(y) - override def defaultValue: Either[String, java.time.YearMonth] = Right(java.time.YearMonth.now) + override def tag: String = Tags.YEAR_MONTH + override def compare(x: YearMonth, y: YearMonth): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, java.time.YearMonth] = + zio.prelude.Validation.succeed(java.time.YearMonth.now) } implicit object ZoneIdType extends StandardType[java.time.ZoneId] { - override def tag: String = Tags.ZONE_ID - override def compare(x: ZoneId, y: ZoneId): Int = x.getId.compareTo(y.getId) // TODO is there a better comparison - override def defaultValue: Either[String, java.time.ZoneId] = Right(java.time.ZoneId.systemDefault) + override def tag: String = Tags.ZONE_ID + override def compare(x: ZoneId, y: ZoneId): Int = x.getId.compareTo(y.getId) // TODO is there a better comparison + override def defaultValue: zio.prelude.Validation[String, java.time.ZoneId] = + zio.prelude.Validation.succeed(java.time.ZoneId.systemDefault) } implicit object ZoneOffsetType extends StandardType[java.time.ZoneOffset] { - override def tag: String = Tags.ZONE_OFFSET - override def compare(x: ZoneOffset, y: ZoneOffset): Int = x.compareTo(y) - override def defaultValue: Either[String, java.time.ZoneOffset] = Right(java.time.ZoneOffset.UTC) + override def tag: String = Tags.ZONE_OFFSET + override def compare(x: ZoneOffset, y: ZoneOffset): Int = x.compareTo(y) + override def defaultValue: zio.prelude.Validation[String, java.time.ZoneOffset] = + zio.prelude.Validation.succeed(java.time.ZoneOffset.UTC) } implicit object DurationType extends StandardType[java.time.Duration] { override def tag: String = Tags.DURATION override def compare(x: time.Duration, y: time.Duration): Int = x.compareTo(y) - override def defaultValue: Either[String, java.time.Duration] = Right(java.time.Duration.ZERO) + override def defaultValue: zio.prelude.Validation[String, java.time.Duration] = + zio.prelude.Validation.succeed(java.time.Duration.ZERO) } implicit object InstantType extends StandardType[java.time.Instant] { override def tag: String = Tags.INSTANT - override def defaultValue: Either[String, Instant] = Right(java.time.Instant.EPOCH) + override def defaultValue: zio.prelude.Validation[String, Instant] = + zio.prelude.Validation.succeed(java.time.Instant.EPOCH) override def compare(x: Instant, y: Instant): Int = x.compareTo(y) } @@ -246,7 +261,8 @@ object StandardType { implicit object LocalDateType extends StandardType[java.time.LocalDate] { override def tag: String = Tags.LOCAL_DATE - override def defaultValue: Either[String, LocalDate] = Right(java.time.LocalDate.now) + override def defaultValue: zio.prelude.Validation[String, LocalDate] = + zio.prelude.Validation.succeed(java.time.LocalDate.now) override def compare(x: LocalDate, y: LocalDate): Int = x.compareTo(y) } @@ -254,7 +270,8 @@ object StandardType { implicit object LocalTimeType extends StandardType[java.time.LocalTime] { override def tag: String = Tags.LOCAL_TIME - override def defaultValue: Either[String, LocalTime] = Right(java.time.LocalTime.MIDNIGHT) + override def defaultValue: zio.prelude.Validation[String, LocalTime] = + zio.prelude.Validation.succeed(java.time.LocalTime.MIDNIGHT) override def compare(x: LocalTime, y: LocalTime): Int = x.compareTo(y) } @@ -262,7 +279,8 @@ object StandardType { implicit object LocalDateTimeType extends StandardType[java.time.LocalDateTime] { override def tag: String = Tags.LOCAL_DATE_TIME - override def defaultValue: Either[String, LocalDateTime] = Right(java.time.LocalDateTime.now) + override def defaultValue: zio.prelude.Validation[String, LocalDateTime] = + zio.prelude.Validation.succeed(java.time.LocalDateTime.now) override def compare(x: LocalDateTime, y: LocalDateTime): Int = x.compareTo(y) } @@ -270,7 +288,8 @@ object StandardType { implicit object OffsetTimeType extends StandardType[java.time.OffsetTime] { override def tag: String = Tags.OFFSET_TIME - override def defaultValue: Either[String, OffsetTime] = Right(java.time.OffsetTime.now) + override def defaultValue: zio.prelude.Validation[String, OffsetTime] = + zio.prelude.Validation.succeed(java.time.OffsetTime.now) override def compare(x: OffsetTime, y: OffsetTime): Int = x.compareTo(y) } @@ -278,7 +297,8 @@ object StandardType { implicit object OffsetDateTimeType extends StandardType[java.time.OffsetDateTime] { override def tag: String = Tags.OFFSET_DATE_TIME - override def defaultValue: Either[String, OffsetDateTime] = Right(java.time.OffsetDateTime.now) + override def defaultValue: zio.prelude.Validation[String, OffsetDateTime] = + zio.prelude.Validation.succeed(java.time.OffsetDateTime.now) override def compare(x: OffsetDateTime, y: OffsetDateTime): Int = x.compareTo(y) } @@ -286,7 +306,8 @@ object StandardType { implicit object ZonedDateTimeType extends StandardType[java.time.ZonedDateTime] { override def tag: String = Tags.ZONED_DATE_TIME - override def defaultValue: Either[String, ZonedDateTime] = Right(java.time.ZonedDateTime.now) + override def defaultValue: zio.prelude.Validation[String, ZonedDateTime] = + zio.prelude.Validation.succeed(java.time.ZonedDateTime.now) override def compare(x: ZonedDateTime, y: ZonedDateTime): Int = x.compareTo(y) } diff --git a/zio-schema/shared/src/main/scala/zio/schema/annotation/validate.scala b/zio-schema/shared/src/main/scala/zio/schema/annotation/validate.scala index cef26e27f..5e675753b 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/annotation/validate.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/annotation/validate.scala @@ -1,5 +1,5 @@ package zio.schema.annotation -import zio.schema.validation.Validation +import zio.schema.validation.SchemaValidation -final case class validate[A](validation: Validation[A]) extends scala.annotation.StaticAnnotation +final case class validate[A](validation: SchemaValidation[A]) extends scala.annotation.StaticAnnotation diff --git a/zio-schema/shared/src/main/scala/zio/schema/codec/BinaryCodecs.scala b/zio-schema/shared/src/main/scala/zio/schema/codec/BinaryCodecs.scala index c57ef9c88..12e1c785b 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/codec/BinaryCodecs.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/codec/BinaryCodecs.scala @@ -32,7 +32,9 @@ object BinaryCodecs { override def streamEncoder[T](implicit ev: IsElementOf[T, Types]): ZPipeline[Any, Nothing, T, Byte] = instances.withInstance((codec: BinaryCodec[T]) => codec.streamEncoder) - override def decode[T](whole: Chunk[Byte])(implicit ev: IsElementOf[T, Types]): Either[DecodeError, T] = + override def decode[T]( + whole: Chunk[Byte] + )(implicit ev: IsElementOf[T, Types]): zio.prelude.Validation[DecodeError, T] = instances.withInstance((codec: BinaryCodec[T]) => codec.decode(whole)) override def streamDecoder[T](implicit ev: IsElementOf[T, Types]): ZPipeline[Any, DecodeError, Byte, T] = diff --git a/zio-schema/shared/src/main/scala/zio/schema/codec/Codecs.scala b/zio-schema/shared/src/main/scala/zio/schema/codec/Codecs.scala index db7e3a89b..dcb4e9952 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/codec/Codecs.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/codec/Codecs.scala @@ -17,12 +17,13 @@ package zio.schema.codec import zio.constraintless._ +import zio.prelude.Validation import zio.stream.ZPipeline trait Codecs[Whole, Element, Types <: TypeList] { def encode[T](value: T)(implicit ev: T IsElementOf Types): Whole def streamEncoder[T](implicit ev: T IsElementOf Types): ZPipeline[Any, Nothing, T, Element] - def decode[T](whole: Whole)(implicit ev: T IsElementOf Types): Either[DecodeError, T] + def decode[T](whole: Whole)(implicit ev: T IsElementOf Types): Validation[DecodeError, T] def streamDecoder[T](implicit ev: T IsElementOf Types): ZPipeline[Any, DecodeError, Element, T] } @@ -37,7 +38,9 @@ object Codecs { final override def streamEncoder[T](implicit ev: IsElementOf[T, Types]): ZPipeline[Any, Nothing, T, Element] = instances.withInstance((codec: Codec[Whole, Element, T]) => codec.streamEncoder) - final override def decode[T](whole: Whole)(implicit ev: IsElementOf[T, Types]): Either[DecodeError, T] = + final override def decode[T]( + whole: Whole + )(implicit ev: IsElementOf[T, Types]): Validation[DecodeError, T] = instances.withInstance((codec: Codec[Whole, Element, T]) => codec.decode(whole)) final override def streamDecoder[T](implicit ev: IsElementOf[T, Types]): ZPipeline[Any, DecodeError, Element, T] = diff --git a/zio-schema/shared/src/main/scala/zio/schema/codec/DecodeError.scala b/zio-schema/shared/src/main/scala/zio/schema/codec/DecodeError.scala index 2189922ef..2d284485c 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/codec/DecodeError.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/codec/DecodeError.scala @@ -4,7 +4,7 @@ import scala.collection.immutable.ListMap import scala.util.control.NoStackTrace import zio.schema.Schema.{ Field, Record } -import zio.schema.validation.Validation +import zio.schema.validation.SchemaValidation import zio.schema.{ DynamicValue, Schema } import zio.{ Cause, Chunk } @@ -13,17 +13,11 @@ sealed trait DecodeError extends Exception with NoStackTrace { self => override def getMessage(): String = message - def and(that: DecodeError): DecodeError = DecodeError.And(self, that) - def or(that: DecodeError): DecodeError = DecodeError.Or(self, that) } object DecodeError { - final case class And(left: DecodeError, right: DecodeError) extends DecodeError { - def message: String = s"${left.message} and ${right.message}" - } - final case class Or(left: DecodeError, right: DecodeError) extends DecodeError { override def message: String = s"${left.message} or ${right.message}" } @@ -40,7 +34,8 @@ object DecodeError { final case class ReadErrorWithPath(path: Chunk[String], cause: Cause[Any], message: String) extends DecodeError - final case class ValidationError(validation: Validation[_], field: Field[_, _], message: String) extends DecodeError + final case class ValidationError(validation: SchemaValidation[_], field: Field[_, _], message: String) + extends DecodeError final case class ExtraFields(fieldName: String, message: String) extends DecodeError diff --git a/zio-schema/shared/src/main/scala/zio/schema/codec/Decoder.scala b/zio-schema/shared/src/main/scala/zio/schema/codec/Decoder.scala index 03f13f42e..217be2a94 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/codec/Decoder.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/codec/Decoder.scala @@ -16,11 +16,12 @@ package zio.schema.codec +import zio.prelude.Validation import zio.stream.ZPipeline trait Decoder[Whole, Element, +A] { - def decode(whole: Whole): Either[DecodeError, A] + def decode(whole: Whole): Validation[DecodeError, A] def streamDecoder: ZPipeline[Any, DecodeError, Element, A] diff --git a/zio-schema/shared/src/main/scala/zio/schema/meta/ExtensibleMetaSchema.scala b/zio-schema/shared/src/main/scala/zio/schema/meta/ExtensibleMetaSchema.scala index 8560c79de..30505c34e 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/meta/ExtensibleMetaSchema.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/meta/ExtensibleMetaSchema.scala @@ -388,17 +388,19 @@ object ExtensibleMetaSchema { private def tupled[BuiltIn <: TypeList]( value: Value[BuiltIn] - ): scala.Either[String, (String, Chunk[String], Boolean)] = - Right((value.valueType.tag, value.path, value.optional)) + ): Validation[String, (String, Chunk[String], Boolean)] = + Validation.succeed((value.valueType.tag, value.path, value.optional)) private def fromTuple[BuiltIn <: TypeList]( tuple: (String, Chunk[String], Boolean) - )(implicit builtInInstances: SchemaInstances[BuiltIn]): scala.Either[String, Value[BuiltIn]] = tuple match { + )(implicit builtInInstances: SchemaInstances[BuiltIn]): Validation[String, Value[BuiltIn]] = tuple match { case (s, path, optional) => - StandardType - .fromString(s) - .map(typ => Value(typ, NodePath(path), optional)) - .toRight(s"unkown standard type $s") + Validation.fromEither( + StandardType + .fromString(s) + .map(typ => Value(typ, NodePath(path), optional)) + .toRight(s"unkown standard type $s") + ) } } final case class Ref[BuiltIn <: TypeList]( diff --git a/zio-schema/shared/src/main/scala/zio/schema/meta/Migration.scala b/zio-schema/shared/src/main/scala/zio/schema/meta/Migration.scala index 908baae5a..336a57277 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/meta/Migration.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/meta/Migration.scala @@ -2,6 +2,7 @@ package zio.schema.meta import scala.collection.immutable.ListMap +import zio.prelude.{ Validation, ZValidation } import zio.schema.meta.ExtensibleMetaSchema.Labelled import zio.schema.{ DynamicValue, StandardType } import zio.{ Chunk, ChunkBuilder } @@ -10,18 +11,18 @@ sealed trait Migration { self => def path: NodePath - def migrate(value: DynamicValue): Either[String, DynamicValue] = + def migrate(value: DynamicValue): Validation[String, DynamicValue] = self match { case Migration.Require(path) => Migration.require(value, path.toList) case Migration.Optional(path) => Migration.makeOptional(value, path.toList) case Migration.ChangeType(path, _) => - Left( + Validation.fail( s"Cannot change type of node at path ${path.render}: No type conversion is available" ) case Migration.DeleteNode(path) => Migration.deleteNode(value, path.toList) - case Migration.AddCase(_, _) => Right(value) + case Migration.AddCase(_, _) => Validation.succeed(value) case Migration.AddNode(path, _) => - Left(s"Cannot add node at path ${path.render}: No default value is available") + Validation.fail(s"Cannot add node at path ${path.render}: No default value is available") case Migration.Relabel(path, transform) => Migration.relabel(value, path.toList, transform) case Migration.IncrementDimensions(path, n) => Migration.incrementDimension(value, path.toList, n) @@ -58,29 +59,25 @@ object Migration { final case class Recursive(override val path: NodePath, relativeNodePath: NodePath, relativeMigration: Migration) extends Migration - def derive(from: MetaSchema, to: MetaSchema): Either[String, Chunk[Migration]] = { + def derive(from: MetaSchema, to: MetaSchema): zio.prelude.Validation[String, Chunk[Migration]] = { def go( acc: Chunk[Migration], path: NodePath, fromSubtree: MetaSchema, toSubtree: MetaSchema, ignoreRefs: Boolean - ): Either[String, Chunk[Migration]] = { + ): zio.prelude.Validation[String, Chunk[Migration]] = { def goProduct( f: MetaSchema, t: MetaSchema, ffields: Chunk[MetaSchema.Labelled], tfields: Chunk[MetaSchema.Labelled] - ): Either[String, Chunk[Migration]] = + ): zio.prelude.Validation[String, Chunk[Migration]] = matchedSubtrees(ffields, tfields).map { case (Labelled(nextPath, fs), Labelled(_, ts)) => go(acc, path / nextPath, fs, ts, ignoreRefs) - }.foldRight[Either[String, Chunk[Migration]]](Right(Chunk.empty)) { - case (err @ Left(_), Right(_)) => err - case (Right(_), err @ Left(_)) => err - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Right(t1), Right(t2)) => Right(t1 ++ t2) - } + }.validateAll() + .map(_.flatten) .map( _ ++ acc ++ transformShape(path, f, t) ++ insertions(path, ffields, tfields) ++ deletions( path, @@ -94,15 +91,11 @@ object Migration { t: MetaSchema, fcases: Chunk[MetaSchema.Labelled], tcases: Chunk[MetaSchema.Labelled] - ): Either[String, Chunk[Migration]] = + ): zio.prelude.Validation[String, Chunk[Migration]] = matchedSubtrees(fcases, tcases).map { case (Labelled(nextPath, fs), Labelled(_, ts)) => go(acc, path / nextPath, fs, ts, ignoreRefs) - }.foldRight[Either[String, Chunk[Migration]]](Right(Chunk.empty)) { - case (err @ Left(_), Right(_)) => err - case (Right(_), err @ Left(_)) => err - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Right(t1), Right(t2)) => Right(t1 ++ t2) - } + }.validateAll() + .map(_.flatten) .map( _ ++ acc ++ transformShape(path, f, t) ++ caseInsertions(path, fcases, tcases) ++ deletions( path, @@ -113,7 +106,7 @@ object Migration { (fromSubtree, toSubtree) match { case (f @ ExtensibleMetaSchema.FailNode(_, _, _), t @ ExtensibleMetaSchema.FailNode(_, _, _)) => - Right( + Validation.succeed( if (f.message == t.message) Chunk.empty else @@ -172,19 +165,20 @@ object Migration { goSum(f, t, fcases, tcases) case (f @ ExtensibleMetaSchema.Value(ftype, _, _), t @ ExtensibleMetaSchema.Value(ttype, _, _)) if ttype != ftype => - Right(transformShape(path, f, t) :+ ChangeType(path, ttype)) + Validation.succeed(transformShape(path, f, t) :+ ChangeType(path, ttype)) case (f @ ExtensibleMetaSchema.Value(_, _, _), t @ ExtensibleMetaSchema.Value(_, _, _)) => - Right(transformShape(path, f, t)) + Validation.succeed(transformShape(path, f, t)) case (f @ ExtensibleMetaSchema.Ref(fromRef, nodePath, _), t @ ExtensibleMetaSchema.Ref(toRef, _, _)) if fromRef == toRef => - if (ignoreRefs) Right(Chunk.empty) + if (ignoreRefs) Validation.succeed(Chunk.empty) else { val recursiveMigrations = acc .filter(_.path.isSubpathOf(fromRef)) .map(relativize(fromRef, nodePath.relativeTo(fromRef))) - Right(recursiveMigrations ++ transformShape(path, f, t)) + Validation.succeed(recursiveMigrations ++ transformShape(path, f, t)) } - case (f, t) => Left(s"Subtrees at path ${renderPath(path)} are not homomorphic: $f cannot be mapped to $t") + case (f, t) => + Validation.fail(s"Subtrees at path ${renderPath(path)} are not homomorphic: $f cannot be mapped to $t") } } @@ -228,7 +222,7 @@ object Migration { * For example, converting from snake to camel case (or vica versa) */ sealed trait LabelTransformation { - def apply(label: String): Either[String, String] + def apply(label: String): zio.prelude.Validation[String, String] } object LabelTransformation {} @@ -289,33 +283,29 @@ object Migration { value: DynamicValue, path: List[String], trace: Chunk[String] = Chunk.empty - )(op: (String, DynamicValue) => Either[String, Option[(String, DynamicValue)]]): Either[String, DynamicValue] = { + )( + op: (String, DynamicValue) => zio.prelude.Validation[String, Option[(String, DynamicValue)]] + ): zio.prelude.Validation[String, DynamicValue] = { (value, path) match { case (DynamicValue.SomeValue(value), _) => - updateLeaf(value, path, trace)(op).map(DynamicValue.SomeValue(_)) - case (DynamicValue.NoneValue, _) => Right(DynamicValue.NoneValue) + updateLeaf(value, path, trace)(op).map(DynamicValue.SomeValue) + case (DynamicValue.NoneValue, _) => Validation.succeed(DynamicValue.NoneValue) case (DynamicValue.Sequence(values), "item" :: remainder) => values.zipWithIndex.map { case (v, idx) => updateLeaf(v, remainder, trace :+ s"item[$idx]")(op) } - .foldRight[Either[String, DynamicValue.Sequence]](Right(DynamicValue.Sequence(Chunk.empty))) { - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Left(e), Right(_)) => Left(e) - case (Right(_), Left(e)) => Left(e) - case (Right(DynamicValue.Sequence(v1s)), Right(DynamicValue.Sequence(v2s))) => - Right(DynamicValue.Sequence(v1s ++ v2s)) - case (Right(v1), Right(DynamicValue.Sequence(v2s))) => Right(DynamicValue.Sequence(v1 +: v2s)) - } + .validateAll() + .map(DynamicValue.Sequence) case (DynamicValue.Tuple(l, r), "left" :: remainder) => updateLeaf(l, remainder, trace :+ "left")(op).map(newLeft => DynamicValue.Tuple(newLeft, r)) case (DynamicValue.Tuple(l, r), "right" :: remainder) => updateLeaf(r, remainder, trace :+ "right")(op).map(newRight => DynamicValue.Tuple(l, newRight)) case (DynamicValue.LeftValue(l), "left" :: remainder) => - updateLeaf(l, remainder, trace :+ "left")(op).map(DynamicValue.LeftValue(_)) + updateLeaf(l, remainder, trace :+ "left")(op).map(DynamicValue.LeftValue) case (value @ DynamicValue.LeftValue(_), "right" :: _) => - Right(value) + Validation.succeed(value) case (DynamicValue.RightValue(r), "right" :: remainder) => - updateLeaf(r, remainder, trace :+ "right")(op).map(DynamicValue.RightValue(_)) + updateLeaf(r, remainder, trace :+ "right")(op).map(DynamicValue.RightValue) case (value @ DynamicValue.RightValue(_), "left" :: _) => - Right(value) + Validation.succeed(value) case (DynamicValue.Record(name, values), leafLabel :: Nil) if values.keySet.contains(leafLabel) => op(leafLabel, values(leafLabel)).map { case Some((newLeafLabel, newLeafValue)) => @@ -327,14 +317,14 @@ object Migration { DynamicValue.Record(name, spliceRecord(values, nextLabel, nextLabel -> updatedValue)) } case (DynamicValue.Record(_, _), nextLabel :: _) => - Left(s"Expected label $nextLabel not found at path ${renderPath(trace)}") + Validation.fail(s"Expected label $nextLabel not found at path ${renderPath(trace)}") case (v @ DynamicValue.Enumeration(_, (caseLabel, _)), nextLabel :: _) if caseLabel != nextLabel => - Right(v) + Validation.succeed(v) case (DynamicValue.Enumeration(id, (caseLabel, caseValue)), nextLabel :: Nil) if caseLabel == nextLabel => op(caseLabel, caseValue).flatMap { - case Some(newCase) => Right(DynamicValue.Enumeration(id, newCase)) + case Some(newCase) => Validation.succeed(DynamicValue.Enumeration(id, newCase)) case None => - Left( + Validation.fail( s"Failed to update leaf node at path ${renderPath(trace :+ nextLabel)}: Cannot remove instantiated case" ) } @@ -349,17 +339,11 @@ object Migration { .map { case (k, idx) => op(s"key[$idx]", k).flatMap { - case Some((_, migrated)) => Right(migrated) - case None => Left(s"invalid update at $path, cannot remove map key") + case Some((_, migrated)) => Validation.succeed(migrated) + case None => Validation.fail(s"invalid update at $path, cannot remove map key") } } - .foldRight[Either[String, Chunk[DynamicValue]]](Right(Chunk.empty)) { - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Left(e), Right(_)) => Left(e) - case (Right(_), Left(e)) => Left(e) - case (Right(value), Right(chunk)) => - Right(value +: chunk) - } + .validateAll() .map { keys => DynamicValue.Dictionary(keys.zip(entries.map(_._2))) } @@ -371,13 +355,7 @@ object Migration { case (k, idx) => updateLeaf(k, remainder, trace :+ s"key[$idx]")(op) } - .foldRight[Either[String, Chunk[DynamicValue]]](Right(Chunk.empty)) { - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Left(e), Right(_)) => Left(e) - case (Right(_), Left(e)) => Left(e) - case (Right(value), Right(chunk)) => - Right(value +: chunk) - } + .validateAll() .map { keys => DynamicValue.Dictionary(keys.zip(entries.map(_._2))) } @@ -388,17 +366,11 @@ object Migration { .map { case (k, idx) => op(s"key[$idx]", k).flatMap { - case Some((_, migrated)) => Right(migrated) - case None => Left(s"invalid update at $path, cannot remove map value") + case Some((_, migrated)) => Validation.succeed(migrated) + case None => Validation.fail(s"invalid update at $path, cannot remove map value") } } - .foldRight[Either[String, Chunk[DynamicValue]]](Right(Chunk.empty)) { - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Left(e), Right(_)) => Left(e) - case (Right(_), Left(e)) => Left(e) - case (Right(value), Right(chunk)) => - Right(value +: chunk) - } + .validateAll() .map { values => DynamicValue.Dictionary(entries.map(_._1).zip(values)) } @@ -410,18 +382,14 @@ object Migration { case (k, idx) => updateLeaf(k, remainder, trace :+ s"value[$idx]")(op) } - .foldRight[Either[String, Chunk[DynamicValue]]](Right(Chunk.empty)) { - case (Left(e1), Left(e2)) => Left(s"$e1;\n$e2") - case (Left(e), Right(_)) => Left(e) - case (Right(_), Left(e)) => Left(e) - case (Right(value), Right(chunk)) => - Right(value +: chunk) - } + .validateAll() .map { values => DynamicValue.Dictionary(entries.map(_._1).zip(values)) } case _ => - Left(s"Failed to update leaf at path ${renderPath(trace ++ path)}: Unexpected node at ${renderPath(trace)}") + Validation.fail( + s"Failed to update leaf at path ${renderPath(trace ++ path)}: Unexpected node at ${renderPath(trace)}" + ) } } @@ -465,11 +433,14 @@ object Migration { } } - protected[schema] def migrateRecursive(value: DynamicValue, migration: Recursive): Either[String, DynamicValue] = { - def go(lastValue: DynamicValue, depth: Int): Either[String, DynamicValue] = + protected[schema] def migrateRecursive( + value: DynamicValue, + migration: Recursive + ): zio.prelude.Validation[String, DynamicValue] = { + def go(lastValue: DynamicValue, depth: Int): zio.prelude.Validation[String, DynamicValue] = materializeRecursive(depth)(migration).migrate(lastValue).flatMap { thisValue => if (thisValue == lastValue) - Right(thisValue) + Validation.succeed(thisValue) else go(thisValue, depth + 1) } @@ -480,15 +451,15 @@ object Migration { value: DynamicValue, path: List[String], newMessage: String - ): Either[String, DynamicValue] = + ): zio.prelude.Validation[String, DynamicValue] = (path, value) match { - case (Nil, DynamicValue.Error(_)) => Right(DynamicValue.Error(newMessage)) - case (Nil, _) => Left(s"Failed to update fail message at root. Unexpected type") + case (Nil, DynamicValue.Error(_)) => Validation.succeed(DynamicValue.Error(newMessage)) + case (Nil, _) => Validation.fail(s"Failed to update fail message at root. Unexpected type") case _ => updateLeaf(value, path) { (label, value) => value match { - case DynamicValue.Error(_) => Right(Some(label -> DynamicValue.Error(newMessage))) - case _ => Left(s"Failed to update fail message at ${renderPath(path)}. Unexpected type") + case DynamicValue.Error(_) => Validation.succeed(Some(label -> DynamicValue.Error(newMessage))) + case _ => Validation.fail(s"Failed to update fail message at ${renderPath(path)}. Unexpected type") } } } @@ -497,10 +468,10 @@ object Migration { value: DynamicValue, path: List[String], n: Int - ): Either[String, DynamicValue] = + ): zio.prelude.Validation[String, DynamicValue] = path match { case Nil => - Right( + Validation.succeed( (0 until n).foldRight(value) { case (_, acc) => DynamicValue.Sequence(Chunk(acc)) @@ -508,7 +479,7 @@ object Migration { ) case _ => updateLeaf(value, path) { (label, v) => - Right( + Validation.succeed( Some( (0 until n).foldRight(label -> v) { case (_, (_, acc)) => @@ -524,50 +495,52 @@ object Migration { value: DynamicValue, path: List[String], n: Int - ): Either[String, DynamicValue] = + ): Validation[String, DynamicValue] = path match { case Nil => - (0 until n).foldRight[Either[String, DynamicValue]](Right(value)) { + Validation.fromEither((0 until n).foldRight[Either[String, DynamicValue]](Right(value)) { case (_, error @ Left(_)) => error case (_, Right(DynamicValue.Sequence(values))) if values.size == 1 => Right(values(0)) case _ => Left( s"Failed to decrement dimensions for node at path ${renderPath(path)}: Can only decrement dimensions on a sequence with one element" ) - } + }) case _ => updateLeaf(value, path) { (label, value) => - (0 until n) - .foldRight[Either[String, DynamicValue]](Right(value)) { - case (_, error @ Left(_)) => error - case (_, Right(DynamicValue.Sequence(values))) if values.size == 1 => Right(values(0)) - case _ => - Left( - s"Failed to decrement dimensions for node at path ${renderPath(path)}: Can only decrement dimensions on a sequence with one element" - ) - } - .map(updatedValue => Some(label -> updatedValue)) + Validation.fromEither( + (0 until n) + .foldRight[Either[String, DynamicValue]](Right(value)) { + case (_, error @ Left(_)) => error + case (_, Right(DynamicValue.Sequence(values))) if values.size == 1 => Right(values(0)) + case _ => + Left( + s"Failed to decrement dimensions for node at path ${renderPath(path)}: Can only decrement dimensions on a sequence with one element" + ) + } + .map(updatedValue => Some(label -> updatedValue)) + ) } } protected[schema] def require( value: DynamicValue, path: List[String] - ): Either[String, DynamicValue] = + ): Validation[String, DynamicValue] = (value, path) match { - case (DynamicValue.SomeValue(v), Nil) => Right(v) + case (DynamicValue.SomeValue(v), Nil) => Validation.succeed(v) case (DynamicValue.NoneValue, Nil) => - Left( + Validation.fail( s"Failed to require node: Optional value was None" ) case _ => updateLeaf(value, path) { case (label, DynamicValue.SomeValue(v)) => - Right(Some(label -> v)) + Validation.succeed(Some(label -> v)) case (_, DynamicValue.NoneValue) => - Left(s"Failed to require leaf at path ${renderPath(path)}: Optional value was not available") + Validation.fail(s"Failed to require leaf at path ${renderPath(path)}: Optional value was not available") case _ => - Left(s"Failed to require leaf at path ${renderPath(path)}: Expected optional value at lead") + Validation.fail(s"Failed to require leaf at path ${renderPath(path)}: Expected optional value at lead") } } @@ -575,15 +548,17 @@ object Migration { value: DynamicValue, path: List[String], transformation: LabelTransformation - ): Either[String, DynamicValue] = + ): zio.prelude.Validation[String, DynamicValue] = path match { - case Nil => Left(s"Cannot relabel node: Path was empty") + case Nil => Validation.fail(s"Cannot relabel node: Path was empty") case _ => updateLeaf(value, path) { (label, value) => transformation(label).fold( error => - Left(s"Failed to relabel node at path ${renderPath(path)}: Relabel transform failed with error $error"), - newLabel => Right(Some(newLabel -> value)) + Validation.fail( + s"Failed to relabel node at path ${renderPath(path)}: Relabel transform failed with error $error" + ), + newLabel => Validation.succeed(Some(newLabel -> value)) ) } } @@ -591,26 +566,30 @@ object Migration { protected[schema] def makeOptional( value: DynamicValue, path: List[String] - ): Either[String, DynamicValue] = + ): zio.prelude.Validation[String, DynamicValue] = (value, path) match { - case (value, Nil) => Right(DynamicValue.SomeValue(value)) + case (value, Nil) => Validation.succeed(DynamicValue.SomeValue(value)) case _ => updateLeaf(value, path) { case (label, value) => - Right(Some(label -> DynamicValue.SomeValue(value))) + Validation.succeed(Some(label -> DynamicValue.SomeValue(value))) } } protected[schema] def deleteNode( value: DynamicValue, path: List[String] - ): Either[String, DynamicValue] = + ): zio.prelude.Validation[String, DynamicValue] = path match { - case Nil => Left(s"Cannot delete node: Path was empty") + case Nil => Validation.fail(s"Cannot delete node: Path was empty") case _ => - updateLeaf(value, path)((_, _) => Right(None)) + updateLeaf(value, path)((_, _) => Validation.succeed(None)) } private def renderPath(path: Iterable[String]): String = path.mkString("/") + implicit private class ChunkExt[+W, +E, +A](c: Chunk[ZValidation[W, E, A]]) { + def validateAll(): ZValidation[W, E, Chunk[A]] = Validation.validateAll(c) + } + } diff --git a/zio-schema/shared/src/main/scala/zio/schema/syntax.scala b/zio-schema/shared/src/main/scala/zio/schema/syntax.scala index ddef44490..5eed212a6 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/syntax.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/syntax.scala @@ -11,7 +11,7 @@ trait SchemaSyntax { */ def diffEach(that: A): Patch[A] = Schema[A].diff(a, that) - def runPatch(diff: Patch[A]): Either[String, A] = + def runPatch(diff: Patch[A]): zio.prelude.Validation[String, A] = Schema[A].patch(a, diff) } @@ -21,7 +21,7 @@ trait SchemaSyntax { implicit class MigrationOps[A: Schema](a: A) { - def migrate[B: Schema]: Either[String, B] = + def migrate[B: Schema]: zio.prelude.Validation[String, B] = Schema[A].migrate(Schema[B]).flatMap(f => f(a)) } } diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/PhoneNumberValidation.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/PhoneNumberValidation.scala index 92da0dd73..a0c6f6d25 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/validation/PhoneNumberValidation.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/validation/PhoneNumberValidation.scala @@ -17,2367 +17,2367 @@ trait PhoneNumberValidation { val digitsWithSeparator: Regex = Regex.digit.exactly(1) ~ optionalSeparator /** Phone number validation for Ascension Island */ - lazy val phoneNumberAC: Validation[String] = { + lazy val phoneNumberAC: SchemaValidation[String] = { val countryCode = Regex.literal("247") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Andorra */ - lazy val phoneNumberAD: Validation[String] = { + lazy val phoneNumberAD: SchemaValidation[String] = { val countryCode = Regex.literal("376") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for United Arab Emirates */ - lazy val phoneNumberAE: Validation[String] = { + lazy val phoneNumberAE: SchemaValidation[String] = { val countryCode = Regex.literal("971") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Afghanistan */ - lazy val phoneNumberAF: Validation[String] = { + lazy val phoneNumberAF: SchemaValidation[String] = { val countryCode = Regex.literal("93") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Antigua and Barbuda */ - lazy val phoneNumberAG: Validation[String] = { + lazy val phoneNumberAG: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("268") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Anguilla */ - lazy val phoneNumberAI: Validation[String] = { + lazy val phoneNumberAI: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("264") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Albania */ - lazy val phoneNumberAL: Validation[String] = { + lazy val phoneNumberAL: SchemaValidation[String] = { val countryCode = Regex.literal("355") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Armenia */ - lazy val phoneNumberAM: Validation[String] = { + lazy val phoneNumberAM: SchemaValidation[String] = { val countryCode = Regex.literal("374") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Netherlands Antilles */ - lazy val phoneNumberAN: Validation[String] = { + lazy val phoneNumberAN: SchemaValidation[String] = { val countryCode = Regex.literal("599") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Angola */ - lazy val phoneNumberAO: Validation[String] = { + lazy val phoneNumberAO: SchemaValidation[String] = { val countryCode = Regex.literal("244") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Antarctica */ - lazy val phoneNumberAQ: Validation[String] = { + lazy val phoneNumberAQ: SchemaValidation[String] = { val countryCode = Regex.literal("672") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Argentina */ - lazy val phoneNumberAR: Validation[String] = { + lazy val phoneNumberAR: SchemaValidation[String] = { val countryCode = Regex.literal("54") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for American Samoa */ - lazy val phoneNumberAS: Validation[String] = { + lazy val phoneNumberAS: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("684") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Austria */ - lazy val phoneNumberAT: Validation[String] = { + lazy val phoneNumberAT: SchemaValidation[String] = { val countryCode = Regex.literal("43") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Australia */ - lazy val phoneNumberAU: Validation[String] = { + lazy val phoneNumberAU: SchemaValidation[String] = { val countryCode = Regex.literal("61") val internationalPrefix = plus | Regex.literal("0011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Aruba */ - lazy val phoneNumberAW: Validation[String] = { + lazy val phoneNumberAW: SchemaValidation[String] = { val countryCode = Regex.literal("297") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Aland Islands */ - lazy val phoneNumberAX: Validation[String] = { + lazy val phoneNumberAX: SchemaValidation[String] = { val countryCode = Regex.literal("358") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val leadingDigits = Regex.literal("18") val phoneNumber = digitsWithSeparator.between(6, 8) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Azerbaijan */ - lazy val phoneNumberAZ: Validation[String] = { + lazy val phoneNumberAZ: SchemaValidation[String] = { val countryCode = Regex.literal("994") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bosnia and Herzegovina */ - lazy val phoneNumberBA: Validation[String] = { + lazy val phoneNumberBA: SchemaValidation[String] = { val countryCode = Regex.literal("387") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Barbados */ - lazy val phoneNumberBB: Validation[String] = { + lazy val phoneNumberBB: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("246") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bangladesh */ - lazy val phoneNumberBD: Validation[String] = { + lazy val phoneNumberBD: SchemaValidation[String] = { val countryCode = Regex.literal("880") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Belgium */ - lazy val phoneNumberBE: Validation[String] = { + lazy val phoneNumberBE: SchemaValidation[String] = { val countryCode = Regex.literal("32") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Burkina Faso */ - lazy val phoneNumberBF: Validation[String] = { + lazy val phoneNumberBF: SchemaValidation[String] = { val countryCode = Regex.literal("226") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bulgaria */ - lazy val phoneNumberBG: Validation[String] = { + lazy val phoneNumberBG: SchemaValidation[String] = { val countryCode = Regex.literal("359") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bahrain */ - lazy val phoneNumberBH: Validation[String] = { + lazy val phoneNumberBH: SchemaValidation[String] = { val countryCode = Regex.literal("973") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Burundi */ - lazy val phoneNumberBI: Validation[String] = { + lazy val phoneNumberBI: SchemaValidation[String] = { val countryCode = Regex.literal("257") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Benin */ - lazy val phoneNumberBJ: Validation[String] = { + lazy val phoneNumberBJ: SchemaValidation[String] = { val countryCode = Regex.literal("229") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint-Barthelemy */ - lazy val phoneNumberBL: Validation[String] = { + lazy val phoneNumberBL: SchemaValidation[String] = { val countryCode = Regex.literal("590") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bermuda */ - lazy val phoneNumberBM: Validation[String] = { + lazy val phoneNumberBM: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("441") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Brunei Darussalam */ - lazy val phoneNumberBN: Validation[String] = { + lazy val phoneNumberBN: SchemaValidation[String] = { val countryCode = Regex.literal("673") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bolivia */ - lazy val phoneNumberBO: Validation[String] = { + lazy val phoneNumberBO: SchemaValidation[String] = { val countryCode = Regex.literal("591") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Caribbean Netherlands */ - lazy val phoneNumberBQ: Validation[String] = { + lazy val phoneNumberBQ: SchemaValidation[String] = { val countryCode = Regex.literal("599") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("347") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Brazil */ - lazy val phoneNumberBR: Validation[String] = { + lazy val phoneNumberBR: SchemaValidation[String] = { val countryCode = Regex.literal("55") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bahamas */ - lazy val phoneNumberBS: Validation[String] = { + lazy val phoneNumberBS: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("242") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bhutan */ - lazy val phoneNumberBT: Validation[String] = { + lazy val phoneNumberBT: SchemaValidation[String] = { val countryCode = Regex.literal("975") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Bouvet Island */ - lazy val phoneNumberBV: Validation[String] = { + lazy val phoneNumberBV: SchemaValidation[String] = { val countryCode = Regex.literal("47") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Botswana */ - lazy val phoneNumberBW: Validation[String] = { + lazy val phoneNumberBW: SchemaValidation[String] = { val countryCode = Regex.literal("267") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Belarus */ - lazy val phoneNumberBY: Validation[String] = { + lazy val phoneNumberBY: SchemaValidation[String] = { val countryCode = Regex.literal("375") val internationalPrefix = plus | Regex.literal("00810") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixEight val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Belize */ - lazy val phoneNumberBZ: Validation[String] = { + lazy val phoneNumberBZ: SchemaValidation[String] = { val countryCode = Regex.literal("501") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Canada */ - lazy val phoneNumberCA: Validation[String] = { + lazy val phoneNumberCA: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cocos (Keeling) Islands */ - lazy val phoneNumberCC: Validation[String] = { + lazy val phoneNumberCC: SchemaValidation[String] = { val countryCode = Regex.literal("61") val internationalPrefix = plus | Regex.literal("0011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Central African Republic */ - lazy val phoneNumberCF: Validation[String] = { + lazy val phoneNumberCF: SchemaValidation[String] = { val countryCode = Regex.literal("236") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Congo (Brazzaville) */ - lazy val phoneNumberCG: Validation[String] = { + lazy val phoneNumberCG: SchemaValidation[String] = { val countryCode = Regex.literal("242") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Congo, (Kinshasa) */ - lazy val phoneNumberCD: Validation[String] = { + lazy val phoneNumberCD: SchemaValidation[String] = { val countryCode = Regex.literal("243") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Switzerland */ - lazy val phoneNumberCH: Validation[String] = { + lazy val phoneNumberCH: SchemaValidation[String] = { val countryCode = Regex.literal("41") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(8, 9) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cote d'Ivoire */ - lazy val phoneNumberCI: Validation[String] = { + lazy val phoneNumberCI: SchemaValidation[String] = { val countryCode = Regex.literal("225") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cook Islands */ - lazy val phoneNumberCK: Validation[String] = { + lazy val phoneNumberCK: SchemaValidation[String] = { val countryCode = Regex.literal("682") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Chile */ - lazy val phoneNumberCL: Validation[String] = { + lazy val phoneNumberCL: SchemaValidation[String] = { val countryCode = Regex.literal("56") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cameroon */ - lazy val phoneNumberCM: Validation[String] = { + lazy val phoneNumberCM: SchemaValidation[String] = { val countryCode = Regex.literal("237") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for China */ - lazy val phoneNumberCN: Validation[String] = { + lazy val phoneNumberCN: SchemaValidation[String] = { val countryCode = Regex.literal("86") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Colombia */ - lazy val phoneNumberCO: Validation[String] = { + lazy val phoneNumberCO: SchemaValidation[String] = { val countryCode = Regex.literal("57") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Costa Rica */ - lazy val phoneNumberCR: Validation[String] = { + lazy val phoneNumberCR: SchemaValidation[String] = { val countryCode = Regex.literal("506") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cuba */ - lazy val phoneNumberCU: Validation[String] = { + lazy val phoneNumberCU: SchemaValidation[String] = { val countryCode = Regex.literal("53") val internationalPrefix = plus | Regex.literal("119") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cape Verde */ - lazy val phoneNumberCV: Validation[String] = { + lazy val phoneNumberCV: SchemaValidation[String] = { val countryCode = Regex.literal("238") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Curacao */ - lazy val phoneNumberCW: Validation[String] = { + lazy val phoneNumberCW: SchemaValidation[String] = { val countryCode = Regex.literal("599") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("69") val phoneNumber = digitsWithSeparator.between(6, 8) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Christmas Island */ - lazy val phoneNumberCX: Validation[String] = { + lazy val phoneNumberCX: SchemaValidation[String] = { val countryCode = Regex.literal("61") val internationalPrefix = plus | Regex.literal("0011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cyprus */ - lazy val phoneNumberCY: Validation[String] = { + lazy val phoneNumberCY: SchemaValidation[String] = { val countryCode = Regex.literal("357") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Czech Republic */ - lazy val phoneNumberCZ: Validation[String] = { + lazy val phoneNumberCZ: SchemaValidation[String] = { val countryCode = Regex.literal("420") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Germany */ - lazy val phoneNumberDE: Validation[String] = { + lazy val phoneNumberDE: SchemaValidation[String] = { val countryCode = Regex.literal("49") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(8, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Djibouti */ - lazy val phoneNumberDJ: Validation[String] = { + lazy val phoneNumberDJ: SchemaValidation[String] = { val countryCode = Regex.literal("253") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Denmark */ - lazy val phoneNumberDK: Validation[String] = { + lazy val phoneNumberDK: SchemaValidation[String] = { val countryCode = Regex.literal("45") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Dominica */ - lazy val phoneNumberDM: Validation[String] = { + lazy val phoneNumberDM: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("767") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Dominican Republic */ - lazy val phoneNumberDO: Validation[String] = { + lazy val phoneNumberDO: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("8001") val phoneNumber = digitsWithSeparator.exactly(6) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Algeria */ - lazy val phoneNumberDZ: Validation[String] = { + lazy val phoneNumberDZ: SchemaValidation[String] = { val countryCode = Regex.literal("213") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Ecuador */ - lazy val phoneNumberEC: Validation[String] = { + lazy val phoneNumberEC: SchemaValidation[String] = { val countryCode = Regex.literal("593") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Estonia */ - lazy val phoneNumberEE: Validation[String] = { + lazy val phoneNumberEE: SchemaValidation[String] = { val countryCode = Regex.literal("372") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Egypt */ - lazy val phoneNumberEG: Validation[String] = { + lazy val phoneNumberEG: SchemaValidation[String] = { val countryCode = Regex.literal("20") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Western Sahara */ - lazy val phoneNumberEH: Validation[String] = { + lazy val phoneNumberEH: SchemaValidation[String] = { val countryCode = Regex.literal("212") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val leadingDigits = Regex.literal("528") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Eritrea */ - lazy val phoneNumberER: Validation[String] = { + lazy val phoneNumberER: SchemaValidation[String] = { val countryCode = Regex.literal("291") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Spain */ - lazy val phoneNumberES: Validation[String] = { + lazy val phoneNumberES: SchemaValidation[String] = { val countryCode = Regex.literal("34") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Ethiopia */ - lazy val phoneNumberET: Validation[String] = { + lazy val phoneNumberET: SchemaValidation[String] = { val countryCode = Regex.literal("251") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Finland */ - lazy val phoneNumberFI: Validation[String] = { + lazy val phoneNumberFI: SchemaValidation[String] = { val countryCode = Regex.literal("358") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val leadingDigits = Regex.literal("1") val phoneNumber = digitsWithSeparator.between(6, 9) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Fiji */ - lazy val phoneNumberFJ: Validation[String] = { + lazy val phoneNumberFJ: SchemaValidation[String] = { val countryCode = Regex.literal("679") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Falkland Islands (Malvinas) */ - lazy val phoneNumberFK: Validation[String] = { + lazy val phoneNumberFK: SchemaValidation[String] = { val countryCode = Regex.literal("500") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Micronesia */ - lazy val phoneNumberFM: Validation[String] = { + lazy val phoneNumberFM: SchemaValidation[String] = { val countryCode = Regex.literal("691") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Faroe Islands */ - lazy val phoneNumberFO: Validation[String] = { + lazy val phoneNumberFO: SchemaValidation[String] = { val countryCode = Regex.literal("298") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for France */ - lazy val phoneNumberFR: Validation[String] = { + lazy val phoneNumberFR: SchemaValidation[String] = { val countryCode = Regex.literal("33") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Gabon */ - lazy val phoneNumberGA: Validation[String] = { + lazy val phoneNumberGA: SchemaValidation[String] = { val countryCode = Regex.literal("241") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for United Kingdom */ - lazy val phoneNumberGB: Validation[String] = { + lazy val phoneNumberGB: SchemaValidation[String] = { val countryCode = Regex.literal("44") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Grenada */ - lazy val phoneNumberGD: Validation[String] = { + lazy val phoneNumberGD: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("473") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Georgia */ - lazy val phoneNumberGE: Validation[String] = { + lazy val phoneNumberGE: SchemaValidation[String] = { val countryCode = Regex.literal("995") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for French Guiana */ - lazy val phoneNumberGF: Validation[String] = { + lazy val phoneNumberGF: SchemaValidation[String] = { val countryCode = Regex.literal("594") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guernsey */ - lazy val phoneNumberGG: Validation[String] = { + lazy val phoneNumberGG: SchemaValidation[String] = { val countryCode = Regex.literal("44") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Ghana */ - lazy val phoneNumberGH: Validation[String] = { + lazy val phoneNumberGH: SchemaValidation[String] = { val countryCode = Regex.literal("233") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Gibraltar */ - lazy val phoneNumberGI: Validation[String] = { + lazy val phoneNumberGI: SchemaValidation[String] = { val countryCode = Regex.literal("350") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Greenland */ - lazy val phoneNumberGL: Validation[String] = { + lazy val phoneNumberGL: SchemaValidation[String] = { val countryCode = Regex.literal("299") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Gambia */ - lazy val phoneNumberGM: Validation[String] = { + lazy val phoneNumberGM: SchemaValidation[String] = { val countryCode = Regex.literal("220") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guinea */ - lazy val phoneNumberGN: Validation[String] = { + lazy val phoneNumberGN: SchemaValidation[String] = { val countryCode = Regex.literal("224") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guadeloupe */ - lazy val phoneNumberGP: Validation[String] = { + lazy val phoneNumberGP: SchemaValidation[String] = { val countryCode = Regex.literal("590") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Equatorial Guinea */ - lazy val phoneNumberGQ: Validation[String] = { + lazy val phoneNumberGQ: SchemaValidation[String] = { val countryCode = Regex.literal("240") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Greece */ - lazy val phoneNumberGR: Validation[String] = { + lazy val phoneNumberGR: SchemaValidation[String] = { val countryCode = Regex.literal("30") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for South Sandwich Islands */ - lazy val phoneNumberGS: Validation[String] = { + lazy val phoneNumberGS: SchemaValidation[String] = { val countryCode = Regex.literal("500") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guatemala */ - lazy val phoneNumberGT: Validation[String] = { + lazy val phoneNumberGT: SchemaValidation[String] = { val countryCode = Regex.literal("502") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guam */ - lazy val phoneNumberGU: Validation[String] = { + lazy val phoneNumberGU: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("671") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guinea-Bissau */ - lazy val phoneNumberGW: Validation[String] = { + lazy val phoneNumberGW: SchemaValidation[String] = { val countryCode = Regex.literal("245") val internationalPrefix = plus | Regex.literal("00001") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Guyana */ - lazy val phoneNumberGY: Validation[String] = { + lazy val phoneNumberGY: SchemaValidation[String] = { val countryCode = Regex.literal("592") val internationalPrefix = plus | Regex.literal("001") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Hong Kong */ - lazy val phoneNumberHK: Validation[String] = { + lazy val phoneNumberHK: SchemaValidation[String] = { val countryCode = Regex.literal("852") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Heard and Mcdonald Islands */ - lazy val phoneNumberHM: Validation[String] = { + lazy val phoneNumberHM: SchemaValidation[String] = { val countryCode = Regex.literal("672") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Honduras */ - lazy val phoneNumberHN: Validation[String] = { + lazy val phoneNumberHN: SchemaValidation[String] = { val countryCode = Regex.literal("504") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Croatia */ - lazy val phoneNumberHR: Validation[String] = { + lazy val phoneNumberHR: SchemaValidation[String] = { val countryCode = Regex.literal("385") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Haiti */ - lazy val phoneNumberHT: Validation[String] = { + lazy val phoneNumberHT: SchemaValidation[String] = { val countryCode = Regex.literal("509") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Hungary */ - lazy val phoneNumberHU: Validation[String] = { + lazy val phoneNumberHU: SchemaValidation[String] = { val countryCode = Regex.literal("36") val nationalPrefix = Regex.literal("06") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefix val phoneNumber = digitsWithSeparator.between(8, 9) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Indonesia */ - lazy val phoneNumberID: Validation[String] = { + lazy val phoneNumberID: SchemaValidation[String] = { val countryCode = Regex.literal("62") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Ireland */ - lazy val phoneNumberIE: Validation[String] = { + lazy val phoneNumberIE: SchemaValidation[String] = { val countryCode = Regex.literal("353") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Israel */ - lazy val phoneNumberIL: Validation[String] = { + lazy val phoneNumberIL: SchemaValidation[String] = { val countryCode = Regex.literal("972") val internationalPrefix = plus | Regex.literal("00") | Regex.literal("01") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Isle of Man */ - lazy val phoneNumberIM: Validation[String] = { + lazy val phoneNumberIM: SchemaValidation[String] = { val countryCode = Regex.literal("44") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val leadingDigits = Regex.literal("74576") val phoneNumber = digitsWithSeparator.between(4, 5) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for India */ - lazy val phoneNumberIN: Validation[String] = { + lazy val phoneNumberIN: SchemaValidation[String] = { val countryCode = Regex.literal("91") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for British Indian Ocean Territory */ - lazy val phoneNumberIO: Validation[String] = { + lazy val phoneNumberIO: SchemaValidation[String] = { val countryCode = Regex.literal("246") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Iraq */ - lazy val phoneNumberIQ: Validation[String] = { + lazy val phoneNumberIQ: SchemaValidation[String] = { val countryCode = Regex.literal("964") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Iran */ - lazy val phoneNumberIR: Validation[String] = { + lazy val phoneNumberIR: SchemaValidation[String] = { val countryCode = Regex.literal("98") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Iceland */ - lazy val phoneNumberIS: Validation[String] = { + lazy val phoneNumberIS: SchemaValidation[String] = { val countryCode = Regex.literal("354") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Italy */ - lazy val phoneNumberIT: Validation[String] = { + lazy val phoneNumberIT: SchemaValidation[String] = { val countryCode = Regex.literal("39") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Jersey */ - lazy val phoneNumberJE: Validation[String] = { + lazy val phoneNumberJE: SchemaValidation[String] = { val countryCode = Regex.literal("44") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Jamaica */ - lazy val phoneNumberJM: Validation[String] = { + lazy val phoneNumberJM: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("658") | Regex.literal("876") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Jordan */ - lazy val phoneNumberJO: Validation[String] = { + lazy val phoneNumberJO: SchemaValidation[String] = { val countryCode = Regex.literal("962") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Japan */ - lazy val phoneNumberJP: Validation[String] = { + lazy val phoneNumberJP: SchemaValidation[String] = { val countryCode = Regex.literal("81") val internationalPrefix = plus | Regex.literal("010") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Kenya */ - lazy val phoneNumberKE: Validation[String] = { + lazy val phoneNumberKE: SchemaValidation[String] = { val countryCode = Regex.literal("254") val internationalPrefix = plus | Regex.literal("000") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Kyrgyzstan */ - lazy val phoneNumberKG: Validation[String] = { + lazy val phoneNumberKG: SchemaValidation[String] = { val countryCode = Regex.literal("996") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cambodia */ - lazy val phoneNumberKH: Validation[String] = { + lazy val phoneNumberKH: SchemaValidation[String] = { val countryCode = Regex.literal("855") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Kiribati */ - lazy val phoneNumberKI: Validation[String] = { + lazy val phoneNumberKI: SchemaValidation[String] = { val countryCode = Regex.literal("686") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Comoros */ - lazy val phoneNumberKM: Validation[String] = { + lazy val phoneNumberKM: SchemaValidation[String] = { val countryCode = Regex.literal("269") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint Kitts and Nevis */ - lazy val phoneNumberKN: Validation[String] = { + lazy val phoneNumberKN: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("869") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for North Korea */ - lazy val phoneNumberKP: Validation[String] = { + lazy val phoneNumberKP: SchemaValidation[String] = { val countryCode = Regex.literal("850") val internationalPrefix = plus | Regex.literal("00") | Regex.literal("99") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for South Korea */ - lazy val phoneNumberKR: Validation[String] = { + lazy val phoneNumberKR: SchemaValidation[String] = { val countryCode = Regex.literal("82") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Kuwait */ - lazy val phoneNumberKW: Validation[String] = { + lazy val phoneNumberKW: SchemaValidation[String] = { val countryCode = Regex.literal("965") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Cayman Islands */ - lazy val phoneNumberKY: Validation[String] = { + lazy val phoneNumberKY: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("345") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Kazakhstan */ - lazy val phoneNumberKZ: Validation[String] = { + lazy val phoneNumberKZ: SchemaValidation[String] = { val countryCode = Regex.literal("7") val internationalPrefix = plus | Regex.literal("00810") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val leadingDigits = Regex.literal("33") | Regex.literal("7") val phoneNumber = digitsWithSeparator.between(6, 8) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Lao PDR */ - lazy val phoneNumberLA: Validation[String] = { + lazy val phoneNumberLA: SchemaValidation[String] = { val countryCode = Regex.literal("856") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Lebanon */ - lazy val phoneNumberLB: Validation[String] = { + lazy val phoneNumberLB: SchemaValidation[String] = { val countryCode = Regex.literal("961") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint Lucia */ - lazy val phoneNumberLC: Validation[String] = { + lazy val phoneNumberLC: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("758") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Liechtenstein */ - lazy val phoneNumberLI: Validation[String] = { + lazy val phoneNumberLI: SchemaValidation[String] = { val countryCode = Regex.literal("423") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Sri Lanka */ - lazy val phoneNumberLK: Validation[String] = { + lazy val phoneNumberLK: SchemaValidation[String] = { val countryCode = Regex.literal("94") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Liberia */ - lazy val phoneNumberLR: Validation[String] = { + lazy val phoneNumberLR: SchemaValidation[String] = { val countryCode = Regex.literal("231") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Lesotho */ - lazy val phoneNumberLS: Validation[String] = { + lazy val phoneNumberLS: SchemaValidation[String] = { val countryCode = Regex.literal("266") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Lithuania */ - lazy val phoneNumberLT: Validation[String] = { + lazy val phoneNumberLT: SchemaValidation[String] = { val countryCode = Regex.literal("370") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixEight val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Luxembourg */ - lazy val phoneNumberLU: Validation[String] = { + lazy val phoneNumberLU: SchemaValidation[String] = { val countryCode = Regex.literal("352") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Latvia */ - lazy val phoneNumberLV: Validation[String] = { + lazy val phoneNumberLV: SchemaValidation[String] = { val countryCode = Regex.literal("371") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Libya */ - lazy val phoneNumberLY: Validation[String] = { + lazy val phoneNumberLY: SchemaValidation[String] = { val countryCode = Regex.literal("218") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Morocco */ - lazy val phoneNumberMA: Validation[String] = { + lazy val phoneNumberMA: SchemaValidation[String] = { val countryCode = Regex.literal("212") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Monaco */ - lazy val phoneNumberMC: Validation[String] = { + lazy val phoneNumberMC: SchemaValidation[String] = { val countryCode = Regex.literal("377") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Moldova */ - lazy val phoneNumberMD: Validation[String] = { + lazy val phoneNumberMD: SchemaValidation[String] = { val countryCode = Regex.literal("373") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Montenegro */ - lazy val phoneNumberME: Validation[String] = { + lazy val phoneNumberME: SchemaValidation[String] = { val countryCode = Regex.literal("382") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint-Martin (French) */ - lazy val phoneNumberMF: Validation[String] = { + lazy val phoneNumberMF: SchemaValidation[String] = { val countryCode = Regex.literal("590") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Madagascar */ - lazy val phoneNumberMG: Validation[String] = { + lazy val phoneNumberMG: SchemaValidation[String] = { val countryCode = Regex.literal("261") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Marshall Islands */ - lazy val phoneNumberMH: Validation[String] = { + lazy val phoneNumberMH: SchemaValidation[String] = { val countryCode = Regex.literal("692") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Macedonia, Republic of */ - lazy val phoneNumberMK: Validation[String] = { + lazy val phoneNumberMK: SchemaValidation[String] = { val countryCode = Regex.literal("389") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mali */ - lazy val phoneNumberML: Validation[String] = { + lazy val phoneNumberML: SchemaValidation[String] = { val countryCode = Regex.literal("223") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Myanmar */ - lazy val phoneNumberMM: Validation[String] = { + lazy val phoneNumberMM: SchemaValidation[String] = { val countryCode = Regex.literal("95") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mongolia */ - lazy val phoneNumberMN: Validation[String] = { + lazy val phoneNumberMN: SchemaValidation[String] = { val countryCode = Regex.literal("976") val internationalPrefix = plus | Regex.literal("001") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Macao, SAR China */ - lazy val phoneNumberMO: Validation[String] = { + lazy val phoneNumberMO: SchemaValidation[String] = { val countryCode = Regex.literal("853") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Northern Mariana Islands */ - lazy val phoneNumberMP: Validation[String] = { + lazy val phoneNumberMP: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("670") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Martinique */ - lazy val phoneNumberMQ: Validation[String] = { + lazy val phoneNumberMQ: SchemaValidation[String] = { val countryCode = Regex.literal("596") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mauritania */ - lazy val phoneNumberMR: Validation[String] = { + lazy val phoneNumberMR: SchemaValidation[String] = { val countryCode = Regex.literal("222") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Montserrat */ - lazy val phoneNumberMS: Validation[String] = { + lazy val phoneNumberMS: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("664") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Malta */ - lazy val phoneNumberMT: Validation[String] = { + lazy val phoneNumberMT: SchemaValidation[String] = { val countryCode = Regex.literal("356") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mauritius */ - lazy val phoneNumberMU: Validation[String] = { + lazy val phoneNumberMU: SchemaValidation[String] = { val countryCode = Regex.literal("230") val internationalPrefix = plus | Regex.literal("0020") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Maldives */ - lazy val phoneNumberMV: Validation[String] = { + lazy val phoneNumberMV: SchemaValidation[String] = { val countryCode = Regex.literal("960") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Malawi */ - lazy val phoneNumberMW: Validation[String] = { + lazy val phoneNumberMW: SchemaValidation[String] = { val countryCode = Regex.literal("265") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mexico */ - lazy val phoneNumberMX: Validation[String] = { + lazy val phoneNumberMX: SchemaValidation[String] = { val countryCode = Regex.literal("52") val nationalPrefix = Regex.literal("01") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefix val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Malaysia */ - lazy val phoneNumberMY: Validation[String] = { + lazy val phoneNumberMY: SchemaValidation[String] = { val countryCode = Regex.literal("60") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mozambique */ - lazy val phoneNumberMZ: Validation[String] = { + lazy val phoneNumberMZ: SchemaValidation[String] = { val countryCode = Regex.literal("258") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Namibia */ - lazy val phoneNumberNA: Validation[String] = { + lazy val phoneNumberNA: SchemaValidation[String] = { val countryCode = Regex.literal("264") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for New Caledonia */ - lazy val phoneNumberNC: Validation[String] = { + lazy val phoneNumberNC: SchemaValidation[String] = { val countryCode = Regex.literal("687") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Niger */ - lazy val phoneNumberNE: Validation[String] = { + lazy val phoneNumberNE: SchemaValidation[String] = { val countryCode = Regex.literal("227") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Norfolk Island */ - lazy val phoneNumberNF: Validation[String] = { + lazy val phoneNumberNF: SchemaValidation[String] = { val countryCode = Regex.literal("672") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Nigeria */ - lazy val phoneNumberNG: Validation[String] = { + lazy val phoneNumberNG: SchemaValidation[String] = { val countryCode = Regex.literal("234") val internationalPrefix = plus | Regex.literal("009") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Nicaragua */ - lazy val phoneNumberNI: Validation[String] = { + lazy val phoneNumberNI: SchemaValidation[String] = { val countryCode = Regex.literal("505") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Netherlands */ - lazy val phoneNumberNL: Validation[String] = { + lazy val phoneNumberNL: SchemaValidation[String] = { val countryCode = Regex.literal("31") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Norway */ - lazy val phoneNumberNO: Validation[String] = { + lazy val phoneNumberNO: SchemaValidation[String] = { val countryCode = Regex.literal("47") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("02") val phoneNumber = digitsWithSeparator.between(6, 8) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Nepal */ - lazy val phoneNumberNP: Validation[String] = { + lazy val phoneNumberNP: SchemaValidation[String] = { val countryCode = Regex.literal("977") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Nauru */ - lazy val phoneNumberNR: Validation[String] = { + lazy val phoneNumberNR: SchemaValidation[String] = { val countryCode = Regex.literal("674") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Niue */ - lazy val phoneNumberNU: Validation[String] = { + lazy val phoneNumberNU: SchemaValidation[String] = { val countryCode = Regex.literal("683") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for New Zealand */ - lazy val phoneNumberNZ: Validation[String] = { + lazy val phoneNumberNZ: SchemaValidation[String] = { val countryCode = Regex.literal("64") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Oman */ - lazy val phoneNumberOM: Validation[String] = { + lazy val phoneNumberOM: SchemaValidation[String] = { val countryCode = Regex.literal("968") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Panama */ - lazy val phoneNumberPA: Validation[String] = { + lazy val phoneNumberPA: SchemaValidation[String] = { val countryCode = Regex.literal("507") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Peru */ - lazy val phoneNumberPE: Validation[String] = { + lazy val phoneNumberPE: SchemaValidation[String] = { val countryCode = Regex.literal("51") val internationalPrefix = plus | Regex.literal("0019") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for French Polynesia */ - lazy val phoneNumberPF: Validation[String] = { + lazy val phoneNumberPF: SchemaValidation[String] = { val countryCode = Regex.literal("689") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Papua New Guinea */ - lazy val phoneNumberPG: Validation[String] = { + lazy val phoneNumberPG: SchemaValidation[String] = { val countryCode = Regex.literal("675") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Philippines */ - lazy val phoneNumberPH: Validation[String] = { + lazy val phoneNumberPH: SchemaValidation[String] = { val countryCode = Regex.literal("63") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Pakistan */ - lazy val phoneNumberPK: Validation[String] = { + lazy val phoneNumberPK: SchemaValidation[String] = { val countryCode = Regex.literal("92") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Poland */ - lazy val phoneNumberPL: Validation[String] = { + lazy val phoneNumberPL: SchemaValidation[String] = { val countryCode = Regex.literal("48") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint Pierre and Miquelon */ - lazy val phoneNumberPM: Validation[String] = { + lazy val phoneNumberPM: SchemaValidation[String] = { val countryCode = Regex.literal("508") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Pitcairn Islands */ - lazy val phoneNumberPN: Validation[String] = { + lazy val phoneNumberPN: SchemaValidation[String] = { val countryCode = Regex.literal("870") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Puerto Rico */ - lazy val phoneNumberPR: Validation[String] = { + lazy val phoneNumberPR: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("787") | Regex.literal("939") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Palestinian Territory */ - lazy val phoneNumberPS: Validation[String] = { + lazy val phoneNumberPS: SchemaValidation[String] = { val countryCode = Regex.literal("970") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Portugal */ - lazy val phoneNumberPT: Validation[String] = { + lazy val phoneNumberPT: SchemaValidation[String] = { val countryCode = Regex.literal("351") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(8, 9) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Palau */ - lazy val phoneNumberPW: Validation[String] = { + lazy val phoneNumberPW: SchemaValidation[String] = { val countryCode = Regex.literal("680") val internationalPrefix = plus | Regex.literal("01") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Paraguay */ - lazy val phoneNumberPY: Validation[String] = { + lazy val phoneNumberPY: SchemaValidation[String] = { val countryCode = Regex.literal("595") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Qatar */ - lazy val phoneNumberQA: Validation[String] = { + lazy val phoneNumberQA: SchemaValidation[String] = { val countryCode = Regex.literal("974") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Reunion */ - lazy val phoneNumberRE: Validation[String] = { + lazy val phoneNumberRE: SchemaValidation[String] = { val countryCode = Regex.literal("262") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Romania */ - lazy val phoneNumberRO: Validation[String] = { + lazy val phoneNumberRO: SchemaValidation[String] = { val countryCode = Regex.literal("40") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Serbia */ - lazy val phoneNumberRS: Validation[String] = { + lazy val phoneNumberRS: SchemaValidation[String] = { val countryCode = Regex.literal("381") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Russia */ - lazy val phoneNumberRU: Validation[String] = { + lazy val phoneNumberRU: SchemaValidation[String] = { val countryCode = Regex.literal("7") val internationalPrefix = plus | Regex.literal("810") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixEight val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Rwanda */ - lazy val phoneNumberRW: Validation[String] = { + lazy val phoneNumberRW: SchemaValidation[String] = { val countryCode = Regex.literal("250") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saudi Arabia */ - lazy val phoneNumberSA: Validation[String] = { + lazy val phoneNumberSA: SchemaValidation[String] = { val countryCode = Regex.literal("966") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Solomon Islands */ - lazy val phoneNumberSB: Validation[String] = { + lazy val phoneNumberSB: SchemaValidation[String] = { val countryCode = Regex.literal("677") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Seychelles */ - lazy val phoneNumberSC: Validation[String] = { + lazy val phoneNumberSC: SchemaValidation[String] = { val countryCode = Regex.literal("248") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Sudan */ - lazy val phoneNumberSD: Validation[String] = { + lazy val phoneNumberSD: SchemaValidation[String] = { val countryCode = Regex.literal("249") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Sweden */ - lazy val phoneNumberSE: Validation[String] = { + lazy val phoneNumberSE: SchemaValidation[String] = { val countryCode = Regex.literal("46") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Singapore */ - lazy val phoneNumberSG: Validation[String] = { + lazy val phoneNumberSG: SchemaValidation[String] = { val countryCode = Regex.literal("65") val internationalPrefix = plus | Regex.literal("0") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint Helena */ - lazy val phoneNumberSH: Validation[String] = { + lazy val phoneNumberSH: SchemaValidation[String] = { val countryCode = Regex.literal("290") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("256") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Slovenia */ - lazy val phoneNumberSI: Validation[String] = { + lazy val phoneNumberSI: SchemaValidation[String] = { val countryCode = Regex.literal("386") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Svalbard and Jan Mayen Islands */ - lazy val phoneNumberSJ: Validation[String] = { + lazy val phoneNumberSJ: SchemaValidation[String] = { val countryCode = Regex.literal("47") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("79") val phoneNumber = digitsWithSeparator.between(6, 8) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Slovakia */ - lazy val phoneNumberSK: Validation[String] = { + lazy val phoneNumberSK: SchemaValidation[String] = { val countryCode = Regex.literal("421") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Sierra Leone */ - lazy val phoneNumberSL: Validation[String] = { + lazy val phoneNumberSL: SchemaValidation[String] = { val countryCode = Regex.literal("232") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for San Marino */ - lazy val phoneNumberSM: Validation[String] = { + lazy val phoneNumberSM: SchemaValidation[String] = { val countryCode = Regex.literal("378") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Senegal */ - lazy val phoneNumberSN: Validation[String] = { + lazy val phoneNumberSN: SchemaValidation[String] = { val countryCode = Regex.literal("221") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Somalia */ - lazy val phoneNumberSO: Validation[String] = { + lazy val phoneNumberSO: SchemaValidation[String] = { val countryCode = Regex.literal("252") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Suriname */ - lazy val phoneNumberSR: Validation[String] = { + lazy val phoneNumberSR: SchemaValidation[String] = { val countryCode = Regex.literal("597") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for South Sudan */ - lazy val phoneNumberSS: Validation[String] = { + lazy val phoneNumberSS: SchemaValidation[String] = { val countryCode = Regex.literal("211") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Sao Tome and Principe */ - lazy val phoneNumberST: Validation[String] = { + lazy val phoneNumberST: SchemaValidation[String] = { val countryCode = Regex.literal("239") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for El Salvador */ - lazy val phoneNumberSV: Validation[String] = { + lazy val phoneNumberSV: SchemaValidation[String] = { val countryCode = Regex.literal("503") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint Marten */ - lazy val phoneNumberSX: Validation[String] = { + lazy val phoneNumberSX: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("721") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Syria */ - lazy val phoneNumberSY: Validation[String] = { + lazy val phoneNumberSY: SchemaValidation[String] = { val countryCode = Regex.literal("963") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Swaziland */ - lazy val phoneNumberSZ: Validation[String] = { + lazy val phoneNumberSZ: SchemaValidation[String] = { val countryCode = Regex.literal("268") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tristan da Cunha */ - lazy val phoneNumberTA: Validation[String] = { + lazy val phoneNumberTA: SchemaValidation[String] = { val countryCode = Regex.literal("290") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("8") val phoneNumber = digitsWithSeparator.between(6, 9) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Turks and Caicos Islands */ - lazy val phoneNumberTC: Validation[String] = { + lazy val phoneNumberTC: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("649") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Chad */ - lazy val phoneNumberTD: Validation[String] = { + lazy val phoneNumberTD: SchemaValidation[String] = { val countryCode = Regex.literal("235") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for French Southern Territories */ - lazy val phoneNumberTF: Validation[String] = { + lazy val phoneNumberTF: SchemaValidation[String] = { val countryCode = Regex.literal("262") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Togo */ - lazy val phoneNumberTG: Validation[String] = { + lazy val phoneNumberTG: SchemaValidation[String] = { val countryCode = Regex.literal("228") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Thailand */ - lazy val phoneNumberTH: Validation[String] = { + lazy val phoneNumberTH: SchemaValidation[String] = { val countryCode = Regex.literal("66") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tajikistan */ - lazy val phoneNumberTJ: Validation[String] = { + lazy val phoneNumberTJ: SchemaValidation[String] = { val countryCode = Regex.literal("992") val internationalPrefix = plus | Regex.literal("00810") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tokelau */ - lazy val phoneNumberTK: Validation[String] = { + lazy val phoneNumberTK: SchemaValidation[String] = { val countryCode = Regex.literal("690") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Timor-Leste */ - lazy val phoneNumberTL: Validation[String] = { + lazy val phoneNumberTL: SchemaValidation[String] = { val countryCode = Regex.literal("670") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Turkmenistan */ - lazy val phoneNumberTM: Validation[String] = { + lazy val phoneNumberTM: SchemaValidation[String] = { val countryCode = Regex.literal("993") val internationalPrefix = plus | Regex.literal("00810") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixEight val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tunisia */ - lazy val phoneNumberTN: Validation[String] = { + lazy val phoneNumberTN: SchemaValidation[String] = { val countryCode = Regex.literal("216") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tonga */ - lazy val phoneNumberTO: Validation[String] = { + lazy val phoneNumberTO: SchemaValidation[String] = { val countryCode = Regex.literal("676") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Turkey */ - lazy val phoneNumberTR: Validation[String] = { + lazy val phoneNumberTR: SchemaValidation[String] = { val countryCode = Regex.literal("90") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Trinidad and Tobago */ - lazy val phoneNumberTT: Validation[String] = { + lazy val phoneNumberTT: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("868") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tuvalu */ - lazy val phoneNumberTV: Validation[String] = { + lazy val phoneNumberTV: SchemaValidation[String] = { val countryCode = Regex.literal("688") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Taiwan */ - lazy val phoneNumberTW: Validation[String] = { + lazy val phoneNumberTW: SchemaValidation[String] = { val countryCode = Regex.literal("886") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Tanzania */ - lazy val phoneNumberTZ: Validation[String] = { + lazy val phoneNumberTZ: SchemaValidation[String] = { val countryCode = Regex.literal("255") val internationalPrefix = plus | Regex.literal("00[056]") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Ukraine */ - lazy val phoneNumberUA: Validation[String] = { + lazy val phoneNumberUA: SchemaValidation[String] = { val countryCode = Regex.literal("380") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Uganda */ - lazy val phoneNumberUG: Validation[String] = { + lazy val phoneNumberUG: SchemaValidation[String] = { val countryCode = Regex.literal("256") val internationalPrefix = plus | Regex.literal("00[057]") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for US Minor Outlying Islands */ - lazy val phoneNumberUM: Validation[String] = { + lazy val phoneNumberUM: SchemaValidation[String] = { val countryCode = Regex.literal("1") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for United States of America */ - lazy val phoneNumberUS: Validation[String] = { + lazy val phoneNumberUS: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Uruguay */ - lazy val phoneNumberUY: Validation[String] = { + lazy val phoneNumberUY: SchemaValidation[String] = { val countryCode = Regex.literal("598") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Uzbekistan */ - lazy val phoneNumberUZ: Validation[String] = { + lazy val phoneNumberUZ: SchemaValidation[String] = { val countryCode = Regex.literal("998") val internationalPrefix = plus | Regex.literal("00810") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixEight val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Holy See (Vatican City State) */ - lazy val phoneNumberVA: Validation[String] = { + lazy val phoneNumberVA: SchemaValidation[String] = { val countryCode = Regex.literal("39") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val leadingDigits = Regex.literal("06698") val phoneNumber = digitsWithSeparator.between(4, 6) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Saint Vincent and Grenadines */ - lazy val phoneNumberVC: Validation[String] = { + lazy val phoneNumberVC: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("784") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Venezuela */ - lazy val phoneNumberVE: Validation[String] = { + lazy val phoneNumberVE: SchemaValidation[String] = { val countryCode = Regex.literal("58") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for British Virgin Islands */ - lazy val phoneNumberVG: Validation[String] = { + lazy val phoneNumberVG: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("284") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Virgin Islands, US */ - lazy val phoneNumberVI: Validation[String] = { + lazy val phoneNumberVI: SchemaValidation[String] = { val countryCode = Regex.literal("1") val internationalPrefix = plus | Regex.literal("011") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixOne val leadingDigits = Regex.literal("340") val phoneNumber = digitsWithSeparator.between(6, 7) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Vietnam */ - lazy val phoneNumberVN: Validation[String] = { + lazy val phoneNumberVN: SchemaValidation[String] = { val countryCode = Regex.literal("84") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Vanuatu */ - lazy val phoneNumberVU: Validation[String] = { + lazy val phoneNumberVU: SchemaValidation[String] = { val countryCode = Regex.literal("678") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Wallis and Futuna Islands */ - lazy val phoneNumberWF: Validation[String] = { + lazy val phoneNumberWF: SchemaValidation[String] = { val countryCode = Regex.literal("681") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Samoa */ - lazy val phoneNumberWS: Validation[String] = { + lazy val phoneNumberWS: SchemaValidation[String] = { val countryCode = Regex.literal("685") val internationalPrefix = plus | Regex.literal("0") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Kosovo */ - lazy val phoneNumberXK: Validation[String] = { + lazy val phoneNumberXK: SchemaValidation[String] = { val countryCode = Regex.literal("383") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Yemen */ - lazy val phoneNumberYE: Validation[String] = { + lazy val phoneNumberYE: SchemaValidation[String] = { val countryCode = Regex.literal("967") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Mayotte */ - lazy val phoneNumberYT: Validation[String] = { + lazy val phoneNumberYT: SchemaValidation[String] = { val countryCode = Regex.literal("262") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val leadingDigits = Regex.literal("269") | Regex.literal("63") val phoneNumber = digitsWithSeparator.between(6, 8) - Validation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ leadingDigits ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for South Africa */ - lazy val phoneNumberZA: Validation[String] = { + lazy val phoneNumberZA: SchemaValidation[String] = { val countryCode = Regex.literal("27") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Zambia */ - lazy val phoneNumberZM: Validation[String] = { + lazy val phoneNumberZM: SchemaValidation[String] = { val countryCode = Regex.literal("260") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } /** Phone number validation for Zimbabwe */ - lazy val phoneNumberZW: Validation[String] = { + lazy val phoneNumberZW: SchemaValidation[String] = { val countryCode = Regex.literal("263") val prefix = internationalPrefix ~ optionalSeparator ~ countryCode | nationalPrefixZero val phoneNumber = digitsWithSeparator.between(9, 10) - Validation.regex(prefix ~ optionalSeparator ~ phoneNumber) + SchemaValidation.regex(prefix ~ optionalSeparator ~ phoneNumber) } } diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/Predicate.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/Predicate.scala index 3f47a297e..0c6415a80 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/validation/Predicate.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/validation/Predicate.scala @@ -3,7 +3,7 @@ package zio.schema.validation import zio.Chunk sealed trait Predicate[A] { - type Errors = Chunk[ValidationError] + type Errors = Chunk[SchemaValidationError] type Result = Either[Errors, Errors] def validate(value: A): Result } @@ -16,21 +16,22 @@ object Predicate { def validate(value: String): Result = if (value.length() >= n) - Right(Chunk(ValidationError.MaxLength(n, value.length(), value))) + Right(Chunk(SchemaValidationError.MaxLength(n, value.length(), value))) else - Left(Chunk(ValidationError.MinLength(n, value.length(), value))) + Left(Chunk(SchemaValidationError.MinLength(n, value.length(), value))) } final case class MaxLength(n: Int) extends Str[String] { def validate(value: String): Result = - if (value.length() <= n) Right(Chunk(ValidationError.MinLength(n, value.length(), value))) - else Left(Chunk(ValidationError.MaxLength(n, value.length(), value))) + if (value.length() <= n) + Right(Chunk(SchemaValidationError.MinLength(n, value.length(), value))) + else Left(Chunk(SchemaValidationError.MaxLength(n, value.length(), value))) } final case class Matches(r: Regex) extends Str[String] { def validate(value: String): Result = - if (r.test(value)) Right(Chunk(ValidationError.NotRegexMatch(value, r))) - else Left(Chunk(ValidationError.RegexMatch(value, r))) + if (r.test(value)) Right(Chunk(SchemaValidationError.NotRegexMatch(value, r))) + else Left(Chunk(SchemaValidationError.RegexMatch(value, r))) } } @@ -44,25 +45,25 @@ object Predicate { def validate(v: A): Result = if (numType.numeric.compare(v, value) > 0) - Right(Chunk(ValidationError.LessThan(v, value))) + Right(Chunk(SchemaValidationError.LessThan(v, value))) else - Left(Chunk(ValidationError.GreaterThan(v, value))) + Left(Chunk(SchemaValidationError.GreaterThan(v, value))) } final case class LessThan[A](numType: NumType[A], value: A) extends Num[A] { def validate(v: A): Result = if (numType.numeric.compare(v, value) < 0) - Right(Chunk(ValidationError.GreaterThan(v, value))) + Right(Chunk(SchemaValidationError.GreaterThan(v, value))) else - Left(Chunk(ValidationError.LessThan(v, value))) + Left(Chunk(SchemaValidationError.LessThan(v, value))) } final case class EqualTo[A](numType: NumType[A], value: A) extends Num[A] { def validate(v: A): Result = if (numType.numeric.compare(v, value) == 0) - Right(Chunk(ValidationError.NotEqualTo(v, value))) + Right(Chunk(SchemaValidationError.NotEqualTo(v, value))) else - Left(Chunk(ValidationError.EqualTo(v, value))) + Left(Chunk(SchemaValidationError.EqualTo(v, value))) } } diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/Regexs.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/Regexs.scala index d3ecd9b44..5d147e735 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/validation/Regexs.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/validation/Regexs.scala @@ -2,13 +2,13 @@ package zio.schema.validation trait Regexs { - val identifier: Validation[String] = - Validation.regex((Regex.digitOrLetter | Regex.oneOf('_')).atLeast(1)) + val identifier: SchemaValidation[String] = + SchemaValidation.regex((Regex.digitOrLetter | Regex.oneOf('_')).atLeast(1)) /** * Checks whether a certain string represents a valid email address. */ - lazy val email: Validation[String] = { + lazy val email: SchemaValidation[String] = { val localPart = Regex.letter ~ (Regex.digitOrLetter | Regex.oneOf('_', '.', '+', '-')).atMost(63) val domainSegment = Regex.digitOrLetter | Regex.oneOf('-') val topLevelDomain = domainSegment.between(2, 4) @@ -20,10 +20,10 @@ trait Regexs { val emailWithIpv6Domain = emailBeginning ~ ipBlock(Regex.literal("IPv6:") ~ ipV6Regex) val completeEmail = emailWithNormalDomain | emailWithIpv4Domain | emailWithIpv6Domain - Validation.regex(completeEmail) && Validation.maxLength(254) + SchemaValidation.regex(completeEmail) && SchemaValidation.maxLength(254) } - lazy val duration: Validation[String] = { + lazy val duration: SchemaValidation[String] = { val posDigit = Regex.between('1', '9') val integer = Regex.digit.+ @@ -41,7 +41,7 @@ trait Regexs { val date = (day | month | year) ~ time.? val duration = Regex.oneOf('P') ~ (date | time | week) - Validation.regex(duration) + SchemaValidation.regex(duration) } private lazy val ipV4Regex: Regex = { @@ -61,7 +61,7 @@ trait Regexs { /** * Checks whether a certain string represents a valid IPv4 address. */ - lazy val ipV4: Validation[String] = Validation.regex(ipV4Regex) + lazy val ipV4: SchemaValidation[String] = SchemaValidation.regex(ipV4Regex) private lazy val ipV6Regex: Regex = { val oneDigitHex = Regex.hexDigit.exactly(1) @@ -86,9 +86,9 @@ trait Regexs { /** * Checks whether a certain string represents a valid IPv6 address. */ - lazy val ipV6: Validation[String] = Validation.regex(ipV6Regex) + lazy val ipV6: SchemaValidation[String] = SchemaValidation.regex(ipV6Regex) - lazy val uuidV4: Validation[String] = { + lazy val uuidV4: SchemaValidation[String] = { val hexOctect = Regex.hexDigit ~ Regex.hexDigit val sep = Regex.oneOf('-') @@ -98,7 +98,7 @@ trait Regexs { val clockSeq = Regex.CharacterSet(Set('8', '9', 'a', 'A', 'b', 'B')) ~ Regex.hexDigit ~ hexOctect val node = hexOctect.exactly(6) - Validation.regex( + SchemaValidation.regex( timeLow ~ sep ~ timeMid ~ sep ~ timeHighAndVersion ~ sep ~ diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/SchemaValidation.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/SchemaValidation.scala new file mode 100644 index 000000000..0719ebd1e --- /dev/null +++ b/zio-schema/shared/src/main/scala/zio/schema/validation/SchemaValidation.scala @@ -0,0 +1,83 @@ +package zio.schema.validation + +import zio.Chunk +import zio.prelude.Validation + +final case class SchemaValidation[A](bool: Bool[Predicate[A]]) { self => + def &&(that: SchemaValidation[A]): SchemaValidation[A] = SchemaValidation(self.bool && that.bool) + def ||(that: SchemaValidation[A]): SchemaValidation[A] = SchemaValidation(self.bool || that.bool) + def unary_! : SchemaValidation[A] = SchemaValidation(!self.bool) + + def validate(value: A): Validation[SchemaValidationError, Unit] = { + type Errors = Chunk[SchemaValidationError] + type Result = Either[Errors, Errors] + def combineAnd(left: Result, right: Result): Result = + (left, right) match { + case (Left(leftErrors), Left(rightErrors)) => Left(leftErrors ++ rightErrors) + case (Left(leftErrors), _) => Left(leftErrors) + case (_, Left(rightErrors)) => Left(rightErrors) + case (Right(leftSuccesses), Right(rightSuccesses)) => Right(leftSuccesses ++ rightSuccesses) + } + + def combineOr(left: Result, right: Result): Result = + (left, right) match { + case (Left(leftErrors), Left(rightErrors)) => Left(leftErrors ++ rightErrors) + case (Left(_), right) => right + case (right, Left(_)) => right + case (Right(leftSuccesses), Right(rightSuccesses)) => Right(leftSuccesses ++ rightSuccesses) + } + + def loop(bool: Bool[Predicate[A]]): Result = { + import Bool._ + bool match { + case And(left, right) => + val leftValidation = loop(left) + val rightValidation = loop(right) + combineAnd(leftValidation, rightValidation) + case Or(left, right) => + val leftValidation = loop(left) + val rightValidation = loop(right) + combineOr(leftValidation, rightValidation) + case Leaf(predicate) => predicate.validate(value) + case Not(value) => loop(value).swap + } + } + + val errors = loop(self.bool).left.getOrElse(Chunk.empty) + errors.nonEmptyOrElse[Validation[SchemaValidationError, Unit]](Validation.succeed(()))( + errors => Validation.failNonEmptyChunk(errors) + ) + } +} + +object SchemaValidation extends Regexs with Time { + import Predicate._ + + // String operations + def minLength(n: Int): SchemaValidation[String] = SchemaValidation(Bool.Leaf(Str.MinLength(n))) + def maxLength(n: Int): SchemaValidation[String] = SchemaValidation(Bool.Leaf(Str.MaxLength(n))) + //Regex + def regex(r: Regex): SchemaValidation[String] = SchemaValidation(Bool.Leaf(Str.Matches(r))) + + // Numerical operations + def greaterThan[A](value: A)(implicit numType: NumType[A]): SchemaValidation[A] = + SchemaValidation(Bool.Leaf(Num.GreaterThan(numType, value))) + + def lessThan[A](value: A)(implicit numType: NumType[A]): SchemaValidation[A] = + SchemaValidation(Bool.Leaf(Num.LessThan(numType, value))) + + def between[A](lower: A, upper: A)(implicit numType: NumType[A]): SchemaValidation[A] = + (greaterThan(lower) || equalTo(lower)) && (lessThan(upper) || equalTo(upper)) + + def equalTo[A](value: A)(implicit numType: NumType[A]): SchemaValidation[A] = + SchemaValidation(Bool.Leaf(Num.EqualTo(numType, value))) + + def succeed[A]: SchemaValidation[A] = SchemaValidation(Bool.Leaf(Predicate.True[A]())) + def fail[A]: SchemaValidation[A] = !succeed[A] + + def allOf[A](vs: SchemaValidation[A]*): SchemaValidation[A] = vs.foldLeft(succeed[A])(_ && _) + def allOf[A](vl: Iterable[SchemaValidation[A]]): SchemaValidation[A] = allOf(vl.toSeq: _*) + + def anyOf[A](vs: SchemaValidation[A]*): SchemaValidation[A] = vs.foldLeft(fail[A])(_ || _) + def anyOf[A](vl: Iterable[SchemaValidation[A]]): SchemaValidation[A] = anyOf(vl.toSeq: _*) +} diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/Time.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/Time.scala index 3436dd143..ddc99be96 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/validation/Time.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/validation/Time.scala @@ -37,9 +37,9 @@ trait Time { * 1:10:30 * */ - def time(format: String): Validation[String] = { + def time(format: String): SchemaValidation[String] = { val regex = parseFormat(format) - Validation.regex(regex) + SchemaValidation.regex(regex) } sealed private trait Field diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/Validation.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/Validation.scala deleted file mode 100644 index 078795ef1..000000000 --- a/zio-schema/shared/src/main/scala/zio/schema/validation/Validation.scala +++ /dev/null @@ -1,79 +0,0 @@ -package zio.schema.validation - -import zio.Chunk - -final case class Validation[A](bool: Bool[Predicate[A]]) { self => - def &&(that: Validation[A]): Validation[A] = Validation(self.bool && that.bool) - def ||(that: Validation[A]): Validation[A] = Validation(self.bool || that.bool) - def unary_! : Validation[A] = Validation(!self.bool) - - def validate(value: A): Either[Chunk[ValidationError], Unit] = { - type Errors = Chunk[ValidationError] - type Result = Either[Errors, Errors] - def combineAnd(left: Result, right: Result): Result = - (left, right) match { - case (Left(leftErrors), Left(rightErrors)) => Left(leftErrors ++ rightErrors) - case (Left(leftErrors), _) => Left(leftErrors) - case (_, Left(rightErrors)) => Left(rightErrors) - case (Right(leftSuccesses), Right(rightSuccesses)) => Right(leftSuccesses ++ rightSuccesses) - } - - def combineOr(left: Result, right: Result): Result = - (left, right) match { - case (Left(leftErrors), Left(rightErrors)) => Left(leftErrors ++ rightErrors) - case (Left(_), right) => right - case (right, Left(_)) => right - case (Right(leftSuccesses), Right(rightSuccesses)) => Right(leftSuccesses ++ rightSuccesses) - } - - def loop(bool: Bool[Predicate[A]]): Result = { - import Bool._ - bool match { - case And(left, right) => - val leftValidation = loop(left) - val rightValidation = loop(right) - combineAnd(leftValidation, rightValidation) - case Or(left, right) => - val leftValidation = loop(left) - val rightValidation = loop(right) - combineOr(leftValidation, rightValidation) - case Leaf(predicate) => predicate.validate(value) - case Not(value) => loop(value).swap - } - } - - loop(self.bool).map(_ => ()) - } -} - -object Validation extends Regexs with Time { - import Predicate._ - - // String operations - def minLength(n: Int): Validation[String] = Validation(Bool.Leaf(Str.MinLength(n))) - def maxLength(n: Int): Validation[String] = Validation(Bool.Leaf(Str.MaxLength(n))) - //Regex - def regex(r: Regex): Validation[String] = Validation(Bool.Leaf(Str.Matches(r))) - - // Numerical operations - def greaterThan[A](value: A)(implicit numType: NumType[A]): Validation[A] = - Validation(Bool.Leaf(Num.GreaterThan(numType, value))) - - def lessThan[A](value: A)(implicit numType: NumType[A]): Validation[A] = - Validation(Bool.Leaf(Num.LessThan(numType, value))) - - def between[A](lower: A, upper: A)(implicit numType: NumType[A]): Validation[A] = - (greaterThan(lower) || equalTo(lower)) && (lessThan(upper) || equalTo(upper)) - - def equalTo[A](value: A)(implicit numType: NumType[A]): Validation[A] = - Validation(Bool.Leaf(Num.EqualTo(numType, value))) - - def succeed[A]: Validation[A] = Validation(Bool.Leaf(Predicate.True[A]())) - def fail[A]: Validation[A] = !succeed[A] - - def allOf[A](vs: Validation[A]*): Validation[A] = vs.foldLeft(succeed[A])(_ && _) - def allOf[A](vl: Iterable[Validation[A]]): Validation[A] = allOf(vl.toSeq: _*) - - def anyOf[A](vs: Validation[A]*): Validation[A] = vs.foldLeft(fail[A])(_ || _) - def anyOf[A](vl: Iterable[Validation[A]]): Validation[A] = anyOf(vl.toSeq: _*) -} diff --git a/zio-schema/shared/src/main/scala/zio/schema/validation/ValidationErrors.scala b/zio-schema/shared/src/main/scala/zio/schema/validation/ValidationErrors.scala index 8deded772..cea9e1cf3 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/validation/ValidationErrors.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/validation/ValidationErrors.scala @@ -1,46 +1,46 @@ package zio.schema.validation -sealed trait ValidationError { +sealed trait SchemaValidationError { def message: String } -object ValidationError { - final case class MinLength(minLength: Int, actualLength: Int, string: String) extends ValidationError { +object SchemaValidationError { + final case class MinLength(minLength: Int, actualLength: Int, string: String) extends SchemaValidationError { override def message: String = s"Expected the length of $string to be at least $minLength characters but was $actualLength characters." } - final case class MaxLength(maxLength: Int, actualLength: Int, string: String) extends ValidationError { + final case class MaxLength(maxLength: Int, actualLength: Int, string: String) extends SchemaValidationError { override def message: String = s"Expected the length of $string to be at most $maxLength characters but was $actualLength characters." } - final case class GreaterThan[A](value: A, expected: A) extends ValidationError { + final case class GreaterThan[A](value: A, expected: A) extends SchemaValidationError { override def message: String = s"$value should be greater than $expected" } - final case class LessThan[A](value: A, expected: A) extends ValidationError { + final case class LessThan[A](value: A, expected: A) extends SchemaValidationError { override def message: String = s"$value should be less than $expected" } - final case class EqualTo[A](value: A, expected: A) extends ValidationError { + final case class EqualTo[A](value: A, expected: A) extends SchemaValidationError { override def message: String = s"$value should be equal to $expected" } - final case class NotEqualTo[A](value: A, expected: A) extends ValidationError { + final case class NotEqualTo[A](value: A, expected: A) extends SchemaValidationError { override def message: String = s"$value should not be equal to $expected" } - final case class RegexMatch(str: String, expected: Regex) extends ValidationError { + final case class RegexMatch(str: String, expected: Regex) extends SchemaValidationError { override def message: String = s"$str does not match $expected" } - final case class NotRegexMatch(str: String, expected: Regex) extends ValidationError { + final case class NotRegexMatch(str: String, expected: Regex) extends SchemaValidationError { override def message: String = s"$str matches a regex other than $expected" } - final case class Generic(message: String) extends ValidationError + final case class Generic(message: String) extends SchemaValidationError } diff --git a/zio-schema/shared/src/test/scala/zio/schema/SchemaAssertions.scala b/zio-schema/shared/src/test/scala/zio/schema/SchemaAssertions.scala index 9b0f26b69..ff91088a7 100644 --- a/zio-schema/shared/src/test/scala/zio/schema/SchemaAssertions.scala +++ b/zio-schema/shared/src/test/scala/zio/schema/SchemaAssertions.scala @@ -7,17 +7,12 @@ object SchemaAssertions { def migratesTo[A: Schema, B: Schema](expected: B): Assertion[A] = Assertion.assertion("migratesTo") { value => - value.migrate[B] match { - case Left(_) => false - case Right(m) if m != expected => false - case _ => - true - } + value.migrate[B].fold(_ => false, _ == expected) } def cannotMigrateValue[A: Schema, B: Schema]: Assertion[A] = Assertion.assertion("cannotMigrateTo") { value => - value.migrate[B].isLeft + value.migrate[B].toEither.isLeft } def hasSameSchema(expected: Schema[_]): Assertion[Schema[_]] = diff --git a/zio-schema/shared/src/test/scala/zio/schema/validation/PhoneNumberValidationSpec.scala b/zio-schema/shared/src/test/scala/zio/schema/validation/PhoneNumberSchemaValidationSpec.scala similarity index 57% rename from zio-schema/shared/src/test/scala/zio/schema/validation/PhoneNumberValidationSpec.scala rename to zio-schema/shared/src/test/scala/zio/schema/validation/PhoneNumberSchemaValidationSpec.scala index eed95ec3e..c8d935828 100644 --- a/zio-schema/shared/src/test/scala/zio/schema/validation/PhoneNumberValidationSpec.scala +++ b/zio-schema/shared/src/test/scala/zio/schema/validation/PhoneNumberSchemaValidationSpec.scala @@ -2,1330 +2,1330 @@ package zio.schema.validation import zio.Scope import zio.test._ -object PhoneNumberValidationSpec extends ZIOSpecDefault { +object PhoneNumberSchemaValidationSpec extends ZIOSpecDefault { def spec: Spec[Environment with TestEnvironment with Scope, Any] = suite("PhoneNumberValidationSpec")( test("Regex phone number validation for Ascension Island") { val validation = PhoneNumberValidation.phoneNumberAC - assertTrue(validation.validate("+247 007 897 156").isRight) + assertTrue(validation.validate("+247 007 897 156").toEither.isRight) }, test("Regex phone number validation for Andorra") { val validation = PhoneNumberValidation.phoneNumberAD - assertTrue(validation.validate("+376 9587541843").isRight) + assertTrue(validation.validate("+376 9587541843").toEither.isRight) }, test("Regex phone number validation for United Arab Emirates") { val validation = PhoneNumberValidation.phoneNumberAE - assertTrue(validation.validate("00 971 0 362744241").isRight) + assertTrue(validation.validate("00 971 0 362744241").toEither.isRight) }, test("Regex phone number validation for Afghanistan") { val validation = PhoneNumberValidation.phoneNumberAF - assertTrue(validation.validate("00 93 0 157218486").isRight) + assertTrue(validation.validate("00 93 0 157218486").toEither.isRight) }, test("Regex phone number validation for Antigua and Barbuda") { val validation = PhoneNumberValidation.phoneNumberAG - assertTrue(validation.validate("011 1 268 612 6402").isRight) + assertTrue(validation.validate("011 1 268 612 6402").toEither.isRight) }, test("Regex phone number validation for Anguilla") { val validation = PhoneNumberValidation.phoneNumberAI - assertTrue(validation.validate("011 1 264 957 0153").isRight) + assertTrue(validation.validate("011 1 264 957 0153").toEither.isRight) }, test("Regex phone number validation for Albania") { val validation = PhoneNumberValidation.phoneNumberAL - assertTrue(validation.validate("+ 355 0747518589").isRight) + assertTrue(validation.validate("+ 355 0747518589").toEither.isRight) }, test("Regex phone number validation for Armenia") { val validation = PhoneNumberValidation.phoneNumberAM - assertTrue(validation.validate("00 374 0756680505").isRight) + assertTrue(validation.validate("00 374 0756680505").toEither.isRight) }, test("Regex phone number validation for Netherlands Antilles") { val validation = PhoneNumberValidation.phoneNumberAN - assertTrue(validation.validate("00 5996053610108").isRight) + assertTrue(validation.validate("00 5996053610108").toEither.isRight) }, test("Regex phone number validation for Angola") { val validation = PhoneNumberValidation.phoneNumberAO - assertTrue(validation.validate("00 2442385294120").isRight) + assertTrue(validation.validate("00 2442385294120").toEither.isRight) }, test("Regex phone number validation for Antarctica") { val validation = PhoneNumberValidation.phoneNumberAQ - assertTrue(validation.validate("00 6720645145061").isRight) + assertTrue(validation.validate("00 6720645145061").toEither.isRight) }, test("Regex phone number validation for Argentina") { val validation = PhoneNumberValidation.phoneNumberAR - assertTrue(validation.validate("+54 90 2883 6466").isRight) + assertTrue(validation.validate("+54 90 2883 6466").toEither.isRight) }, test("Regex phone number validation for American Samoa") { val validation = PhoneNumberValidation.phoneNumberAS - assertTrue(validation.validate("011 1 684 262 8882").isRight) + assertTrue(validation.validate("011 1 684 262 8882").toEither.isRight) }, test("Regex phone number validation for Austria") { val validation = PhoneNumberValidation.phoneNumberAT - assertTrue(validation.validate("+43 75 7429 2998").isRight) + assertTrue(validation.validate("+43 75 7429 2998").toEither.isRight) }, test("Regex phone number validation for Australia") { val validation = PhoneNumberValidation.phoneNumberAU - assertTrue(validation.validate("0011 61 2 8238 5964").isRight) + assertTrue(validation.validate("0011 61 2 8238 5964").toEither.isRight) }, test("Regex phone number validation for Aruba") { val validation = PhoneNumberValidation.phoneNumberAW - assertTrue(validation.validate("00 2979763865107").isRight) + assertTrue(validation.validate("00 2979763865107").toEither.isRight) }, test("Regex phone number validation for Aland Islands") { val validation = PhoneNumberValidation.phoneNumberAX - assertTrue(validation.validate("+358 18 6919660").isRight) + assertTrue(validation.validate("+358 18 6919660").toEither.isRight) }, test("Regex phone number validation for Azerbaijan") { val validation = PhoneNumberValidation.phoneNumberAZ - assertTrue(validation.validate("+994 6152139308").isRight) + assertTrue(validation.validate("+994 6152139308").toEither.isRight) }, test("Regex phone number validation for Bosnia and Herzegovina") { val validation = PhoneNumberValidation.phoneNumberBA - assertTrue(validation.validate("+387 4089348656").isRight) + assertTrue(validation.validate("+387 4089348656").toEither.isRight) }, test("Regex phone number validation for Barbados") { val validation = PhoneNumberValidation.phoneNumberBB - assertTrue(validation.validate("011 1 246 990 0727").isRight) + assertTrue(validation.validate("011 1 246 990 0727").toEither.isRight) }, test("Regex phone number validation for Bangladesh") { val validation = PhoneNumberValidation.phoneNumberBD - assertTrue(validation.validate("+880 7320198614").isRight) + assertTrue(validation.validate("+880 7320198614").toEither.isRight) }, test("Regex phone number validation for Belgium") { val validation = PhoneNumberValidation.phoneNumberBE - assertTrue(validation.validate("+32 8965598550").isRight) + assertTrue(validation.validate("+32 8965598550").toEither.isRight) }, test("Regex phone number validation for Burkina Faso") { val validation = PhoneNumberValidation.phoneNumberBF - assertTrue(validation.validate("00 2267355948208").isRight) + assertTrue(validation.validate("00 2267355948208").toEither.isRight) }, test("Regex phone number validation for Bulgaria") { val validation = PhoneNumberValidation.phoneNumberBG - assertTrue(validation.validate("+359 3442692667").isRight) + assertTrue(validation.validate("+359 3442692667").toEither.isRight) }, test("Regex phone number validation for Bahrain") { val validation = PhoneNumberValidation.phoneNumberBH - assertTrue(validation.validate("00 9739488339568").isRight) + assertTrue(validation.validate("00 9739488339568").toEither.isRight) }, test("Regex phone number validation for Burundi") { val validation = PhoneNumberValidation.phoneNumberBI - assertTrue(validation.validate("00 2574280643674").isRight) + assertTrue(validation.validate("00 2574280643674").toEither.isRight) }, test("Regex phone number validation for Benin") { val validation = PhoneNumberValidation.phoneNumberBJ - assertTrue(validation.validate("00 2298643095311").isRight) + assertTrue(validation.validate("00 2298643095311").toEither.isRight) }, test("Regex phone number validation for Saint-Barthelemy") { val validation = PhoneNumberValidation.phoneNumberBL - assertTrue(validation.validate("+590 6941370797").isRight) + assertTrue(validation.validate("+590 6941370797").toEither.isRight) }, test("Regex phone number validation for Bermuda") { val validation = PhoneNumberValidation.phoneNumberBM - assertTrue(validation.validate("011 1 441 5849940").isRight) + assertTrue(validation.validate("011 1 441 5849940").toEither.isRight) }, test("Regex phone number validation for Brunei Darussalam") { val validation = PhoneNumberValidation.phoneNumberBN - assertTrue(validation.validate("00 6736806811588").isRight) + assertTrue(validation.validate("00 6736806811588").toEither.isRight) }, test("Regex phone number validation for Bolivia") { val validation = PhoneNumberValidation.phoneNumberBO - assertTrue(validation.validate("+591 7962476910").isRight) + assertTrue(validation.validate("+591 7962476910").toEither.isRight) }, test("Regex phone number validation for Caribbean Netherlands") { val validation = PhoneNumberValidation.phoneNumberBQ - assertTrue(validation.validate("00 599 347 0831770").isRight) + assertTrue(validation.validate("00 599 347 0831770").toEither.isRight) }, test("Regex phone number validation for Brazil") { val validation = PhoneNumberValidation.phoneNumberBR - assertTrue(validation.validate("+55 2309750213").isRight) + assertTrue(validation.validate("+55 2309750213").toEither.isRight) }, test("Regex phone number validation for Bahamas") { val validation = PhoneNumberValidation.phoneNumberBS - assertTrue(validation.validate("011 1 242 6083082").isRight) + assertTrue(validation.validate("011 1 242 6083082").toEither.isRight) }, test("Regex phone number validation for Bhutan") { val validation = PhoneNumberValidation.phoneNumberBT - assertTrue(validation.validate("00 9756295499608").isRight) + assertTrue(validation.validate("00 9756295499608").toEither.isRight) }, test("Regex phone number validation for Bouvet Island") { val validation = PhoneNumberValidation.phoneNumberBV - assertTrue(validation.validate("00 474251138559").isRight) + assertTrue(validation.validate("00 474251138559").toEither.isRight) }, test("Regex phone number validation for Botswana") { val validation = PhoneNumberValidation.phoneNumberBW - assertTrue(validation.validate("00 2671639040488").isRight) + assertTrue(validation.validate("00 2671639040488").toEither.isRight) }, test("Regex phone number validation for Belarus") { val validation = PhoneNumberValidation.phoneNumberBY - assertTrue(validation.validate("00810 375 376602746").isRight) + assertTrue(validation.validate("00810 375 376602746").toEither.isRight) }, test("Regex phone number validation for Belize") { val validation = PhoneNumberValidation.phoneNumberBZ - assertTrue(validation.validate("00 5010929861925").isRight) + assertTrue(validation.validate("00 5010929861925").toEither.isRight) }, test("Regex phone number validation for Canada") { val validation = PhoneNumberValidation.phoneNumberCA - assertTrue(validation.validate("011 1 3665464257").isRight) + assertTrue(validation.validate("011 1 3665464257").toEither.isRight) }, test("Regex phone number validation for Cocos (Keeling) Islands") { val validation = PhoneNumberValidation.phoneNumberCC - assertTrue(validation.validate("0011 61 963775620").isRight) + assertTrue(validation.validate("0011 61 963775620").toEither.isRight) }, test("Regex phone number validation for Congo, (Kinshasa)") { val validation = PhoneNumberValidation.phoneNumberCD - assertTrue(validation.validate("00 243 9494344055").isRight) + assertTrue(validation.validate("00 243 9494344055").toEither.isRight) }, test("Regex phone number validation for Central African Republic") { val validation = PhoneNumberValidation.phoneNumberCF - assertTrue(validation.validate("+236 59 6075 5901").isRight) + assertTrue(validation.validate("+236 59 6075 5901").toEither.isRight) }, test("Regex phone number validation for Congo (Brazzaville)") { val validation = PhoneNumberValidation.phoneNumberCG - assertTrue(validation.validate("00 24283 8219 9231").isRight) + assertTrue(validation.validate("00 24283 8219 9231").toEither.isRight) }, test("Regex phone number validation for Switzerland") { val validation = PhoneNumberValidation.phoneNumberCH - assertTrue(validation.validate("+41 62 9504 5752").isRight) - assertTrue(validation.validate("0041791234567").isRight) && - assertTrue(validation.validate("0041 79 123 45 67").isRight) && - assertTrue(validation.validate("+41791234567").isRight) && - assertTrue(validation.validate("+41 79 123 45 67").isRight) && - assertTrue(validation.validate("0791234567").isRight) && - assertTrue(validation.validate("-41 79 123 45 67").isLeft) && - assertTrue(validation.validate("+41 79 123 45 678").isLeft) && - assertTrue(validation.validate("79 123 45 678").isLeft) + assertTrue(validation.validate("+41 62 9504 5752").toEither.isRight) + assertTrue(validation.validate("0041791234567").toEither.isRight) && + assertTrue(validation.validate("0041 79 123 45 67").toEither.isRight) && + assertTrue(validation.validate("+41791234567").toEither.isRight) && + assertTrue(validation.validate("+41 79 123 45 67").toEither.isRight) && + assertTrue(validation.validate("0791234567").toEither.isRight) && + assertTrue(validation.validate("-41 79 123 45 67").toEither.isLeft) && + assertTrue(validation.validate("+41 79 123 45 678").toEither.isLeft) && + assertTrue(validation.validate("79 123 45 678").toEither.isLeft) }, test("Regex phone number validation for CĂ´te d'Ivoire") { val validation = PhoneNumberValidation.phoneNumberCI - assertTrue(validation.validate("00 2256102971096").isRight) + assertTrue(validation.validate("00 2256102971096").toEither.isRight) }, test("Regex phone number validation for Cook Islands") { val validation = PhoneNumberValidation.phoneNumberCK - assertTrue(validation.validate("00 6829326903969").isRight) + assertTrue(validation.validate("00 6829326903969").toEither.isRight) }, test("Regex phone number validation for Chile") { val validation = PhoneNumberValidation.phoneNumberCL - assertTrue(validation.validate("00 565768733529").isRight) + assertTrue(validation.validate("00 565768733529").toEither.isRight) }, test("Regex phone number validation for Cameroon") { val validation = PhoneNumberValidation.phoneNumberCM - assertTrue(validation.validate("00 2379601725044").isRight) + assertTrue(validation.validate("00 2379601725044").toEither.isRight) }, test("Regex phone number validation for China") { val validation = PhoneNumberValidation.phoneNumberCN - assertTrue(validation.validate("00 86 6313884064").isRight) + assertTrue(validation.validate("00 86 6313884064").toEither.isRight) }, test("Regex phone number validation for Colombia") { val validation = PhoneNumberValidation.phoneNumberCO - assertTrue(validation.validate("00 57 5035525009").isRight) + assertTrue(validation.validate("00 57 5035525009").toEither.isRight) }, test("Regex phone number validation for Costa Rica") { val validation = PhoneNumberValidation.phoneNumberCR - assertTrue(validation.validate("+506 2608425852").isRight) + assertTrue(validation.validate("+506 2608425852").toEither.isRight) }, test("Regex phone number validation for Cuba") { val validation = PhoneNumberValidation.phoneNumberCU - assertTrue(validation.validate("119 53 8684721023").isRight) + assertTrue(validation.validate("119 53 8684721023").toEither.isRight) }, test("Regex phone number validation for Cape Verde") { val validation = PhoneNumberValidation.phoneNumberCV - assertTrue(validation.validate("+238 54 1914 6255").isRight) + assertTrue(validation.validate("+238 54 1914 6255").toEither.isRight) }, test("Regex phone number validation for Curacao") { val validation = PhoneNumberValidation.phoneNumberCW - assertTrue(validation.validate("+599 69 9206 6789").isRight) + assertTrue(validation.validate("+599 69 9206 6789").toEither.isRight) }, test("Regex phone number validation for Christmas Island") { val validation = PhoneNumberValidation.phoneNumberCX - assertTrue(validation.validate("0011 61 8606709622").isRight) + assertTrue(validation.validate("0011 61 8606709622").toEither.isRight) }, test("Regex phone number validation for Cyprus") { val validation = PhoneNumberValidation.phoneNumberCY - assertTrue(validation.validate("00 3570126511197").isRight) + assertTrue(validation.validate("00 3570126511197").toEither.isRight) }, test("Regex phone number validation for Czech Republic") { val validation = PhoneNumberValidation.phoneNumberCZ - assertTrue(validation.validate("00 4209207508015").isRight) + assertTrue(validation.validate("00 4209207508015").toEither.isRight) }, test("Regex phone number validation for Germany") { val validation = PhoneNumberValidation.phoneNumberDE - assertTrue(validation.validate("00 49 8591548021").isRight) - assertTrue(validation.validate("+49 30 901820").isRight) && - assertTrue(validation.validate("004930901820").isRight) && - assertTrue(validation.validate("030901820").isRight) && - assertTrue(validation.validate("030 901820").isRight) && - assertTrue(validation.validate("+49 1522 343333").isRight) && - assertTrue(validation.validate("+49 152 901820").isRight) && - assertTrue(validation.validate("0049 152 901820").isRight) && - assertTrue(validation.validate("0041 30 901820").isLeft) && - assertTrue(validation.validate("49 152 901820").isLeft) && - assertTrue(validation.validate("049 152 901820").isLeft) + assertTrue(validation.validate("00 49 8591548021").toEither.isRight) + assertTrue(validation.validate("+49 30 901820").toEither.isRight) && + assertTrue(validation.validate("004930901820").toEither.isRight) && + assertTrue(validation.validate("030901820").toEither.isRight) && + assertTrue(validation.validate("030 901820").toEither.isRight) && + assertTrue(validation.validate("+49 1522 343333").toEither.isRight) && + assertTrue(validation.validate("+49 152 901820").toEither.isRight) && + assertTrue(validation.validate("0049 152 901820").toEither.isRight) && + assertTrue(validation.validate("0041 30 901820").toEither.isLeft) && + assertTrue(validation.validate("49 152 901820").toEither.isLeft) && + assertTrue(validation.validate("049 152 901820").toEither.isLeft) }, test("Regex phone number validation for Djibouti") { val validation = PhoneNumberValidation.phoneNumberDJ - assertTrue(validation.validate("00 2539228818387").isRight) + assertTrue(validation.validate("00 2539228818387").toEither.isRight) }, test("Regex phone number validation for Denmark") { val validation = PhoneNumberValidation.phoneNumberDK - assertTrue(validation.validate("00 450829342925").isRight) + assertTrue(validation.validate("00 450829342925").toEither.isRight) }, test("Regex phone number validation for Dominica") { val validation = PhoneNumberValidation.phoneNumberDM - assertTrue(validation.validate("011 1 767 117 934").isRight) + assertTrue(validation.validate("011 1 767 117 934").toEither.isRight) }, test("Regex phone number validation for Dominican Republic") { val validation = PhoneNumberValidation.phoneNumberDO - assertTrue(validation.validate("011 1 8001 026250").isRight) + assertTrue(validation.validate("011 1 8001 026250").toEither.isRight) }, test("Regex phone number validation for Algeria") { val validation = PhoneNumberValidation.phoneNumberDZ - assertTrue(validation.validate("00 213 1519404947").isRight) + assertTrue(validation.validate("00 213 1519404947").toEither.isRight) }, test("Regex phone number validation for Ecuador") { val validation = PhoneNumberValidation.phoneNumberEC - assertTrue(validation.validate("00 593 7661327173").isRight) + assertTrue(validation.validate("00 593 7661327173").toEither.isRight) }, test("Regex phone number validation for Estonia") { val validation = PhoneNumberValidation.phoneNumberEE - assertTrue(validation.validate("00 3727289832181").isRight) + assertTrue(validation.validate("00 3727289832181").toEither.isRight) }, test("Regex phone number validation for Egypt") { val validation = PhoneNumberValidation.phoneNumberEG - assertTrue(validation.validate("00 20 3371313171").isRight) + assertTrue(validation.validate("00 20 3371313171").toEither.isRight) }, test("Regex phone number validation for Western Sahara") { val validation = PhoneNumberValidation.phoneNumberEH - assertTrue(validation.validate("00 212 528 7355097").isRight) + assertTrue(validation.validate("00 212 528 7355097").toEither.isRight) }, test("Regex phone number validation for Eritrea") { val validation = PhoneNumberValidation.phoneNumberER - assertTrue(validation.validate("00 291 1389368590").isRight) + assertTrue(validation.validate("00 291 1389368590").toEither.isRight) }, test("Regex phone number validation for Spain") { val validation = PhoneNumberValidation.phoneNumberES - assertTrue(validation.validate("00 345499372300").isRight) + assertTrue(validation.validate("00 345499372300").toEither.isRight) }, test("Regex phone number validation for Ethiopia") { val validation = PhoneNumberValidation.phoneNumberET - assertTrue(validation.validate("00 251 9034175157").isRight) + assertTrue(validation.validate("00 251 9034175157").toEither.isRight) }, test("Regex phone number validation for Finland") { val validation = PhoneNumberValidation.phoneNumberFI - assertTrue(validation.validate("+358 1 20 504 1325").isRight) + assertTrue(validation.validate("+358 1 20 504 1325").toEither.isRight) }, test("Regex phone number validation for Fiji") { val validation = PhoneNumberValidation.phoneNumberFJ - assertTrue(validation.validate("00 6792349653587").isRight) + assertTrue(validation.validate("00 6792349653587").toEither.isRight) }, test("Regex phone number validation for Falkland Islands (Malvinas)") { val validation = PhoneNumberValidation.phoneNumberFK - assertTrue(validation.validate("00 5004003005535").isRight) + assertTrue(validation.validate("00 5004003005535").toEither.isRight) }, test("Regex phone number validation for Micronesia, Federated States of") { val validation = PhoneNumberValidation.phoneNumberFM - assertTrue(validation.validate("00 6918410093532").isRight) + assertTrue(validation.validate("00 6918410093532").toEither.isRight) }, test("Regex phone number validation for Faroe Islands") { val validation = PhoneNumberValidation.phoneNumberFO - assertTrue(validation.validate("00 298 5560667813").isRight) + assertTrue(validation.validate("00 298 5560667813").toEither.isRight) }, test("Regex phone number validation for France") { val validation = PhoneNumberValidation.phoneNumberFR - assertTrue(validation.validate("00 33 13 3901 4277").isRight) + assertTrue(validation.validate("00 33 13 3901 4277").toEither.isRight) }, test("Regex phone number validation for Gabon") { val validation = PhoneNumberValidation.phoneNumberGA - assertTrue(validation.validate("00 241 97 2596 5544").isRight) + assertTrue(validation.validate("00 241 97 2596 5544").toEither.isRight) }, test("Regex phone number validation for United Kingdom") { val validation = PhoneNumberValidation.phoneNumberGB - assertTrue(validation.validate("+44 94 2730 0927").isRight) + assertTrue(validation.validate("+44 94 2730 0927").toEither.isRight) }, test("Regex phone number validation for Grenada") { val validation = PhoneNumberValidation.phoneNumberGD - assertTrue(validation.validate("011 1 473 0027293").isRight) + assertTrue(validation.validate("011 1 473 0027293").toEither.isRight) }, test("Regex phone number validation for Georgia") { val validation = PhoneNumberValidation.phoneNumberGE - assertTrue(validation.validate("+995 40 9347 1630").isRight) + assertTrue(validation.validate("+995 40 9347 1630").toEither.isRight) }, test("Regex phone number validation for French Guiana") { val validation = PhoneNumberValidation.phoneNumberGF - assertTrue(validation.validate("+594 18 821 2131").isRight) + assertTrue(validation.validate("+594 18 821 2131").toEither.isRight) }, test("Regex phone number validation for Guernsey") { val validation = PhoneNumberValidation.phoneNumberGG - assertTrue(validation.validate("00 44 37 9295 8099").isRight) + assertTrue(validation.validate("00 44 37 9295 8099").toEither.isRight) }, test("Regex phone number validation for Ghana") { val validation = PhoneNumberValidation.phoneNumberGH - assertTrue(validation.validate("+233 18 4682 1216").isRight) + assertTrue(validation.validate("+233 18 4682 1216").toEither.isRight) }, test("Regex phone number validation for Gibraltar") { val validation = PhoneNumberValidation.phoneNumberGI - assertTrue(validation.validate("00 3508527907652").isRight) + assertTrue(validation.validate("00 3508527907652").toEither.isRight) }, test("Regex phone number validation for Greenland") { val validation = PhoneNumberValidation.phoneNumberGL - assertTrue(validation.validate("00 2996975320055").isRight) + assertTrue(validation.validate("00 2996975320055").toEither.isRight) }, test("Regex phone number validation for Gambia") { val validation = PhoneNumberValidation.phoneNumberGM - assertTrue(validation.validate("00 2208600678245").isRight) + assertTrue(validation.validate("00 2208600678245").toEither.isRight) }, test("Regex phone number validation for Guinea") { val validation = PhoneNumberValidation.phoneNumberGN - assertTrue(validation.validate("00 2246345663760").isRight) + assertTrue(validation.validate("00 2246345663760").toEither.isRight) }, test("Regex phone number validation for Guadeloupe") { val validation = PhoneNumberValidation.phoneNumberGP - assertTrue(validation.validate("00 590 15 1203 0997").isRight) + assertTrue(validation.validate("00 590 15 1203 0997").toEither.isRight) }, test("Regex phone number validation for Equatorial Guinea") { val validation = PhoneNumberValidation.phoneNumberGQ - assertTrue(validation.validate("00 2408656400449").isRight) + assertTrue(validation.validate("00 2408656400449").toEither.isRight) }, test("Regex phone number validation for Greece") { val validation = PhoneNumberValidation.phoneNumberGR - assertTrue(validation.validate("00 305729313542").isRight) + assertTrue(validation.validate("00 305729313542").toEither.isRight) }, test("Regex phone number validation for South Sandwich Islands") { val validation = PhoneNumberValidation.phoneNumberGS - assertTrue(validation.validate("00 5003096544376").isRight) + assertTrue(validation.validate("00 5003096544376").toEither.isRight) }, test("Regex phone number validation for Guatemala") { val validation = PhoneNumberValidation.phoneNumberGT - assertTrue(validation.validate("00 5029817333325").isRight) + assertTrue(validation.validate("00 5029817333325").toEither.isRight) }, test("Regex phone number validation for Guam") { val validation = PhoneNumberValidation.phoneNumberGU - assertTrue(validation.validate("011 1 671 5507500").isRight) + assertTrue(validation.validate("011 1 671 5507500").toEither.isRight) }, test("Regex phone number validation for Guinea-Bissau") { val validation = PhoneNumberValidation.phoneNumberGW - assertTrue(validation.validate("00001 245 72 3061 6510").isRight) + assertTrue(validation.validate("00001 245 72 3061 6510").toEither.isRight) }, test("Regex phone number validation for Guyana") { val validation = PhoneNumberValidation.phoneNumberGY - assertTrue(validation.validate("001 5923161184154").isRight) + assertTrue(validation.validate("001 5923161184154").toEither.isRight) }, test("Regex phone number validation for Hong Kong") { val validation = PhoneNumberValidation.phoneNumberHK - assertTrue(validation.validate("00 8521317558295").isRight) + assertTrue(validation.validate("00 8521317558295").toEither.isRight) }, test("Regex phone number validation for Heard and Mcdonald Islands") { val validation = PhoneNumberValidation.phoneNumberHM - assertTrue(validation.validate("00 6723191710825").isRight) + assertTrue(validation.validate("00 6723191710825").toEither.isRight) }, test("Regex phone number validation for Honduras") { val validation = PhoneNumberValidation.phoneNumberHN - assertTrue(validation.validate("00 5047371910554").isRight) + assertTrue(validation.validate("00 5047371910554").toEither.isRight) }, test("Regex phone number validation for Croatia") { val validation = PhoneNumberValidation.phoneNumberHR - assertTrue(validation.validate("00 385 52 1194 4850").isRight) + assertTrue(validation.validate("00 385 52 1194 4850").toEither.isRight) }, test("Regex phone number validation for Haiti") { val validation = PhoneNumberValidation.phoneNumberHT - assertTrue(validation.validate("00 5092551395589").isRight) + assertTrue(validation.validate("00 5092551395589").toEither.isRight) }, test("Regex phone number validation for Hungary") { val validation = PhoneNumberValidation.phoneNumberHU - assertTrue(validation.validate("+36 18 925 2015").isRight) - assertTrue(validation.validate("003612318855").isRight) && - assertTrue(validation.validate("0036 1 231 88 55").isRight) && - assertTrue(validation.validate("0036 1 231 8855").isRight) && - assertTrue(validation.validate("+3611234567").isRight) && - assertTrue(validation.validate("+36 1 123 45 67").isRight) && - assertTrue(validation.validate("+36 1 123 4567").isRight) && - assertTrue(validation.validate("0611234567").isRight) && - assertTrue(validation.validate("0036-30-231-88-55").isRight) && - assertTrue(validation.validate("0036-30-231-8855").isRight) && - assertTrue(validation.validate("+36301234567").isRight) && - assertTrue(validation.validate("+36-30-123-45-67").isRight) && - assertTrue(validation.validate("+36-30-123-4567").isRight) && - assertTrue(validation.validate("06301234567").isRight) && - assertTrue(validation.validate("+36 11 123 45 67").isRight) && - assertTrue(validation.validate("+36 5 123 45 67").isRight) && - assertTrue(validation.validate("+36 1 123 45 678").isRight) && - assertTrue(validation.validate("-36 1 123 45 67").isLeft) && - assertTrue(validation.validate("1 123 45 678").isLeft) && - assertTrue(validation.validate("-36-30-123-45-67").isLeft) && - assertTrue(validation.validate("+36-30-123-45-678").isLeft) && - assertTrue(validation.validate("30-123-45-678").isLeft) + assertTrue(validation.validate("+36 18 925 2015").toEither.isRight) + assertTrue(validation.validate("003612318855").toEither.isRight) && + assertTrue(validation.validate("0036 1 231 88 55").toEither.isRight) && + assertTrue(validation.validate("0036 1 231 8855").toEither.isRight) && + assertTrue(validation.validate("+3611234567").toEither.isRight) && + assertTrue(validation.validate("+36 1 123 45 67").toEither.isRight) && + assertTrue(validation.validate("+36 1 123 4567").toEither.isRight) && + assertTrue(validation.validate("0611234567").toEither.isRight) && + assertTrue(validation.validate("0036-30-231-88-55").toEither.isRight) && + assertTrue(validation.validate("0036-30-231-8855").toEither.isRight) && + assertTrue(validation.validate("+36301234567").toEither.isRight) && + assertTrue(validation.validate("+36-30-123-45-67").toEither.isRight) && + assertTrue(validation.validate("+36-30-123-4567").toEither.isRight) && + assertTrue(validation.validate("06301234567").toEither.isRight) && + assertTrue(validation.validate("+36 11 123 45 67").toEither.isRight) && + assertTrue(validation.validate("+36 5 123 45 67").toEither.isRight) && + assertTrue(validation.validate("+36 1 123 45 678").toEither.isRight) && + assertTrue(validation.validate("-36 1 123 45 67").toEither.isLeft) && + assertTrue(validation.validate("1 123 45 678").toEither.isLeft) && + assertTrue(validation.validate("-36-30-123-45-67").toEither.isLeft) && + assertTrue(validation.validate("+36-30-123-45-678").toEither.isLeft) && + assertTrue(validation.validate("30-123-45-678").toEither.isLeft) }, test("Regex phone number validation for Indonesia") { val validation = PhoneNumberValidation.phoneNumberID - assertTrue(validation.validate("+62 69 5257 3582").isRight) + assertTrue(validation.validate("+62 69 5257 3582").toEither.isRight) }, test("Regex phone number validation for Ireland") { val validation = PhoneNumberValidation.phoneNumberIE - assertTrue(validation.validate("+353 82 9286 4067").isRight) + assertTrue(validation.validate("+353 82 9286 4067").toEither.isRight) }, test("Regex phone number validation for Israel") { val validation = PhoneNumberValidation.phoneNumberIL - assertTrue(validation.validate("01 972 60 8248 1948").isRight) + assertTrue(validation.validate("01 972 60 8248 1948").toEither.isRight) }, test("Regex phone number validation for Isle of Man") { val validation = PhoneNumberValidation.phoneNumberIM - assertTrue(validation.validate("+44 74576 49 709").isRight) + assertTrue(validation.validate("+44 74576 49 709").toEither.isRight) }, test("Regex phone number validation for India") { val validation = PhoneNumberValidation.phoneNumberIN - assertTrue(validation.validate("00 91 90 3412 7804").isRight) + assertTrue(validation.validate("00 91 90 3412 7804").toEither.isRight) }, test("Regex phone number validation for British Indian Ocean Territory") { val validation = PhoneNumberValidation.phoneNumberIO - assertTrue(validation.validate("00 2462992060814").isRight) + assertTrue(validation.validate("00 2462992060814").toEither.isRight) }, test("Regex phone number validation for Iraq") { val validation = PhoneNumberValidation.phoneNumberIQ - assertTrue(validation.validate("+964 257 4565 059").isRight) + assertTrue(validation.validate("+964 257 4565 059").toEither.isRight) }, test("Regex phone number validation for Iran") { val validation = PhoneNumberValidation.phoneNumberIR - assertTrue(validation.validate("00 98 19 3019 1031").isRight) + assertTrue(validation.validate("00 98 19 3019 1031").toEither.isRight) }, test("Regex phone number validation for Iceland") { val validation = PhoneNumberValidation.phoneNumberIS - assertTrue(validation.validate("00 3541289658929").isRight) + assertTrue(validation.validate("00 3541289658929").toEither.isRight) }, test("Regex phone number validation for Italy") { val validation = PhoneNumberValidation.phoneNumberIT - assertTrue(validation.validate("00 393878141457").isRight) + assertTrue(validation.validate("00 393878141457").toEither.isRight) }, test("Regex phone number validation for Jersey") { val validation = PhoneNumberValidation.phoneNumberJE - assertTrue(validation.validate("+44 57 9972 9605").isRight) + assertTrue(validation.validate("+44 57 9972 9605").toEither.isRight) }, test("Regex phone number validation for Jamaica") { val validation = PhoneNumberValidation.phoneNumberJM - assertTrue(validation.validate("011 1 658 1150558").isRight) + assertTrue(validation.validate("011 1 658 1150558").toEither.isRight) }, test("Regex phone number validation for Jordan") { val validation = PhoneNumberValidation.phoneNumberJO - assertTrue(validation.validate("00 962 84 4532 6108").isRight) + assertTrue(validation.validate("00 962 84 4532 6108").toEither.isRight) }, test("Regex phone number validation for Japan") { val validation = PhoneNumberValidation.phoneNumberJP - assertTrue(validation.validate("010 81 20 4493 0924").isRight) + assertTrue(validation.validate("010 81 20 4493 0924").toEither.isRight) }, test("Regex phone number validation for Kenya") { val validation = PhoneNumberValidation.phoneNumberKE - assertTrue(validation.validate("000 254 48 5947 4534").isRight) + assertTrue(validation.validate("000 254 48 5947 4534").toEither.isRight) }, test("Regex phone number validation for Kyrgyzstan") { val validation = PhoneNumberValidation.phoneNumberKG - assertTrue(validation.validate("+996 16 6735 9115").isRight) + assertTrue(validation.validate("+996 16 6735 9115").toEither.isRight) }, test("Regex phone number validation for Cambodia") { val validation = PhoneNumberValidation.phoneNumberKH - assertTrue(validation.validate("+855 43 4519 9326").isRight) + assertTrue(validation.validate("+855 43 4519 9326").toEither.isRight) }, test("Regex phone number validation for Kiribati") { val validation = PhoneNumberValidation.phoneNumberKI - assertTrue(validation.validate("+686 77 5928 5264").isRight) + assertTrue(validation.validate("+686 77 5928 5264").toEither.isRight) }, test("Regex phone number validation for Comoros") { val validation = PhoneNumberValidation.phoneNumberKM - assertTrue(validation.validate("00 2698571387031").isRight) + assertTrue(validation.validate("00 2698571387031").toEither.isRight) }, test("Regex phone number validation for Saint Kitts and Nevis") { val validation = PhoneNumberValidation.phoneNumberKN - assertTrue(validation.validate("011 1 869 6539479").isRight) + assertTrue(validation.validate("011 1 869 6539479").toEither.isRight) }, test("Regex phone number validation for North Korea") { val validation = PhoneNumberValidation.phoneNumberKP - assertTrue(validation.validate("99 850 17 0277 0657").isRight) + assertTrue(validation.validate("99 850 17 0277 0657").toEither.isRight) }, test("Regex phone number validation for South Korea") { val validation = PhoneNumberValidation.phoneNumberKR - assertTrue(validation.validate("+82 9649592789").isRight) + assertTrue(validation.validate("+82 9649592789").toEither.isRight) }, test("Regex phone number validation for Kuwait") { val validation = PhoneNumberValidation.phoneNumberKW - assertTrue(validation.validate("+965 28 5107 9046").isRight) + assertTrue(validation.validate("+965 28 5107 9046").toEither.isRight) }, test("Regex phone number validation for Cayman Islands") { val validation = PhoneNumberValidation.phoneNumberKY - assertTrue(validation.validate("011 1 345 0106523").isRight) + assertTrue(validation.validate("011 1 345 0106523").toEither.isRight) }, test("Regex phone number validation for Kazakhstan") { val validation = PhoneNumberValidation.phoneNumberKZ - assertTrue(validation.validate("00810 7 33 1450 8219").isRight) + assertTrue(validation.validate("00810 7 33 1450 8219").toEither.isRight) }, test("Regex phone number validation for Lao PDR") { val validation = PhoneNumberValidation.phoneNumberLA - assertTrue(validation.validate("00 856 5368127779").isRight) + assertTrue(validation.validate("00 856 5368127779").toEither.isRight) }, test("Regex phone number validation for Lebanon") { val validation = PhoneNumberValidation.phoneNumberLB - assertTrue(validation.validate("+961 3652044279").isRight) + assertTrue(validation.validate("+961 3652044279").toEither.isRight) }, test("Regex phone number validation for Saint Lucia") { val validation = PhoneNumberValidation.phoneNumberLC - assertTrue(validation.validate("011 1 758 0471732").isRight) + assertTrue(validation.validate("011 1 758 0471732").toEither.isRight) }, test("Regex phone number validation for Liechtenstein") { val validation = PhoneNumberValidation.phoneNumberLI - assertTrue(validation.validate("00 423 6420715797").isRight) + assertTrue(validation.validate("00 423 6420715797").toEither.isRight) }, test("Regex phone number validation for Sri Lanka") { val validation = PhoneNumberValidation.phoneNumberLK - assertTrue(validation.validate("00 94 1935386465").isRight) + assertTrue(validation.validate("00 94 1935386465").toEither.isRight) }, test("Regex phone number validation for Liberia") { val validation = PhoneNumberValidation.phoneNumberLR - assertTrue(validation.validate("00 231 6596099981").isRight) + assertTrue(validation.validate("00 231 6596099981").toEither.isRight) }, test("Regex phone number validation for Lesotho") { val validation = PhoneNumberValidation.phoneNumberLS - assertTrue(validation.validate("00 2662854967720").isRight) + assertTrue(validation.validate("00 2662854967720").toEither.isRight) }, test("Regex phone number validation for Lithuania") { val validation = PhoneNumberValidation.phoneNumberLT - assertTrue(validation.validate("00 370 1974024335").isRight) + assertTrue(validation.validate("00 370 1974024335").toEither.isRight) }, test("Regex phone number validation for Luxembourg") { val validation = PhoneNumberValidation.phoneNumberLU - assertTrue(validation.validate("00 3523 505709778").isRight) + assertTrue(validation.validate("00 3523 505709778").toEither.isRight) }, test("Regex phone number validation for Latvia") { val validation = PhoneNumberValidation.phoneNumberLV - assertTrue(validation.validate("00 3712161145531").isRight) + assertTrue(validation.validate("00 3712161145531").toEither.isRight) }, test("Regex phone number validation for Libya") { val validation = PhoneNumberValidation.phoneNumberLY - assertTrue(validation.validate("00 218 8264419925").isRight) + assertTrue(validation.validate("00 218 8264419925").toEither.isRight) }, test("Regex phone number validation for Morocco") { val validation = PhoneNumberValidation.phoneNumberMA - assertTrue(validation.validate("00 212 3517364769").isRight) + assertTrue(validation.validate("00 212 3517364769").toEither.isRight) }, test("Regex phone number validation for Monaco") { val validation = PhoneNumberValidation.phoneNumberMC - assertTrue(validation.validate("00 377 2021117087").isRight) + assertTrue(validation.validate("00 377 2021117087").toEither.isRight) }, test("Regex phone number validation for Moldova") { val validation = PhoneNumberValidation.phoneNumberMD - assertTrue(validation.validate("00 373 4446201390").isRight) + assertTrue(validation.validate("00 373 4446201390").toEither.isRight) }, test("Regex phone number validation for Montenegro") { val validation = PhoneNumberValidation.phoneNumberME - assertTrue(validation.validate("+382 19 7927 6970").isRight) + assertTrue(validation.validate("+382 19 7927 6970").toEither.isRight) }, test("Regex phone number validation for Saint-Martin (French)") { val validation = PhoneNumberValidation.phoneNumberMF - assertTrue(validation.validate("+590 01 0516 3845").isRight) + assertTrue(validation.validate("+590 01 0516 3845").toEither.isRight) }, test("Regex phone number validation for Madagascar") { val validation = PhoneNumberValidation.phoneNumberMG - assertTrue(validation.validate("+261 353 5945 041").isRight) + assertTrue(validation.validate("+261 353 5945 041").toEither.isRight) }, test("Regex phone number validation for Marshall Islands") { val validation = PhoneNumberValidation.phoneNumberMH - assertTrue(validation.validate("011 692 5127396972").isRight) + assertTrue(validation.validate("011 692 5127396972").toEither.isRight) }, test("Regex phone number validation for Macedonia") { val validation = PhoneNumberValidation.phoneNumberMK - assertTrue(validation.validate("+389 408 929 2478").isRight) + assertTrue(validation.validate("+389 408 929 2478").toEither.isRight) }, test("Regex phone number validation for Mali") { val validation = PhoneNumberValidation.phoneNumberML - assertTrue(validation.validate("00 2233170146268").isRight) + assertTrue(validation.validate("00 2233170146268").toEither.isRight) }, test("Regex phone number validation for Myanmar") { val validation = PhoneNumberValidation.phoneNumberMM - assertTrue(validation.validate("+95 05 8180 4483").isRight) + assertTrue(validation.validate("+95 05 8180 4483").toEither.isRight) }, test("Regex phone number validation for Mongolia") { val validation = PhoneNumberValidation.phoneNumberMN - assertTrue(validation.validate("001 976 15 3640 9604").isRight) + assertTrue(validation.validate("001 976 15 3640 9604").toEither.isRight) }, test("Regex phone number validation for Macao") { val validation = PhoneNumberValidation.phoneNumberMO - assertTrue(validation.validate("00 8531510792742").isRight) + assertTrue(validation.validate("00 8531510792742").toEither.isRight) }, test("Regex phone number validation for Northern Mariana Islands") { val validation = PhoneNumberValidation.phoneNumberMP - assertTrue(validation.validate("011 1 670 893 643").isRight) + assertTrue(validation.validate("011 1 670 893 643").toEither.isRight) }, test("Regex phone number validation for Martinique") { val validation = PhoneNumberValidation.phoneNumberMQ - assertTrue(validation.validate("+596 1932085020").isRight) + assertTrue(validation.validate("+596 1932085020").toEither.isRight) }, test("Regex phone number validation for Mauritania") { val validation = PhoneNumberValidation.phoneNumberMR - assertTrue(validation.validate("+222 54 6048 0691").isRight) + assertTrue(validation.validate("+222 54 6048 0691").toEither.isRight) }, test("Regex phone number validation for Montserrat") { val validation = PhoneNumberValidation.phoneNumberMS - assertTrue(validation.validate("011 1 664 393 4545").isRight) + assertTrue(validation.validate("011 1 664 393 4545").toEither.isRight) }, test("Regex phone number validation for Malta") { val validation = PhoneNumberValidation.phoneNumberMT - assertTrue(validation.validate("00 3565701318096").isRight) + assertTrue(validation.validate("00 3565701318096").toEither.isRight) }, test("Regex phone number validation for Mauritius") { val validation = PhoneNumberValidation.phoneNumberMU - assertTrue(validation.validate("0020 230 12 9500 3440").isRight) + assertTrue(validation.validate("0020 230 12 9500 3440").toEither.isRight) }, test("Regex phone number validation for Maldives") { val validation = PhoneNumberValidation.phoneNumberMV - assertTrue(validation.validate("00 9601707178237").isRight) + assertTrue(validation.validate("00 9601707178237").toEither.isRight) }, test("Regex phone number validation for Malawi") { val validation = PhoneNumberValidation.phoneNumberMW - assertTrue(validation.validate("00 265 4648760757").isRight) + assertTrue(validation.validate("00 265 4648760757").toEither.isRight) }, test("Regex phone number validation for Mexico") { val validation = PhoneNumberValidation.phoneNumberMX - assertTrue(validation.validate("+52 55 1831 3440").isRight) + assertTrue(validation.validate("+52 55 1831 3440").toEither.isRight) }, test("Regex phone number validation for Malaysia") { val validation = PhoneNumberValidation.phoneNumberMY - assertTrue(validation.validate("+60 8189523546").isRight) + assertTrue(validation.validate("+60 8189523546").toEither.isRight) }, test("Regex phone number validation for Mozambique") { val validation = PhoneNumberValidation.phoneNumberMZ - assertTrue(validation.validate("+2589622830508").isRight) + assertTrue(validation.validate("+2589622830508").toEither.isRight) }, test("Regex phone number validation for Namibia") { val validation = PhoneNumberValidation.phoneNumberNA - assertTrue(validation.validate("+264 4876840196").isRight) + assertTrue(validation.validate("+264 4876840196").toEither.isRight) }, test("Regex phone number validation for New Caledonia") { val validation = PhoneNumberValidation.phoneNumberNC - assertTrue(validation.validate("+6872884247049").isRight) + assertTrue(validation.validate("+6872884247049").toEither.isRight) }, test("Regex phone number validation for Niger") { val validation = PhoneNumberValidation.phoneNumberNE - assertTrue(validation.validate("+2271480678971").isRight) + assertTrue(validation.validate("+2271480678971").toEither.isRight) }, test("Regex phone number validation for Norfolk Island") { val validation = PhoneNumberValidation.phoneNumberNF - assertTrue(validation.validate("+6725311013853").isRight) + assertTrue(validation.validate("+6725311013853").toEither.isRight) }, test("Regex phone number validation for Nigeria") { val validation = PhoneNumberValidation.phoneNumberNG - assertTrue(validation.validate("009 234 78 6668 2580").isRight) + assertTrue(validation.validate("009 234 78 6668 2580").toEither.isRight) }, test("Regex phone number validation for Nicaragua") { val validation = PhoneNumberValidation.phoneNumberNI - assertTrue(validation.validate("+5057480416270").isRight) + assertTrue(validation.validate("+5057480416270").toEither.isRight) }, test("Regex phone number validation for Netherlands") { val validation = PhoneNumberValidation.phoneNumberNL - assertTrue(validation.validate("+31 3437953416").isRight) + assertTrue(validation.validate("+31 3437953416").toEither.isRight) }, test("Regex phone number validation for Norway") { val validation = PhoneNumberValidation.phoneNumberNO - assertTrue(validation.validate("+47 02 6239 2816").isRight) + assertTrue(validation.validate("+47 02 6239 2816").toEither.isRight) }, test("Regex phone number validation for Nepal") { val validation = PhoneNumberValidation.phoneNumberNP - assertTrue(validation.validate("00 977 8947592034").isRight) + assertTrue(validation.validate("00 977 8947592034").toEither.isRight) }, test("Regex phone number validation for Nauru") { val validation = PhoneNumberValidation.phoneNumberNR - assertTrue(validation.validate("+674 14 0184 1819").isRight) + assertTrue(validation.validate("+674 14 0184 1819").toEither.isRight) }, test("Regex phone number validation for Niue") { val validation = PhoneNumberValidation.phoneNumberNU - assertTrue(validation.validate("00 683 81 5796 1422").isRight) + assertTrue(validation.validate("00 683 81 5796 1422").toEither.isRight) }, test("Regex phone number validation for New Zealand") { val validation = PhoneNumberValidation.phoneNumberNZ - assertTrue(validation.validate("00 64 4309656720").isRight) + assertTrue(validation.validate("00 64 4309656720").toEither.isRight) }, test("Regex phone number validation for Oman") { val validation = PhoneNumberValidation.phoneNumberOM - assertTrue(validation.validate("+968 17 4687 2788").isRight) + assertTrue(validation.validate("+968 17 4687 2788").toEither.isRight) }, test("Regex phone number validation for Panama") { val validation = PhoneNumberValidation.phoneNumberPA - assertTrue(validation.validate("+507 10 8679 9468").isRight) + assertTrue(validation.validate("+507 10 8679 9468").toEither.isRight) }, test("Regex phone number validation for Peru") { val validation = PhoneNumberValidation.phoneNumberPE - assertTrue(validation.validate("0019 51 51 6407 3711").isRight) + assertTrue(validation.validate("0019 51 51 6407 3711").toEither.isRight) }, test("Regex phone number validation for French Polynesia") { val validation = PhoneNumberValidation.phoneNumberPF - assertTrue(validation.validate("00 689 31 4664 6885").isRight) + assertTrue(validation.validate("00 689 31 4664 6885").toEither.isRight) }, test("Regex phone number validation for Papua New Guinea") { val validation = PhoneNumberValidation.phoneNumberPG - assertTrue(validation.validate("+675 10 2567 0318").isRight) + assertTrue(validation.validate("+675 10 2567 0318").toEither.isRight) }, test("Regex phone number validation for Philippines") { val validation = PhoneNumberValidation.phoneNumberPH - assertTrue(validation.validate("00 63 2851764972").isRight) + assertTrue(validation.validate("00 63 2851764972").toEither.isRight) }, test("Regex phone number validation for Pakistan") { val validation = PhoneNumberValidation.phoneNumberPK - assertTrue(validation.validate("+92 7553664097").isRight) + assertTrue(validation.validate("+92 7553664097").toEither.isRight) }, test("Regex phone number validation for Poland") { val validation = PhoneNumberValidation.phoneNumberPL - assertTrue(validation.validate("00 48168250790").isRight) + assertTrue(validation.validate("00 48168250790").toEither.isRight) }, test("Regex phone number validation for Saint Pierre and Miquelon") { val validation = PhoneNumberValidation.phoneNumberPM - assertTrue(validation.validate("00 508 3214890710").isRight) + assertTrue(validation.validate("00 508 3214890710").toEither.isRight) }, test("Regex phone number validation for Pitcairn Islands") { val validation = PhoneNumberValidation.phoneNumberPN - assertTrue(validation.validate("+870 92 6226 9171").isRight) + assertTrue(validation.validate("+870 92 6226 9171").toEither.isRight) }, test("Regex phone number validation for Puerto Rico") { val validation = PhoneNumberValidation.phoneNumberPR - assertTrue(validation.validate("011 1 787 475 939").isRight) + assertTrue(validation.validate("011 1 787 475 939").toEither.isRight) }, test("Regex phone number validation for Palestinian Territory") { val validation = PhoneNumberValidation.phoneNumberPS - assertTrue(validation.validate("00 970 5758777122").isRight) + assertTrue(validation.validate("00 970 5758777122").toEither.isRight) }, test("Regex phone number validation for Portugal") { val validation = PhoneNumberValidation.phoneNumberPT - assertTrue(validation.validate("+3516910095620").isRight) - assertTrue(validation.validate("00351211140200").isRight) && - assertTrue(validation.validate("00351 211 140 200").isRight) && - assertTrue(validation.validate("00351 21 114 02 00").isRight) && - assertTrue(validation.validate("+351211140200").isRight) && - assertTrue(validation.validate("+351 21 114 02 00").isRight) && - assertTrue(validation.validate("+351 21 114 0200").isRight) && - assertTrue(validation.validate("-351 21 114 02 00").isLeft) && - assertTrue(validation.validate("+351 21 114 02 006").isLeft) && - assertTrue(validation.validate("21 114 02 006").isLeft) + assertTrue(validation.validate("+3516910095620").toEither.isRight) + assertTrue(validation.validate("00351211140200").toEither.isRight) && + assertTrue(validation.validate("00351 211 140 200").toEither.isRight) && + assertTrue(validation.validate("00351 21 114 02 00").toEither.isRight) && + assertTrue(validation.validate("+351211140200").toEither.isRight) && + assertTrue(validation.validate("+351 21 114 02 00").toEither.isRight) && + assertTrue(validation.validate("+351 21 114 0200").toEither.isRight) && + assertTrue(validation.validate("-351 21 114 02 00").toEither.isLeft) && + assertTrue(validation.validate("+351 21 114 02 006").toEither.isLeft) && + assertTrue(validation.validate("21 114 02 006").toEither.isLeft) }, test("Regex phone number validation for Palau") { val validation = PhoneNumberValidation.phoneNumberPW - assertTrue(validation.validate("01 680 54 5298 6941").isRight) + assertTrue(validation.validate("01 680 54 5298 6941").toEither.isRight) }, test("Regex phone number validation for Paraguay") { val validation = PhoneNumberValidation.phoneNumberPY - assertTrue(validation.validate("+595 7488642578").isRight) + assertTrue(validation.validate("+595 7488642578").toEither.isRight) }, test("Regex phone number validation for Qatar") { val validation = PhoneNumberValidation.phoneNumberQA - assertTrue(validation.validate("00 974094360402").isRight) + assertTrue(validation.validate("00 974094360402").toEither.isRight) }, test("Regex phone number validation for RĂ©union") { val validation = PhoneNumberValidation.phoneNumberRE - assertTrue(validation.validate("00 262 8485511353").isRight) + assertTrue(validation.validate("00 262 8485511353").toEither.isRight) }, test("Regex phone number validation for Romania") { val validation = PhoneNumberValidation.phoneNumberRO - assertTrue(validation.validate("+40 4126654789").isRight) + assertTrue(validation.validate("+40 4126654789").toEither.isRight) }, test("Regex phone number validation for Serbia") { val validation = PhoneNumberValidation.phoneNumberRS - assertTrue(validation.validate("00 381 5718415376").isRight) - assertTrue(validation.validate("+381111234567").isRight) && - assertTrue(validation.validate("+381 11 123 45 67").isRight) && - assertTrue(validation.validate("00381111234567").isRight) && - assertTrue(validation.validate("00381 11 123 45 67").isRight) && - assertTrue(validation.validate("00381 230 123 45 67").isRight) && - assertTrue(validation.validate("0111234567").isRight) && - assertTrue(validation.validate("-381 11 123 45 67").isLeft) && - assertTrue(validation.validate("+381 11 123 45 6789").isLeft) && - assertTrue(validation.validate("11 123 45 678").isLeft) + assertTrue(validation.validate("00 381 5718415376").toEither.isRight) + assertTrue(validation.validate("+381111234567").toEither.isRight) && + assertTrue(validation.validate("+381 11 123 45 67").toEither.isRight) && + assertTrue(validation.validate("00381111234567").toEither.isRight) && + assertTrue(validation.validate("00381 11 123 45 67").toEither.isRight) && + assertTrue(validation.validate("00381 230 123 45 67").toEither.isRight) && + assertTrue(validation.validate("0111234567").toEither.isRight) && + assertTrue(validation.validate("-381 11 123 45 67").toEither.isLeft) && + assertTrue(validation.validate("+381 11 123 45 6789").toEither.isLeft) && + assertTrue(validation.validate("11 123 45 678").toEither.isLeft) }, test("Regex phone number validation for Russian Federation") { val validation = PhoneNumberValidation.phoneNumberRU - assertTrue(validation.validate("810 7 8023940837").isRight) + assertTrue(validation.validate("810 7 8023940837").toEither.isRight) }, test("Regex phone number validation for Rwanda") { val validation = PhoneNumberValidation.phoneNumberRW - assertTrue(validation.validate("00 250 1071423830").isRight) + assertTrue(validation.validate("00 250 1071423830").toEither.isRight) }, test("Regex phone number validation for Saudi Arabia") { val validation = PhoneNumberValidation.phoneNumberSA - assertTrue(validation.validate("+966 2314438338").isRight) + assertTrue(validation.validate("+966 2314438338").toEither.isRight) }, test("Regex phone number validation for Solomon Islands") { val validation = PhoneNumberValidation.phoneNumberSB - assertTrue(validation.validate("+677 68 0771 5592").isRight) + assertTrue(validation.validate("+677 68 0771 5592").toEither.isRight) }, test("Regex phone number validation for Seychelles") { val validation = PhoneNumberValidation.phoneNumberSC - assertTrue(validation.validate("+2483511003232").isRight) + assertTrue(validation.validate("+2483511003232").toEither.isRight) }, test("Regex phone number validation for Sudan") { val validation = PhoneNumberValidation.phoneNumberSD - assertTrue(validation.validate("+249 8299453804").isRight) + assertTrue(validation.validate("+249 8299453804").toEither.isRight) }, test("Regex phone number validation for Sweden") { val validation = PhoneNumberValidation.phoneNumberSE - assertTrue(validation.validate("+46 3782292031").isRight) + assertTrue(validation.validate("+46 3782292031").toEither.isRight) }, test("Regex phone number validation for Singapore") { val validation = PhoneNumberValidation.phoneNumberSG - assertTrue(validation.validate("0 65 894769144").isRight) + assertTrue(validation.validate("0 65 894769144").toEither.isRight) }, test("Regex phone number validation for Saint Helena") { val validation = PhoneNumberValidation.phoneNumberSH - assertTrue(validation.validate("+290 256 649 891").isRight) + assertTrue(validation.validate("+290 256 649 891").toEither.isRight) }, test("Regex phone number validation for Slovenia") { val validation = PhoneNumberValidation.phoneNumberSI - assertTrue(validation.validate("+386 9216604503").isRight) + assertTrue(validation.validate("+386 9216604503").toEither.isRight) }, test("Regex phone number validation for Svalbard and Jan Mayen Islands") { val validation = PhoneNumberValidation.phoneNumberSJ - assertTrue(validation.validate("+47 79 13828050").isRight) + assertTrue(validation.validate("+47 79 13828050").toEither.isRight) }, test("Regex phone number validation for Slovakia") { val validation = PhoneNumberValidation.phoneNumberSK - assertTrue(validation.validate("00 421 9837820736").isRight) + assertTrue(validation.validate("00 421 9837820736").toEither.isRight) }, test("Regex phone number validation for Sierra Leone") { val validation = PhoneNumberValidation.phoneNumberSL - assertTrue(validation.validate("00 232 4479684349").isRight) + assertTrue(validation.validate("00 232 4479684349").toEither.isRight) }, test("Regex phone number validation for San Marino") { val validation = PhoneNumberValidation.phoneNumberSM - assertTrue(validation.validate("00 378038935173").isRight) + assertTrue(validation.validate("00 378038935173").toEither.isRight) }, test("Regex phone number validation for Senegal") { val validation = PhoneNumberValidation.phoneNumberSN - assertTrue(validation.validate("00 2218570840759").isRight) + assertTrue(validation.validate("00 2218570840759").toEither.isRight) }, test("Regex phone number validation for Somalia") { val validation = PhoneNumberValidation.phoneNumberSO - assertTrue(validation.validate("00 252 2908185816").isRight) + assertTrue(validation.validate("00 252 2908185816").toEither.isRight) }, test("Regex phone number validation for Suriname") { val validation = PhoneNumberValidation.phoneNumberSR - assertTrue(validation.validate("00 5975953326179").isRight) + assertTrue(validation.validate("00 5975953326179").toEither.isRight) }, test("Regex phone number validation for South Sudan") { val validation = PhoneNumberValidation.phoneNumberSS - assertTrue(validation.validate("00 211 6613246029").isRight) + assertTrue(validation.validate("00 211 6613246029").toEither.isRight) }, test("Regex phone number validation for Sao Tome and Principe") { val validation = PhoneNumberValidation.phoneNumberST - assertTrue(validation.validate("00 239431200296").isRight) + assertTrue(validation.validate("00 239431200296").toEither.isRight) }, test("Regex phone number validation for El Salvador") { val validation = PhoneNumberValidation.phoneNumberSV - assertTrue(validation.validate("00 503389285910").isRight) + assertTrue(validation.validate("00 503389285910").toEither.isRight) }, test("Regex phone number validation for Saint Marten") { val validation = PhoneNumberValidation.phoneNumberSX - assertTrue(validation.validate("011 1 721 528183").isRight) + assertTrue(validation.validate("011 1 721 528183").toEither.isRight) }, test("Regex phone number validation for Syria") { val validation = PhoneNumberValidation.phoneNumberSY - assertTrue(validation.validate("00 963 3253918464").isRight) + assertTrue(validation.validate("00 963 3253918464").toEither.isRight) }, test("Regex phone number validation for Swaziland") { val validation = PhoneNumberValidation.phoneNumberSZ - assertTrue(validation.validate("00 268184154720").isRight) + assertTrue(validation.validate("00 268184154720").toEither.isRight) }, test("Regex phone number validation for Tristan da Cunha") { val validation = PhoneNumberValidation.phoneNumberTA - assertTrue(validation.validate("+290 8 63587169").isRight) + assertTrue(validation.validate("+290 8 63587169").toEither.isRight) }, test("Regex phone number validation for Turks and Caicos Islands") { val validation = PhoneNumberValidation.phoneNumberTC - assertTrue(validation.validate("011 1 649 102537").isRight) + assertTrue(validation.validate("011 1 649 102537").toEither.isRight) }, test("Regex phone number validation for Chad") { val validation = PhoneNumberValidation.phoneNumberTD - assertTrue(validation.validate("00 2359209745639").isRight) + assertTrue(validation.validate("00 2359209745639").toEither.isRight) }, test("Regex phone number validation for French Southern Territories") { val validation = PhoneNumberValidation.phoneNumberTF - assertTrue(validation.validate("00 262 4215656462").isRight) + assertTrue(validation.validate("00 262 4215656462").toEither.isRight) }, test("Regex phone number validation for Togo") { val validation = PhoneNumberValidation.phoneNumberTG - assertTrue(validation.validate("00 2281952004914").isRight) + assertTrue(validation.validate("00 2281952004914").toEither.isRight) }, test("Regex phone number validation for Thailand") { val validation = PhoneNumberValidation.phoneNumberTH - assertTrue(validation.validate("00 66 7946617112").isRight) + assertTrue(validation.validate("00 66 7946617112").toEither.isRight) }, test("Regex phone number validation for Tajikistan") { val validation = PhoneNumberValidation.phoneNumberTJ - assertTrue(validation.validate("00810 992 57 5953 7962").isRight) + assertTrue(validation.validate("00810 992 57 5953 7962").toEither.isRight) }, test("Regex phone number validation for Tokelau") { val validation = PhoneNumberValidation.phoneNumberTK - assertTrue(validation.validate("00 6908354403605").isRight) + assertTrue(validation.validate("00 6908354403605").toEither.isRight) }, test("Regex phone number validation for Timor-Leste") { val validation = PhoneNumberValidation.phoneNumberTL - assertTrue(validation.validate("00 6704835783535").isRight) + assertTrue(validation.validate("00 6704835783535").toEither.isRight) }, test("Regex phone number validation for Turkmenistan") { val validation = PhoneNumberValidation.phoneNumberTM - assertTrue(validation.validate("00810 993 299 05 5741").isRight) + assertTrue(validation.validate("00810 993 299 05 5741").toEither.isRight) }, test("Regex phone number validation for Tunisia") { val validation = PhoneNumberValidation.phoneNumberTN - assertTrue(validation.validate("00 2162273895609").isRight) + assertTrue(validation.validate("00 2162273895609").toEither.isRight) }, test("Regex phone number validation for Tonga") { val validation = PhoneNumberValidation.phoneNumberTO - assertTrue(validation.validate("00 6769802885047").isRight) + assertTrue(validation.validate("00 6769802885047").toEither.isRight) }, test("Regex phone number validation for Turkey") { val validation = PhoneNumberValidation.phoneNumberTR - assertTrue(validation.validate("00 90 8195268757").isRight) + assertTrue(validation.validate("00 90 8195268757").toEither.isRight) }, test("Regex phone number validation for Trinidad and Tobago") { val validation = PhoneNumberValidation.phoneNumberTT - assertTrue(validation.validate("011 1 868 432 464").isRight) + assertTrue(validation.validate("011 1 868 432 464").toEither.isRight) }, test("Regex phone number validation for Tuvalu") { val validation = PhoneNumberValidation.phoneNumberTV - assertTrue(validation.validate("+688 75 8858 5314").isRight) + assertTrue(validation.validate("+688 75 8858 5314").toEither.isRight) }, test("Regex phone number validation for Taiwan") { val validation = PhoneNumberValidation.phoneNumberTW - assertTrue(validation.validate("+886 35 6499 1065").isRight) + assertTrue(validation.validate("+886 35 6499 1065").toEither.isRight) }, test("Regex phone number validation for Tanzania") { val validation = PhoneNumberValidation.phoneNumberTZ - assertTrue(validation.validate("+255 0143374246").isRight) + assertTrue(validation.validate("+255 0143374246").toEither.isRight) }, test("Regex phone number validation for Ukraine") { val validation = PhoneNumberValidation.phoneNumberUA - assertTrue(validation.validate("00 380 8406262037").isRight) + assertTrue(validation.validate("00 380 8406262037").toEither.isRight) }, test("Regex phone number validation for Uganda") { val validation = PhoneNumberValidation.phoneNumberUG - assertTrue(validation.validate("+256 3856449691").isRight) + assertTrue(validation.validate("+256 3856449691").toEither.isRight) }, test("Regex phone number validation for US Minor Outlying Islands") { val validation = PhoneNumberValidation.phoneNumberUM - assertTrue(validation.validate("+1 929 131 901").isRight) + assertTrue(validation.validate("+1 929 131 901").toEither.isRight) }, test("Regex phone number validation for United States of America") { val validation = PhoneNumberValidation.phoneNumberUS - assertTrue(validation.validate("011 1 447142964").isRight) + assertTrue(validation.validate("011 1 447142964").toEither.isRight) }, test("Regex phone number validation for Uruguay") { val validation = PhoneNumberValidation.phoneNumberUY - assertTrue(validation.validate("00 598 0928779109").isRight) + assertTrue(validation.validate("00 598 0928779109").toEither.isRight) }, test("Regex phone number validation for Uzbekistan") { val validation = PhoneNumberValidation.phoneNumberUZ - assertTrue(validation.validate("00810 998 251 702 0097").isRight) + assertTrue(validation.validate("00810 998 251 702 0097").toEither.isRight) }, test("Regex phone number validation for Holy See (Vatican City State)") { val validation = PhoneNumberValidation.phoneNumberVA - assertTrue(validation.validate("+39 06698 10418").isRight) + assertTrue(validation.validate("+39 06698 10418").toEither.isRight) }, test("Regex phone number validation for Saint Vincent and Grenadines") { val validation = PhoneNumberValidation.phoneNumberVC - assertTrue(validation.validate("011 1 784 3314547").isRight) + assertTrue(validation.validate("011 1 784 3314547").toEither.isRight) }, test("Regex phone number validation for Venezuela") { val validation = PhoneNumberValidation.phoneNumberVE - assertTrue(validation.validate("+58 0161257166").isRight) + assertTrue(validation.validate("+58 0161257166").toEither.isRight) }, test("Regex phone number validation for British Virgin Islands") { val validation = PhoneNumberValidation.phoneNumberVG - assertTrue(validation.validate("011 1 284 966822").isRight) + assertTrue(validation.validate("011 1 284 966822").toEither.isRight) }, test("Regex phone number validation for Virgin Islands, US") { val validation = PhoneNumberValidation.phoneNumberVI - assertTrue(validation.validate("011 1 340 249394").isRight) + assertTrue(validation.validate("011 1 340 249394").toEither.isRight) }, test("Regex phone number validation for Viet Nam") { val validation = PhoneNumberValidation.phoneNumberVN - assertTrue(validation.validate("00 84 5582883606").isRight) + assertTrue(validation.validate("00 84 5582883606").toEither.isRight) }, test("Regex phone number validation for Vanuatu") { val validation = PhoneNumberValidation.phoneNumberVU - assertTrue(validation.validate("00 6786895604772").isRight) + assertTrue(validation.validate("00 6786895604772").toEither.isRight) }, test("Regex phone number validation for Wallis and Futuna Islands") { val validation = PhoneNumberValidation.phoneNumberWF - assertTrue(validation.validate("00 6816712124320").isRight) + assertTrue(validation.validate("00 6816712124320").toEither.isRight) }, test("Regex phone number validation for Samoa") { val validation = PhoneNumberValidation.phoneNumberWS - assertTrue(validation.validate("0 6856225946106").isRight) + assertTrue(validation.validate("0 6856225946106").toEither.isRight) }, test("Regex phone number validation for Kosovo") { val validation = PhoneNumberValidation.phoneNumberXK - assertTrue(validation.validate("00 383 4979043799").isRight) + assertTrue(validation.validate("00 383 4979043799").toEither.isRight) }, test("Regex phone number validation for Yemen") { val validation = PhoneNumberValidation.phoneNumberYE - assertTrue(validation.validate("00 967 8589630609").isRight) + assertTrue(validation.validate("00 967 8589630609").toEither.isRight) }, test("Regex phone number validation for Mayotte") { val validation = PhoneNumberValidation.phoneNumberYT - assertTrue(validation.validate("00 262 269 44 43 21").isRight) + assertTrue(validation.validate("00 262 269 44 43 21").toEither.isRight) }, test("Regex phone number validation for South Africa") { val validation = PhoneNumberValidation.phoneNumberZA - assertTrue(validation.validate("00 27 0081060414").isRight) + assertTrue(validation.validate("00 27 0081060414").toEither.isRight) }, test("Regex phone number validation for Zambia") { val validation = PhoneNumberValidation.phoneNumberZM - assertTrue(validation.validate("00 260 3563071452").isRight) + assertTrue(validation.validate("00 260 3563071452").toEither.isRight) }, test("Regex phone number validation for Zimbabwe") { val validation = PhoneNumberValidation.phoneNumberZW - assertTrue(validation.validate("+263 1141482994").isRight) + assertTrue(validation.validate("+263 1141482994").toEither.isRight) } ) } diff --git a/zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala b/zio-schema/shared/src/test/scala/zio/schema/validation/SchemaValidationSpec$.scala similarity index 77% rename from zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala rename to zio-schema/shared/src/test/scala/zio/schema/validation/SchemaValidationSpec$.scala index 22f0176bc..25a690e37 100644 --- a/zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala +++ b/zio-schema/shared/src/test/scala/zio/schema/validation/SchemaValidationSpec$.scala @@ -8,72 +8,72 @@ import scala.util.Try import zio.Scope import zio.test._ -object ValidationSpec extends ZIOSpecDefault { - import zio.schema.validation.ValidationSpec.Hour._ - import zio.schema.validation.ValidationSpec.Minute._ - import zio.schema.validation.ValidationSpec.Second._ - import zio.schema.validation.ValidationSpec.Fraction._ - import zio.schema.validation.ValidationSpec.AmPm._ +object SchemaValidationSpec extends ZIOSpecDefault { + import zio.schema.validation.SchemaValidationSpec.Hour._ + import zio.schema.validation.SchemaValidationSpec.Minute._ + import zio.schema.validation.SchemaValidationSpec.Second._ + import zio.schema.validation.SchemaValidationSpec.Fraction._ + import zio.schema.validation.SchemaValidationSpec.AmPm._ def spec: Spec[Environment with TestEnvironment with Scope, Any] = suite("ValidationSpec")( test("Greater than") { - val validation = Validation.greaterThan(4) + val validation = SchemaValidation.greaterThan(4) - assertTrue(validation.validate(4).isLeft) && - assertTrue(validation.validate(5).isRight) && - assertTrue(validation.validate(6).isRight) && - assertTrue(validation.validate(3).isLeft) + assertTrue(validation.validate(4).toEither.isLeft) && + assertTrue(validation.validate(5).toEither.isRight) && + assertTrue(validation.validate(6).toEither.isRight) && + assertTrue(validation.validate(3).toEither.isLeft) }, test("Less than") { - val validation = Validation.lessThan(4) + val validation = SchemaValidation.lessThan(4) - assertTrue(validation.validate(3).isRight) && - assertTrue(validation.validate(2).isRight) && - assertTrue(validation.validate(5).isLeft) && - assertTrue(validation.validate(4).isLeft) + assertTrue(validation.validate(3).toEither.isRight) && + assertTrue(validation.validate(2).toEither.isRight) && + assertTrue(validation.validate(5).toEither.isLeft) && + assertTrue(validation.validate(4).toEither.isLeft) }, test("Equal to") { - val validation = Validation.equalTo(3) + val validation = SchemaValidation.equalTo(3) - assertTrue(validation.validate(3).isRight) && - assertTrue(validation.validate(5).isLeft) && - assertTrue(validation.validate(2).isLeft) + assertTrue(validation.validate(3).toEither.isRight) && + assertTrue(validation.validate(5).toEither.isLeft) && + assertTrue(validation.validate(2).toEither.isLeft) }, test("MinLength") { - val validation = Validation.minLength(4) + val validation = SchemaValidation.minLength(4) - assertTrue(validation.validate("hello").isRight) && - assertTrue(validation.validate("Todd").isRight) && - assertTrue(validation.validate("how").isLeft) && - assertTrue(validation.validate("hi").isLeft) + assertTrue(validation.validate("hello").toEither.isRight) && + assertTrue(validation.validate("Todd").toEither.isRight) && + assertTrue(validation.validate("how").toEither.isLeft) && + assertTrue(validation.validate("hi").toEither.isLeft) }, test("MaxLength") { - val validation = Validation.maxLength(4) + val validation = SchemaValidation.maxLength(4) - assertTrue(validation.validate("Todd").isRight) && - assertTrue(validation.validate("how").isRight) && - assertTrue(validation.validate("hello").isLeft) && - assertTrue(validation.validate("Automobile").isLeft) + assertTrue(validation.validate("Todd").toEither.isRight) && + assertTrue(validation.validate("how").toEither.isRight) && + assertTrue(validation.validate("hello").toEither.isLeft) && + assertTrue(validation.validate("Automobile").toEither.isLeft) }, test("Regex digit or letter Validation") { - val validation = Validation.regex(Regex.digitOrLetter) - - assertTrue(validation.validate("a").isRight) && - assertTrue(validation.validate("1").isRight) && - assertTrue(validation.validate("12").isLeft) && - assertTrue(validation.validate("*").isLeft) && - assertTrue(validation.validate("ab").isLeft) && - assertTrue(validation.validate("").isLeft) && - assertTrue(validation.validate("&").isLeft) + val validation = SchemaValidation.regex(Regex.digitOrLetter) + + assertTrue(validation.validate("a").toEither.isRight) && + assertTrue(validation.validate("1").toEither.isRight) && + assertTrue(validation.validate("12").toEither.isLeft) && + assertTrue(validation.validate("*").toEither.isLeft) && + assertTrue(validation.validate("ab").toEither.isLeft) && + assertTrue(validation.validate("").toEither.isLeft) && + assertTrue(validation.validate("&").toEither.isLeft) }, test("Regex identifier Validation") { - val validation = Validation.identifier + val validation = SchemaValidation.identifier - assertTrue(validation.validate("_").isRight) && - assertTrue(validation.validate("a").isRight) && - assertTrue(validation.validate("ab").isRight) && - assertTrue(validation.validate("").isLeft) && - assertTrue(validation.validate("*").isLeft) + assertTrue(validation.validate("_").toEither.isRight) && + assertTrue(validation.validate("a").toEither.isRight) && + assertTrue(validation.validate("ab").toEither.isRight) && + assertTrue(validation.validate("").toEither.isLeft) && + assertTrue(validation.validate("*").toEither.isLeft) }, suite("Regex email Validation")( test("should reject an invalid email") { @@ -101,10 +101,10 @@ object ValidationSpec extends ZIOSpecDefault { "postmaster@[2001:cdba:0:0:0:0:3257:9652]" ) } - val validationResult = (value: String) => Validation.email.validate(value) + val validationResult = (value: String) => SchemaValidation.email.validate(value) checkAll(examples) { email => - assertTrue(validationResult(email).isLeft) + assertTrue(validationResult(email).toEither.isLeft) } }, test("should accept a correct email") { @@ -124,10 +124,10 @@ object ValidationSpec extends ZIOSpecDefault { "postmaster@[IPv6:2001:cdba:0:0:0:0:3257:9652]" ) } - val validationResult = (value: String) => Validation.email.validate(value) + val validationResult = (value: String) => SchemaValidation.email.validate(value) checkAll(examples) { email => - assertTrue(validationResult(email).isRight) + assertTrue(validationResult(email).toEither.isRight) } } ), @@ -149,10 +149,10 @@ object ValidationSpec extends ZIOSpecDefault { ) } - val validationResult = (value: String) => Validation.ipV4.validate(value) + val validationResult = (value: String) => SchemaValidation.ipV4.validate(value) checkAll(examples) { ip => - assertTrue(validationResult(ip).isRight) + assertTrue(validationResult(ip).toEither.isRight) } }, test("should reject an invalid IPv4 address") { @@ -166,10 +166,10 @@ object ValidationSpec extends ZIOSpecDefault { ) } - val validationResult = (value: String) => Validation.ipV4.validate(value) + val validationResult = (value: String) => SchemaValidation.ipV4.validate(value) checkAll(examples) { ip => - assertTrue(validationResult(ip).isLeft) + assertTrue(validationResult(ip).toEither.isLeft) } } ), @@ -194,10 +194,10 @@ object ValidationSpec extends ZIOSpecDefault { ) } - val validationResult = (value: String) => Validation.ipV6.validate(value) + val validationResult = (value: String) => SchemaValidation.ipV6.validate(value) checkAll(examples) { ip => - assertTrue(validationResult(ip).isRight) + assertTrue(validationResult(ip).toEither.isRight) } }, test("should reject an invalid IPv6 address") { @@ -209,26 +209,26 @@ object ValidationSpec extends ZIOSpecDefault { ) } - val validationResult = (value: String) => Validation.ipV6.validate(value) + val validationResult = (value: String) => SchemaValidation.ipV6.validate(value) checkAll(examples) { ip => - assertTrue(validationResult(ip).isLeft) + assertTrue(validationResult(ip).toEither.isLeft) } } ), suite("Regex uuid Validations")( test("valid UUID") { - val validation = Validation.uuidV4 + val validation = SchemaValidation.uuidV4 check(Gen.uuid) { uuid => - assertTrue(validation.validate(uuid.toString).isRight) + assertTrue(validation.validate(uuid.toString).toEither.isRight) } }, test("invalid UUID") { - val validation = Validation.uuidV4 - assertTrue(validation.validate("1e3118de-ddb6-11ec-8653-93e6961d46be").isLeft) && - assertTrue(validation.validate("487f5075-fa89-4723-a26d-2e7a13245").isLeft) && - assertTrue(validation.validate("487f5075fa894723a26d2e7a13245135").isLeft) && - assertTrue(validation.validate("").isLeft) + val validation = SchemaValidation.uuidV4 + assertTrue(validation.validate("1e3118de-ddb6-11ec-8653-93e6961d46be").toEither.isLeft) && + assertTrue(validation.validate("487f5075-fa89-4723-a26d-2e7a13245").toEither.isLeft) && + assertTrue(validation.validate("487f5075fa894723a26d2e7a13245135").toEither.isLeft) && + assertTrue(validation.validate("").toEither.isLeft) } ), test("Time Validation HH") { @@ -328,7 +328,7 @@ object ValidationSpec extends ZIOSpecDefault { }, test("Regex duration Validation") { check(Gen.finiteDuration) { duration => - assertTrue(Validation.duration.validate(duration.toString).isRight) + assertTrue(SchemaValidation.duration.validate(duration.toString).toEither.isRight) } } ) @@ -354,12 +354,12 @@ object ValidationSpec extends ZIOSpecDefault { private def parseTimes(createTimesConfig: CreateTimesConfig, format: String): ParsedTimes = { val times = createTimes(exampleTimes, createTimesConfig) val wrongTimes = createTimes(wrongExampleTimes, createTimesConfig) - val validation = Validation.time(format) + val validation = SchemaValidation.time(format) val formatter = DateTimeFormatter.ofPattern(format, Locale.US) def innerParse(times: Seq[String]) = times.map { time => - val valid = validation.validate(time).isRight + val valid = validation.validate(time).toEither.isRight val parsed = Try(formatter.parse(time)).isSuccess ParsedTime(time, valid, parsed) } diff --git a/zio-schema/shared/src/test/scala/zio/schema/validation/TimeSpec.scala b/zio-schema/shared/src/test/scala/zio/schema/validation/TimeSpec.scala index cac22bc68..0eaba92ed 100644 --- a/zio-schema/shared/src/test/scala/zio/schema/validation/TimeSpec.scala +++ b/zio-schema/shared/src/test/scala/zio/schema/validation/TimeSpec.scala @@ -8,48 +8,48 @@ object TimeSpec extends ZIOSpecDefault { def spec: Spec[Environment with TestEnvironment with Scope, Any] = suite("TimeSpec")( test("Valid formats") { - assert(Validation.time("H"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HH"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("h"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("hh"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("m"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("mm"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("s"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("ss"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("S"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("SS"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("SSS"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("SSSSSSSSS"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HHmm"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("H:m"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("H:m a"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HH:mm"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HH:mm a"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HHmmss"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HH:mm:ss"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HH:mm:ssa"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("HH:mm:ss a"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("a HH:mm:ss"))(isSubtype[Validation[String]](anything)) && - assert(Validation.time("H:m:s a"))(isSubtype[Validation[String]](anything)) + assert(SchemaValidation.time("H"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HH"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("h"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("hh"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("m"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("mm"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("s"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("ss"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("S"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("SS"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("SSS"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("SSSSSSSSS"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HHmm"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("H:m"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("H:m a"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HH:mm"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HH:mm a"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HHmmss"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HH:mm:ss"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HH:mm:ssa"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("HH:mm:ss a"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("a HH:mm:ss"))(isSubtype[SchemaValidation[String]](anything)) && + assert(SchemaValidation.time("H:m:s a"))(isSubtype[SchemaValidation[String]](anything)) }, test("Invalid formats") { - assert(Validation.time("HHH"))(throws(hasMessage(containsString("max length for")))) && - assert(Validation.time("hhh"))(throws(hasMessage(containsString("max length for")))) && - assert(Validation.time("mmm"))(throws(hasMessage(containsString("max length for")))) && - assert(Validation.time("sss"))(throws(hasMessage(containsString("max length for")))) && - assert(Validation.time("SSSSSSSSSS"))(throws(hasMessage(containsString("max length for")))) && - assert(Validation.time("aa"))(throws(hasMessage(containsString("max length for")))) && - assert(Validation.time("HHmmH"))(throws(hasMessage(containsString("already used in format")))) && - assert(Validation.time("HHmmsm"))(throws(hasMessage(containsString("already used in format")))) && - assert(Validation.time("hhmmhh"))(throws(hasMessage(containsString("already used in format")))) && - assert(Validation.time("a HH:mm:s a"))(throws(hasMessage(containsString("already used in format")))) && - assert(Validation.time("HH:mm:ss.SS S"))(throws(hasMessage(containsString("already used in format")))) && - assert(Validation.time(":"))(throws(hasMessage(containsString("There is no time field")))) && - assert(Validation.time("b"))(throws(hasMessage(containsString("All letters are reserved")))) && - assert(Validation.time("j"))(throws(hasMessage(containsString("All letters are reserved")))) && - assert(Validation.time("B"))(throws(hasMessage(containsString("All letters are reserved")))) && - assert(Validation.time("J"))(throws(hasMessage(containsString("All letters are reserved")))) && - assert(Validation.time(""))(throws(hasMessage(containsString("There is no time field")))) + assert(SchemaValidation.time("HHH"))(throws(hasMessage(containsString("max length for")))) && + assert(SchemaValidation.time("hhh"))(throws(hasMessage(containsString("max length for")))) && + assert(SchemaValidation.time("mmm"))(throws(hasMessage(containsString("max length for")))) && + assert(SchemaValidation.time("sss"))(throws(hasMessage(containsString("max length for")))) && + assert(SchemaValidation.time("SSSSSSSSSS"))(throws(hasMessage(containsString("max length for")))) && + assert(SchemaValidation.time("aa"))(throws(hasMessage(containsString("max length for")))) && + assert(SchemaValidation.time("HHmmH"))(throws(hasMessage(containsString("already used in format")))) && + assert(SchemaValidation.time("HHmmsm"))(throws(hasMessage(containsString("already used in format")))) && + assert(SchemaValidation.time("hhmmhh"))(throws(hasMessage(containsString("already used in format")))) && + assert(SchemaValidation.time("a HH:mm:s a"))(throws(hasMessage(containsString("already used in format")))) && + assert(SchemaValidation.time("HH:mm:ss.SS S"))(throws(hasMessage(containsString("already used in format")))) && + assert(SchemaValidation.time(":"))(throws(hasMessage(containsString("There is no time field")))) && + assert(SchemaValidation.time("b"))(throws(hasMessage(containsString("All letters are reserved")))) && + assert(SchemaValidation.time("j"))(throws(hasMessage(containsString("All letters are reserved")))) && + assert(SchemaValidation.time("B"))(throws(hasMessage(containsString("All letters are reserved")))) && + assert(SchemaValidation.time("J"))(throws(hasMessage(containsString("All letters are reserved")))) && + assert(SchemaValidation.time(""))(throws(hasMessage(containsString("There is no time field")))) } ) }