@zio.dev/zio-blocks 0.0.33 → 0.0.51

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.
Files changed (150) hide show
  1. package/guides/compile-time-resource-safety-with-scope.md +16 -17
  2. package/guides/getting-started-with-mux.md +1507 -0
  3. package/guides/query-dsl-extending.md +161 -102
  4. package/guides/query-dsl-fluent-builder.md +217 -157
  5. package/guides/query-dsl-reified-optics.md +12 -10
  6. package/guides/query-dsl-sql.md +246 -165
  7. package/guides/telemetry-guide.md +1069 -0
  8. package/guides/zio-schema-migration.md +29 -22
  9. package/index.md +292 -50
  10. package/package.json +1 -1
  11. package/plans/config-follow-up-prs.md +188 -0
  12. package/plans/config-pr-assessment-roadmap.md +310 -0
  13. package/reference/MuxDataFlow.jsx +250 -0
  14. package/reference/async.md +651 -0
  15. package/reference/chunk.md +3533 -308
  16. package/reference/codegen/case-class.md +436 -0
  17. package/reference/codegen/emitter-config.md +383 -0
  18. package/reference/codegen/examples.md +664 -0
  19. package/reference/codegen/field.md +316 -0
  20. package/reference/codegen/index.md +317 -0
  21. package/reference/codegen/scala-emitter.md +392 -0
  22. package/reference/codegen/scala-file.md +276 -0
  23. package/reference/codegen/sealed-trait.md +408 -0
  24. package/reference/codegen/type-definition.md +340 -0
  25. package/reference/codegen/type-ref.md +201 -0
  26. package/reference/combinators.md +347 -117
  27. package/reference/config.md +158 -0
  28. package/reference/context.md +4 -4
  29. package/reference/datastar.md +346 -0
  30. package/reference/docs.md +1461 -345
  31. package/reference/endpoint/auth-type.md +146 -0
  32. package/reference/endpoint/endpoint.md +297 -0
  33. package/reference/endpoint/http-codec.md +249 -0
  34. package/reference/endpoint/index.md +825 -0
  35. package/reference/endpoint/path-codec.md +237 -0
  36. package/reference/endpoint/route-pattern.md +196 -0
  37. package/reference/endpoint/route-tree.md +111 -0
  38. package/reference/endpoint/segment-codec.md +212 -0
  39. package/reference/html.md +1120 -0
  40. package/reference/htmx/attribute-values.md +359 -0
  41. package/reference/htmx/hx-encoding.md +111 -0
  42. package/reference/htmx/hx-params.md +204 -0
  43. package/reference/htmx/hx-swap.md +276 -0
  44. package/reference/htmx/hx-sync.md +251 -0
  45. package/reference/htmx/hx-target.md +314 -0
  46. package/reference/htmx/hx-trigger.md +457 -0
  47. package/reference/htmx/hx-url-update.md +239 -0
  48. package/reference/htmx/index.md +855 -0
  49. package/reference/http-model/index.md +47 -0
  50. package/reference/http-model/model.md +1481 -0
  51. package/reference/http-model/schema.md +747 -0
  52. package/reference/maybe.md +826 -0
  53. package/reference/media-type.md +2 -2
  54. package/reference/mux.mdx +823 -0
  55. package/reference/openapi.md +1351 -0
  56. package/reference/resource-management/defer-handle.md +1 -1
  57. package/reference/resource-management/resource.md +31 -2
  58. package/reference/resource-management/scope.md +28 -12
  59. package/reference/resource-management/wire.md +3 -7
  60. package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
  61. package/reference/ringbuffer/MpscDiagram.jsx +618 -0
  62. package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
  63. package/reference/ringbuffer/SpscDiagram.jsx +677 -0
  64. package/reference/ringbuffer/advanced.mdx +109 -0
  65. package/reference/ringbuffer/index.mdx +145 -0
  66. package/reference/ringbuffer/mpmc.mdx +151 -0
  67. package/reference/ringbuffer/mpsc.mdx +132 -0
  68. package/reference/ringbuffer/spmc.mdx +108 -0
  69. package/reference/ringbuffer/spsc.mdx +344 -0
  70. package/reference/{allows.md → schema/allows.md} +4 -4
  71. package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
  72. package/reference/{binding.md → schema/binding.md} +2 -3
  73. package/reference/schema/built-in-codecs/avro.md +451 -0
  74. package/reference/schema/built-in-codecs/bson.md +480 -0
  75. package/reference/schema/built-in-codecs/csv.md +564 -0
  76. package/reference/schema/built-in-codecs/index.md +77 -0
  77. package/reference/schema/built-in-codecs/json/index.md +295 -0
  78. package/reference/schema/built-in-codecs/json/json-config.md +217 -0
  79. package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
  80. package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
  81. package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
  82. package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
  83. package/reference/schema/built-in-codecs/messagepack.md +508 -0
  84. package/reference/schema/built-in-codecs/thrift.md +433 -0
  85. package/reference/schema/built-in-codecs/toon.md +1078 -0
  86. package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
  87. package/reference/schema/built-in-codecs/yaml.md +552 -0
  88. package/reference/{codec.md → schema/codec.md} +10 -10
  89. package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
  90. package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
  91. package/reference/schema/format.md +92 -0
  92. package/reference/schema/index.md +50 -0
  93. package/reference/schema/migration.md +297 -0
  94. package/reference/{modifier.md → schema/modifier.md} +58 -7
  95. package/reference/{optics.md → schema/optics.md} +2 -2
  96. package/reference/{patch.md → schema/patch.md} +1 -1
  97. package/{path-interpolator.md → reference/schema/path-interpolator.md} +165 -72
  98. package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
  99. package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
  100. package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
  101. package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
  102. package/reference/{schema.md → schema/schema.md} +12 -0
  103. package/reference/{structural-types.md → schema/structural-types.md} +1 -1
  104. package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
  105. package/reference/smithy.md +533 -0
  106. package/reference/sql/db-codec-deriver.md +71 -0
  107. package/reference/sql/db-codec.md +687 -0
  108. package/reference/sql/db-con.md +271 -0
  109. package/reference/sql/db-connection.md +153 -0
  110. package/reference/sql/db-param-writer.md +77 -0
  111. package/reference/sql/db-param.md +66 -0
  112. package/reference/sql/db-result-reader.md +146 -0
  113. package/reference/sql/db-tx.md +82 -0
  114. package/reference/sql/db-value.md +41 -0
  115. package/reference/sql/ddl.md +85 -0
  116. package/reference/sql/frag.md +254 -0
  117. package/reference/sql/index.md +341 -0
  118. package/reference/sql/repo.md +600 -0
  119. package/reference/sql/sql-dialect.md +73 -0
  120. package/reference/sql/sql-logger.md +62 -0
  121. package/reference/sql/sql-name-mapper.md +70 -0
  122. package/reference/sql/table-metadata.md +134 -0
  123. package/reference/sql/table.md +448 -0
  124. package/reference/sql/transactor-zio.md +399 -0
  125. package/reference/sql/transactor.md +353 -0
  126. package/reference/sql-zio.md +112 -0
  127. package/reference/streams/concurrent-operators.md +106 -0
  128. package/reference/streams/index.md +653 -0
  129. package/reference/streams/pipeline.md +718 -0
  130. package/reference/streams/reader.md +1284 -0
  131. package/reference/streams/scala-2-compatibility.md +55 -0
  132. package/reference/streams/sink.md +1426 -0
  133. package/reference/streams/stream.md +2526 -0
  134. package/reference/streams/writer.md +1045 -0
  135. package/reference/streams/zero-boxing.md +275 -0
  136. package/reference/telemetry.md +693 -0
  137. package/reference/typeid.md +5 -19
  138. package/sidebars.js +238 -43
  139. package/reference/formats.md +0 -694
  140. package/reference/http-model.md +0 -1716
  141. package/reference/streams.md +0 -989
  142. package/ringbuffer.md +0 -249
  143. /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
  144. /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
  145. /package/reference/{lazy.md → schema/lazy.md} +0 -0
  146. /package/reference/{reflect.md → schema/reflect.md} +0 -0
  147. /package/reference/{registers.md → schema/registers.md} +0 -0
  148. /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
  149. /package/reference/{syntax.md → schema/syntax.md} +0 -0
  150. /package/reference/{validation.md → schema/validation.md} +0 -0
@@ -167,6 +167,68 @@ import zio.blocks.schema.json._
167
167
  val jsonCodec = Person.schema.derive(JsonFormat)
168
168
  ```
169
169
 
170
+ ## Customizing Derivation with Instance and Modifier Overrides
171
+
172
+ By default, `Deriver` automatically derives codecs for all types. But sometimes you need to customize how specific types are encoded or decoded—for example, encoding `LocalDate` as `"dd/MM/yyyy"` instead of ISO format.
173
+
174
+ ZIO Blocks provides three levels of customization, in progressive order:
175
+
176
+ 1. **Type-level override** (`Deriver.withInstance`) — Override the codec for ALL occurrences of a type. Configure once, use everywhere:
177
+
178
+ ```scala
179
+ import java.time.LocalDate
180
+ import java.time.format.DateTimeFormatter
181
+
182
+ // Create a custom JsonCodec for LocalDate
183
+ val customDateCodec: JsonCodec[LocalDate] = new JsonCodec[LocalDate] {
184
+ private val fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy")
185
+ def decodeValue(in: JsonReader): LocalDate = LocalDate.parse(in.readString(), fmt)
186
+ def encodeValue(x: LocalDate, out: JsonWriter): Unit = out.writeVal(fmt.format(x))
187
+ // ... AST overrides ...
188
+ }
189
+
190
+ // Configure the deriver once
191
+ val myDeriver = JsonCodecDeriver.withInstance[LocalDate](customDateCodec)
192
+
193
+ // Use everywhere — all LocalDate fields use the custom codec
194
+ val codec1 = Schema[Event].deriving(myDeriver).derive
195
+ val codec2 = Schema[Meeting].deriving(myDeriver).derive
196
+ ```
197
+
198
+ 2. **Field-level override** (`Deriver.withInstance` with typeId + termName) — Override a specific field only:
199
+
200
+ ```scala
201
+ // Only Event.date uses custom format; other LocalDate fields are unchanged
202
+ val deriver = JsonCodecDeriver.withInstance[Event, LocalDate](
203
+ TypeId.of[Event], "date", customDateCodec
204
+ )
205
+ ```
206
+
207
+ 3. **Modifier override** (`Deriver.withModifier`) — Rename fields, add aliases:
208
+
209
+ ```scala
210
+ val deriver = JsonCodecDeriver.withModifier(
211
+ TypeId.of[Person], "firstName", Modifier.rename("first_name")
212
+ )
213
+ ```
214
+
215
+ ### Chaining Overrides
216
+
217
+ Overrides compose, allowing you to build complex derivers incrementally:
218
+
219
+ ```scala
220
+ val myDeriver = JsonCodecDeriver
221
+ .withInstance[LocalDate](customDateCodec)
222
+ .withModifier(TypeId.of[Event], "name", Modifier.rename("title"))
223
+ ```
224
+
225
+ ### Important Notes
226
+
227
+ - `withInstance` and `withModifier` return a NEW deriver (they are immutable).
228
+ - When combined with `DerivationBuilder`, deriver-level instance overrides take precedence over builder-level instance overrides. Modifier override precedence is order-sensitive and should not be assumed to follow the same rule.
229
+ - Unknown `termName` values are silently ignored.
230
+ - The `B` type parameter in field-level `withInstance` is not statically checked against the actual field type.
231
+
170
232
  ## Example 1: Deriving a `Show` Type Class Instance
171
233
 
172
234
  Let's say we want to derive a `Show` type class instance for any type of type `A`:
@@ -1455,7 +1517,7 @@ Now we can use the derived `Gen[Person]` instance to generate random `Person` va
1455
1517
 
1456
1518
  ```scala
1457
1519
  val random = new Random(42) // Seeded for reproducible output
1458
- // random: Random = scala.util.Random@643bb7d2
1520
+ // random: Random = scala.util.Random@d903a4c
1459
1521
 
1460
1522
  Person.gen.generate(random)
1461
1523
  // res14: Person = Person(name = "p", age = -1360544799)
@@ -0,0 +1,533 @@
1
+ ---
2
+ id: smithy
3
+ title: "Smithy"
4
+ ---
5
+
6
+ `zio-blocks-smithy` is a **Smithy IDL parser and AST library** providing a complete representation of Smithy 2.0 API models. It enables parsing Smithy IDL text into rich data structures, querying shape definitions, and pretty-printing models back to valid IDL syntax—all without external dependencies.
7
+
8
+ ## Installation
9
+
10
+ Add the library to your build configuration:
11
+
12
+ ```scala
13
+ libraryDependencies += "dev.zio" %% "zio-blocks-smithy" % "0.0.51"
14
+ ```
15
+
16
+ Supported Scala versions: 2.13.x and 3.x
17
+
18
+ ## Quick Start
19
+
20
+ Parse Smithy IDL text into a model, query shapes, and serialize back:
21
+
22
+ ```scala
23
+ import zio.blocks.smithy._
24
+
25
+ val smithyText = """$version: "2"
26
+ namespace com.example.api
27
+
28
+ structure User {
29
+ @required
30
+ id: String
31
+ name: String
32
+ }
33
+
34
+ operation GetUser {
35
+ input: GetUserInput
36
+ output: User
37
+ }
38
+
39
+ structure GetUserInput {
40
+ @required
41
+ id: String
42
+ }
43
+ """
44
+
45
+ // Parse IDL text into a model
46
+ val result = SmithyModel.parse(smithyText)
47
+
48
+ // Access shapes and data
49
+ result match {
50
+ case Right(model) =>
51
+ model.findShape("User").foreach { userDef =>
52
+ println(s"Found shape: ${userDef.name}")
53
+ }
54
+ case Left(error) =>
55
+ println(s"Parse error: ${error.message}")
56
+ }
57
+
58
+ // Serialize back to IDL
59
+ result.foreach { model =>
60
+ val idlText = model.prettyPrint
61
+ println(idlText)
62
+ }
63
+ ```
64
+
65
+ ## Core Types
66
+
67
+ The library provides core types that work together to parse, query, and serialize Smithy models. The main types work together in a parsing → querying → serialization pipeline:
68
+
69
+ ```
70
+ Smithy IDL Text
71
+ ↓
72
+ SmithyModel.parse (public API)
73
+ ↓
74
+ SmithyModel (contains shapes, metadata, traits)
75
+ ├─ shapes: List[ShapeDefinition]
76
+ │ └─ shape: Shape (sealed trait — central type)
77
+ │ ├─ StructureShape(members: List[MemberDefinition])
78
+ │ ├─ ListShape(member: MemberDefinition)
79
+ │ ├─ MapShape(key: MemberDefinition, value: MemberDefinition)
80
+ │ ├─ ServiceShape(operations, resources, errors)
81
+ │ ├─ OperationShape(input, output, errors)
82
+ │ ├─ UnionShape(members: List[MemberDefinition])
83
+ │ ├─ StringShape, BooleanShape, IntegerShape, etc.
84
+ │ └─ ... (and other shape subtypes)
85
+ ├─ MemberDefinition(name: String, target: ShapeId, traits: List[TraitApplication])
86
+ ├─ TraitApplication(id: ShapeId, value: Option[NodeValue])
87
+ ├─ ShapeId (namespace + name identifier)
88
+ └─ NodeValue (metadata values: String, Number, Boolean, Array, Object, Null)
89
+ ↓
90
+ SmithyModel.prettyPrint (public API)
91
+ ↓
92
+ Smithy IDL Text
93
+ ```
94
+
95
+ The root container for a Smithy model. Contains version, namespace, shapes, metadata, and trait applications. The case class and companion object expose the following API:
96
+
97
+ ```scala
98
+ case class SmithyModel(
99
+ version: String, // Smithy version (e.g., "2")
100
+ namespace: String,
101
+ useStatements: List[ShapeId],
102
+ metadata: Map[String, NodeValue],
103
+ shapes: List[ShapeDefinition],
104
+ applyStatements: List[ApplyStatement] = Nil
105
+ ) {
106
+ def findShape(name: String): Option[ShapeDefinition]
107
+ def allShapeIds: List[ShapeId]
108
+ def prettyPrint: String
109
+ def prettyPrint(indent: Int): String
110
+ }
111
+
112
+ object SmithyModel {
113
+ def parse(input: String): Either[SmithyError, SmithyModel]
114
+ }
115
+ ```
116
+
117
+ ## Parsing
118
+
119
+ Parse Smithy IDL text into structured models using `SmithyModel.parse`, handle errors, and validate round-trips.
120
+
121
+ ### Basic Parsing
122
+
123
+ Parse Smithy IDL text and handle the result:
124
+
125
+ ```scala
126
+ import zio.blocks.smithy._
127
+
128
+ val smithyText = """$version: "2"
129
+ namespace com.example
130
+
131
+ string Name
132
+ """
133
+
134
+ SmithyModel.parse(smithyText) match {
135
+ case Right(model) =>
136
+ println(s"Parsed ${model.shapes.length} shapes")
137
+ case Left(error) =>
138
+ println(s"Error: ${error.message}")
139
+ }
140
+ ```
141
+
142
+ ### Handling Parse Errors
143
+
144
+ Access error details including line and column information when parsing fails. `SmithyError` provides detailed context to help locate and fix issues in your Smithy definitions:
145
+
146
+ ```scala
147
+ import zio.blocks.smithy._
148
+
149
+ val invalidSmithy = """$version: "2"
150
+ namespace com.example
151
+
152
+ structure User {
153
+ invalid syntax
154
+ }
155
+ """
156
+
157
+ SmithyModel.parse(invalidSmithy) match {
158
+ case Right(_) =>
159
+ println("Unexpected success")
160
+ case Left(error) =>
161
+ println(s"Error at line ${error.line}, column ${error.column}: ${error.message}")
162
+ }
163
+ ```
164
+
165
+ ### Round-Trip Validation
166
+
167
+ Verify a model parses correctly by round-tripping (parse → serialize → parse again):
168
+
169
+ ```scala
170
+ import zio.blocks.smithy._
171
+
172
+ val original = """$version: "2"
173
+ namespace com.example
174
+
175
+ string MyString
176
+ """
177
+
178
+ val parsed = SmithyModel.parse(original)
179
+ val reprinted = parsed.map(_.prettyPrint)
180
+ val reparsed = reprinted.flatMap(SmithyModel.parse)
181
+
182
+ println(reparsed.isRight) // true if round-trip succeeds
183
+ ```
184
+
185
+ ## Querying & Traversing Shapes
186
+
187
+ Once you have a parsed model, query shapes by name, pattern match on shape types, and traverse their members.
188
+
189
+ ### Finding Shapes
190
+
191
+ Locate shapes by name or retrieve all shape identifiers:
192
+
193
+ ```scala
194
+ import zio.blocks.smithy._
195
+
196
+ val model = SmithyModel.parse("""$version: "2"
197
+ namespace example
198
+
199
+ structure User {
200
+ id: String
201
+ name: String
202
+ }
203
+ """).toOption.get
204
+
205
+ // Find by name
206
+ model.findShape("User").foreach { shapeDef =>
207
+ println(s"Found: ${shapeDef.name}")
208
+ }
209
+
210
+ // Get all shape IDs
211
+ val allIds = model.allShapeIds
212
+ println(s"Total shapes: ${allIds.length}")
213
+ ```
214
+
215
+ ### Pattern Matching on Shapes
216
+
217
+ Determine shape type and access type-specific properties:
218
+
219
+ ```scala
220
+ import zio.blocks.smithy._
221
+
222
+ val model = SmithyModel.parse("""$version: "2"
223
+ namespace example
224
+
225
+ structure User { id: String }
226
+ list UserIds { member: String }
227
+ """).toOption.get
228
+
229
+ model.findShape("User").foreach { shapeDef =>
230
+ shapeDef.shape match {
231
+ case struct: StructureShape =>
232
+ println(s"Structure with ${struct.members.length} members")
233
+ case list: ListShape =>
234
+ println(s"List of ${list.member.target}")
235
+ case _ =>
236
+ println("Other shape type")
237
+ }
238
+ }
239
+ ```
240
+
241
+ ### Traversing Members
242
+
243
+ Iterate over structure/union members and inspect their traits:
244
+
245
+ ```scala
246
+ import zio.blocks.smithy._
247
+
248
+ val model = SmithyModel.parse("""$version: "2"
249
+ namespace example
250
+
251
+ structure User {
252
+ @required
253
+ id: String
254
+ name: String
255
+ }
256
+ """).toOption.get
257
+
258
+ model.findShape("User").foreach { shapeDef =>
259
+ shapeDef.shape match {
260
+ case struct: StructureShape =>
261
+ struct.members.foreach { member =>
262
+ val required = member.traits.exists(_.id.name == "required")
263
+ println(s"${member.name}: ${member.target} (required: $required)")
264
+ }
265
+ case _ => ()
266
+ }
267
+ }
268
+ ```
269
+
270
+ ## Building Models Programmatically
271
+
272
+ Construct Smithy models in code by creating shapes, adding traits, and assembling them into a complete model.
273
+
274
+ ### Creating Shapes
275
+
276
+ Programmatically construct shapes and assemble them into a complete model:
277
+
278
+ ```scala
279
+ import zio.blocks.smithy._
280
+
281
+ val userStructure = StructureShape(
282
+ "User",
283
+ traits = Nil,
284
+ members = List(
285
+ MemberDefinition(
286
+ "id",
287
+ ShapeId("smithy.api", "String"),
288
+ traits = List(TraitApplication.required)
289
+ ),
290
+ MemberDefinition(
291
+ "name",
292
+ ShapeId("smithy.api", "String"),
293
+ traits = Nil
294
+ )
295
+ )
296
+ )
297
+
298
+ val model = SmithyModel(
299
+ version = "2",
300
+ namespace = "com.example",
301
+ useStatements = Nil,
302
+ metadata = Map.empty,
303
+ shapes = List(ShapeDefinition("User", userStructure))
304
+ )
305
+ ```
306
+
307
+ ### Adding Traits
308
+
309
+ Attach metadata traits to shapes during construction. `TraitApplication` provides companion object helper methods like `required`, `documentation`, and others for common traits:
310
+
311
+ ```scala
312
+ import zio.blocks.smithy._
313
+
314
+ val serviceShape = ServiceShape(
315
+ "UserService",
316
+ traits = List(
317
+ TraitApplication.documentation("User management API")
318
+ ),
319
+ version = Some("1.0"),
320
+ operations = List(
321
+ ShapeId("com.example", "GetUser"),
322
+ ShapeId("com.example", "CreateUser")
323
+ ),
324
+ resources = Nil,
325
+ errors = Nil
326
+ )
327
+ ```
328
+
329
+ ## Serializing Models
330
+
331
+ Convert models back to valid Smithy IDL text using `prettyPrint`, with options for custom formatting.
332
+
333
+ ### Basic Serialization
334
+
335
+ Convert a model to valid Smithy IDL text:
336
+
337
+ ```scala
338
+ import zio.blocks.smithy._
339
+
340
+ val model = SmithyModel(
341
+ version = "2",
342
+ namespace = "com.example",
343
+ useStatements = Nil,
344
+ metadata = Map.empty,
345
+ shapes = List(
346
+ ShapeDefinition("Name", StringShape("Name"))
347
+ )
348
+ )
349
+
350
+ val idlText = model.prettyPrint
351
+ println(idlText)
352
+ ```
353
+
354
+ ### Custom Indentation
355
+
356
+ Control indentation width when serializing models:
357
+
358
+ ```scala
359
+ import zio.blocks.smithy._
360
+
361
+ val model = SmithyModel(
362
+ version = "2",
363
+ namespace = "com.example",
364
+ useStatements = Nil,
365
+ metadata = Map.empty,
366
+ shapes = List(
367
+ ShapeDefinition("Data", StructureShape(
368
+ "Data",
369
+ traits = Nil,
370
+ members = List(
371
+ MemberDefinition("field1", ShapeId("smithy.api", "String")),
372
+ MemberDefinition("field2", ShapeId("smithy.api", "String"))
373
+ )
374
+ ))
375
+ )
376
+ )
377
+
378
+ val compact = model.prettyPrint(indent = 2)
379
+ val verbose = model.prettyPrint(indent = 8)
380
+ ```
381
+
382
+ ## Common Use-Cases
383
+
384
+ See how to apply Smithy parsing and querying to real-world workflows: code generation, validation, and model transformation.
385
+
386
+ ### Use-Case 1: Code Generation
387
+
388
+ Load a Smithy model and generate code for each operation:
389
+
390
+ ```scala
391
+ import zio.blocks.smithy._
392
+
393
+ val model = SmithyModel.parse("""$version: "2"
394
+ namespace api
395
+
396
+ service MyService {
397
+ operations: [GetUser, CreateUser]
398
+ }
399
+
400
+ @http(method: "GET", uri: "/users/{id}")
401
+ operation GetUser {
402
+ input: GetUserInput
403
+ output: User
404
+ }
405
+
406
+ @http(method: "POST", uri: "/users")
407
+ operation CreateUser {
408
+ input: CreateUserInput
409
+ output: User
410
+ }
411
+
412
+ structure User { id: String, name: String }
413
+ structure GetUserInput { @required id: String }
414
+ structure CreateUserInput { @required name: String }
415
+ """).toOption.get
416
+
417
+ // Generate code stubs for each operation by pattern matching:
418
+
419
+ model.shapes.foreach { shapeDef =>
420
+ shapeDef.shape match {
421
+ case op: OperationShape =>
422
+ println(s"// Generate operation: ${op.name}")
423
+ op.input.foreach(in => println(s"// input: ${in.name}"))
424
+ op.output.foreach(out => println(s"// output: ${out.name}"))
425
+ case _ => ()
426
+ }
427
+ }
428
+ ```
429
+
430
+ ### Use-Case 2: Validation & Analysis
431
+
432
+ Find deprecated shapes and analyze trait coverage:
433
+
434
+ ```scala
435
+ import zio.blocks.smithy._
436
+
437
+ val model = SmithyModel.parse("""$version: "2"
438
+ namespace example
439
+
440
+ @deprecated
441
+ structure LegacyUser { id: String }
442
+
443
+ structure ModernUser {
444
+ @required
445
+ id: String
446
+ email: String
447
+ }
448
+ """).toOption.get
449
+
450
+ // Find all deprecated shapes:
451
+
452
+ val deprecated = model.shapes.filter { shapeDef =>
453
+ shapeDef.shape.traits.exists(_.id.name == "deprecated")
454
+ }
455
+
456
+ println(s"Deprecated shapes: ${deprecated.map(_.name)}")
457
+ ```
458
+
459
+ ### Use-Case 3: Model Transformation
460
+
461
+ Parse, modify, and re-serialize a model with updated metadata:
462
+
463
+ ```scala
464
+ import zio.blocks.smithy._
465
+
466
+ val original = """$version: "2"
467
+ namespace com.example
468
+
469
+ string UserId
470
+ """
471
+
472
+ val modified = SmithyModel.parse(original).map { model =>
473
+ // Add metadata to the model:
474
+
475
+ val newMetadata = model.metadata + ("version" -> NodeValue.String("1.0"))
476
+ model.copy(metadata = newMetadata)
477
+ }
478
+
479
+ modified.foreach { model =>
480
+ println(model.prettyPrint)
481
+ }
482
+ ```
483
+
484
+ ## Running the Examples
485
+
486
+ All code from this guide is available as runnable examples in the `smithy-examples` module. Examples demonstrate different aspects of the Smithy library.
487
+
488
+ **1. Clone the repository and navigate to the project:**
489
+
490
+ ```bash
491
+ git clone https://github.com/zio/zio-blocks.git
492
+ cd zio-blocks
493
+ ```
494
+
495
+ **2. Run individual examples with sbt:**
496
+
497
+ ### Step 1: Basic Parsing and Querying
498
+
499
+ Parse Smithy IDL text, find shapes by name, and access their structure and metadata:
500
+
501
+ ```bash
502
+ sbt "smithy-examples/runMain smithyexample.BasicParsingAndQuerying"
503
+ ```
504
+
505
+ ### Step 2: Building Models Programmatically
506
+
507
+ Construct Smithy models in code by creating shapes, adding traits, and assembling them into a complete model:
508
+
509
+ ```bash
510
+ sbt "smithy-examples/runMain smithyexample.BuildingModelsAndTraits"
511
+ ```
512
+
513
+ ### Step 3: Validation and Analysis
514
+
515
+ Analyze Smithy models for completeness, find deprecated shapes, check for documentation, and validate API contracts:
516
+
517
+ ```bash
518
+ sbt "smithy-examples/runMain smithyexample.ValidationAndAnalysis"
519
+ ```
520
+
521
+ ### Step 4: Complete Example — Book Store API
522
+
523
+ A comprehensive end-to-end workflow showing a complete book store API model with parsing, entity analysis, error handling, code generation, and statistics:
524
+
525
+ ```bash
526
+ sbt "smithy-examples/runMain smithyexample.BookStoreAPI"
527
+ ```
528
+
529
+ **3. Or compile all examples at once:**
530
+
531
+ ```bash
532
+ sbt "smithy-examples/compile"
533
+ ```
@@ -0,0 +1,71 @@
1
+ ---
2
+ id: db-codec-deriver
3
+ title: "DbCodecDeriver"
4
+ description: "Reference for DbCodecDeriver, the schema-driven derivation engine that converts a Schema[A] into a DbCodec[A] in the sql module."
5
+ keywords:
6
+ - "DbCodecDeriver schema derivation"
7
+ - "DbCodec automatic derivation"
8
+ - "Deriver DbCodec"
9
+ - "SqlNameMapper column naming"
10
+ - "withColumnNameMapper"
11
+ - "deriveRecord deriveVariant"
12
+ - "JSONB fallback codec"
13
+ ---
14
+
15
+ `DbCodecDeriver` is a schema-driven derivation engine that converts a `Schema[A]` into a `DbCodec[A]`.
16
+
17
+ The companion object `DbCodecDeriver` is itself an instance of the class constructed with the default `SqlNameMapper.SnakeCase`. `DbCodec.derived`, `DbCodec.builder`, `DbCodec.derivedWith`, and `Table.derived` all delegate to this deriver; application code rarely constructs or calls it directly.
18
+
19
+ Key properties:
20
+ - **Schema-driven** — derivation is entirely data-driven from the `Schema`'s `Reflect` tree; no separate macro or annotation processor is involved beyond `Schema.derived`.
21
+ - **Configurable naming** — the `columnNameMapper: SqlNameMapper` constructor parameter controls how Scala field names become SQL column names; the default is `SnakeCase`.
22
+ - **Annotation-aware** — `@Modifier.transient` fields are skipped; `@Modifier.rename` overrides the mapper for individual fields; `@Modifier.config("sql.inline","true")` flattens a nested record into the parent's column list.
23
+ - **JSONB fallback** — non-inline nested records, sequences, maps, and dynamic values fall back to a single `TEXT` / `JSONB` column backed by `DbCodec.jsonb`.
24
+
25
+ The structural shape of `DbCodecDeriver` is:
26
+
27
+ ```scala
28
+ class DbCodecDeriver(columnNameMapper: SqlNameMapper = SqlNameMapper.SnakeCase)
29
+ extends Deriver[DbCodec]
30
+
31
+ object DbCodecDeriver extends DbCodecDeriver(SqlNameMapper.SnakeCase) {
32
+ def withColumnNameMapper(mapper: SqlNameMapper): DbCodecDeriver
33
+ }
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ The following example shows the three most common ways to reach `DbCodecDeriver`: through the `derives` clause on a case class, through `DbCodec.derived` (equivalent), and through `DbCodecDeriver.withColumnNameMapper` when a non-default naming strategy is needed.
39
+
40
+ ```scala
41
+ import zio.blocks.sql.{DbCodec, DbCodecDeriver, SqlNameMapper}
42
+ import zio.blocks.schema.Schema
43
+
44
+ // 1. Derives clause — most concise
45
+ case class User(userId: Int, fullName: String) derives DbCodec
46
+ DbCodec[User].columns
47
+ // res0: IndexedSeq[String] = Vector("user_id", "full_name")
48
+
49
+ // 2. DbCodec.derived — equivalent, explicit
50
+ case class Event(eventId: Long, eventType: String)
51
+ object Event { implicit val schema: Schema[Event] = Schema.derived }
52
+ val eventCodec = DbCodec.derived[Event]
53
+ // eventCodec: DbCodec[Event] = zio.blocks.sql.DbCodecDeriver$$anon$20@66f22c33
54
+ eventCodec.columns
55
+ // res1: IndexedSeq[String] = Vector("event_id", "event_type")
56
+
57
+ // 3. withColumnNameMapper — use Identity when your DB already uses camelCase
58
+ case class Widget(widgetId: Int, widgetName: String)
59
+ object Widget { implicit val schema: Schema[Widget] = Schema.derived }
60
+
61
+ val identityDeriver = DbCodecDeriver.withColumnNameMapper(SqlNameMapper.Identity)
62
+ // identityDeriver: DbCodecDeriver = zio.blocks.sql.DbCodecDeriver@33803e98
63
+ val widgetCodec = Widget.schema.deriving(identityDeriver).derive
64
+ // widgetCodec: DbCodec[Widget] = zio.blocks.sql.DbCodecDeriver$$anon$20@35131fba
65
+ widgetCodec.columns
66
+ // res2: IndexedSeq[String] = Vector("widgetId", "widgetName")
67
+ ```
68
+
69
+ ## See Also
70
+
71
+ For the naming strategy that `DbCodecDeriver` applies, see [SqlNameMapper](./sql-name-mapper.md). For the `DbCodec` type that derivation produces, see [DbCodec](./db-codec.md). For `Table.derived` and DDL generation, see [Table](./table.md).