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

Revamping Documentation: Enhancing, Restructuring and Covering More Topics #581

Merged
merged 65 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
9733f83
refactor docs.
khajavi Jul 4, 2023
6482280
add manual and automatic derivation.
khajavi Jul 5, 2023
21ea286
integration with zio streams.
khajavi Jul 8, 2023
0a3e44f
add more packages to installation section.
khajavi Jul 8, 2023
751e119
add comment for fail constructor.
khajavi Jul 9, 2023
8e8e32b
primitives.
khajavi Jul 9, 2023
47e3fcb
transforming schemas.
khajavi Jul 9, 2023
d3bf9b9
sequence section.
khajavi Jul 9, 2023
88fdf3c
map collection.
khajavi Jul 10, 2023
6c91333
schema for set collection.
khajavi Jul 10, 2023
1bd2bef
record section.
khajavi Jul 10, 2023
751fa38
add case class section.
khajavi Jul 10, 2023
dfc8367
refactor.
khajavi Jul 10, 2023
5e6deed
generic record.
khajavi Jul 10, 2023
243b69e
either.
khajavi Jul 10, 2023
c0c3d33
enumeration.
khajavi Jul 10, 2023
e640822
chunk and vector.
khajavi Jul 10, 2023
fc0bccd
fail.
khajavi Jul 10, 2023
4b1b2df
tuples.
khajavi Jul 10, 2023
a5dd59c
update readme.
khajavi Jul 10, 2023
da4a61e
refactor sidebars.
khajavi Jul 10, 2023
377d555
add more resources for zio schema.
khajavi Jul 11, 2023
6dbd47c
getting the default value of a schema.
khajavi Jul 11, 2023
538a778
sidebar label for operations.
khajavi Jul 11, 2023
a5969c8
reorder sidebar items.
khajavi Jul 11, 2023
86f4154
generate ordering for schemas.
khajavi Jul 11, 2023
4339593
fix mdoc errors.
khajavi Jul 11, 2023
a1a1868
diffing and patching.
khajavi Jul 11, 2023
175e04a
automatic migration.
khajavi Jul 11, 2023
814a25f
schema serialization.
khajavi Jul 11, 2023
b6cacac
fix typo.
khajavi Jul 11, 2023
e4a74e4
add more resources.
khajavi Jul 12, 2023
60a42db
mapping dto to domain object.
khajavi Jul 13, 2023
1b60598
example for Schema#migrate method.
khajavi Jul 13, 2023
82a13e2
improve sentences.
khajavi Jul 13, 2023
eabb44f
add nuttycombe talk to resource section.
khajavi Jul 15, 2023
caf01ec
dynamic data representation.
khajavi Jul 16, 2023
400b620
dynamic value migration.
khajavi Jul 16, 2023
f8b8e6d
schema migration.
khajavi Jul 17, 2023
de2767c
derive ordering.
khajavi Jul 17, 2023
2c0ab52
separate article for getting the default value.
khajavi Jul 17, 2023
2ca42c5
separate article for diffing and patching.
khajavi Jul 17, 2023
bff2288
separate other articles.
khajavi Jul 17, 2023
745c8eb
validation section.
khajavi Jul 17, 2023
40d6dac
update dynamic data representation article.
khajavi Jul 18, 2023
1555fc8
reified optics.
khajavi Jul 19, 2023
78812e0
avro codecs.
khajavi Jul 30, 2023
5e465a8
add bson codecs.
khajavi Jul 31, 2023
13d0ae6
improve apache avro doc.
khajavi Jul 31, 2023
4ee9b38
add zio-schema-bson to doc's dependencies.
khajavi Jul 31, 2023
45abefc
add json codec article.
khajavi Jul 31, 2023
9ac4732
add message pack section.
khajavi Jul 31, 2023
1409e5f
add protobuf section.
khajavi Jul 31, 2023
4bbcce4
update message pack.
khajavi Jul 31, 2023
d6e5985
add apache thrift section to codecs.
khajavi Aug 1, 2023
3cfef9c
refactor.
khajavi Aug 1, 2023
84df435
refactor.
khajavi Aug 1, 2023
efef629
organize sidebar.
khajavi Aug 2, 2023
47af326
overview of all operations.
khajavi Aug 2, 2023
7bb60b1
update introduction section.
khajavi Aug 2, 2023
9325101
update readme.
khajavi Aug 2, 2023
ad5a885
Merge branch 'main' into zio-schema-docs
khajavi Aug 2, 2023
d464145
update readme.
khajavi Aug 2, 2023
a64a823
Merge branch 'main' into zio-schema-docs
khajavi Sep 9, 2023
9706436
update readme.
khajavi Sep 9, 2023
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
95 changes: 56 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,76 +10,93 @@

## Introduction

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.
ZIO Schema helps us to solve some of the most common problems in distributed computing, such as serialization, deserialization, and data migration.

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.

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.

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):
## What Problems Does ZIO Schema Solve?

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:

- Codecs for any supported protocol (JSON, protobuf, etc.), so data structures can be serialized and deserialized in a principled way
- Diffing, patching, merging, and other generic-data-based operations
- Migration of data structures from one schema to another compatible schema
- Derivation of arbitrary type classes (`Eq`, `Show`, `Ord`, etc.) from the structure of the data
1. Metaprogramming without macros, reflection, or complicated implicit derivations.
1. Creating serialization and deserialization codecs for any supported protocol (JSON, Protobuf, etc.)
2. Deriving standard type classes (`Eq`, `Show`, `Ordering`, etc.) from the structure of the data
3. Default values for data types
2. Automate ETL (Extract, Transform, Load) pipelines
1. Diffing: diffing between two values of the same type
2. Patching: applying a diff to a value to update it
3. Migration: migrating values from one type to another
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.

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.

_ZIO Schema_ is used by a growing number of ZIO libraries, including _ZIO Flow_, _ZIO Redis_, _ZIO Web_, _ZIO SQL_ and _ZIO DynamoDB_.
_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).

## Installation

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

```scala
libraryDependencies += "dev.zio" %% "zio-schema" % "0.4.12"
libraryDependencies += "dev.zio" %% "zio-schema-bson" % "0.4.12"
libraryDependencies += "dev.zio" %% "zio-schema-json" % "0.4.12"
libraryDependencies += "dev.zio" %% "zio-schema-protobuf" % "0.4.12"

// Required for automatic generic derivation of schemas
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % "0.4.12",
libraryDependencies += "dev.zio" %% "zio-schema" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-avro" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-bson" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-json" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-msg-pack" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-protobuf" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-thrift" % "0.4.13"
libraryDependencies += "dev.zio" %% "zio-schema-zio-test" % "0.4.13"

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

## Example

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:
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:

```scala
import zio.console.putStrLn
import zio.schema.codec.ProtobufCodec._
import zio._
import zio.stream._
import zio.schema.codec.{BinaryCodec, ProtobufCodec}
import zio.schema.{DeriveSchema, Schema}
import zio.stream.ZStream
import zio.{Chunk, ExitCode, URIO}

final case class Person(name: String, age: Int, id: String)
final case class Person(name: String, age: Int)

object Person {
implicit val schema: Schema[Person] = DeriveSchema.gen[Person]
implicit val schema: Schema[Person] = DeriveSchema.gen
val protobufCodec: BinaryCodec[Person] = ProtobufCodec.protobufCodec
}

Person.schema

import zio.schema.syntax._

Person("Alex", 31, "0123").diff(Person("Alex", 31, "124"))
object Main extends ZIOAppDefault {
def run =
ZStream
.succeed(Person("John", 43))
.via(Person.protobufCodec.streamEncoder)
.runCollect
.flatMap(x =>
Console.printLine(s"Encoded data with protobuf codec: ${toHex(x)}")
)

def toHex(chunk: Chunk[Byte]): String =
chunk.map("%02X".format(_)).mkString
}
```

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

zio.Runtime.default.unsafe.run(
ZStream
.succeed(Person("Thomas", 23, "2354"))
.transduce(
encoder(Person.schema)
)
.runCollect
.flatMap(x => putStrLn(s"Encoded data with protobuf codec: ${toHex(x)}"))
).getOrThrowFiberFailure()
```scala
Encoded data with protobuf codec: 0A044A6F686E102B
```


## Resources

- [Zymposium - ZIO Schema](https://www.youtube.com/watch?v=GfNiDaL5aIM) by John A. De Goes, Adam Fraser and Kit Langton (May 2021)
- [Zymposium - ZIO Schema](https://www.youtube.com/watch?v=GfNiDaL5aIM) by John A. De Goes, Adam Fraser, and Kit Langton (May 2021)
- [ZIO SCHEMA: A Toolkit For Functional Distributed Computing](https://www.youtube.com/watch?v=lJziseYKvHo&t=481s) by Dan Harris (Functional Scala 2021)
- [Creating Declarative Query Plans With ZIO Schema](https://www.youtube.com/watch?v=ClePN4P9_pg) by Dan Harris (ZIO World 2022)
- [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

## Documentation

Expand Down
10 changes: 10 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,14 @@ lazy val docs = project
|sbt test
|```""".stripMargin
)
.dependsOn(
zioSchemaJVM,
zioSchemaProtobufJVM,
zioSchemaJsonJVM,
zioSchemaOpticsJVM,
zioSchemaAvroJVM,
zioSchemaBsonJVM,
zioSchemaMsgPackJVM,
zioSchemaThriftJVM
)
.enablePlugins(WebsitePlugin)
91 changes: 91 additions & 0 deletions docs/automatic-schema-derivation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
id: automatic-schema-derivation
title: "Automatic Schema Derivation"
---

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.

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.

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.

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:

```scala
libraryDependencies += "dev.zio" %% "zio-schema-derivation" % @VERSION@
```

Once again, let's revisit our domain models:

```scala mdoc:compile-only
final case class Person(name: String, age: Int)

sealed trait 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
}

final case class Customer(person: Person, paymentMethod: PaymentMethod)
```

We can easily use auto derivation to create schemas:

```scala
import zio.schema._
import zio.schema.codec._

final case class Person(name: String, age: Int)

object Person {
implicit val schema: Schema[Person] = DeriveSchema.gen[Person]
}

sealed trait PaymentMethod

object PaymentMethod {

implicit val schema: Schema[PaymentMethod] =
DeriveSchema.gen[PaymentMethod]

final case class CreditCard(
number: String,
expirationMonth: Int,
expirationYear: Int
) extends PaymentMethod

final case class WireTransfer(accountNumber: String, bankCode: String)
extends PaymentMethod
}

final case class Customer(person: Person, paymentMethod: PaymentMethod)

object Customer {
implicit val schema: Schema[Customer] = DeriveSchema.gen[Customer]
}
```

Now we can write an example that demonstrates a roundtrip test for protobuf codecs:

```scala
// Create a customer instance
val customer =
Customer(
person = Person("John Doe", 42),
paymentMethod = PaymentMethod.CreditCard("1000100010001000", 6, 2024)
)

// Create binary codec from customer
val customerCodec: BinaryCodec[Customer] =
ProtobufCodec.protobufCodec[Customer]

// Encode the customer object
val encodedCustomer: Chunk[Byte] = customerCodec.encode(customer)

// Decode the byte array back to the person instance
val decodedCustomer: Either[DecodeError, Customer] =
customerCodec.decode(encodedCustomer)

assert(Right(customer) == decodedCustomer)
```
Loading
Loading