Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: adding currency support #680

Merged
merged 29 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
43a91df
initial version
Andrapyre May 3, 2024
fc75b5f
initial test modifications
Andrapyre May 3, 2024
9253c10
fixing tests
Andrapyre May 4, 2024
cdd623a
adding more tests and revising docs
Andrapyre May 4, 2024
7b36d3f
fixing formatting
Andrapyre May 4, 2024
77832e2
updating readme
Andrapyre May 4, 2024
f662459
Revert "updating readme"
Andrapyre May 4, 2024
ee8b536
fixing tests
Andrapyre May 4, 2024
7feb43e
fixing json codec test again
Andrapyre May 4, 2024
34fc06c
removing json currency tests
Andrapyre May 4, 2024
7730b44
staging
Andrapyre May 5, 2024
18a8243
removing zone offset
Andrapyre May 5, 2024
8b880c1
fixing null locale
Andrapyre May 5, 2024
197010c
adding ci
Andrapyre May 5, 2024
e0d42a4
Revert "adding ci"
Andrapyre May 5, 2024
de36381
removing comparison in currency standard type
Andrapyre May 5, 2024
7f9e292
adding platform specific tests
Andrapyre May 5, 2024
d331c6b
Revert "removing comparison in currency standard type"
Andrapyre May 5, 2024
83c8fb9
fixing formatting and error handling
Andrapyre May 6, 2024
991dabb
fixing linting
Andrapyre May 6, 2024
779c090
fixing currency tests
Andrapyre May 6, 2024
a93108c
adding docs
Andrapyre May 7, 2024
2429473
fixing bug in patch law and adding tests
Andrapyre May 7, 2024
5dd4666
revising doc generator and adding test types
Andrapyre May 8, 2024
1b8b915
updating readme
Andrapyre May 9, 2024
fb83abb
fixing default currency value
Andrapyre May 9, 2024
acf9f40
revising docs
Andrapyre May 9, 2024
1cb746a
finalizing after self-review
Andrapyre May 10, 2024
76e7b6c
fixing broken default currency test
Andrapyre May 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ _ZIO Schema_ is used by a growing number of ZIO libraries, including [ZIO Flow](
In order to use this library, we need to add the following lines in our `build.sbt` file:

```scala
libraryDependencies += "dev.zio" %% "zio-schema" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-avro" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-bson" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-json" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-msg-pack" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-protobuf" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-thrift" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-zio-test" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-avro" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-bson" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-json" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-msg-pack" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-protobuf" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-thrift" % "1.1.1"
libraryDependencies += "dev.zio" %% "zio-schema-zio-test" % "1.1.1"

// Required for the automatic generic derivation of schemas
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % "1.1.0"
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % "1.1.1"
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided"
```

Expand Down
4 changes: 4 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,10 @@ lazy val docs = project
mainModuleName := (zioSchemaJVM / moduleName).value,
projectStage := ProjectStage.Development,
ScalaUnidoc / unidoc / unidocProjectFilter := inProjects(),
mdoc := {
(Compile / run).evaluated
mdoc.evaluated
},
readmeContribution +=
"""|
|#### TL;DR
Expand Down
13 changes: 2 additions & 11 deletions docs/basic-building-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,10 @@ To describe scalar data type `A`, we use the `Primitive[A]` data type which basi
case class Primitive[A](standardType: StandardType[A]) extends Schema[A]
```

Primitive values are represented using the `Primitive[A]` type class and represent the elements, that we cannot further define through other means. If we visualize our data structure as a tree, primitives are the leaves.
Primitive values are represented using the `Primitive[A]` type class and represent the elements that we cannot further define through other means. If we visualize our data structure as a tree, primitives are the leaves.

ZIO Schema provides a number of built-in primitive types, that we can use to represent our data. These can be found in the [`StandardType`](https://github.com/zio/zio-schema/blob/main/zio-schema/shared/src/main/scala/zio/schema/StandardType.scala) companion-object:
For a list of all standard types (and therefore primitive types) with built-in support, please see the [standard type reference](standard-type-reference.md)

```scala
sealed trait StandardType[A]
object StandardType {
implicit object UnitType extends StandardType[Unit]
implicit object StringType extends StandardType[String]
implicit object BoolType extends StandardType[Boolean]
// ...
}
```

Inside `Schema`'s companion object, we have an implicit conversion from `StandardType[A]` to `Schema[A]`:

Expand Down
1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const sidebars = {
"motivation",
"use-cases",
"basic-building-blocks",
"standard-type-reference",
{
type: "category",
label: "Writing Schema",
Expand Down
41 changes: 41 additions & 0 deletions docs/standard-type-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
id: standard-type-reference
title: "Standard Type Reference"
---
# Standard Type Reference

ZIO Schema provides a number of built-in primitive types, that we can use to represent our data. These can be seen in the following table:

|Standard Type|JVM Support|ScalaJS Support|Scala Native Support|
|--------------|:--------------:|:--------------:|:--------------:|
|`Boolean`|✅|✅|✅|
|`Byte`|✅|✅|✅|
|`Char`|✅|✅|✅|
|`Chunk[Byte]`|✅|✅|✅|
|`Double`|✅|✅|✅|
|`Float`|✅|✅|✅|
|`Int`|✅|✅|✅|
|`Long`|✅|✅|✅|
|`Short`|✅|✅|✅|
|`String`|✅|✅|✅|
|`Unit`|✅|✅|✅|
|`java.math.BigDecimal`|✅|✅|✅|
|`java.math.BigInteger`|✅|✅|✅|
|`java.time.DayOfWeek`|✅|✅|✅|
|`java.time.Duration`|✅|✅|✅|
|`java.time.Instant`|✅|✅|✅|
|`java.time.LocalDate`|✅|✅|✅|
|`java.time.LocalDateTime`|✅|✅|✅|
|`java.time.LocalTime`|✅|✅|✅|
|`java.time.Month`|✅|✅|✅|
|`java.time.MonthDay`|✅|✅|✅|
|`java.time.OffsetDateTime`|✅|✅|✅|
|`java.time.OffsetTime`|✅|✅|✅|
|`java.time.Period`|✅|✅|✅|
|`java.time.Year`|✅|✅|✅|
|`java.time.YearMonth`|✅|✅|✅|
|`java.time.ZoneId`|✅|✅|✅|
|`java.time.ZoneOffset`|✅|✅|✅|
|`java.time.ZonedDateTime`|✅|✅|✅|
|`java.util.Currency`|✅|❌|❌|
|`java.util.UUID`|✅|❌|✅|
19 changes: 19 additions & 0 deletions tests/js/src/test/scala-2/zio/schema/PlatformSpecificGen.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package zio.schema

import zio.schema.SchemaGen.SchemaTest
import zio.schema.StandardTypeGen.StandardTypeAndGen
import zio.test.Gen

object PlatformSpecificGen {

val platformSpecificStandardTypes: Gen[Any, StandardType[_]] = Gen.fromIterable(
List.empty
)

def platformSpecificStandardTypeAndGen(standardTypeGen: StandardType[_]): StandardTypeAndGen[_] =
standardTypeGen match {
case _ => StandardType.UnitType -> Gen.unit: StandardTypeAndGen[_]
}

val platformSpecificSchemasAndGens: List[SchemaTest[_]] = List.empty
}
24 changes: 24 additions & 0 deletions tests/jvm/src/test/scala-2/zio/schema/PlatformSpecificGen.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package zio.schema

import zio.schema.SchemaGen.SchemaTest
import zio.schema.StandardTypeGen.StandardTypeAndGen
import zio.test.Gen

object PlatformSpecificGen {

val platformSpecificStandardTypes: Gen[Any, StandardType[_]] = Gen.fromIterable(
List(
StandardType.CurrencyType
)
)

def platformSpecificStandardTypeAndGen(standardTypeGen: StandardType[_]): StandardTypeAndGen[_] =
standardTypeGen match {
case typ: StandardType.CurrencyType.type => typ -> Gen.currency
case _ => StandardType.UnitType -> Gen.unit: StandardTypeAndGen[_]
}

val platformSpecificSchemasAndGens: List[SchemaTest[_]] = List(
SchemaTest("Currency", StandardType.CurrencyType, Gen.currency)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package zio.schema

import zio.schema.SchemaGen.SchemaTest
import zio.schema.StandardTypeGen.StandardTypeAndGen
import zio.test.Gen

object PlatformSpecificGen {

val platformSpecificStandardTypes: Gen[Any, StandardType[_]] = Gen.fromIterable(
List.empty
)

def platformSpecificStandardTypeAndGen(standardTypeGen: StandardType[_]): StandardTypeAndGen[_] =
standardTypeGen match {
case _ => StandardType.UnitType -> Gen.unit: StandardTypeAndGen[_]
}

val platformSpecificSchemasAndGens: List[SchemaTest[_]] = List.empty
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ object DynamicValueGen {
case typ: StandardType.ZoneOffsetType.type => gen(typ, JavaTimeGen.anyZoneOffset)
case typ: StandardType.UnitType.type => Gen.const(DynamicValue.Primitive((), typ))
case typ: StandardType.UUIDType.type => gen(typ, Gen.uuid)
case typ: StandardType.CurrencyType.type => gen(typ, Gen.currency)
}
}

Expand Down
158 changes: 72 additions & 86 deletions tests/shared/src/test/scala-2/zio/schema/PatchSpec.scala
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
package zio.schema

import zio.schema.StandardType._
import zio.schema.DeriveSchema.gen
import zio.schema.SchemaGen.{ SchemaTest, schemasAndGens }
import zio.schema.types.Arities._
import zio.schema.types.{ Arities, Recursive }
import zio.test.Assertion._
import zio.test._
import zio.{ Chunk, Scope, URIO }
import zio.{ Scope, URIO }

object PatchSpec extends ZIOSpecDefault {

def spec: Spec[TestEnvironment with Scope, Any] = suite("PatchSpec")(
suite("identity law")(
suite("standard types")(
test("Int")(patchIdentityLaw[Int]),
test("Long")(patchIdentityLaw[Long]),
test("Float")(patchIdentityLaw[Float]),
test("Double")(patchIdentityLaw[Double]),
test("Boolean")(patchIdentityLaw[Boolean]),
test("Bytes")(patchIdentityLaw[Chunk[Byte]]),
suite("Either") {
test("primitive")(patchIdentityLaw[Either[String, String]])
},
suite("Option") {
test("primitive")(patchIdentityLaw[Option[String]])
}
schemaPatchIdentityLawTests()
),
suite("option")(
schemaPatchIdentityLawTests(Some(schema => Schema.option(schema)))
),
suite("either")(
schemaPatchIdentityLawTests(Some(schema => Schema.either(schema, schema)), Some(name => s"Either[$name,$name]"))
),
suite("records")(
test("singleton")(patchIdentityLaw[Singleton.type]),
Expand All @@ -39,56 +35,17 @@ object PatchSpec extends ZIOSpecDefault {
),
suite("patch law")(
suite("standard types")(
test("Int")(patchLaw[Int]),
test("Long")(patchLaw[Long]),
test("Float")(patchLaw[Float]),
test("Double")(patchLaw[Double]),
test("Boolean")(patchLaw[Boolean]),
test("String")(patchLaw[String]),
test("ZonedDateTime")(patchLaw[java.time.ZonedDateTime]),
test("OffsetDateTime")(patchLaw[java.time.OffsetDateTime]),
test("OffsetTime")(patchLaw[java.time.OffsetTime]),
test("LocalTime")(patchLaw[java.time.LocalTime]),
test("LocalDate")(patchLaw[java.time.LocalDate]),
test("Instant")(patchLaw[java.time.Instant]),
test("Duration")(patchLaw[java.time.Duration]),
test("ZoneOffset")(patchLaw[java.time.ZoneOffset]),
test("ZoneId")(patchLaw[java.time.ZoneId]),
test("YearMonth")(patchLaw[java.time.YearMonth]),
test("Year")(patchLaw[java.time.Year]),
test("Period")(patchLaw[java.time.Period]),
test("MonthDay")(patchLaw[java.time.MonthDay]) @@ TestAspect.ignore, // TODO Leap years!
test("Month")(patchLaw[java.time.Month]),
test("DayOfWeek")(patchLaw[java.time.DayOfWeek]),
test("BigInteger")(patchLaw[java.math.BigInteger]),
test("BigDecimal")(patchLaw[java.math.BigDecimal]),
test("Bytes")(patchLaw[Chunk[Byte]])
schemaPatchLawTests()
),
suite("option")(
schemaPatchLawTests(Some(schema => Schema.option(schema)))
),
suite("sequences")(
suite("either")(
schemaPatchLawTests(Some(schema => Schema.either(schema, schema)), Some(name => s"Either[$name,$name]"))
),
suite("lists")(
suite("of standard types")(
test("Int")(patchLaw[List[Int]]),
test("Long")(patchLaw[List[Long]]),
test("Float")(patchLaw[List[Float]]),
test("Double")(patchLaw[List[Double]]),
test("Boolean")(patchLaw[List[Boolean]]),
test("String")(patchLaw[List[String]]),
test("ZonedDateTime")(patchLaw[List[java.time.ZonedDateTime]]),
test("OffsetDateTime")(patchLaw[List[java.time.OffsetDateTime]]),
test("OffsetTime")(patchLaw[List[java.time.OffsetTime]]),
test("LocalTime")(patchLaw[List[java.time.LocalTime]]),
test("LocalDate")(patchLaw[List[java.time.LocalDate]]),
test("Instant")(patchLaw[List[java.time.Instant]]),
test("Duration")(patchLaw[List[java.time.Duration]]),
test("ZoneOffset")(patchLaw[List[java.time.ZoneOffset]]),
test("ZoneId")(patchLaw[List[java.time.ZoneId]]),
test("YearMonth")(patchLaw[List[java.time.YearMonth]]),
test("Year")(patchLaw[List[java.time.Year]]),
test("Period")(patchLaw[List[java.time.Period]]),
test("MonthDay")(patchLaw[List[java.time.MonthDay]]) @@ TestAspect.ignore, // TODO Leap years!
test("Month")(patchLaw[List[java.time.Month]]),
test("DayOfWeek")(patchLaw[List[java.time.DayOfWeek]]),
test("BigInteger")(patchLaw[List[java.math.BigInteger]]),
test("BigDecimal")(patchLaw[List[java.math.BigDecimal]])
schemaPatchLawTests(Some((primitiveSchema => Schema.list(primitiveSchema))))
),
suite("of records")(
test("Dog")(patchLaw[List[Pet.Dog]])
Expand All @@ -98,31 +55,21 @@ object PatchSpec extends ZIOSpecDefault {
test("recursive")(patchLaw[List[Recursive]])
)
),
suite("vectors")(
suite("of standard types")(
schemaPatchLawTests(Some((primitiveSchema => Schema.vector(primitiveSchema))))
),
suite("of records")(
test("Dog")(patchLaw[Vector[Pet.Dog]])
),
suite("of enumerations")(
test("Pet")(patchLaw[Vector[Pet]]),
test("recursive")(patchLaw[Vector[Recursive]])
)
),
suite("sets")(
suite("of standard types")(
test("Int")(patchLaw[Set[Int]]),
test("Long")(patchLaw[Set[Long]]),
test("Float")(patchLaw[Set[Float]]),
test("Double")(patchLaw[Set[Double]]),
test("Boolean")(patchLaw[Set[Boolean]]),
test("String")(patchLaw[Set[String]]),
test("ZonedDateTime")(patchLaw[Set[java.time.ZonedDateTime]]),
test("OffsetDateTime")(patchLaw[Set[java.time.OffsetDateTime]]),
test("OffsetTime")(patchLaw[Set[java.time.OffsetTime]]),
test("LocalTime")(patchLaw[Set[java.time.LocalTime]]),
test("LocalDate")(patchLaw[Set[java.time.LocalDate]]),
test("Instant")(patchLaw[Set[java.time.Instant]]),
test("Duration")(patchLaw[Set[java.time.Duration]]),
test("ZoneOffset")(patchLaw[Set[java.time.ZoneOffset]]),
test("ZoneId")(patchLaw[Set[java.time.ZoneId]]),
test("YearMonth")(patchLaw[Set[java.time.YearMonth]]),
test("Year")(patchLaw[Set[java.time.Year]]),
test("Period")(patchLaw[Set[java.time.Period]]),
test("MonthDay")(patchLaw[Set[java.time.MonthDay]]) @@ TestAspect.ignore, // TODO Leap years!
test("Month")(patchLaw[Set[java.time.Month]]),
test("DayOfWeek")(patchLaw[Set[java.time.DayOfWeek]]),
test("BigInteger")(patchLaw[Set[java.math.BigInteger]]),
test("BigDecimal")(patchLaw[Set[java.math.BigDecimal]])
schemaPatchLawTests(Some((primitiveSchema => Schema.set(primitiveSchema))))
),
suite("of records")(
test("Dog")(patchLaw[Set[Pet.Dog]])
Expand All @@ -134,7 +81,10 @@ object PatchSpec extends ZIOSpecDefault {
),
suite("maps")(
suite("of standard types")(
test("Int -> Int")(patchLaw[Map[Int, Int]])
schemaPatchLawTests(
Some((primitiveSchema => Schema.map(primitiveSchema, primitiveSchema))),
Some(name => (s"$name -> $name"))
)
),
suite("of records")(
test("Int -> Dog")(patchLaw[Map[Int, Pet.Dog]]),
Expand Down Expand Up @@ -173,6 +123,42 @@ object PatchSpec extends ZIOSpecDefault {
assertTrue(schema.diff(a, a).isIdentical)
}

private def schemaPatchIdentityLawTests(
schemaConversionFuncOption: Option[Schema[_] => Schema[_]] = None,
renamingFuncOption: Option[String => String] = None
): List[Spec[Sized with TestConfig, Nothing]] =
schemaPatchTests(schema => patchIdentityLaw(schema), schemaConversionFuncOption, renamingFuncOption)

private def schemaPatchLawTests(
schemaConversionFuncOption: Option[Schema[_] => Schema[_]] = None,
renamingFuncOption: Option[String => String] = None
): List[Spec[Sized with TestConfig, Nothing]] =
schemaPatchTests(schema => patchLaw(schema), schemaConversionFuncOption, renamingFuncOption)

private def schemaPatchTests(
patchingFunc: Schema[_] => URIO[Sized with TestConfig, TestResult],
schemaConversionFuncOption: Option[Schema[_] => Schema[_]],
renamingFuncOption: Option[String => String]
): List[Spec[Sized with TestConfig, Nothing]] =
schemasAndGens.map {
case SchemaTest(name, standardType, _) =>
val primitiveSchema = Schema.primitive(standardType)
val finalSchema = schemaConversionFuncOption.fold[Schema[_]](primitiveSchema) { schemaConversionFunc =>
schemaConversionFunc(primitiveSchema)
}
val finalTestName = renamingFuncOption.fold(name)(renamingFunc => renamingFunc(name))
standardType match {
case _ @StandardType.MonthDayType =>
test(finalTestName) {
patchingFunc(finalSchema)
} @@ TestAspect.ignore // TODO Leap years!
case _ =>
test(finalTestName) {
patchingFunc(finalSchema)
}
}
}

private def patchLaw[A](implicit schema: Schema[A]): URIO[Sized with TestConfig, TestResult] = {
val gen = DeriveGen.gen[A]
check(gen <*> gen) {
Expand Down
Loading
Loading