@zio.dev/zio-blocks 0.0.1 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.md +143 -15
- package/package.json +5 -2
- package/reference/binding.md +8 -14
- package/reference/chunk.md +36 -36
- package/reference/docs.md +2 -2
- package/reference/dynamic-value.md +34 -34
- package/reference/formats.md +16 -16
- package/reference/json-schema.md +20 -20
- package/reference/json.md +47 -47
- package/reference/optics.md +51 -37
- package/reference/reflect.md +3 -3
- package/reference/registers.md +7 -7
- package/reference/schema.md +18 -18
- package/reference/syntax.md +16 -16
- package/scope.md +481 -161
- package/reference/modifier.md +0 -276
- package/reference/reflect-transform.md +0 -387
- package/reference/type-class-derivation-internals.md +0 -632
package/reference/optics.md
CHANGED
|
@@ -218,7 +218,7 @@ It takes a `Reflect.Variant.Bound[S]` representing the schema of the sum type `S
|
|
|
218
218
|
|
|
219
219
|
Assume you have a `Notification` sealed trait representing different notification types:
|
|
220
220
|
|
|
221
|
-
```scala
|
|
221
|
+
```scala
|
|
222
222
|
import zio.blocks.schema._
|
|
223
223
|
|
|
224
224
|
sealed trait Notification
|
|
@@ -234,7 +234,7 @@ object Notification {
|
|
|
234
234
|
|
|
235
235
|
First, we need to define schemas for each case class and then write a prism for each case (here we define a prism for the `Email` case):
|
|
236
236
|
|
|
237
|
-
```scala
|
|
237
|
+
```scala
|
|
238
238
|
import zio.blocks.schema._
|
|
239
239
|
|
|
240
240
|
sealed trait Notification
|
|
@@ -281,7 +281,7 @@ object Notification {
|
|
|
281
281
|
|
|
282
282
|
The `optic` macro inside the `CompanionOptics` trait creates a prism using intuitive selector syntax with the `when[CaseType]` method:
|
|
283
283
|
|
|
284
|
-
```scala
|
|
284
|
+
```scala
|
|
285
285
|
import zio.blocks.schema._
|
|
286
286
|
|
|
287
287
|
sealed trait Notification
|
|
@@ -304,7 +304,7 @@ The macro inspects the selector expression `_.when[Email]`, validates that `Emai
|
|
|
304
304
|
|
|
305
305
|
For nested structures, the `optic` macro can compose prisms with lenses by chaining case selection with field access:
|
|
306
306
|
|
|
307
|
-
```scala
|
|
307
|
+
```scala
|
|
308
308
|
sealed trait Response
|
|
309
309
|
object Response extends CompanionOptics[Response] {
|
|
310
310
|
case class Success(data: Data) extends Response
|
|
@@ -325,7 +325,7 @@ object Response extends CompanionOptics[Response] {
|
|
|
325
325
|
|
|
326
326
|
When you compose a prism with a lens using the `optic` macro, the result is an `Optional`—an optic that may fail to focus (because the sum type might be a different case) but if it succeeds, always finds the field:
|
|
327
327
|
|
|
328
|
-
```scala
|
|
328
|
+
```scala
|
|
329
329
|
val response = Response.Success(Response.Data(1, "hello"))
|
|
330
330
|
|
|
331
331
|
Response.successValue.getOption(response)
|
|
@@ -339,11 +339,25 @@ Response.successValue.getOption(Response.Failure("error"))
|
|
|
339
339
|
|
|
340
340
|
Now let's explore prism operations. Assume we have some sample notifications:
|
|
341
341
|
|
|
342
|
-
```scala
|
|
342
|
+
```scala
|
|
343
343
|
// Sample notifications
|
|
344
344
|
val emailNotif: Notification = Notification.Email("user@example.com", "Hello", "Welcome!")
|
|
345
|
+
// emailNotif: Notification = Email(
|
|
346
|
+
// to = "user@example.com",
|
|
347
|
+
// subject = "Hello",
|
|
348
|
+
// body = "Welcome!"
|
|
349
|
+
// )
|
|
345
350
|
val smsNotif: Notification = Notification.SMS("+1234567890", "Your code is 1234")
|
|
351
|
+
// smsNotif: Notification = SMS(
|
|
352
|
+
// phoneNumber = "+1234567890",
|
|
353
|
+
// message = "Your code is 1234"
|
|
354
|
+
// )
|
|
346
355
|
val pushNotif: Notification = Notification.Push("device-abc", "Alert", Map("action" -> "open"))
|
|
356
|
+
// pushNotif: Notification = Push(
|
|
357
|
+
// deviceId = "device-abc",
|
|
358
|
+
// title = "Alert",
|
|
359
|
+
// payload = Map("action" -> "open")
|
|
360
|
+
// )
|
|
347
361
|
```
|
|
348
362
|
|
|
349
363
|
1. **`Prism#getOption`** — Extract the case if it matches, otherwise None
|
|
@@ -557,7 +571,7 @@ Beside the above composition methods, `Optional` provides specialized constructo
|
|
|
557
571
|
|
|
558
572
|
The most common way to manually construct an `Optional` is by composing a `Lens` with a `Prism`. Assume you have a `PaymentMethod` sum type which has multiple cases, and we have written a prism for one of its cases, e.g., `CreditCard`:
|
|
559
573
|
|
|
560
|
-
```scala
|
|
574
|
+
```scala
|
|
561
575
|
import zio.blocks.schema._
|
|
562
576
|
|
|
563
577
|
sealed trait PaymentMethod
|
|
@@ -574,7 +588,7 @@ object PaymentMethod extends CompanionOptics[PaymentMethod] {
|
|
|
574
588
|
|
|
575
589
|
And also assume we have a `Customer` record that has a `payment` field of type `PaymentMethod` and we have written a lens for that field:
|
|
576
590
|
|
|
577
|
-
```scala
|
|
591
|
+
```scala
|
|
578
592
|
case class Customer(name: String, payment: PaymentMethod)
|
|
579
593
|
object Customer extends CompanionOptics[Customer] {
|
|
580
594
|
implicit val schema: Schema[Customer] = Schema.derived
|
|
@@ -586,7 +600,7 @@ object Customer extends CompanionOptics[Customer] {
|
|
|
586
600
|
|
|
587
601
|
We can now compose the `payment` lens with the `creditCard` prism to create an `Optional` that focuses on the `CreditCard` details within a `Customer`:
|
|
588
602
|
|
|
589
|
-
```scala
|
|
603
|
+
```scala
|
|
590
604
|
// Compose lens and prism manually to get Optional
|
|
591
605
|
val creditCard: Optional[Customer, PaymentMethod.CreditCard] =
|
|
592
606
|
Optional(Customer.payment, PaymentMethod.creditCard)
|
|
@@ -596,7 +610,7 @@ val creditCard: Optional[Customer, PaymentMethod.CreditCard] =
|
|
|
596
610
|
|
|
597
611
|
For accessing elements at specific indices in sequences:
|
|
598
612
|
|
|
599
|
-
```scala
|
|
613
|
+
```scala
|
|
600
614
|
import zio.blocks.schema._
|
|
601
615
|
|
|
602
616
|
case class Order(id: String, items: List[String])
|
|
@@ -624,7 +638,7 @@ The `optic` macro inside the `CompanionOptics` trait creates optionals automatic
|
|
|
624
638
|
|
|
625
639
|
By combining the `.when[Case]` (prism) and `.field-name` (lens) syntax of optic macro, you can create optionals that focus on the inner values of ADTs:
|
|
626
640
|
|
|
627
|
-
```scala
|
|
641
|
+
```scala
|
|
628
642
|
import zio.blocks.schema._
|
|
629
643
|
|
|
630
644
|
case class ApiResponse(
|
|
@@ -673,7 +687,7 @@ object Response extends CompanionOptics[Response] {
|
|
|
673
687
|
|
|
674
688
|
We can access elements at specific indices in sequences using `.at(index)` syntax in `optic` macro:
|
|
675
689
|
|
|
676
|
-
```scala
|
|
690
|
+
```scala
|
|
677
691
|
import zio.blocks.schema._
|
|
678
692
|
|
|
679
693
|
case class OrderItem(sku: String, quantity: Int)
|
|
@@ -697,7 +711,7 @@ object Order extends CompanionOptics[Order] {
|
|
|
697
711
|
|
|
698
712
|
Usage:
|
|
699
713
|
|
|
700
|
-
```scala
|
|
714
|
+
```scala
|
|
701
715
|
val order = Order("ord-1", List(
|
|
702
716
|
OrderItem("SKU-A", 2),
|
|
703
717
|
OrderItem("SKU-B", 1)
|
|
@@ -715,7 +729,7 @@ Order.firstItemSku.getOption(order) // => Some("SKU-A")
|
|
|
715
729
|
|
|
716
730
|
To access values at a specific key, we can use `.atKey(key)` syntax in `optic` macro:
|
|
717
731
|
|
|
718
|
-
```scala
|
|
732
|
+
```scala
|
|
719
733
|
import zio.blocks.schema._
|
|
720
734
|
|
|
721
735
|
case class Config(settings: Map[String, String])
|
|
@@ -733,7 +747,7 @@ object Config extends CompanionOptics[Config] {
|
|
|
733
747
|
|
|
734
748
|
Here is how you can use these optionals:
|
|
735
749
|
|
|
736
|
-
```scala
|
|
750
|
+
```scala
|
|
737
751
|
val config = Config(Map("host" -> "localhost", "port" -> "8080"))
|
|
738
752
|
|
|
739
753
|
Config.hostSetting.getOption(config) // => Some("localhost")
|
|
@@ -744,7 +758,7 @@ Config.setting("timeout").getOption(config) // => None (key not present)
|
|
|
744
758
|
|
|
745
759
|
To access the inner value of wrapper types (newtypes, opaque types) you can use the `.wrapped[T]` syntax in `optic` macro:
|
|
746
760
|
|
|
747
|
-
```scala
|
|
761
|
+
```scala
|
|
748
762
|
import zio.blocks.schema._
|
|
749
763
|
|
|
750
764
|
// Assume Email is a wrapper around String with validation
|
|
@@ -812,7 +826,7 @@ object Traversal {
|
|
|
812
826
|
|
|
813
827
|
For example, to create a traversal over all items in a shopping cart represented as a list and quantities as a vector, you can do the following:
|
|
814
828
|
|
|
815
|
-
```scala
|
|
829
|
+
```scala
|
|
816
830
|
import zio.blocks.schema._
|
|
817
831
|
|
|
818
832
|
case class ShoppingCart(items: List[String], quantities: Vector[Int])
|
|
@@ -848,7 +862,7 @@ object Traversal {
|
|
|
848
862
|
|
|
849
863
|
Let's say you have an inventory represented as a map of product names to stock counts. You can create traversals for both keys and values as follows:
|
|
850
864
|
|
|
851
|
-
```scala
|
|
865
|
+
```scala
|
|
852
866
|
import zio.blocks.schema._
|
|
853
867
|
|
|
854
868
|
case class Inventory(stock: Map[String, Int])
|
|
@@ -871,7 +885,7 @@ The `optic` macro inside the `CompanionOptics` trait creates traversals using in
|
|
|
871
885
|
|
|
872
886
|
1. Use `.each` to traverse all elements in a sequence (List, Vector, Set, ArraySeq):
|
|
873
887
|
|
|
874
|
-
```scala
|
|
888
|
+
```scala
|
|
875
889
|
import zio.blocks.schema._
|
|
876
890
|
|
|
877
891
|
case class Order(id: String, items: List[String], prices: Vector[Double])
|
|
@@ -888,7 +902,7 @@ object Order extends CompanionOptics[Order] {
|
|
|
888
902
|
|
|
889
903
|
2. Use `.eachKey` to traverse all keys and `.eachValue` to traverse all values in a map:
|
|
890
904
|
|
|
891
|
-
```scala
|
|
905
|
+
```scala
|
|
892
906
|
import zio.blocks.schema._
|
|
893
907
|
|
|
894
908
|
case class UserScores(scores: Map[String, Int])
|
|
@@ -905,7 +919,7 @@ object UserScores extends CompanionOptics[UserScores] {
|
|
|
905
919
|
|
|
906
920
|
3. Use `.atIndices(indices)` to traverse elements at specific indices:
|
|
907
921
|
|
|
908
|
-
```scala
|
|
922
|
+
```scala
|
|
909
923
|
import zio.blocks.schema._
|
|
910
924
|
|
|
911
925
|
case class Matrix(rows: Vector[Vector[Int]])
|
|
@@ -919,7 +933,7 @@ object Matrix extends CompanionOptics[Matrix] {
|
|
|
919
933
|
|
|
920
934
|
4. Use `.atKeys(keys)` to traverse values at specific keys:
|
|
921
935
|
|
|
922
|
-
```scala
|
|
936
|
+
```scala
|
|
923
937
|
import zio.blocks.schema._
|
|
924
938
|
|
|
925
939
|
case class Environment(variables: Map[String, String])
|
|
@@ -933,7 +947,7 @@ object Environment extends CompanionOptics[Environment] {
|
|
|
933
947
|
|
|
934
948
|
Please note that the `optic` macro supports chaining traversals with field access for deep navigation:
|
|
935
949
|
|
|
936
|
-
```scala
|
|
950
|
+
```scala
|
|
937
951
|
import zio.blocks.schema._
|
|
938
952
|
|
|
939
953
|
case class LineItem(sku: String, price: Double, quantity: Int)
|
|
@@ -960,7 +974,7 @@ object Invoice extends CompanionOptics[Invoice] {
|
|
|
960
974
|
|
|
961
975
|
Let's explore traversal operations with a practical example. Assume we have a `Team` case class with a list of members and a map of scores:
|
|
962
976
|
|
|
963
|
-
```scala
|
|
977
|
+
```scala
|
|
964
978
|
import zio.blocks.schema._
|
|
965
979
|
|
|
966
980
|
case class Team(name: String, members: List[String], scores: Map[String, Int])
|
|
@@ -981,7 +995,7 @@ val team = Team(
|
|
|
981
995
|
|
|
982
996
|
1. `Traversal#fold` aggregates all focused values:
|
|
983
997
|
|
|
984
|
-
```scala
|
|
998
|
+
```scala
|
|
985
999
|
// Count all members
|
|
986
1000
|
Team.allMembers.fold(team)(0, (count, _) => count + 1)
|
|
987
1001
|
// => 3
|
|
@@ -997,7 +1011,7 @@ Team.allMembers.fold(team)("", (acc, name) => if (acc.isEmpty) name else s"$acc,
|
|
|
997
1011
|
|
|
998
1012
|
2. `Traversal#reduceOrFail` reduces with error handling:
|
|
999
1013
|
|
|
1000
|
-
```scala
|
|
1014
|
+
```scala
|
|
1001
1015
|
// Find the maximum score
|
|
1002
1016
|
Team.allScores.reduceOrFail(team)(math.max)
|
|
1003
1017
|
// => Right(100)
|
|
@@ -1030,7 +1044,7 @@ Team.allPlayerNames.modify(team, name => s"Player: $name")
|
|
|
1030
1044
|
|
|
1031
1045
|
4. `Traversal#modifyOption` — Modify returning Option
|
|
1032
1046
|
|
|
1033
|
-
```scala
|
|
1047
|
+
```scala
|
|
1034
1048
|
// Modify non-empty collection
|
|
1035
1049
|
Team.allMembers.modifyOption(team, _.toUpperCase)
|
|
1036
1050
|
// => Some(Team("Alpha", List("ALICE", "BOB", "CHARLIE"), Map(...)))
|
|
@@ -1043,7 +1057,7 @@ Team.allMembers.modifyOption(emptyTeam, _.toUpperCase)
|
|
|
1043
1057
|
|
|
1044
1058
|
5. `Traversal#modifyOrFail` — Modify with detailed error on failure
|
|
1045
1059
|
|
|
1046
|
-
```scala
|
|
1060
|
+
```scala
|
|
1047
1061
|
// Successful modification
|
|
1048
1062
|
Team.allMembers.modifyOrFail(team, _.toUpperCase)
|
|
1049
1063
|
// => Right(Team("Alpha", List("ALICE", "BOB", "CHARLIE"), Map(...)))
|
|
@@ -1138,7 +1152,7 @@ This method takes two lenses: the first from `S` to `T`, and the second from `T`
|
|
|
1138
1152
|
|
|
1139
1153
|
For example, if we have a `Person` case class that contains an `Address` and we want to create a lens to access the `street` field of the `Address` within `Person`, we can do so as follows:
|
|
1140
1154
|
|
|
1141
|
-
```scala
|
|
1155
|
+
```scala
|
|
1142
1156
|
import zio.blocks.schema._
|
|
1143
1157
|
|
|
1144
1158
|
case class Address(street: String, city: String)
|
|
@@ -1186,7 +1200,7 @@ object Person {
|
|
|
1186
1200
|
|
|
1187
1201
|
The `optic` macro (or its alias `$`) provides a more concise way to derive composed lenses. By extending `CompanionOptics[T]` and using selector syntax, you can derive the same lenses with significantly less boilerplate:
|
|
1188
1202
|
|
|
1189
|
-
```scala
|
|
1203
|
+
```scala
|
|
1190
1204
|
import zio.blocks.schema._
|
|
1191
1205
|
|
|
1192
1206
|
case class Address(street: String, city: String)
|
|
@@ -1317,7 +1331,7 @@ Employee.emailAddress.getOption(employee2)
|
|
|
1317
1331
|
|
|
1318
1332
|
The `optic` macro supports case selection using the `.when[T]` syntax, which makes composing lenses with prisms much more concise:
|
|
1319
1333
|
|
|
1320
|
-
```scala
|
|
1334
|
+
```scala
|
|
1321
1335
|
import zio.blocks.schema._
|
|
1322
1336
|
|
|
1323
1337
|
sealed trait ContactInfo
|
|
@@ -1364,7 +1378,7 @@ When you compose a `Lens` with an `Optional`, the result is also an `Optional`.
|
|
|
1364
1378
|
|
|
1365
1379
|
Building on our previous example, suppose we have a `Company` that contains an `Employee`:
|
|
1366
1380
|
|
|
1367
|
-
```scala
|
|
1381
|
+
```scala
|
|
1368
1382
|
case class Company(name: String, ceo: Employee)
|
|
1369
1383
|
object Company {
|
|
1370
1384
|
implicit val schema: Schema[Company] = Schema.derived[Company]
|
|
@@ -1389,7 +1403,7 @@ object Company {
|
|
|
1389
1403
|
|
|
1390
1404
|
Now you can work with the CEO's email contact through the company:
|
|
1391
1405
|
|
|
1392
|
-
```scala
|
|
1406
|
+
```scala
|
|
1393
1407
|
val techCorp = Company("TechCorp", Employee("Alice", ContactInfo.Email("alice@tech.com")))
|
|
1394
1408
|
val retailCo = Company("RetailCo", Employee("Bob", ContactInfo.Phone("555-9999")))
|
|
1395
1409
|
|
|
@@ -1416,7 +1430,7 @@ This composition pattern is powerful for navigating through complex nested struc
|
|
|
1416
1430
|
|
|
1417
1431
|
With the `optic` macro, you can express the entire path in a single selector expression:
|
|
1418
1432
|
|
|
1419
|
-
```scala
|
|
1433
|
+
```scala
|
|
1420
1434
|
import zio.blocks.schema._
|
|
1421
1435
|
|
|
1422
1436
|
case class Company(name: String, ceo: Employee)
|
|
@@ -1454,7 +1468,7 @@ If you have a record containing a collection field and you want to operate on al
|
|
|
1454
1468
|
|
|
1455
1469
|
For example, let's create a `Department` that has a list of employees, and we want to access all employee names:
|
|
1456
1470
|
|
|
1457
|
-
```scala
|
|
1471
|
+
```scala
|
|
1458
1472
|
case class Department(name: String, employees: List[Employee])
|
|
1459
1473
|
object Department {
|
|
1460
1474
|
implicit val schema: Schema[Department] = Schema.derived[Department]
|
|
@@ -1557,7 +1571,7 @@ This example demonstrates the power of optics composition: you can build complex
|
|
|
1557
1571
|
|
|
1558
1572
|
The `optic` macro supports collection traversal using the `.each` syntax. This allows you to express traversals over lists, vectors, and other sequences in a concise path expression:
|
|
1559
1573
|
|
|
1560
|
-
```scala
|
|
1574
|
+
```scala
|
|
1561
1575
|
import zio.blocks.schema._
|
|
1562
1576
|
|
|
1563
1577
|
case class Department(name: String, employees: List[Employee])
|
|
@@ -1594,7 +1608,7 @@ The result is a `Traversal[Department, String]` that focuses on all email addres
|
|
|
1594
1608
|
|
|
1595
1609
|
For maps, the macro provides `.eachKey` and `.eachValue` for traversing keys and values, respectively:
|
|
1596
1610
|
|
|
1597
|
-
```scala
|
|
1611
|
+
```scala
|
|
1598
1612
|
import zio.blocks.schema._
|
|
1599
1613
|
|
|
1600
1614
|
case class Inventory(items: Map[String, Int])
|
package/reference/reflect.md
CHANGED
|
@@ -84,7 +84,7 @@ case class Record[F[_, _], A](
|
|
|
84
84
|
|
|
85
85
|
The following example shows a `Person` case class represented as a `Reflect.Record`:
|
|
86
86
|
|
|
87
|
-
```scala
|
|
87
|
+
```scala
|
|
88
88
|
import zio.blocks.schema._
|
|
89
89
|
import zio.blocks.schema.binding.RegisterOffset._
|
|
90
90
|
import zio.blocks.schema.binding._
|
|
@@ -387,7 +387,7 @@ case class Tree(value: Int, children: List[Tree])
|
|
|
387
387
|
|
|
388
388
|
We can define its schema using `Reflect.Deferred` as follows:
|
|
389
389
|
|
|
390
|
-
```scala
|
|
390
|
+
```scala
|
|
391
391
|
import zio.blocks.schema._
|
|
392
392
|
import zio.blocks.schema.binding.RegisterOffset.RegisterOffset
|
|
393
393
|
import zio.blocks.schema.binding._
|
|
@@ -508,7 +508,7 @@ The auto-derivation mechanism inspects the structure of your data types at compi
|
|
|
508
508
|
|
|
509
509
|
To leverage auto-derivation, simply define an implicit `Schema` for your type using `Schema.derived`:
|
|
510
510
|
|
|
511
|
-
```scala
|
|
511
|
+
```scala
|
|
512
512
|
import zio.blocks.schema.Schema
|
|
513
513
|
|
|
514
514
|
case class Person(name: String, age: Int)
|
package/reference/registers.md
CHANGED
|
@@ -10,13 +10,13 @@ The register system is one of the key innovations in ZIO Blocks (ZIO Schema 2) t
|
|
|
10
10
|
|
|
11
11
|
When building generic abstractions over data types (like serialization libraries), you need to describe all possible constructions and deconstructions uniformly. The traditional approach uses tuples and boxed primitives. For example assume we have a simple record data type:
|
|
12
12
|
|
|
13
|
-
```scala
|
|
13
|
+
```scala
|
|
14
14
|
case class Person(name: String, age: Int)
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
A traditional library might represent it as tuple when serializing/deserializing:
|
|
18
18
|
|
|
19
|
-
```scala
|
|
19
|
+
```scala
|
|
20
20
|
trait Tuple
|
|
21
21
|
case class Tuple2[A, B]( _1: A, _2: B) extends Tuple
|
|
22
22
|
case class Tuple3[A, B, C](_1: A, _2: B, _3: C) extends Tuple
|
|
@@ -25,7 +25,7 @@ case class Tuple3[A, B, C](_1: A, _2: B, _3: C) extends Tuple
|
|
|
25
25
|
|
|
26
26
|
Tuple is generic data structure that can hold values of any type. So serializing `Person` would involve converting it to/from `Tuple2[String, Int]`:
|
|
27
27
|
|
|
28
|
-
```scala
|
|
28
|
+
```scala
|
|
29
29
|
case class Person(name: String, age: Int)
|
|
30
30
|
val person = Person("john", 42)
|
|
31
31
|
|
|
@@ -155,7 +155,7 @@ RegisterOffset.getObjects(RegisterOffset(bytes = 4, ints = 2, objects = 3)) // o
|
|
|
155
155
|
|
|
156
156
|
`Registers` is a mutable container that holds values. It's created with an initial capacity:
|
|
157
157
|
|
|
158
|
-
```scala
|
|
158
|
+
```scala
|
|
159
159
|
import zio.blocks.schema.binding._
|
|
160
160
|
import zio.blocks.schema.binding.RegisterOffset._
|
|
161
161
|
|
|
@@ -207,7 +207,7 @@ When setting or getting a value, you are required to provide one or two of the f
|
|
|
207
207
|
|
|
208
208
|
Encoding data instances into registers involves mapping each field of a data type to its corresponding position in the two register arrays (byte array for primitives and object array for references). For example, assume we have a `Person` data type as below:
|
|
209
209
|
|
|
210
|
-
```scala
|
|
210
|
+
```scala
|
|
211
211
|
case class Person(
|
|
212
212
|
name: String,
|
|
213
213
|
email: String,
|
|
@@ -219,7 +219,7 @@ case class Person(
|
|
|
219
219
|
|
|
220
220
|
We can encode it with registers, as follows:
|
|
221
221
|
|
|
222
|
-
```scala
|
|
222
|
+
```scala
|
|
223
223
|
import zio.blocks.schema.binding._
|
|
224
224
|
import zio.blocks.schema.binding.RegisterOffset._
|
|
225
225
|
|
|
@@ -254,7 +254,7 @@ registers.setDouble(
|
|
|
254
254
|
|
|
255
255
|
Conversely, to decode the `Person` data type from registers, you would read the values back from their respective positions:
|
|
256
256
|
|
|
257
|
-
```scala
|
|
257
|
+
```scala
|
|
258
258
|
import zio.blocks.schema.binding._
|
|
259
259
|
import zio.blocks.schema.binding.RegisterOffset._
|
|
260
260
|
// Decode Person from registers
|
package/reference/schema.md
CHANGED
|
@@ -61,7 +61,7 @@ ZIO Blocks provides both automatic schema derivation and also ways to manually c
|
|
|
61
61
|
|
|
62
62
|
To leverage auto-derivation, simply define an implicit `Schema` for your type using `Schema.derived`:
|
|
63
63
|
|
|
64
|
-
```scala
|
|
64
|
+
```scala
|
|
65
65
|
import zio.blocks.schema.Schema
|
|
66
66
|
|
|
67
67
|
case class Person(name: String, age: Int)
|
|
@@ -75,7 +75,7 @@ It will automatically derive the schema for `Person` based on its structure. Aft
|
|
|
75
75
|
|
|
76
76
|
For sealed traits (ADTs), it will derive the schema for all subtypes as well:
|
|
77
77
|
|
|
78
|
-
```scala
|
|
78
|
+
```scala
|
|
79
79
|
import zio.blocks.schema.Schema
|
|
80
80
|
|
|
81
81
|
sealed trait Shape
|
|
@@ -97,7 +97,7 @@ ZIO Blocks ships with a comprehensive set of pre-defined schemas for standard Sc
|
|
|
97
97
|
|
|
98
98
|
The foundational building blocks for all data types. These schemas leverage the [register-based architecture](registers.md) for zero-allocation performance:
|
|
99
99
|
|
|
100
|
-
```scala
|
|
100
|
+
```scala
|
|
101
101
|
import zio.blocks.schema.Schema
|
|
102
102
|
|
|
103
103
|
Schema[Unit] // The unit type (singleton value)
|
|
@@ -116,7 +116,7 @@ Schema[String] // Immutable character sequence
|
|
|
116
116
|
|
|
117
117
|
For financial calculations and scenarios requiring exact decimal representation:
|
|
118
118
|
|
|
119
|
-
```scala
|
|
119
|
+
```scala
|
|
120
120
|
import zio.blocks.schema.Schema
|
|
121
121
|
|
|
122
122
|
Schema[BigInt] // Arbitrary precision integer
|
|
@@ -127,7 +127,7 @@ Schema[BigDecimal] // Arbitrary precision decimal
|
|
|
127
127
|
|
|
128
128
|
Complete coverage of the modern Java Time API for robust date/time handling:
|
|
129
129
|
|
|
130
|
-
```scala
|
|
130
|
+
```scala
|
|
131
131
|
import zio.blocks.schema.Schema
|
|
132
132
|
|
|
133
133
|
// Date components
|
|
@@ -159,7 +159,7 @@ Schema[java.time.MonthDay] // Month and day combination
|
|
|
159
159
|
|
|
160
160
|
There are also schemas for frequently used Java utility types, UUID and Currency:
|
|
161
161
|
|
|
162
|
-
```scala
|
|
162
|
+
```scala
|
|
163
163
|
import zio.blocks.schema.Schema
|
|
164
164
|
|
|
165
165
|
Schema[java.util.UUID] // 128-bit universally unique identifier
|
|
@@ -170,7 +170,7 @@ Schema[java.util.Currency] // ISO 4217 currency code
|
|
|
170
170
|
|
|
171
171
|
ZIO Blocks provides specialized `Option` schemas optimized for primitive types. These avoid boxing overhead by storing primitive values directly in registers:
|
|
172
172
|
|
|
173
|
-
```scala
|
|
173
|
+
```scala
|
|
174
174
|
import zio.blocks.schema.Schema
|
|
175
175
|
|
|
176
176
|
import zio.blocks.schema.Schema
|
|
@@ -207,7 +207,7 @@ To learn how to create custom collection schemas, check out the [`Sequence`](./r
|
|
|
207
207
|
|
|
208
208
|
ZIO Blocks includes a built-in schema for `DynamicValue`, a semi-structured data representation that serves as a superset of JSON:
|
|
209
209
|
|
|
210
|
-
```scala
|
|
210
|
+
```scala
|
|
211
211
|
import zio.blocks.schema._
|
|
212
212
|
|
|
213
213
|
val schema = Schema[DynamicValue] // Semi-structured data (superset of JSON)
|
|
@@ -315,7 +315,7 @@ ZIO Blocks has built-in support for several popular formats, currently `AvroForm
|
|
|
315
315
|
|
|
316
316
|
The following example demonstrates encoding and decoding a `Person` case class to/from JSON using the built-in `JsonFormat`:
|
|
317
317
|
|
|
318
|
-
```scala
|
|
318
|
+
```scala
|
|
319
319
|
import java.nio.ByteBuffer
|
|
320
320
|
|
|
321
321
|
import zio.blocks.schema._
|
|
@@ -387,7 +387,7 @@ ZIO Blocks allows attaching metadata to schemas and their fields, such as docume
|
|
|
387
387
|
|
|
388
388
|
Here is an example of how to set and retrieve documentation values:
|
|
389
389
|
|
|
390
|
-
```scala
|
|
390
|
+
```scala
|
|
391
391
|
import zio.blocks.schema._
|
|
392
392
|
|
|
393
393
|
case class Person(name: String, age: Int)
|
|
@@ -413,7 +413,7 @@ The important thing to note here is that we can use optics to target specific fi
|
|
|
413
413
|
|
|
414
414
|
Similarly, you can set and get example values:
|
|
415
415
|
|
|
416
|
-
```scala
|
|
416
|
+
```scala
|
|
417
417
|
import zio.blocks.schema._
|
|
418
418
|
|
|
419
419
|
// Add example values
|
|
@@ -430,7 +430,7 @@ val fieldExamples: Schema[Person] =
|
|
|
430
430
|
|
|
431
431
|
There are also methods for setting and getting default values:
|
|
432
432
|
|
|
433
|
-
```scala
|
|
433
|
+
```scala
|
|
434
434
|
// Add default value to schema
|
|
435
435
|
val withDefault: Schema[Person] = Schema[Person]
|
|
436
436
|
.defaultValue(Person("Unknown", 0))
|
|
@@ -451,7 +451,7 @@ val ageDefault: Option[Int] =
|
|
|
451
451
|
|
|
452
452
|
To access a specific part of a schema, we can use the `Schema#get` method, which takes an optic and returns the reflection of the targeted field.
|
|
453
453
|
|
|
454
|
-
```scala
|
|
454
|
+
```scala
|
|
455
455
|
import zio.blocks.schema._
|
|
456
456
|
|
|
457
457
|
case class Person(name: String, address: Address)
|
|
@@ -479,7 +479,7 @@ val addressSchema: Option[Reflect.Bound[Address]] =
|
|
|
479
479
|
|
|
480
480
|
This method enables us to retrieve the schema for any nested field using optics. For example, to get the schema for the `street` field inside the `address` of a `Person`, we can do as follows:
|
|
481
481
|
|
|
482
|
-
```scala
|
|
482
|
+
```scala
|
|
483
483
|
val streetSchema: Option[Reflect.Bound[String]] =
|
|
484
484
|
Schema[Person].get(Person.address(Address.street))
|
|
485
485
|
```
|
|
@@ -498,7 +498,7 @@ case class Schema[A](reflect: Reflect.Bound[A]) {
|
|
|
498
498
|
|
|
499
499
|
Here is an example of updating the documentation of a nested field:
|
|
500
500
|
|
|
501
|
-
```scala
|
|
501
|
+
```scala
|
|
502
502
|
// Update schema at a specific path
|
|
503
503
|
val updated: Option[Schema[Person]] = Schema[Person]
|
|
504
504
|
.updated(Person.address)(_.doc("Mailing address"))
|
|
@@ -526,7 +526,7 @@ case class Schema[A](reflect: Reflect.Bound[A]) {
|
|
|
526
526
|
|
|
527
527
|
These methods enable us to use `@@` syntax for applying aspects to either the entire schema or a specific path within the schema using optics:
|
|
528
528
|
|
|
529
|
-
```scala
|
|
529
|
+
```scala
|
|
530
530
|
import zio.blocks.schema._
|
|
531
531
|
|
|
532
532
|
// Apply aspect to entire schema
|
|
@@ -560,7 +560,7 @@ final case class Schema[A](reflect: Reflect.Bound[A]) {
|
|
|
560
560
|
|
|
561
561
|
Here is an example of adding modifiers to a schema:
|
|
562
562
|
|
|
563
|
-
```scala
|
|
563
|
+
```scala
|
|
564
564
|
// Add modifier to schema
|
|
565
565
|
val modified: Schema[Person] = Schema[Person]
|
|
566
566
|
.modifier(Modifier.config("db.table-name", "person_table"))
|
|
@@ -590,7 +590,7 @@ The `transform` method allows you to define transformations that can fail by thr
|
|
|
590
590
|
|
|
591
591
|
Here are examples of both:
|
|
592
592
|
|
|
593
|
-
```scala
|
|
593
|
+
```scala
|
|
594
594
|
import zio.blocks.schema.{Schema, SchemaError}
|
|
595
595
|
|
|
596
596
|
// For types with validation (may fail)
|