|
10 | 10 |
|
11 | 11 | ## Introduction
|
12 | 12 |
|
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. |
14 | 16 |
|
15 | 17 | 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.
|
16 | 18 |
|
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: |
18 | 22 |
|
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. |
23 | 32 |
|
24 | 33 | 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.
|
25 | 34 |
|
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). |
27 | 36 |
|
28 | 37 | ## Installation
|
29 | 38 |
|
30 | 39 | In order to use this library, we need to add the following lines in our `build.sbt` file:
|
31 | 40 |
|
32 | 41 | ```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" |
40 | 53 | libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided"
|
41 | 54 | ```
|
42 | 55 |
|
43 | 56 | ## Example
|
44 | 57 |
|
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: |
46 | 59 |
|
47 | 60 | ```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} |
50 | 64 | import zio.schema.{DeriveSchema, Schema}
|
51 |
| -import zio.stream.ZStream |
52 |
| -import zio.{Chunk, ExitCode, URIO} |
53 | 65 |
|
54 |
| -final case class Person(name: String, age: Int, id: String) |
| 66 | +final case class Person(name: String, age: Int) |
| 67 | + |
55 | 68 | 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 |
57 | 71 | }
|
58 | 72 |
|
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 | +``` |
64 | 87 |
|
65 |
| -def toHex(chunk: Chunk[Byte]): String = |
66 |
| - chunk.toArray.map("%02X".format(_)).mkString |
| 88 | +Here is the output of running the above program: |
67 | 89 |
|
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 |
77 | 92 | ```
|
78 | 93 |
|
79 |
| - |
80 | 94 | ## Resources
|
81 | 95 |
|
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 |
83 | 100 |
|
84 | 101 | ## Documentation
|
85 | 102 |
|
|
0 commit comments