@zio.dev/zio-blocks 0.0.33 → 0.0.55
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/adr/2026-07-18-data-migration.md +123 -0
- package/guides/async-getting-started.md +687 -0
- package/guides/compile-time-resource-safety-with-scope.md +21 -16
- package/guides/getting-started-with-mux.md +1395 -0
- package/guides/query-dsl-extending.md +161 -102
- package/guides/query-dsl-fluent-builder.md +217 -157
- package/guides/query-dsl-reified-optics.md +12 -10
- package/guides/query-dsl-sql.md +640 -165
- package/guides/sql-checked-interpolation.md +173 -0
- package/guides/sql-transactions.md +286 -0
- package/guides/telemetry-guide.md +1130 -0
- package/guides/zio-schema-migration.md +29 -22
- package/index.md +248 -389
- package/package.json +1 -1
- package/plans/config-follow-up-prs.md +188 -0
- package/plans/config-pr-assessment-roadmap.md +310 -0
- package/reference/MuxDataFlow.jsx +250 -0
- package/reference/async.md +1499 -0
- package/reference/chunk.md +3533 -308
- package/reference/codegen/case-class.md +436 -0
- package/reference/codegen/emitter-config.md +383 -0
- package/reference/codegen/examples.md +664 -0
- package/reference/codegen/field.md +316 -0
- package/reference/codegen/index.md +317 -0
- package/reference/codegen/scala-emitter.md +392 -0
- package/reference/codegen/scala-file.md +276 -0
- package/reference/codegen/sealed-trait.md +408 -0
- package/reference/codegen/type-definition.md +340 -0
- package/reference/codegen/type-ref.md +201 -0
- package/reference/combinators.md +347 -117
- package/reference/config/config-decoder.md +460 -0
- package/reference/config/config-source.md +489 -0
- package/reference/config/errors.md +278 -0
- package/reference/config/flags.md +369 -0
- package/reference/config/formats.md +314 -0
- package/reference/config/index.md +304 -0
- package/reference/config/rollout.md +336 -0
- package/reference/context.md +9 -52
- package/reference/data-migration.md +269 -0
- package/reference/datastar/attributes.md +302 -0
- package/reference/datastar/events.md +234 -0
- package/reference/datastar/index.md +256 -0
- package/reference/datastar/signals.md +230 -0
- package/reference/datastar/sse.md +295 -0
- package/reference/datastar.md +346 -0
- package/reference/docs.md +1461 -345
- package/reference/endpoint/auth-type.md +146 -0
- package/reference/endpoint/bulk-creation.md +96 -0
- package/reference/endpoint/endpoint.md +297 -0
- package/reference/endpoint/http-codec.md +249 -0
- package/reference/endpoint/index.md +745 -0
- package/reference/endpoint/path-codec.md +225 -0
- package/reference/endpoint/route-pattern.md +194 -0
- package/reference/endpoint/route-tree.md +111 -0
- package/reference/endpoint/segment-codec.md +199 -0
- package/reference/html.md +1424 -0
- package/reference/htmx/attribute-values.md +359 -0
- package/reference/htmx/hx-encoding.md +111 -0
- package/reference/htmx/hx-params.md +204 -0
- package/reference/htmx/hx-swap.md +276 -0
- package/reference/htmx/hx-sync.md +251 -0
- package/reference/htmx/hx-target.md +314 -0
- package/reference/htmx/hx-trigger.md +457 -0
- package/reference/htmx/hx-url-update.md +239 -0
- package/reference/htmx/index.md +807 -0
- package/reference/htmx/response-headers.md +240 -0
- package/reference/http-model/headers.md +735 -0
- package/reference/http-model/index.md +49 -0
- package/reference/http-model/model.md +1517 -0
- package/reference/http-model/schema-codecs.md +522 -0
- package/reference/http-model/schema.md +750 -0
- package/reference/http-model/server-sent-event.md +341 -0
- package/reference/jwt.md +195 -0
- package/reference/maybe.md +943 -0
- package/reference/media-type.md +2 -2
- package/reference/mux.md +254 -0
- package/reference/mux.mdx +828 -0
- package/reference/openapi.md +1351 -0
- package/reference/projection.md +654 -0
- package/reference/resource-management/defer-handle.md +1 -1
- package/reference/resource-management/resource.md +31 -98
- package/reference/resource-management/scope.md +28 -220
- package/reference/resource-management/wire.md +5 -55
- package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
- package/reference/ringbuffer/MpscDiagram.jsx +618 -0
- package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
- package/reference/ringbuffer/SpscDiagram.jsx +677 -0
- package/reference/ringbuffer/advanced.mdx +109 -0
- package/reference/ringbuffer/index.mdx +145 -0
- package/reference/ringbuffer/mpmc.mdx +185 -0
- package/reference/ringbuffer/mpsc.mdx +164 -0
- package/reference/ringbuffer/spmc.mdx +108 -0
- package/reference/ringbuffer/spsc.mdx +416 -0
- package/reference/{allows.md → schema/allows.md} +4 -100
- package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
- package/reference/{binding.md → schema/binding.md} +3 -4
- package/reference/schema/built-in-codecs/avro.md +451 -0
- package/reference/schema/built-in-codecs/bson.md +510 -0
- package/reference/schema/built-in-codecs/csv.md +564 -0
- package/reference/schema/built-in-codecs/index.md +77 -0
- package/reference/schema/built-in-codecs/json/index.md +295 -0
- package/reference/schema/built-in-codecs/json/json-config.md +217 -0
- package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
- package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
- package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
- package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
- package/reference/schema/built-in-codecs/messagepack.md +508 -0
- package/reference/schema/built-in-codecs/thrift.md +433 -0
- package/reference/schema/built-in-codecs/toon.md +1078 -0
- package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
- package/reference/schema/built-in-codecs/yaml.md +552 -0
- package/reference/{codec.md → schema/codec.md} +11 -11
- package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +196 -5
- package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
- package/reference/schema/format.md +92 -0
- package/reference/schema/index.md +52 -0
- package/reference/schema/migration.md +297 -0
- package/reference/{modifier.md → schema/modifier.md} +58 -7
- package/reference/{optics.md → schema/optics.md} +2 -2
- package/reference/{patch.md → schema/patch.md} +1 -1
- package/{path-interpolator.md → reference/schema/path-interpolator.md} +167 -72
- package/reference/schema/reflect-transformer.md +140 -0
- package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
- package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
- package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
- package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
- package/reference/schema/schema-search.md +263 -0
- package/reference/{schema.md → schema/schema.md} +22 -2
- package/reference/{structural-types.md → schema/structural-types.md} +1 -1
- package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
- package/reference/smithy.md +1032 -0
- package/reference/sql/db-codec-deriver.md +71 -0
- package/reference/sql/db-codec.md +687 -0
- package/reference/sql/db-con.md +271 -0
- package/reference/sql/db-connection.md +153 -0
- package/reference/sql/db-param-writer.md +77 -0
- package/reference/sql/db-param.md +66 -0
- package/reference/sql/db-result-reader.md +148 -0
- package/reference/sql/db-tx.md +114 -0
- package/reference/sql/db-value.md +41 -0
- package/reference/sql/ddl.md +85 -0
- package/reference/sql/frag.md +288 -0
- package/reference/sql/index.md +341 -0
- package/reference/sql/repo.md +600 -0
- package/reference/sql/sql-dialect.md +73 -0
- package/reference/sql/sql-logger.md +62 -0
- package/reference/sql/sql-name-mapper.md +70 -0
- package/reference/sql/table-metadata.md +134 -0
- package/reference/sql/table.md +448 -0
- package/reference/sql/transactor-zio.md +399 -0
- package/reference/sql/transactor.md +363 -0
- package/reference/sql-zio.md +112 -0
- package/reference/streams/core/index.md +32 -0
- package/reference/streams/core/pipeline.md +854 -0
- package/reference/streams/core/sink.md +1404 -0
- package/reference/streams/core/stream.md +3236 -0
- package/reference/streams/execution-and-compatibility/async-execution.md +822 -0
- package/reference/streams/execution-and-compatibility/index.md +35 -0
- package/reference/streams/execution-and-compatibility/platform-differences.md +297 -0
- package/reference/streams/execution-and-compatibility/scala-2-compatibility.md +88 -0
- package/reference/streams/execution-and-compatibility/zero-boxing.md +393 -0
- package/reference/streams/index.md +726 -0
- package/reference/streams/primitives/index.md +30 -0
- package/reference/streams/primitives/reader.md +1992 -0
- package/reference/streams/primitives/writer.md +1201 -0
- package/reference/telemetry/common/any-value.md +90 -0
- package/reference/telemetry/common/attribute-key.md +87 -0
- package/reference/telemetry/common/attributes.md +118 -0
- package/reference/telemetry/common/index.md +39 -0
- package/reference/telemetry/common/instrumentation-scope.md +24 -0
- package/reference/telemetry/common/resource.md +34 -0
- package/reference/telemetry/index.md +311 -0
- package/reference/telemetry/logging/index.md +197 -0
- package/reference/telemetry/logging/log-enrichment.md +72 -0
- package/reference/telemetry/logging/log-formatter.md +100 -0
- package/reference/telemetry/logging/log-record-processor.md +56 -0
- package/reference/telemetry/logging/log-record.md +44 -0
- package/reference/telemetry/logging/log-writer.md +64 -0
- package/reference/telemetry/logging/logger-provider.md +142 -0
- package/reference/telemetry/logging/logger.md +83 -0
- package/reference/telemetry/logging/severity.md +62 -0
- package/reference/telemetry/metrics/index.md +150 -0
- package/reference/telemetry/metrics/instruments.md +183 -0
- package/reference/telemetry/metrics/labeled-instruments.md +74 -0
- package/reference/telemetry/metrics/meter-provider.md +76 -0
- package/reference/telemetry/metrics/meter.md +98 -0
- package/reference/telemetry/metrics/metric-data.md +57 -0
- package/reference/telemetry/otel/custom-exporter.md +216 -0
- package/reference/telemetry/otel/index.md +212 -0
- package/reference/telemetry/tracing/index.md +155 -0
- package/reference/telemetry/tracing/sampler.md +89 -0
- package/reference/telemetry/tracing/span-builder.md +57 -0
- package/reference/telemetry/tracing/span-context.md +39 -0
- package/reference/telemetry/tracing/span-data.md +32 -0
- package/reference/telemetry/tracing/span-kind.md +55 -0
- package/reference/telemetry/tracing/span-processor.md +53 -0
- package/reference/telemetry/tracing/span-status.md +47 -0
- package/reference/telemetry/tracing/span.md +117 -0
- package/reference/telemetry/tracing/tracer-provider.md +91 -0
- package/reference/telemetry/tracing/tracer.md +52 -0
- package/reference/typeid.md +5 -83
- package/sidebars.js +376 -43
- package/undocumented-report.md +528 -270
- package/reference/formats.md +0 -694
- package/reference/http-model.md +0 -1716
- package/reference/streams.md +0 -989
- package/ringbuffer.md +0 -249
- /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
- /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
- /package/reference/{lazy.md → schema/lazy.md} +0 -0
- /package/reference/{reflect.md → schema/reflect.md} +0 -0
- /package/reference/{registers.md → schema/registers.md} +0 -0
- /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
- /package/reference/{syntax.md → schema/syntax.md} +0 -0
- /package/reference/{validation.md → schema/validation.md} +0 -0
|
@@ -3,13 +3,20 @@ id: path-interpolator
|
|
|
3
3
|
title: "Path Interpolator"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
:::note
|
|
7
|
+
To use the path interpolator `p"..."`, you must import the schema package: `import zio.blocks.schema._`
|
|
8
|
+
:::
|
|
9
|
+
|
|
6
10
|
The path interpolator `p"..."` is a compile-time string interpolator for constructing `DynamicOptic` instances in ZIO Blocks. It provides a clean, concise syntax for building optic paths that navigate through complex data structures, with all parsing and validation happening at compile time for zero runtime overhead.
|
|
7
11
|
|
|
8
12
|
**Why use the path interpolator?**
|
|
9
13
|
|
|
10
14
|
Instead of manually constructing optics like this:
|
|
11
15
|
|
|
16
|
+
|
|
12
17
|
```scala
|
|
18
|
+
import zio.blocks.schema._
|
|
19
|
+
|
|
13
20
|
DynamicOptic(Vector(
|
|
14
21
|
DynamicOptic.Node.Field("users"),
|
|
15
22
|
DynamicOptic.Node.Elements,
|
|
@@ -20,6 +27,8 @@ DynamicOptic(Vector(
|
|
|
20
27
|
You can write:
|
|
21
28
|
|
|
22
29
|
```scala
|
|
30
|
+
import zio.blocks.schema._
|
|
31
|
+
|
|
23
32
|
p".users[*].email"
|
|
24
33
|
```
|
|
25
34
|
|
|
@@ -46,9 +55,11 @@ val path = p".users[0].name"
|
|
|
46
55
|
|
|
47
56
|
## Syntax Reference
|
|
48
57
|
|
|
58
|
+
This section documents the complete path syntax with examples for each component type.
|
|
59
|
+
|
|
49
60
|
### Field Access
|
|
50
61
|
|
|
51
|
-
Access fields in records using dot notation. The leading dot is optional
|
|
62
|
+
Access fields in records using dot notation. The leading dot is optional:
|
|
52
63
|
|
|
53
64
|
```scala
|
|
54
65
|
// With leading dot
|
|
@@ -64,7 +75,7 @@ p".user.address.street"
|
|
|
64
75
|
// Equivalent to: Field("user") → Field("address") → Field("street")
|
|
65
76
|
```
|
|
66
77
|
|
|
67
|
-
|
|
78
|
+
Field names can also include special characters and keywords:
|
|
68
79
|
|
|
69
80
|
```scala
|
|
70
81
|
p"._private" // Fields starting with underscore
|
|
@@ -77,7 +88,7 @@ p".true" // Keywords as field names (true, false, null)
|
|
|
77
88
|
|
|
78
89
|
Access sequence elements by index, multiple indices, or ranges.
|
|
79
90
|
|
|
80
|
-
|
|
91
|
+
To access a single element by index:
|
|
81
92
|
|
|
82
93
|
```scala
|
|
83
94
|
p"[0]" // AtIndex(0)
|
|
@@ -85,7 +96,7 @@ p"[42]" // AtIndex(42)
|
|
|
85
96
|
p"[2147483647]" // AtIndex(Int.MaxValue)
|
|
86
97
|
```
|
|
87
98
|
|
|
88
|
-
|
|
99
|
+
To access multiple elements at specific indices:
|
|
89
100
|
|
|
90
101
|
```scala
|
|
91
102
|
p"[0,1,2]" // AtIndices(Seq(0, 1, 2))
|
|
@@ -93,7 +104,7 @@ p"[0, 2, 5]" // AtIndices(Seq(0, 2, 5)) - spaces allowed
|
|
|
93
104
|
p"[5,2,8,1]" // Order preserved
|
|
94
105
|
```
|
|
95
106
|
|
|
96
|
-
|
|
107
|
+
To select a range of consecutive elements:
|
|
97
108
|
|
|
98
109
|
```scala
|
|
99
110
|
p"[0:5]" // AtIndices(Seq(0, 1, 2, 3, 4))
|
|
@@ -105,14 +116,14 @@ p"[10:5]" // AtIndices(Seq.empty) - inverted range
|
|
|
105
116
|
|
|
106
117
|
### Element Selectors
|
|
107
118
|
|
|
108
|
-
Select all elements in a sequence using wildcard syntax
|
|
119
|
+
Select all elements in a sequence using wildcard syntax:
|
|
109
120
|
|
|
110
121
|
```scala
|
|
111
122
|
p"[*]" // Elements - all elements
|
|
112
123
|
p"[:*]" // Elements - alternative syntax
|
|
113
124
|
```
|
|
114
125
|
|
|
115
|
-
|
|
126
|
+
To navigate nested sequences:
|
|
116
127
|
|
|
117
128
|
```scala
|
|
118
129
|
p"[*][*]" // Nested sequences: all elements of all elements
|
|
@@ -123,7 +134,7 @@ p"[*][0]" // First element of each sequence
|
|
|
123
134
|
|
|
124
135
|
Access map values by key, where keys can be strings, integers, booleans, or characters.
|
|
125
136
|
|
|
126
|
-
|
|
137
|
+
To use string keys:
|
|
127
138
|
|
|
128
139
|
```scala
|
|
129
140
|
p"""{"host"}""" // AtMapKey(String("host"))
|
|
@@ -133,7 +144,7 @@ p"""{"🎉"}""" // Emoji keys
|
|
|
133
144
|
p"""{""}""" // Empty string key
|
|
134
145
|
```
|
|
135
146
|
|
|
136
|
-
|
|
147
|
+
To use integer keys:
|
|
137
148
|
|
|
138
149
|
```scala
|
|
139
150
|
p"{42}" // AtMapKey(Int(42))
|
|
@@ -143,14 +154,14 @@ p"{2147483647}" // AtMapKey(Int.MaxValue)
|
|
|
143
154
|
p"{-2147483648}" // AtMapKey(Int.MinValue)
|
|
144
155
|
```
|
|
145
156
|
|
|
146
|
-
|
|
157
|
+
To use boolean keys:
|
|
147
158
|
|
|
148
159
|
```scala
|
|
149
160
|
p"{true}" // AtMapKey(Boolean(true))
|
|
150
161
|
p"{false}" // AtMapKey(Boolean(false))
|
|
151
162
|
```
|
|
152
163
|
|
|
153
|
-
|
|
164
|
+
To use character keys:
|
|
154
165
|
|
|
155
166
|
```scala
|
|
156
167
|
p"{'a'}" // AtMapKey(Char('a'))
|
|
@@ -158,7 +169,7 @@ p"{' '}" // AtMapKey(Char(' '))
|
|
|
158
169
|
p"{'9'}" // AtMapKey(Char('9'))
|
|
159
170
|
```
|
|
160
171
|
|
|
161
|
-
|
|
172
|
+
To use multiple keys of the same or mixed types:
|
|
162
173
|
|
|
163
174
|
```scala
|
|
164
175
|
p"""{"foo", "bar", "baz"}""" // AtMapKeys(Seq(...))
|
|
@@ -172,7 +183,7 @@ p"""{"s", 'c', 42, true}""" // All supported types
|
|
|
172
183
|
|
|
173
184
|
### Map Selectors
|
|
174
185
|
|
|
175
|
-
Select all keys or all values in a map
|
|
186
|
+
Select all keys or all values in a map:
|
|
176
187
|
|
|
177
188
|
```scala
|
|
178
189
|
p"{*}" // MapValues - all values
|
|
@@ -180,7 +191,7 @@ p"{:*}" // MapValues - alternative syntax
|
|
|
180
191
|
p"{*:}" // MapKeys - all keys
|
|
181
192
|
```
|
|
182
193
|
|
|
183
|
-
|
|
194
|
+
To apply map selectors to nested maps:
|
|
184
195
|
|
|
185
196
|
```scala
|
|
186
197
|
p"{*}{*}" // Nested maps: all values of all values
|
|
@@ -189,7 +200,7 @@ p"{*:}{*:}" // All keys of all keys
|
|
|
189
200
|
|
|
190
201
|
### Variant Case Access
|
|
191
202
|
|
|
192
|
-
Navigate into a specific variant case using angle brackets
|
|
203
|
+
Navigate into a specific variant case using angle brackets:
|
|
193
204
|
|
|
194
205
|
```scala
|
|
195
206
|
p"<Left>" // Case("Left")
|
|
@@ -198,7 +209,7 @@ p"<Some>" // Case("Some")
|
|
|
198
209
|
p"<None>" // Case("None")
|
|
199
210
|
```
|
|
200
211
|
|
|
201
|
-
|
|
212
|
+
Variant case names can include special characters and keywords:
|
|
202
213
|
|
|
203
214
|
```scala
|
|
204
215
|
p"<_Empty>" // Cases starting with underscore
|
|
@@ -206,7 +217,7 @@ p"<Case1>" // Cases with digits
|
|
|
206
217
|
p"<café>" // Unicode case names
|
|
207
218
|
```
|
|
208
219
|
|
|
209
|
-
|
|
220
|
+
To navigate nested variant cases:
|
|
210
221
|
|
|
211
222
|
```scala
|
|
212
223
|
p"<A><B><C>" // Nested variants
|
|
@@ -216,7 +227,7 @@ p"<A><B><C>" // Nested variants
|
|
|
216
227
|
|
|
217
228
|
Search for values matching a schema pattern anywhere in a data structure using the `#` prefix.
|
|
218
229
|
|
|
219
|
-
|
|
230
|
+
To search for nominal types by name:
|
|
220
231
|
|
|
221
232
|
```scala
|
|
222
233
|
p"#Person" // Find all values of type Person
|
|
@@ -224,7 +235,7 @@ p"#User" // Find all values of type User
|
|
|
224
235
|
p"#Address" // Find all values of type Address
|
|
225
236
|
```
|
|
226
237
|
|
|
227
|
-
|
|
238
|
+
To search for primitive types:
|
|
228
239
|
|
|
229
240
|
```scala
|
|
230
241
|
p"#string" // Find all string values
|
|
@@ -233,7 +244,7 @@ p"#boolean" // Find all boolean values
|
|
|
233
244
|
p"#uuid" // Find all UUID values
|
|
234
245
|
```
|
|
235
246
|
|
|
236
|
-
|
|
247
|
+
To search for records with specific field structures:
|
|
237
248
|
|
|
238
249
|
```scala
|
|
239
250
|
p"#record { name: string }" // Find records with a string 'name' field
|
|
@@ -241,13 +252,13 @@ p"#record { name: string, age: int }" // Find records with both fields
|
|
|
241
252
|
p"#record { items: list(Person) }" // Nested schema
|
|
242
253
|
```
|
|
243
254
|
|
|
244
|
-
|
|
255
|
+
To search for variants with specific case structures:
|
|
245
256
|
|
|
246
257
|
```scala
|
|
247
258
|
p"#variant { Left: int, Right: string }" // Find Either-like variants
|
|
248
259
|
```
|
|
249
260
|
|
|
250
|
-
|
|
261
|
+
To search for collection types:
|
|
251
262
|
|
|
252
263
|
```scala
|
|
253
264
|
p"#list(string)" // Find lists of strings
|
|
@@ -256,13 +267,15 @@ p"#map(string, int)" // Find maps from string to int
|
|
|
256
267
|
p"#option(Person)" // Find optional Person values
|
|
257
268
|
```
|
|
258
269
|
|
|
259
|
-
|
|
270
|
+
`set(...)` and `vector(...)` work as synonyms for `list(...)` — all three parse to the same `SchemaRepr.Sequence` pattern, since the pattern only cares about the element type, not which collection it comes from.
|
|
271
|
+
|
|
272
|
+
To match any value regardless of type:
|
|
260
273
|
|
|
261
274
|
```scala
|
|
262
275
|
p"#_" // Find any value (matches everything)
|
|
263
276
|
```
|
|
264
277
|
|
|
265
|
-
|
|
278
|
+
To combine path navigation with schema search:
|
|
266
279
|
|
|
267
280
|
```scala
|
|
268
281
|
p".users#Person" // Search for Person in users field
|
|
@@ -284,7 +297,7 @@ String and character literals support standard escape sequences:
|
|
|
284
297
|
| `\"` | `"` | Double quote |
|
|
285
298
|
| `\\` | `\` | Backslash |
|
|
286
299
|
|
|
287
|
-
|
|
300
|
+
Here are some examples of escape sequences in use:
|
|
288
301
|
|
|
289
302
|
```scala
|
|
290
303
|
p"""{"foo\nbar"}""" // String key with newline
|
|
@@ -300,6 +313,8 @@ Combine different path elements to navigate complex nested structures.
|
|
|
300
313
|
|
|
301
314
|
### Field → Sequence
|
|
302
315
|
|
|
316
|
+
Access sequence elements by index or range through a field:
|
|
317
|
+
|
|
303
318
|
```scala
|
|
304
319
|
p".items[0]" // First item
|
|
305
320
|
p".items[*]" // All items
|
|
@@ -309,6 +324,8 @@ p".items[0:5]" // Items 0 through 4
|
|
|
309
324
|
|
|
310
325
|
### Field → Map
|
|
311
326
|
|
|
327
|
+
Access map values by key through a field:
|
|
328
|
+
|
|
312
329
|
```scala
|
|
313
330
|
p""".config{"host"}""" // Map lookup
|
|
314
331
|
p".settings{42}" // Integer key
|
|
@@ -318,6 +335,8 @@ p".lookup{*:}" // All map keys
|
|
|
318
335
|
|
|
319
336
|
### Field → Variant
|
|
320
337
|
|
|
338
|
+
Navigate into variant cases through a field:
|
|
339
|
+
|
|
321
340
|
```scala
|
|
322
341
|
p".result<Success>" // Variant case
|
|
323
342
|
p".response<Ok>" // HTTP response variant
|
|
@@ -325,6 +344,8 @@ p".response<Ok>" // HTTP response variant
|
|
|
325
344
|
|
|
326
345
|
### Nested Structures
|
|
327
346
|
|
|
347
|
+
Combine different path elements to build complex navigation through nested data:
|
|
348
|
+
|
|
328
349
|
```scala
|
|
329
350
|
// Record in sequence
|
|
330
351
|
p".users[0].name"
|
|
@@ -345,6 +366,8 @@ p".response<Ok>.body"
|
|
|
345
366
|
|
|
346
367
|
### Deeply Nested Paths
|
|
347
368
|
|
|
369
|
+
Chain multiple path operators for deeply nested data structures:
|
|
370
|
+
|
|
348
371
|
```scala
|
|
349
372
|
// Complex nested navigation
|
|
350
373
|
p""".root.children[*].metadata{"tags"}[0]"""
|
|
@@ -359,35 +382,47 @@ p""".a[0]{"k"}<V>.b[*]{*}.c{*:}"""
|
|
|
359
382
|
|
|
360
383
|
## Root and Empty Paths
|
|
361
384
|
|
|
385
|
+
An empty path refers to the root of the data structure:
|
|
386
|
+
|
|
362
387
|
```scala
|
|
363
388
|
p"" // Empty path = root
|
|
364
|
-
// Equivalent to: DynamicOptic.root
|
|
365
|
-
// Equivalent to: DynamicOptic(Vector.empty)
|
|
366
389
|
```
|
|
367
390
|
|
|
368
391
|
## Compile-Time Safety
|
|
369
392
|
|
|
370
393
|
The path interpolator **rejects runtime interpolation** to prevent unsafe dynamic path construction.
|
|
371
394
|
|
|
372
|
-
|
|
395
|
+
### Examples of Safety Checks
|
|
396
|
+
|
|
397
|
+
Runtime interpolation will fail to compile:
|
|
373
398
|
|
|
374
399
|
```scala
|
|
400
|
+
import zio.blocks.schema._
|
|
401
|
+
|
|
375
402
|
val fieldName = "email"
|
|
376
403
|
val path = p".$fieldName"
|
|
377
404
|
// Error: Path interpolator does not support runtime arguments.
|
|
378
|
-
//
|
|
405
|
+
// error:
|
|
406
|
+
// Path interpolator does not support runtime arguments. Use only literal strings like p".field[0]"
|
|
407
|
+
// val path = p".$fieldName"
|
|
408
|
+
// ^^^^^^^^^^^^^
|
|
379
409
|
```
|
|
380
410
|
|
|
381
|
-
|
|
411
|
+
Array indices also cannot be interpolated at runtime:
|
|
382
412
|
|
|
383
413
|
```scala
|
|
414
|
+
import zio.blocks.schema._
|
|
415
|
+
|
|
384
416
|
val idx = 5
|
|
385
417
|
val path = p"[$idx]"
|
|
386
418
|
// Error: Path interpolator does not support runtime arguments.
|
|
387
|
-
//
|
|
419
|
+
// error:
|
|
420
|
+
// Path interpolator does not support runtime arguments. Use only literal strings like p".field[0]"
|
|
421
|
+
// val path = p"[$idx]"
|
|
422
|
+
// ^^^^^^^^^
|
|
388
423
|
```
|
|
389
424
|
|
|
390
|
-
|
|
425
|
+
Instead, use only literal strings at compile time:
|
|
391
426
|
|
|
392
427
|
```scala
|
|
393
428
|
val path = p".users[0].email" // ✓ Works
|
|
@@ -395,31 +430,46 @@ val path = p".users[0].email" // ✓ Works
|
|
|
395
430
|
|
|
396
431
|
### Parse Error Examples
|
|
397
432
|
|
|
398
|
-
Invalid syntax is caught at compile time:
|
|
433
|
+
Invalid syntax is caught at compile time. Here are examples of common errors:
|
|
399
434
|
|
|
400
435
|
```scala
|
|
436
|
+
import zio.blocks.schema._
|
|
437
|
+
|
|
401
438
|
// Unterminated string
|
|
402
439
|
p"""{"foo"""
|
|
403
|
-
// Error: Unterminated string literal
|
|
440
|
+
// Error: Unterminated string literal
|
|
404
441
|
|
|
405
|
-
// Invalid escape sequence
|
|
442
|
+
// Invalid escape sequence
|
|
406
443
|
p"""{"foo\x"}"""
|
|
407
|
-
// Error: Invalid escape sequence
|
|
444
|
+
// Error: Invalid escape sequence
|
|
408
445
|
|
|
409
446
|
// Unexpected character
|
|
410
447
|
p".field@"
|
|
411
|
-
// Error: Unexpected character '@'
|
|
448
|
+
// Error: Unexpected character '@'
|
|
412
449
|
|
|
413
450
|
// Invalid identifier
|
|
414
451
|
p"."
|
|
415
|
-
// Error: Invalid identifier
|
|
452
|
+
// Error: Invalid identifier
|
|
453
|
+
// error:
|
|
454
|
+
// Unterminated string literal starting at position 1
|
|
455
|
+
// error:
|
|
456
|
+
// Invalid escape sequence '\x' at position 6
|
|
457
|
+
// error:
|
|
458
|
+
// Unexpected character '@' at position 6. Expected field, index, map, or variant accessor
|
|
459
|
+
// error:
|
|
460
|
+
// Invalid identifier at position 1
|
|
461
|
+
// error:
|
|
462
|
+
// Conflicting definitions:
|
|
463
|
+
// val path: zio.blocks.schema.DynamicOptic in object MdocApp at line 14 and
|
|
464
|
+
// val path: zio.blocks.schema.DynamicOptic in object MdocApp at line 114
|
|
465
|
+
//
|
|
416
466
|
```
|
|
417
467
|
|
|
418
468
|
## Performance
|
|
419
469
|
|
|
420
470
|
**Zero Runtime Overhead**
|
|
421
471
|
|
|
422
|
-
All path parsing and validation occurs at **compile time**. The interpolator generates the exact same bytecode as manual `DynamicOptic` construction:
|
|
472
|
+
All path parsing and validation occurs at **compile time**. The interpolator generates the exact same bytecode as manual `DynamicOptic` construction. Here's the comparison:
|
|
423
473
|
|
|
424
474
|
```scala
|
|
425
475
|
// These produce identical bytecode:
|
|
@@ -436,8 +486,12 @@ There is **no runtime parsing**, **no reflection**, and **no performance penalty
|
|
|
436
486
|
|
|
437
487
|
## Examples
|
|
438
488
|
|
|
489
|
+
This section shows practical examples of using the path interpolator with realistic data structures.
|
|
490
|
+
|
|
439
491
|
### Accessing Nested Fields
|
|
440
492
|
|
|
493
|
+
To access deeply nested fields in a data structure:
|
|
494
|
+
|
|
441
495
|
```scala
|
|
442
496
|
import zio.blocks.schema._
|
|
443
497
|
|
|
@@ -447,14 +501,18 @@ case class Person(name: String, age: Int, address: Address)
|
|
|
447
501
|
// Access nested street field
|
|
448
502
|
val streetPath = p".address.street"
|
|
449
503
|
|
|
450
|
-
// Use with DynamicValue
|
|
451
|
-
val person =
|
|
504
|
+
// Use with DynamicValue - example (requires actual DynamicValue instance)
|
|
505
|
+
val person: DynamicValue = ???
|
|
452
506
|
val street = person.get(streetPath)
|
|
453
507
|
```
|
|
454
508
|
|
|
455
509
|
### Working with Collections
|
|
456
510
|
|
|
511
|
+
To work with sequences and access elements by index or range:
|
|
512
|
+
|
|
457
513
|
```scala
|
|
514
|
+
import zio.blocks.schema._
|
|
515
|
+
|
|
458
516
|
case class User(id: Int, email: String, tags: Seq[String])
|
|
459
517
|
case class Company(name: String, users: Seq[User])
|
|
460
518
|
|
|
@@ -470,7 +528,11 @@ val specificUsersPath = p".users[0,2,5]"
|
|
|
470
528
|
|
|
471
529
|
### Map Lookups
|
|
472
530
|
|
|
531
|
+
To work with map data structures and access values by key:
|
|
532
|
+
|
|
473
533
|
```scala
|
|
534
|
+
import zio.blocks.schema._
|
|
535
|
+
|
|
474
536
|
case class Config(
|
|
475
537
|
settings: Map[String, String],
|
|
476
538
|
ports: Map[Int, String]
|
|
@@ -491,13 +553,21 @@ val allPortsPath = p"ports{*:}"
|
|
|
491
553
|
|
|
492
554
|
### Variant Case Handling
|
|
493
555
|
|
|
556
|
+
To navigate variant cases in your data structures:
|
|
557
|
+
|
|
494
558
|
```scala
|
|
559
|
+
import zio.blocks.schema._
|
|
560
|
+
|
|
495
561
|
sealed trait Result[+A]
|
|
496
562
|
case class Success[A](value: A) extends Result[A]
|
|
497
563
|
case class Failure(error: String) extends Result[Nothing]
|
|
498
564
|
|
|
499
565
|
case class Response(result: Result[User])
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
Use paths to navigate into specific cases:
|
|
500
569
|
|
|
570
|
+
```scala
|
|
501
571
|
// Navigate into Success case
|
|
502
572
|
val successValuePath = p".result<Success>.value"
|
|
503
573
|
|
|
@@ -507,7 +577,11 @@ val errorPath = p".result<Failure>.error"
|
|
|
507
577
|
|
|
508
578
|
### Real-World Example: API Response
|
|
509
579
|
|
|
580
|
+
To extract specific data from complex nested API response structures:
|
|
581
|
+
|
|
510
582
|
```scala
|
|
583
|
+
import zio.blocks.schema._
|
|
584
|
+
|
|
511
585
|
case class Metadata(tags: Seq[String], version: Int)
|
|
512
586
|
case class Item(id: String, data: String, metadata: Metadata)
|
|
513
587
|
case class ApiResponse(
|
|
@@ -531,8 +605,12 @@ val apiKeyPath = p"""config{"api_key"}"""
|
|
|
531
605
|
|
|
532
606
|
## Before & After Comparison
|
|
533
607
|
|
|
608
|
+
This comparison shows how the path interpolator simplifies optic path construction compared to manual approaches.
|
|
609
|
+
|
|
534
610
|
### Manual Construction (Before)
|
|
535
611
|
|
|
612
|
+
Manual path construction requires verbose imports and careful construction:
|
|
613
|
+
|
|
536
614
|
```scala
|
|
537
615
|
import zio.blocks.schema.DynamicOptic
|
|
538
616
|
import zio.blocks.schema.DynamicOptic.Node
|
|
@@ -582,7 +660,7 @@ val path2 = p""".root.children[*].metadata{"tags"}[0]"""
|
|
|
582
660
|
val path3 = p"""data{"foo", "bar", 42}"""
|
|
583
661
|
```
|
|
584
662
|
|
|
585
|
-
|
|
663
|
+
The path interpolator provides significant benefits:
|
|
586
664
|
|
|
587
665
|
- **90% less code** for typical paths
|
|
588
666
|
- **Easier to read** and understand intent
|
|
@@ -592,9 +670,15 @@ val path3 = p"""data{"foo", "bar", 42}"""
|
|
|
592
670
|
|
|
593
671
|
## Practical Usage Patterns
|
|
594
672
|
|
|
673
|
+
These patterns demonstrate effective ways to use the path interpolator in real-world scenarios.
|
|
674
|
+
|
|
595
675
|
### Building Paths Dynamically (at Compile Time)
|
|
596
676
|
|
|
677
|
+
While runtime variables are not supported, you can compose literal paths at compile time:
|
|
678
|
+
|
|
597
679
|
```scala
|
|
680
|
+
import zio.blocks.schema._
|
|
681
|
+
|
|
598
682
|
// You can't use runtime variables, but you can compose literal paths:
|
|
599
683
|
val basePath = p".data.items"
|
|
600
684
|
val emailPath = basePath(p"[*].email")
|
|
@@ -603,26 +687,31 @@ val emailPath = basePath(p"[*].email")
|
|
|
603
687
|
|
|
604
688
|
### Working with DynamicValue
|
|
605
689
|
|
|
690
|
+
To navigate and extract values from dynamic data:
|
|
691
|
+
|
|
606
692
|
```scala
|
|
607
693
|
import zio.blocks.schema._
|
|
608
694
|
|
|
609
|
-
val data: DynamicValue =
|
|
695
|
+
val data: DynamicValue = ???
|
|
610
696
|
|
|
611
697
|
// Navigate and extract
|
|
612
698
|
val value = data.get(p".users[0].email")
|
|
613
699
|
|
|
614
|
-
// Update at path
|
|
615
|
-
val
|
|
700
|
+
// Update at path (using appropriate constructor)
|
|
701
|
+
val ageValue: DynamicValue = ???
|
|
702
|
+
val updated = data.set(p".users[0].age", ageValue)
|
|
616
703
|
```
|
|
617
704
|
|
|
618
705
|
### Integration with Schema Optics
|
|
619
706
|
|
|
707
|
+
To use path interpolators with schema-based optics:
|
|
708
|
+
|
|
620
709
|
```scala
|
|
621
710
|
import zio.blocks.schema._
|
|
622
711
|
|
|
623
|
-
case class
|
|
624
|
-
object
|
|
625
|
-
implicit val schema: Schema[
|
|
712
|
+
case class UserRecord(name: String, email: String)
|
|
713
|
+
object UserRecord extends CompanionOptics[UserRecord] {
|
|
714
|
+
implicit val schema: Schema[UserRecord] = Schema.derived
|
|
626
715
|
|
|
627
716
|
// Use path interpolator for complex lenses
|
|
628
717
|
val email = $(_.email)
|
|
@@ -634,23 +723,22 @@ val dynamicPath = p".email"
|
|
|
634
723
|
|
|
635
724
|
## Tips and Best Practices
|
|
636
725
|
|
|
637
|
-
1. **Use the leading dot for clarity**: While optional, `p".field"` is more explicit than `p"field"
|
|
726
|
+
1. **Use the leading dot for clarity**: While optional, `p".field"` is more explicit than `p"field"`:
|
|
638
727
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
3. **Compose paths when needed**: Break complex paths into reusable components
|
|
642
|
-
```scala
|
|
728
|
+
```scala mdoc:compile-only
|
|
643
729
|
val userPath = p".users[0]"
|
|
644
730
|
val emailPath = userPath(p".email")
|
|
645
731
|
```
|
|
646
732
|
|
|
647
|
-
4. **Use raw strings for map keys**: Triple-quoted strings avoid escape hell
|
|
648
|
-
|
|
733
|
+
4. **Use raw strings for map keys**: Triple-quoted strings avoid escape hell:
|
|
734
|
+
|
|
735
|
+
```scala mdoc:compile-only
|
|
649
736
|
p"""config{"api.key"}""" // Better than p"config{\"api.key\"}"
|
|
650
737
|
```
|
|
651
738
|
|
|
652
|
-
5. **Document complex paths**: Add comments explaining what nested paths navigate
|
|
653
|
-
|
|
739
|
+
5. **Document complex paths**: Add comments explaining what nested paths navigate:
|
|
740
|
+
|
|
741
|
+
```scala mdoc:compile-only
|
|
654
742
|
// Get the first tag from each user's metadata
|
|
655
743
|
val tagsPath = p".users[*].metadata.tags[0]"
|
|
656
744
|
```
|
|
@@ -670,29 +758,36 @@ These limitations ensure compile-time safety and zero runtime overhead.
|
|
|
670
758
|
|
|
671
759
|
```scala
|
|
672
760
|
val optic = DynamicOptic.root.field("users").elements.field("email")
|
|
761
|
+
// optic: DynamicOptic = DynamicOptic(
|
|
762
|
+
// IndexedSeq(Field("users"), Elements, Field("email"))
|
|
763
|
+
// )
|
|
673
764
|
println(optic) // Output: .users[*].email
|
|
765
|
+
// .users[*].email
|
|
674
766
|
|
|
675
767
|
// The output can be copy-pasted into p"..."
|
|
676
768
|
val same = p".users[*].email"
|
|
769
|
+
// same: DynamicOptic = DynamicOptic(
|
|
770
|
+
// Vector(Field("users"), Elements, Field("email"))
|
|
771
|
+
// )
|
|
677
772
|
```
|
|
678
773
|
|
|
679
774
|
**Examples:**
|
|
680
775
|
|
|
681
|
-
| DynamicOptic Construction |
|
|
682
|
-
|
|
683
|
-
| `DynamicOptic.root.field("name")` |
|
|
684
|
-
| `DynamicOptic.root.field("address").field("street")` |
|
|
685
|
-
| `DynamicOptic.root.caseOf("Some")`
|
|
686
|
-
| `DynamicOptic.root.at(0)`
|
|
687
|
-
| `DynamicOptic.root.atIndices(0, 2, 5)`
|
|
688
|
-
| `DynamicOptic.elements`
|
|
689
|
-
| `DynamicOptic.root.atKey("host")`
|
|
690
|
-
| `DynamicOptic.root.atKey(80)`
|
|
691
|
-
| `DynamicOptic.mapValues`
|
|
692
|
-
| `DynamicOptic.mapKeys`
|
|
693
|
-
| `DynamicOptic.wrapped`
|
|
694
|
-
| `DynamicOptic.root.searchSchema(SchemaRepr.Nominal("Person"))`
|
|
695
|
-
| `DynamicOptic.root.searchSchema(SchemaRepr.Primitive("string"))`
|
|
776
|
+
| DynamicOptic Construction | Interpolator Syntax |
|
|
777
|
+
|------------------------------------------------------|---------------------|
|
|
778
|
+
| `DynamicOptic.root.field("name")` | `p".name"` |
|
|
779
|
+
| `DynamicOptic.root.field("address").field("street")` | `p".address.street"` |
|
|
780
|
+
| `DynamicOptic.root.caseOf("Some")` | `p"<Some>"` |
|
|
781
|
+
| `DynamicOptic.root.at(0)` | `p"[0]"` |
|
|
782
|
+
| `DynamicOptic.root.atIndices(0, 2, 5)` | `p"[0,2,5]"` |
|
|
783
|
+
| `DynamicOptic.elements` | `p"[*]"` |
|
|
784
|
+
| `DynamicOptic.root.atKey("host")` | `p"{"host"}"` |
|
|
785
|
+
| `DynamicOptic.root.atKey(80)` | `p"{80}"` |
|
|
786
|
+
| `DynamicOptic.mapValues` | `p"{*}"` |
|
|
787
|
+
| `DynamicOptic.mapKeys` | `p"{*:}"` |
|
|
788
|
+
| `DynamicOptic.wrapped` | `p".~"` |
|
|
789
|
+
| `DynamicOptic.root.searchSchema(SchemaRepr.Nominal("Person"))` | `p"#Person"` |
|
|
790
|
+
| `DynamicOptic.root.searchSchema(SchemaRepr.Primitive("string"))` | `p"#string"` |
|
|
696
791
|
|
|
697
792
|
## Summary
|
|
698
793
|
|