@zio.dev/zio-blocks 0.0.22 → 0.0.25
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/guides/query-dsl-extending.md +758 -0
- package/guides/query-dsl-fluent-builder.md +1287 -0
- package/guides/query-dsl-reified-optics.md +494 -0
- package/guides/query-dsl-sql.md +680 -0
- package/index.md +42 -39
- package/package.json +1 -1
- package/reference/codec.md +20 -18
- package/reference/docs.md +1 -1
- package/reference/dynamic-optic.md +4 -0
- package/reference/json-schema.md +1 -1
- package/reference/json.md +2 -2
- package/reference/media-type.md +460 -0
- package/reference/optics.md +4 -0
- package/reference/schema-expr.md +669 -0
- package/reference/schema.md +1 -0
- package/reference/type-class-derivation.md +50 -12
- package/scope.md +744 -490
- package/sidebars.js +12 -0
- package/undocumented-report.md +331 -0
|
@@ -193,6 +193,7 @@ import zio.blocks.schema.DynamicValue.Null
|
|
|
193
193
|
import zio.blocks.schema.binding.*
|
|
194
194
|
import zio.blocks.schema.derive.Deriver
|
|
195
195
|
import zio.blocks.typeid.TypeId
|
|
196
|
+
import zio.blocks.docs.Doc
|
|
196
197
|
|
|
197
198
|
object DeriveShow extends Deriver[Show] {
|
|
198
199
|
|
|
@@ -1450,7 +1451,7 @@ Now we can use the derived `Gen[Person]` instance to generate random `Person` va
|
|
|
1450
1451
|
|
|
1451
1452
|
```scala
|
|
1452
1453
|
val random = new Random(42) // Seeded for reproducible output
|
|
1453
|
-
// random: Random = scala.util.Random@
|
|
1454
|
+
// random: Random = scala.util.Random@280d230c
|
|
1454
1455
|
|
|
1455
1456
|
Person.gen.generate(random)
|
|
1456
1457
|
// res14: Person = Person(name = "p", age = -1360544799)
|
|
@@ -1598,12 +1599,13 @@ val tc: TC[A] = schema.deriving(deriver)
|
|
|
1598
1599
|
.derive // finalize the derivation
|
|
1599
1600
|
```
|
|
1600
1601
|
|
|
1601
|
-
The `DerivationBuilder` offers
|
|
1602
|
+
The `DerivationBuilder` offers three overloaded `instance` methods for providing custom type class instances:
|
|
1602
1603
|
|
|
1603
1604
|
```scala
|
|
1604
1605
|
final case class DerivationBuilder[TC[_], A](...) {
|
|
1605
1606
|
def instance[B](optic: Optic[A, B], instance: => TC[B]): DerivationBuilder[TC, A]
|
|
1606
|
-
def instance[B](typeId: TypeId[B],
|
|
1607
|
+
def instance[B](typeId: TypeId[B], instance: => TC[B]): DerivationBuilder[TC, A]
|
|
1608
|
+
def instance[P, B](typeId: TypeId[P], termName: String, instance: => TC[B]): DerivationBuilder[TC, A]
|
|
1607
1609
|
}
|
|
1608
1610
|
```
|
|
1609
1611
|
|
|
@@ -1695,15 +1697,38 @@ personShow.show(Person("Alice", 30))
|
|
|
1695
1697
|
// res32: String = "Person(name = \"Alice\", age = #30)"
|
|
1696
1698
|
```
|
|
1697
1699
|
|
|
1700
|
+
### Overriding by TypeId and Term Name
|
|
1701
|
+
|
|
1702
|
+
The third overload takes a `TypeId[P]` identifying the **parent** record or variant and a `termName` string identifying a field or case within it. This provides medium precision between optic-based (exact path) and type-based (all occurrences) overrides, and is useful when you want to override a specific field across all locations where the parent type appears without having to enumerate each path with an optic:
|
|
1703
|
+
|
|
1704
|
+
```scala
|
|
1705
|
+
val customAgeShow: Show[Int] = new Show[Int] {
|
|
1706
|
+
def show(value: Int): String = s"age=$value"
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
val personShow: Show[Person] = Person.schema
|
|
1710
|
+
.deriving(DeriveShow)
|
|
1711
|
+
.instance(Person.schema.reflect.typeId, "age", customAgeShow)
|
|
1712
|
+
.derive
|
|
1713
|
+
```
|
|
1714
|
+
|
|
1715
|
+
The `typeId` refers to the parent record/variant type (here `Person`), not the field type. If no term with the given name exists in the parent type, the override is silently ignored.
|
|
1716
|
+
|
|
1717
|
+
```scala
|
|
1718
|
+
personShow.show(Person("Alice", 30))
|
|
1719
|
+
// res33: String = "Person(name = \"Alice\", age = age=30)"
|
|
1720
|
+
```
|
|
1721
|
+
|
|
1698
1722
|
### Resolution Order
|
|
1699
1723
|
|
|
1700
1724
|
When the derivation engine encounters a schema node, it resolves the type class instance using the following priority order:
|
|
1701
1725
|
|
|
1702
1726
|
1. **Optic-based override** (most precise): If an instance override was registered using an optic that matches the current path in the schema tree, that instance is used.
|
|
1703
|
-
2. **TypeId-
|
|
1704
|
-
3. **
|
|
1727
|
+
2. **TypeId + term-name override** (medium precision): If no optic-based match is found, it checks for an override registered by parent type ID and term name.
|
|
1728
|
+
3. **TypeId-based override** (more general): If no term-name match is found, it checks for an instance override registered by type ID.
|
|
1729
|
+
4. **Automatic derivation** (default): If no override is found, the deriver's method (e.g., `derivePrimitive`, `deriveRecord`) is called to automatically derive the instance.
|
|
1705
1730
|
|
|
1706
|
-
This means you can set a global override by type and then selectively refine specific fields using optics:
|
|
1731
|
+
This means you can set a global override by type and then selectively refine specific fields using optics or term names:
|
|
1707
1732
|
|
|
1708
1733
|
```scala
|
|
1709
1734
|
val companyShow: Show[Company] = Company.schema
|
|
@@ -1721,7 +1746,7 @@ In this example, all `String` fields use single quotes, except for the CEO's nam
|
|
|
1721
1746
|
|
|
1722
1747
|
```scala
|
|
1723
1748
|
companyShow.show(Company(Person("Alice", 30), "tech"))
|
|
1724
|
-
//
|
|
1749
|
+
// res34: String = "Company(ceo = Person(name = ALICE, age = 30), industry = 'tech')"
|
|
1725
1750
|
```
|
|
1726
1751
|
|
|
1727
1752
|
### Chaining Multiple Overrides
|
|
@@ -1742,7 +1767,7 @@ val personShow: Show[Person] = Person.schema
|
|
|
1742
1767
|
|
|
1743
1768
|
```scala
|
|
1744
1769
|
personShow.show(Person("Alice", 30))
|
|
1745
|
-
//
|
|
1770
|
+
// res35: String = "Person(name = <<Alice>>, age = age=30)"
|
|
1746
1771
|
```
|
|
1747
1772
|
|
|
1748
1773
|
## Custom Modifiers
|
|
@@ -1755,12 +1780,13 @@ While modifiers can be attached to schemas directly using Scala annotations (e.g
|
|
|
1755
1780
|
- You need different modifiers for different derivation contexts (e.g., one JSON codec with renamed fields, another without)
|
|
1756
1781
|
- You want to keep the schema clean and push format-specific concerns into the derivation layer
|
|
1757
1782
|
|
|
1758
|
-
The `DerivationBuilder` offers
|
|
1783
|
+
The `DerivationBuilder` offers three overloaded `modifier` methods:
|
|
1759
1784
|
|
|
1760
1785
|
```scala
|
|
1761
1786
|
final case class DerivationBuilder[TC[_], A](...) {
|
|
1762
|
-
def modifier[B](typeId: TypeId[B],
|
|
1763
|
-
def modifier[B](optic: Optic[A, B], modifier: Modifier)
|
|
1787
|
+
def modifier[B](typeId: TypeId[B], modifier: Modifier.Reflect): DerivationBuilder[TC, A]
|
|
1788
|
+
def modifier[B](optic: Optic[A, B], modifier: Modifier): DerivationBuilder[TC, A]
|
|
1789
|
+
def modifier[B](typeId: TypeId[B], termName: String, modifier: Modifier.Term): DerivationBuilder[TC, A]
|
|
1764
1790
|
}
|
|
1765
1791
|
```
|
|
1766
1792
|
|
|
@@ -1822,7 +1848,7 @@ val user = User(1L, "Alice", "alice@example.com", 95.5)
|
|
|
1822
1848
|
// internalScore = 95.5
|
|
1823
1849
|
// )
|
|
1824
1850
|
new String(jsonCodec.encode(user), "UTF-8")
|
|
1825
|
-
//
|
|
1851
|
+
// res36: String = "{\"id\":1,\"full_name\":\"Alice\",\"email\":\"alice@example.com\"}"
|
|
1826
1852
|
```
|
|
1827
1853
|
|
|
1828
1854
|
### Adding Modifiers by TypeId
|
|
@@ -1837,6 +1863,18 @@ val jsonCodec: JsonBinaryCodec[User] = User.schema
|
|
|
1837
1863
|
.derive
|
|
1838
1864
|
```
|
|
1839
1865
|
|
|
1866
|
+
### Adding Modifiers by TypeId and Term Name
|
|
1867
|
+
|
|
1868
|
+
The `modifier` method with `TypeId` and `termName` allows you to add a `Modifier.Term` to a specific field or case identified by name inside a parent type identified by its `TypeId`. This is useful when you want to target a specific term without constructing an optic for it. The `typeId` refers to the parent record/variant type that owns the term. If no term with the given name exists in the parent type, the modifier is silently ignored:
|
|
1869
|
+
|
|
1870
|
+
```scala
|
|
1871
|
+
val jsonCodec: JsonBinaryCodec[User] = User.schema
|
|
1872
|
+
.deriving(JsonBinaryCodecDeriver)
|
|
1873
|
+
.modifier(User.schema.reflect.typeId, "name", Modifier.rename("full_name"))
|
|
1874
|
+
.modifier(User.schema.reflect.typeId, "internalScore", Modifier.transient())
|
|
1875
|
+
.derive
|
|
1876
|
+
```
|
|
1877
|
+
|
|
1840
1878
|
## Derivation Process In-Depth
|
|
1841
1879
|
|
|
1842
1880
|
Until now, we learned how to implement the `Deriver` methods for different schema patterns. But we haven't yet discussed how the overall derivation process works. In this section, we will go through the main steps of derivation in detail.
|