@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.
- package/guides/compile-time-resource-safety-with-scope.md +16 -17
- package/guides/getting-started-with-mux.md +1507 -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 +246 -165
- package/guides/telemetry-guide.md +1069 -0
- package/guides/zio-schema-migration.md +29 -22
- package/index.md +292 -50
- 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 +651 -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.md +158 -0
- package/reference/context.md +4 -4
- package/reference/datastar.md +346 -0
- package/reference/docs.md +1461 -345
- package/reference/endpoint/auth-type.md +146 -0
- package/reference/endpoint/endpoint.md +297 -0
- package/reference/endpoint/http-codec.md +249 -0
- package/reference/endpoint/index.md +825 -0
- package/reference/endpoint/path-codec.md +237 -0
- package/reference/endpoint/route-pattern.md +196 -0
- package/reference/endpoint/route-tree.md +111 -0
- package/reference/endpoint/segment-codec.md +212 -0
- package/reference/html.md +1120 -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 +855 -0
- package/reference/http-model/index.md +47 -0
- package/reference/http-model/model.md +1481 -0
- package/reference/http-model/schema.md +747 -0
- package/reference/maybe.md +826 -0
- package/reference/media-type.md +2 -2
- package/reference/mux.mdx +823 -0
- package/reference/openapi.md +1351 -0
- package/reference/resource-management/defer-handle.md +1 -1
- package/reference/resource-management/resource.md +31 -2
- package/reference/resource-management/scope.md +28 -12
- package/reference/resource-management/wire.md +3 -7
- 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 +151 -0
- package/reference/ringbuffer/mpsc.mdx +132 -0
- package/reference/ringbuffer/spmc.mdx +108 -0
- package/reference/ringbuffer/spsc.mdx +344 -0
- package/reference/{allows.md → schema/allows.md} +4 -4
- package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
- package/reference/{binding.md → schema/binding.md} +2 -3
- package/reference/schema/built-in-codecs/avro.md +451 -0
- package/reference/schema/built-in-codecs/bson.md +480 -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} +10 -10
- package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
- package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
- package/reference/schema/format.md +92 -0
- package/reference/schema/index.md +50 -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} +165 -72
- 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.md → schema/schema.md} +12 -0
- 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 +533 -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 +146 -0
- package/reference/sql/db-tx.md +82 -0
- package/reference/sql/db-value.md +41 -0
- package/reference/sql/ddl.md +85 -0
- package/reference/sql/frag.md +254 -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 +353 -0
- package/reference/sql-zio.md +112 -0
- package/reference/streams/concurrent-operators.md +106 -0
- package/reference/streams/index.md +653 -0
- package/reference/streams/pipeline.md +718 -0
- package/reference/streams/reader.md +1284 -0
- package/reference/streams/scala-2-compatibility.md +55 -0
- package/reference/streams/sink.md +1426 -0
- package/reference/streams/stream.md +2526 -0
- package/reference/streams/writer.md +1045 -0
- package/reference/streams/zero-boxing.md +275 -0
- package/reference/telemetry.md +693 -0
- package/reference/typeid.md +5 -19
- package/sidebars.js +238 -43
- 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
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: csv
|
|
3
|
+
title: "CSV Codec Module"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import Tabs from '@theme/Tabs';
|
|
7
|
+
import TabItem from '@theme/TabItem';
|
|
8
|
+
|
|
9
|
+
`zio-blocks-schema-csv` is a **schema-driven CSV codec module** for serializing and deserializing Scala types to and from CSV format. It provides RFC 4180-compliant parsing and generation with zero dependencies and support for 27 primitive types plus flat record (case class) types. Core types: `CsvCodec`, `CsvConfig`, `CsvError`, `CsvReader`, `CsvWriter`, `CsvFormat`.
|
|
10
|
+
|
|
11
|
+
The main public API is `CsvCodec[A]`, which extends `TextCodec[A]` and provides CSV-specific header support:
|
|
12
|
+
|
|
13
|
+
```scala
|
|
14
|
+
import java.nio.CharBuffer
|
|
15
|
+
import zio.blocks.schema.SchemaError
|
|
16
|
+
|
|
17
|
+
// API signature (conceptual - simplified for clarity)
|
|
18
|
+
trait CsvCodec[A] {
|
|
19
|
+
def headerNames: IndexedSeq[String]
|
|
20
|
+
def encode(value: A, output: CharBuffer): Unit
|
|
21
|
+
def decode(input: CharBuffer): Either[SchemaError, A]
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Motivation
|
|
26
|
+
|
|
27
|
+
CSV is the de facto standard for tabular data exchange across systems, but parsing and serialization are often error-prone when done manually. `zio-blocks-schema-csv` eliminates this friction by deriving codec instances directly from your Scala types using ZIO Schema. You describe your data shape once, and the module handles:
|
|
28
|
+
- RFC 4180-compliant parsing and generation with proper quote escaping
|
|
29
|
+
- Precise error reporting with row/column locations
|
|
30
|
+
- Zero-overhead errors (no stack traces) optimized for CSV stream processing
|
|
31
|
+
- Cross-platform support (JVM and Scala.js)
|
|
32
|
+
|
|
33
|
+
Rather than writing custom parsers or relying on string-based configuration, you work with strongly-typed schemas that the compiler validates.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
Add the module to your `build.sbt`:
|
|
38
|
+
|
|
39
|
+
```sbt
|
|
40
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-schema-csv" % "0.0.51"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For Scala.js, use `%%%` instead of `%%`:
|
|
44
|
+
|
|
45
|
+
```sbt
|
|
46
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-schema-csv" % "0.0.51"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Supported Scala versions: 2.13.x and 3.x
|
|
50
|
+
|
|
51
|
+
## Introduction
|
|
52
|
+
|
|
53
|
+
The module provides a complete pipeline for CSV codec derivation and usage:
|
|
54
|
+
|
|
55
|
+
1. **Define your type** — Any Scala type with a `Schema` instance
|
|
56
|
+
2. **Derive a codec** — Use `CsvFormat` to obtain a `CsvCodec[A]`
|
|
57
|
+
3. **Parse or serialize** — Call `CsvCodec#decode` or `CsvCodec#encode`
|
|
58
|
+
4. **Handle errors** — Catch `CsvError` with row/column location information
|
|
59
|
+
|
|
60
|
+
The derivation process is automatic for supported types (all 27 primitives and flat records). Unsupported types (sealed traits, sequences, maps) are rejected at derivation time with clear error messages.
|
|
61
|
+
|
|
62
|
+
## How They Work Together
|
|
63
|
+
|
|
64
|
+
The CSV codec pipeline flows through these layers:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
1. User defines Schema[A] for their type
|
|
68
|
+
↓
|
|
69
|
+
2. Schema.derive(CsvFormat) creates CsvCodec[A]
|
|
70
|
+
↓
|
|
71
|
+
3. CsvCodecDeriver converts Schema to codec implementation
|
|
72
|
+
- For primitives: type-specific encoders/decoders
|
|
73
|
+
- For records: field-by-field composition
|
|
74
|
+
↓
|
|
75
|
+
4. CsvCodec#encode writes values to CSV rows (via CsvWriter)
|
|
76
|
+
CsvCodec#decode reads CSV rows to values (via CsvReader)
|
|
77
|
+
↓
|
|
78
|
+
5. CsvReader/CsvWriter handle RFC 4180 quote escaping
|
|
79
|
+
CsvConfig customizes delimiters, terminators, quoting
|
|
80
|
+
↓
|
|
81
|
+
6. CsvError reports ParseError or TypeError with location
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Typical workflow:**
|
|
85
|
+
|
|
86
|
+
A user type flows through the derivation and encoding pipeline as follows:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
User type (e.g., case class Person)
|
|
90
|
+
↓
|
|
91
|
+
Schema.derived (automatic via macro)
|
|
92
|
+
↓
|
|
93
|
+
.derive(CsvFormat) → CsvCodec[Person]
|
|
94
|
+
↓
|
|
95
|
+
Use codec.headerNames for column names
|
|
96
|
+
↓
|
|
97
|
+
Use codec.encode(person, buffer) to serialize
|
|
98
|
+
Use codec.decode(buffer) to deserialize
|
|
99
|
+
↓
|
|
100
|
+
Handle CsvError.ParseError or TypeError on failure
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Common Patterns
|
|
104
|
+
|
|
105
|
+
This section shows 4 practical patterns for working with CSV codecs in real-world scenarios.
|
|
106
|
+
|
|
107
|
+
### Pattern 1: Derive and Use a Simple Codec
|
|
108
|
+
|
|
109
|
+
To derive and use a CSV codec for a record type:
|
|
110
|
+
|
|
111
|
+
```scala
|
|
112
|
+
import zio.blocks.schema._
|
|
113
|
+
import zio.blocks.schema.csv._
|
|
114
|
+
import java.nio.CharBuffer
|
|
115
|
+
|
|
116
|
+
case class Person(name: String, age: Int, email: String)
|
|
117
|
+
|
|
118
|
+
object Person {
|
|
119
|
+
implicit val schema: Schema[Person] = Schema.derived
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
val codec = Person.schema.derive(CsvFormat)
|
|
123
|
+
val person = Person("Alice", 30, "alice@example.com")
|
|
124
|
+
val buffer = CharBuffer.allocate(256)
|
|
125
|
+
codec.encode(person, buffer)
|
|
126
|
+
buffer.flip()
|
|
127
|
+
val encoded = buffer.toString
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Pattern 2: Customize CSV Format with CsvConfig
|
|
131
|
+
|
|
132
|
+
When you need tab-separated values (TSV) or a different delimiter, pass a custom `CsvConfig` to the derivation or directly to encoding/decoding methods.
|
|
133
|
+
|
|
134
|
+
To use a tab-separated format instead of comma-separated:
|
|
135
|
+
|
|
136
|
+
```scala
|
|
137
|
+
import zio.blocks.schema._
|
|
138
|
+
import zio.blocks.schema.csv._
|
|
139
|
+
|
|
140
|
+
case class Record(id: Int, value: String)
|
|
141
|
+
|
|
142
|
+
object Record {
|
|
143
|
+
implicit val schema: Schema[Record] = Schema.derived
|
|
144
|
+
// Note: Schema#derive accepts only a single format argument
|
|
145
|
+
// TSV configuration would be set through the format's configuration API
|
|
146
|
+
val tsvCodec = schema.derive(CsvFormat) // See CsvConfig for available options
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Pattern 3: Handle CSV Errors with Location Information
|
|
151
|
+
|
|
152
|
+
CSV errors report the exact row and column where parsing or type conversion failed, allowing you to give users precise feedback.
|
|
153
|
+
|
|
154
|
+
To handle parsing errors in a user-friendly way:
|
|
155
|
+
|
|
156
|
+
```scala
|
|
157
|
+
import zio.blocks.schema._
|
|
158
|
+
import zio.blocks.schema.csv._
|
|
159
|
+
import java.nio.CharBuffer
|
|
160
|
+
|
|
161
|
+
case class Employee(id: Int, name: String, salary: BigDecimal)
|
|
162
|
+
|
|
163
|
+
object Employee {
|
|
164
|
+
implicit val schema: Schema[Employee] = Schema.derived
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
val codec = Employee.schema.derive(CsvFormat)
|
|
168
|
+
val csvData = "id,name,salary\n1,Alice,invalid\n"
|
|
169
|
+
|
|
170
|
+
// Attempt to parse the CSV
|
|
171
|
+
val result = codec.decode(CharBuffer.wrap(csvData))
|
|
172
|
+
|
|
173
|
+
result match {
|
|
174
|
+
case Right(employee) => println(s"Parsed: $employee")
|
|
175
|
+
case Left(error) =>
|
|
176
|
+
// CsvError is wrapped in SchemaError
|
|
177
|
+
println(s"Parse error: ${error.getMessage}")
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Pattern 4: Working with Headers
|
|
182
|
+
|
|
183
|
+
Access the derived header names and use them to construct CSV output or validate input.
|
|
184
|
+
|
|
185
|
+
To get the column headers for a record type:
|
|
186
|
+
|
|
187
|
+
```scala
|
|
188
|
+
import zio.blocks.schema._
|
|
189
|
+
import zio.blocks.schema.csv._
|
|
190
|
+
|
|
191
|
+
case class Product(sku: String, name: String, price: Double)
|
|
192
|
+
|
|
193
|
+
object Product {
|
|
194
|
+
implicit val schema: Schema[Product] = Schema.derived
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
val codec = Product.schema.derive(CsvFormat)
|
|
198
|
+
val headers = codec.headerNames
|
|
199
|
+
// headers: IndexedSeq[String] = Vector("sku", "name", "price")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## CsvCodec[A]
|
|
203
|
+
|
|
204
|
+
Abstract codec for encoding and decoding values to and from CSV format. Extends `TextCodec[A]` and provides CSV-specific header support.
|
|
205
|
+
|
|
206
|
+
### Construction
|
|
207
|
+
|
|
208
|
+
Codecs are derived automatically from `Schema[A]` using `CsvFormat`:
|
|
209
|
+
|
|
210
|
+
```scala
|
|
211
|
+
import zio.blocks.schema._
|
|
212
|
+
import zio.blocks.schema.csv._
|
|
213
|
+
|
|
214
|
+
case class User(id: Int, username: String)
|
|
215
|
+
|
|
216
|
+
object User {
|
|
217
|
+
implicit val schema: Schema[User] = Schema.derived
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
val codec: CsvCodec[User] = User.schema.derive(CsvFormat)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Header Names
|
|
224
|
+
|
|
225
|
+
To access the CSV column headers derived from a record type:
|
|
226
|
+
|
|
227
|
+
```scala
|
|
228
|
+
import zio.blocks.schema._
|
|
229
|
+
import zio.blocks.schema.csv._
|
|
230
|
+
|
|
231
|
+
case class Book(title: String, author: String, isbn: String)
|
|
232
|
+
|
|
233
|
+
object Book {
|
|
234
|
+
implicit val schema: Schema[Book] = Schema.derived
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
val codec = Book.schema.derive(CsvFormat)
|
|
238
|
+
val headers: IndexedSeq[String] = codec.headerNames
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Encoding Values
|
|
242
|
+
|
|
243
|
+
To serialize a value to CSV format in a `CharBuffer`:
|
|
244
|
+
|
|
245
|
+
```scala
|
|
246
|
+
import zio.blocks.schema._
|
|
247
|
+
import zio.blocks.schema.csv._
|
|
248
|
+
import java.nio.CharBuffer
|
|
249
|
+
|
|
250
|
+
case class Item(name: String, quantity: Int)
|
|
251
|
+
|
|
252
|
+
object Item {
|
|
253
|
+
implicit val schema: Schema[Item] = Schema.derived
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
val codec = Item.schema.derive(CsvFormat)
|
|
257
|
+
val item = Item("Widget", 42)
|
|
258
|
+
val buffer = CharBuffer.allocate(512)
|
|
259
|
+
codec.encode(item, buffer)
|
|
260
|
+
buffer.flip()
|
|
261
|
+
val csvLine = buffer.toString
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Decoding Values
|
|
265
|
+
|
|
266
|
+
To parse CSV data from a `CharBuffer` into a value:
|
|
267
|
+
|
|
268
|
+
```scala
|
|
269
|
+
import zio.blocks.schema._
|
|
270
|
+
import zio.blocks.schema.csv._
|
|
271
|
+
import java.nio.CharBuffer
|
|
272
|
+
|
|
273
|
+
case class Sales(product: String, amount: BigDecimal)
|
|
274
|
+
|
|
275
|
+
object Sales {
|
|
276
|
+
implicit val schema: Schema[Sales] = Schema.derived
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
val codec = Sales.schema.derive(CsvFormat)
|
|
280
|
+
val csvData = "product,amount\nWidget,99.99\n"
|
|
281
|
+
val result: Either[SchemaError, Sales] = codec.decode(CharBuffer.wrap(csvData))
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## CsvConfig
|
|
287
|
+
|
|
288
|
+
Configuration for CSV parsing and generation, controlling delimiters, quoting, line termination, and header handling.
|
|
289
|
+
|
|
290
|
+
### Overview
|
|
291
|
+
|
|
292
|
+
`CsvConfig` is a case class with sensible RFC 4180 defaults. Customize it when you need different delimiters (e.g., tabs), custom line endings, or different quoting behavior.
|
|
293
|
+
|
|
294
|
+
### Defaults and Presets
|
|
295
|
+
|
|
296
|
+
The standard RFC 4180 CSV format:
|
|
297
|
+
|
|
298
|
+
```scala
|
|
299
|
+
import zio.blocks.schema.csv._
|
|
300
|
+
|
|
301
|
+
val config: CsvConfig = CsvConfig.default
|
|
302
|
+
// CsvConfig(',', '"', "\r\n", hasHeader = true, nullValue = "")
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
A tab-separated values (TSV) preset with tabs as delimiters:
|
|
306
|
+
|
|
307
|
+
```scala
|
|
308
|
+
import zio.blocks.schema.csv._
|
|
309
|
+
|
|
310
|
+
val tsvConfig: CsvConfig = CsvConfig.tsv
|
|
311
|
+
// CsvConfig('\t', '"', "\r\n", hasHeader = true, nullValue = "")
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Configuration Fields
|
|
315
|
+
|
|
316
|
+
- **`delimiter`** (default: `','`) — Character separating fields in a row
|
|
317
|
+
- **`quoteChar`** (default: `'"'`) — Character to quote fields containing delimiters or newlines; escapes quotes within quoted fields by doubling
|
|
318
|
+
- **`lineTerminator`** (default: `"\r\n"`) — Sequence terminating each row (RFC 4180 standard is CRLF)
|
|
319
|
+
- **`hasHeader`** (default: `true`) — Whether the first row contains column headers
|
|
320
|
+
- **`nullValue`** (default: `""`) — String representation for null values
|
|
321
|
+
|
|
322
|
+
### Custom Configuration
|
|
323
|
+
|
|
324
|
+
To use a pipe-delimited format:
|
|
325
|
+
|
|
326
|
+
```scala
|
|
327
|
+
import zio.blocks.schema.csv._
|
|
328
|
+
|
|
329
|
+
val customConfig = CsvConfig(
|
|
330
|
+
delimiter = '|',
|
|
331
|
+
quoteChar = '"',
|
|
332
|
+
lineTerminator = "\n",
|
|
333
|
+
hasHeader = true,
|
|
334
|
+
nullValue = "NULL"
|
|
335
|
+
)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## CsvError
|
|
341
|
+
|
|
342
|
+
Sealed abstract class representing errors during CSV parsing and type conversion. Designed for high-performance CSV processing with zero-overhead exceptions (no stack traces).
|
|
343
|
+
|
|
344
|
+
### Error Hierarchy
|
|
345
|
+
|
|
346
|
+
All CSV errors track row and column information (both 1-based) for precise error reporting.
|
|
347
|
+
|
|
348
|
+
**ParseError** — Occurs when CSV format is invalid:
|
|
349
|
+
|
|
350
|
+
```scala
|
|
351
|
+
import zio.blocks.schema.csv._
|
|
352
|
+
|
|
353
|
+
val parseError = CsvError.ParseError("Unclosed quoted field", row = 2, column = 15)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**TypeError** — Occurs when a field cannot be converted to the expected type:
|
|
357
|
+
|
|
358
|
+
```scala
|
|
359
|
+
import zio.blocks.schema.csv._
|
|
360
|
+
|
|
361
|
+
val typeError = CsvError.TypeError(
|
|
362
|
+
"Invalid integer: abc",
|
|
363
|
+
row = 3,
|
|
364
|
+
column = 5,
|
|
365
|
+
fieldName = "age"
|
|
366
|
+
)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Error Information
|
|
370
|
+
|
|
371
|
+
Both error types provide detailed context:
|
|
372
|
+
|
|
373
|
+
```scala
|
|
374
|
+
import zio.blocks.schema.csv._
|
|
375
|
+
|
|
376
|
+
val error = CsvError.ParseError("Unexpected character after closing quote", row = 1, column = 10)
|
|
377
|
+
val message: String = error.getMessage
|
|
378
|
+
val row: Int = error.row
|
|
379
|
+
val column: Int = error.column
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## CsvReader
|
|
385
|
+
|
|
386
|
+
Low-level CSV row parser implementing RFC 4180 with a state machine approach. Provides stateless utility methods for parsing individual rows, headers, and complete documents.
|
|
387
|
+
|
|
388
|
+
### Parsing a Single Row
|
|
389
|
+
|
|
390
|
+
To parse one CSV row starting at a given offset in the input:
|
|
391
|
+
|
|
392
|
+
```scala
|
|
393
|
+
import zio.blocks.schema.csv._
|
|
394
|
+
|
|
395
|
+
val input = "Alice,30,alice@example.com\nBob,25,bob@example.com\n"
|
|
396
|
+
val config = CsvConfig.default
|
|
397
|
+
|
|
398
|
+
val result: Either[CsvError, (IndexedSeq[String], Int)] =
|
|
399
|
+
CsvReader.readRow(input, offset = 0, config)
|
|
400
|
+
|
|
401
|
+
result match {
|
|
402
|
+
case Right((fields, nextOffset)) =>
|
|
403
|
+
println(s"Fields: $fields")
|
|
404
|
+
println(s"Next offset: $nextOffset")
|
|
405
|
+
case Left(err) =>
|
|
406
|
+
println(s"Parse error: ${err.getMessage}")
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Parsing the Header Row
|
|
411
|
+
|
|
412
|
+
To parse just the first row as column headers:
|
|
413
|
+
|
|
414
|
+
```scala
|
|
415
|
+
import zio.blocks.schema.csv._
|
|
416
|
+
|
|
417
|
+
val input = "name,age,email\nAlice,30,alice@example.com\n"
|
|
418
|
+
val config = CsvConfig.default
|
|
419
|
+
|
|
420
|
+
val result: Either[CsvError, (IndexedSeq[String], Int)] =
|
|
421
|
+
CsvReader.readHeader(input, config)
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Parsing Complete CSV
|
|
425
|
+
|
|
426
|
+
To parse a complete CSV document (header and all data rows):
|
|
427
|
+
|
|
428
|
+
```scala
|
|
429
|
+
import zio.blocks.schema.csv._
|
|
430
|
+
|
|
431
|
+
val csv = "name,age\nAlice,30\nBob,25\n"
|
|
432
|
+
val config = CsvConfig.default
|
|
433
|
+
|
|
434
|
+
val result: Either[CsvError, (IndexedSeq[String], IndexedSeq[IndexedSeq[String]])] =
|
|
435
|
+
CsvReader.readAll(csv, config)
|
|
436
|
+
|
|
437
|
+
result match {
|
|
438
|
+
case Right((header, rows)) =>
|
|
439
|
+
println(s"Header: $header")
|
|
440
|
+
rows.foreach(row => println(s"Row: $row"))
|
|
441
|
+
case Left(err) =>
|
|
442
|
+
println(s"Parse error: ${err.getMessage}")
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## CsvWriter
|
|
449
|
+
|
|
450
|
+
Low-level CSV row serializer implementing RFC 4180 with proper field escaping.
|
|
451
|
+
|
|
452
|
+
### Writing a Single Row
|
|
453
|
+
|
|
454
|
+
To serialize one row of fields to CSV format:
|
|
455
|
+
|
|
456
|
+
```scala
|
|
457
|
+
import zio.blocks.schema.csv._
|
|
458
|
+
|
|
459
|
+
val fields: IndexedSeq[String] = Vector("Alice", "30", "alice@example.com")
|
|
460
|
+
val config = CsvConfig.default
|
|
461
|
+
|
|
462
|
+
val csvLine: String = CsvWriter.writeRow(fields, config)
|
|
463
|
+
// Result: "Alice,30,alice@example.com\r\n"
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Writing Headers
|
|
467
|
+
|
|
468
|
+
To write a header row (semantically identical to `CsvWriter#writeRow` but communicates intent):
|
|
469
|
+
|
|
470
|
+
```scala
|
|
471
|
+
import zio.blocks.schema.csv._
|
|
472
|
+
|
|
473
|
+
val columnNames: IndexedSeq[String] = Vector("name", "age", "email")
|
|
474
|
+
val config = CsvConfig.default
|
|
475
|
+
|
|
476
|
+
val csvHeader: String = CsvWriter.writeHeader(columnNames, config)
|
|
477
|
+
// Result: "name,age,email\r\n"
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Writing Complete CSV
|
|
481
|
+
|
|
482
|
+
To write a complete CSV document with headers and data rows:
|
|
483
|
+
|
|
484
|
+
```scala
|
|
485
|
+
import zio.blocks.schema.csv._
|
|
486
|
+
|
|
487
|
+
val header: IndexedSeq[String] = Vector("product", "quantity")
|
|
488
|
+
val rows: Seq[IndexedSeq[String]] = Seq(
|
|
489
|
+
Vector("Widget", "10"),
|
|
490
|
+
Vector("Gadget", "5"),
|
|
491
|
+
Vector("Gizmo", "8")
|
|
492
|
+
)
|
|
493
|
+
val config = CsvConfig.default
|
|
494
|
+
|
|
495
|
+
val csv: String = CsvWriter.writeAll(header, rows, config)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### RFC 4180 Escaping
|
|
499
|
+
|
|
500
|
+
`CsvWriter` automatically escapes fields according to RFC 4180:
|
|
501
|
+
- Fields containing the delimiter, quote character, or newlines are wrapped in quotes
|
|
502
|
+
- Quote characters within quoted fields are doubled (e.g., `Alice "The Expert" Smith` becomes `"Alice ""The Expert"" Smith"`)
|
|
503
|
+
- Fields not requiring escaping are written as-is for readability
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## CsvCodecDeriver
|
|
508
|
+
|
|
509
|
+
Implements schema-driven derivation of `CsvCodec[A]` instances. Automatically handles 27 primitive types and flat record types, rejecting unsupported types (sealed traits, sequences, maps) with clear error messages.
|
|
510
|
+
|
|
511
|
+
### Primitive Type Support
|
|
512
|
+
|
|
513
|
+
All 27 ZIO Schema primitives are supported:
|
|
514
|
+
- Numeric: `Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `BigInt`, `BigDecimal`
|
|
515
|
+
- Logical: `Boolean`, `Char`, `String`
|
|
516
|
+
- Temporal: `Instant`, `LocalDate`, `LocalDateTime`, `LocalTime`, `Duration`, `Period`, `Year`, `YearMonth`, `MonthDay`, `Month`, `DayOfWeek`, `ZonedDateTime`, `OffsetDateTime`, `OffsetTime`, `ZoneId`, `ZoneOffset`
|
|
517
|
+
- Special: `UUID`, `Currency`, `Unit`
|
|
518
|
+
|
|
519
|
+
### Record Type Support
|
|
520
|
+
|
|
521
|
+
Flat case classes (records with no variant or sequence fields) are fully supported. Each field becomes a CSV column with the field name as the header:
|
|
522
|
+
|
|
523
|
+
```scala
|
|
524
|
+
import zio.blocks.schema._
|
|
525
|
+
import zio.blocks.schema.csv._
|
|
526
|
+
|
|
527
|
+
case class Address(street: String, city: String, zip: String)
|
|
528
|
+
|
|
529
|
+
object Address {
|
|
530
|
+
implicit val schema: Schema[Address] = Schema.derived
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
val codec = Address.schema.derive(CsvFormat)
|
|
534
|
+
val headers = codec.headerNames // Vector("street", "city", "zip")
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Unsupported Types
|
|
538
|
+
|
|
539
|
+
Attempting to derive a codec for unsupported types (sealed traits, sequences, maps, dynamic types) results in a clear compile-time or derivation-time error. The deriver rejects these to prevent silent failures in CSV processing.
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## CsvFormat
|
|
544
|
+
|
|
545
|
+
Integration point with ZIO Schema's format system. Provides `TextFormat[CsvCodec]` to enable `Schema[A].derive(CsvFormat)` for any supported type.
|
|
546
|
+
|
|
547
|
+
### Using CsvFormat
|
|
548
|
+
|
|
549
|
+
To derive a CSV codec using the standard format:
|
|
550
|
+
|
|
551
|
+
```scala
|
|
552
|
+
import zio.blocks.schema._
|
|
553
|
+
import zio.blocks.schema.csv._
|
|
554
|
+
|
|
555
|
+
case class Sensor(id: Long, temperature: Double, humidity: Float)
|
|
556
|
+
|
|
557
|
+
object Sensor {
|
|
558
|
+
implicit val schema: Schema[Sensor] = Schema.derived
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
val codec = Sensor.schema.derive(CsvFormat)
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
`CsvFormat` is a singleton object extending `TextFormat[CsvCodec]` with the MIME type `"text/csv"` and the `CsvCodecDeriver` as its derivation strategy.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: index
|
|
3
|
+
title: "Built-in Formats and Codecs"
|
|
4
|
+
sidebar_label: "Built-in Formats and Codecs"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
ZIO Blocks Schema provides codec derivation for multiple serialization formats. Once you have a `Schema[A]` for your data type, you can derive codecs for most formats using the unified `Schema.derive(Format)` pattern. BSON uses a different API: `BsonSchemaCodec.bsonCodec(schema)`. See the [Format documentation](../format.md) for details on how formats work.
|
|
8
|
+
|
|
9
|
+
## Built-in Codecs
|
|
10
|
+
|
|
11
|
+
Here's a summary of the codecs currently supported by ZIO Blocks. Most codecs provide a `BinaryFormat` or `TextFormat` object that can be passed to `derive`. BSON uses a different API (see below). See the dedicated codec documentation for installation, usage examples, and detailed type mappings:
|
|
12
|
+
|
|
13
|
+
| Derivation API | Codec Type | MIME Type | Module | Documentation |
|
|
14
|
+
|---------------------|-----------------------|-----------------------|---------------------------------|---------------------------------|
|
|
15
|
+
| `JsonFormat` | `JsonCodec[A]` | `application/json` | `zio-blocks-schema` | [JSON](./json/index.md) |
|
|
16
|
+
| `AvroFormat` | `AvroCodec[A]` | `application/avro` | `zio-blocks-schema-avro` | [Avro](./avro.md) |
|
|
17
|
+
| `BsonSchemaCodec` | `BsonCodec[A]` | `application/bson` | `zio-blocks-schema-bson` | [BSON](./bson.md) |
|
|
18
|
+
| `CsvFormat` | `CsvCodec[A]` | `text/csv` | `zio-blocks-schema-csv` | [CSV](./csv.md) |
|
|
19
|
+
| `MessagePackFormat` | `MessagePackCodec[A]` | `application/msgpack` | `zio-blocks-schema-messagepack` | [MessagePack](./messagepack.md) |
|
|
20
|
+
| `ThriftFormat` | `ThriftCodec[A]` | `application/thrift` | `zio-blocks-schema-thrift` | [Thrift](./thrift.md) |
|
|
21
|
+
| `ToonFormat` | `ToonCodec[A]` | `text/toon` | `zio-blocks-schema-toon` | [TOON](./toon.md) |
|
|
22
|
+
| `XmlFormat` | `XmlCodec[A]` | `application/xml` | `zio-blocks-schema-xml` | [XML](./xml.md) |
|
|
23
|
+
| `YamlFormat` | `YamlCodec[A]` | `application/yaml` | `zio-blocks-schema-yaml` | [YAML](./yaml.md) |
|
|
24
|
+
|
|
25
|
+
## Supported Types
|
|
26
|
+
|
|
27
|
+
Most formats support the full set of ZIO Blocks Schema primitive types. Some formats have limitations:
|
|
28
|
+
- **CSV** supports only flat records and primitive types (no variants, sequences, maps, or dynamic types)
|
|
29
|
+
- **XML** supports records, sequences, and variants with configurable discriminator strategies
|
|
30
|
+
- Other formats support all composite types listed below
|
|
31
|
+
|
|
32
|
+
For format-specific limitations, see the dedicated codec documentation.
|
|
33
|
+
|
|
34
|
+
**Numeric Types**:
|
|
35
|
+
- `Boolean`, `Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `Char`
|
|
36
|
+
- `BigInt`, `BigDecimal`
|
|
37
|
+
|
|
38
|
+
**Text Types**:
|
|
39
|
+
- `String`
|
|
40
|
+
|
|
41
|
+
**Special Types**:
|
|
42
|
+
- `Unit`, `UUID`, `Currency`
|
|
43
|
+
|
|
44
|
+
**Java Time Types**:
|
|
45
|
+
- `Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`
|
|
46
|
+
- `OffsetTime`, `OffsetDateTime`, `ZonedDateTime`
|
|
47
|
+
- `Duration`, `Period`
|
|
48
|
+
- `Year`, `YearMonth`, `MonthDay`
|
|
49
|
+
- `DayOfWeek`, `Month`
|
|
50
|
+
- `ZoneId`, `ZoneOffset`
|
|
51
|
+
|
|
52
|
+
**Composite Types**:
|
|
53
|
+
- Records (case classes)
|
|
54
|
+
- Variants (sealed traits)
|
|
55
|
+
- Sequences (`List`, `Vector`, `Set`, `Array`, etc.)
|
|
56
|
+
- Maps (`Map[K, V]`)
|
|
57
|
+
- Options (`Option[A]`)
|
|
58
|
+
- Eithers (`Either[A, B]`)
|
|
59
|
+
- Wrappers (newtypes)
|
|
60
|
+
|
|
61
|
+
## Cross-Platform Support
|
|
62
|
+
|
|
63
|
+
| Format | JVM | Scala.js |
|
|
64
|
+
|-------------|-----|----------|
|
|
65
|
+
| JSON | ✓ | ✓ |
|
|
66
|
+
| TOON | ✓ | ✓ |
|
|
67
|
+
| MessagePack | ✓ | ✓ |
|
|
68
|
+
| CSV | ✓ | ✓ |
|
|
69
|
+
| XML | ✓ | ✓ |
|
|
70
|
+
| YAML | ✓ | ✓ |
|
|
71
|
+
| Avro | ✓ | ✗ |
|
|
72
|
+
| Thrift | ✓ | ✗ |
|
|
73
|
+
| BSON | ✓ | ✗ |
|
|
74
|
+
|
|
75
|
+
## Error Handling
|
|
76
|
+
|
|
77
|
+
All formats return `Either[SchemaError, A]` for decoding operations. Errors include path information for debugging, showing exactly where in nested structures a decoding failure occurred. See individual codec documentation for format-specific error details.
|