Skip to content

Commit 0e06f98

Browse files
authored
Revamping Documentation: Enhancing, Restructuring and Covering More Topics (#581)
* refactor docs. * add manual and automatic derivation. * integration with zio streams. * add more packages to installation section. * add comment for fail constructor. * primitives. * transforming schemas. * sequence section. * map collection. * schema for set collection. * record section. * add case class section. * refactor. * generic record. * either. * enumeration. * chunk and vector. * fail. * tuples. * update readme. * refactor sidebars. * add more resources for zio schema. * getting the default value of a schema. * sidebar label for operations. * reorder sidebar items. * generate ordering for schemas. * fix mdoc errors. * diffing and patching. * automatic migration. * schema serialization. * fix typo. * add more resources. * mapping dto to domain object. * example for Schema#migrate method. * improve sentences. * add nuttycombe talk to resource section. * dynamic data representation. * dynamic value migration. * schema migration. * derive ordering. * separate article for getting the default value. * separate article for diffing and patching. * separate other articles. * validation section. * update dynamic data representation article. * reified optics. * avro codecs. * add bson codecs. * improve apache avro doc. * add zio-schema-bson to doc's dependencies. * add json codec article. * add message pack section. * add protobuf section. * update message pack. * add apache thrift section to codecs. * refactor. * refactor. * organize sidebar. * overview of all operations. * update introduction section. * update readme. * update readme. * update readme.
1 parent aa0770e commit 0e06f98

33 files changed

+2782
-633
lines changed

README.md

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,76 +10,93 @@
1010

1111
## Introduction
1212

13-
Schema is a structure of a data type. ZIO Schema reifies the concept of structure for data types. It makes a high-level description of any data type and makes them as first-class values.
13+
ZIO Schema helps us to solve some of the most common problems in distributed computing, such as serialization, deserialization, and data migration.
14+
15+
It turns a compiled-time construct (the type of a data structure) into a runtime construct (a value that can be read, manipulated, and composed at runtime). A schema is a structure of a data type. ZIO Schema reifies the concept of structure for data types. It makes a high-level description of any data type and makes them first-class values.
1416

1517
Creating a schema for a data type helps us to write codecs for that data type. So this library can be a host of functionalities useful for writing codecs and protocols like JSON, Protobuf, CSV, and so forth.
1618

17-
With schema descriptions that can be automatically derived for case classes and sealed traits, _ZIO Schema_ will be going to provide powerful features for free (Note that the project is in the development stage and all these features are not supported yet):
19+
## What Problems Does ZIO Schema Solve?
20+
21+
With schema descriptions that can be automatically derived for case classes and sealed traits, _ZIO Schema_ will be going to provide powerful features for free:
1822

19-
- Codecs for any supported protocol (JSON, protobuf, etc.), so data structures can be serialized and deserialized in a principled way
20-
- Diffing, patching, merging, and other generic-data-based operations
21-
- Migration of data structures from one schema to another compatible schema
22-
- Derivation of arbitrary type classes (`Eq`, `Show`, `Ord`, etc.) from the structure of the data
23+
1. Metaprogramming without macros, reflection, or complicated implicit derivations.
24+
1. Creating serialization and deserialization codecs for any supported protocol (JSON, Protobuf, etc.)
25+
2. Deriving standard type classes (`Eq`, `Show`, `Ordering`, etc.) from the structure of the data
26+
3. Default values for data types
27+
2. Automate ETL (Extract, Transform, Load) pipelines
28+
1. Diffing: diffing between two values of the same type
29+
2. Patching: applying a diff to a value to update it
30+
3. Migration: migrating values from one type to another
31+
3. Computations as data: Not only we can turn types into values, but we can also turn computations into values. This opens up a whole new world of possibilities concerning distributed computing.
2332

2433
When our data structures need to be serialized, deserialized, persisted, or transported across the wire, then _ZIO Schema_ lets us focus on data modeling and automatically tackle all the low-level, messy details for us.
2534

26-
_ZIO Schema_ is used by a growing number of ZIO libraries, including _ZIO Flow_, _ZIO Redis_, _ZIO Web_, _ZIO SQL_ and _ZIO DynamoDB_.
35+
_ZIO Schema_ is used by a growing number of ZIO libraries, including [ZIO Flow](https://zio.dev/zio-flow), [ZIO Redis](https://zio-redis), [ZIO SQL](https://zio.dev/zio-sql) and [ZIO DynamoDB](https://zio.dev/zio-dynamodb).
2736

2837
## Installation
2938

3039
In order to use this library, we need to add the following lines in our `build.sbt` file:
3140

3241
```scala
33-
libraryDependencies += "dev.zio" %% "zio-schema" % "0.4.13"
34-
libraryDependencies += "dev.zio" %% "zio-schema-bson" % "0.4.13"
35-
libraryDependencies += "dev.zio" %% "zio-schema-json" % "0.4.13"
36-
libraryDependencies += "dev.zio" %% "zio-schema-protobuf" % "0.4.13"
37-
38-
// Required for automatic generic derivation of schemas
39-
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % "0.4.13",
42+
libraryDependencies += "dev.zio" %% "zio-schema" % "0.4.14"
43+
libraryDependencies += "dev.zio" %% "zio-schema-avro" % "0.4.14"
44+
libraryDependencies += "dev.zio" %% "zio-schema-bson" % "0.4.14"
45+
libraryDependencies += "dev.zio" %% "zio-schema-json" % "0.4.14"
46+
libraryDependencies += "dev.zio" %% "zio-schema-msg-pack" % "0.4.14"
47+
libraryDependencies += "dev.zio" %% "zio-schema-protobuf" % "0.4.14"
48+
libraryDependencies += "dev.zio" %% "zio-schema-thrift" % "0.4.14"
49+
libraryDependencies += "dev.zio" %% "zio-schema-zio-test" % "0.4.14"
50+
51+
// Required for the automatic generic derivation of schemas
52+
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % "0.4.14"
4053
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided"
4154
```
4255

4356
## Example
4457

45-
In this simple example first, we create a schema for `Person` and then run the _diff_ operation on two instances of the `Person` data type, and finally we encode a Person instance using _Protobuf_ protocol:
58+
In this simple example first, we create a schema for `Person` and then run the _diff_ operation on two instances of the `Person` data type, and finally, we encode a Person instance using _Protobuf_ protocol:
4659

4760
```scala
48-
import zio.console.putStrLn
49-
import zio.schema.codec.ProtobufCodec._
61+
import zio._
62+
import zio.stream._
63+
import zio.schema.codec.{BinaryCodec, ProtobufCodec}
5064
import zio.schema.{DeriveSchema, Schema}
51-
import zio.stream.ZStream
52-
import zio.{Chunk, ExitCode, URIO}
5365

54-
final case class Person(name: String, age: Int, id: String)
66+
final case class Person(name: String, age: Int)
67+
5568
object Person {
56-
implicit val schema: Schema[Person] = DeriveSchema.gen[Person]
69+
implicit val schema: Schema[Person] = DeriveSchema.gen
70+
val protobufCodec: BinaryCodec[Person] = ProtobufCodec.protobufCodec
5771
}
5872

59-
Person.schema
60-
61-
import zio.schema.syntax._
62-
63-
Person("Alex", 31, "0123").diff(Person("Alex", 31, "124"))
73+
object Main extends ZIOAppDefault {
74+
def run =
75+
ZStream
76+
.succeed(Person("John", 43))
77+
.via(Person.protobufCodec.streamEncoder)
78+
.runCollect
79+
.flatMap(x =>
80+
Console.printLine(s"Encoded data with protobuf codec: ${toHex(x)}")
81+
)
82+
83+
def toHex(chunk: Chunk[Byte]): String =
84+
chunk.map("%02X".format(_)).mkString
85+
}
86+
```
6487

65-
def toHex(chunk: Chunk[Byte]): String =
66-
chunk.toArray.map("%02X".format(_)).mkString
88+
Here is the output of running the above program:
6789

68-
zio.Runtime.default.unsafe.run(
69-
ZStream
70-
.succeed(Person("Thomas", 23, "2354"))
71-
.transduce(
72-
encoder(Person.schema)
73-
)
74-
.runCollect
75-
.flatMap(x => putStrLn(s"Encoded data with protobuf codec: ${toHex(x)}"))
76-
).getOrThrowFiberFailure()
90+
```scala
91+
Encoded data with protobuf codec: 0A044A6F686E102B
7792
```
7893

79-
8094
## Resources
8195

82-
- [Zymposium - ZIO Schema](https://www.youtube.com/watch?v=GfNiDaL5aIM) by John A. De Goes, Adam Fraser and Kit Langton (May 2021)
96+
- [Zymposium - ZIO Schema](https://www.youtube.com/watch?v=GfNiDaL5aIM) by John A. De Goes, Adam Fraser, and Kit Langton (May 2021)
97+
- [ZIO SCHEMA: A Toolkit For Functional Distributed Computing](https://www.youtube.com/watch?v=lJziseYKvHo&t=481s) by Dan Harris (Functional Scala 2021)
98+
- [Creating Declarative Query Plans With ZIO Schema](https://www.youtube.com/watch?v=ClePN4P9_pg) by Dan Harris (ZIO World 2022)
99+
- [Describing Data...with free applicative functors (and more)](https://www.youtube.com/watch?v=oRLkb6mqvVM) by Kris Nuttycombe (Scala World) on the idea behind the [xenomorph](https://github.com/nuttycom/xenomorph) library
83100

84101
## Documentation
85102

build.sbt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,14 @@ lazy val docs = project
341341
|sbt test
342342
|```""".stripMargin
343343
)
344+
.dependsOn(
345+
zioSchemaJVM,
346+
zioSchemaProtobufJVM,
347+
zioSchemaJsonJVM,
348+
zioSchemaOpticsJVM,
349+
zioSchemaAvroJVM,
350+
zioSchemaBsonJVM,
351+
zioSchemaMsgPackJVM,
352+
zioSchemaThriftJVM
353+
)
344354
.enablePlugins(WebsitePlugin)

docs/automatic-schema-derivation.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
id: automatic-schema-derivation
3+
title: "Automatic Schema Derivation"
4+
---
5+
6+
Automatic schema derivation is the process of generating schema definitions for data types automatically, without the need to manually write them. It allows us to generate the schema for a data type based on its structure and annotations.
7+
8+
Instead of manually specifying the schema for each data type, we can rely on automatic schema derivation to generate the schema for us. This approach can save time and reduce the potential for errors, especially when dealing with complex data models.
9+
10+
By leveraging reflection and type introspection using macros, automatic schema derivation analyzes the structure of the data type and its fields, including their names, types, and annotations. It then generates the corresponding schema definition based on this analysis.
11+
12+
ZIO streamlines schema derivation through its `zio-schema-derivation` package, which utilizes the capabilities of Scala macros to automatically derive schemas. In order to use automatic schema derivation, we neeed to add the following line to our `build.sbt` file:
13+
14+
```scala
15+
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % @VERSION@
16+
```
17+
18+
Once again, let's revisit our domain models:
19+
20+
```scala mdoc:compile-only
21+
final case class Person(name: String, age: Int)
22+
23+
sealed trait PaymentMethod
24+
25+
object PaymentMethod {
26+
final case class CreditCard(number: String, expirationMonth: Int, expirationYear: Int) extends PaymentMethod
27+
final case class WireTransfer(accountNumber: String, bankCode: String) extends PaymentMethod
28+
}
29+
30+
final case class Customer(person: Person, paymentMethod: PaymentMethod)
31+
```
32+
33+
We can easily use auto derivation to create schemas:
34+
35+
```scala
36+
import zio.schema._
37+
import zio.schema.codec._
38+
39+
final case class Person(name: String, age: Int)
40+
41+
object Person {
42+
implicit val schema: Schema[Person] = DeriveSchema.gen[Person]
43+
}
44+
45+
sealed trait PaymentMethod
46+
47+
object PaymentMethod {
48+
49+
implicit val schema: Schema[PaymentMethod] =
50+
DeriveSchema.gen[PaymentMethod]
51+
52+
final case class CreditCard(
53+
number: String,
54+
expirationMonth: Int,
55+
expirationYear: Int
56+
) extends PaymentMethod
57+
58+
final case class WireTransfer(accountNumber: String, bankCode: String)
59+
extends PaymentMethod
60+
}
61+
62+
final case class Customer(person: Person, paymentMethod: PaymentMethod)
63+
64+
object Customer {
65+
implicit val schema: Schema[Customer] = DeriveSchema.gen[Customer]
66+
}
67+
```
68+
69+
Now we can write an example that demonstrates a roundtrip test for protobuf codecs:
70+
71+
```scala
72+
// Create a customer instance
73+
val customer =
74+
Customer(
75+
person = Person("John Doe", 42),
76+
paymentMethod = PaymentMethod.CreditCard("1000100010001000", 6, 2024)
77+
)
78+
79+
// Create binary codec from customer
80+
val customerCodec: BinaryCodec[Customer] =
81+
ProtobufCodec.protobufCodec[Customer]
82+
83+
// Encode the customer object
84+
val encodedCustomer: Chunk[Byte] = customerCodec.encode(customer)
85+
86+
// Decode the byte array back to the person instance
87+
val decodedCustomer: Either[DecodeError, Customer] =
88+
customerCodec.decode(encodedCustomer)
89+
90+
assert(Right(customer) == decodedCustomer)
91+
```

0 commit comments

Comments
 (0)