@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.
Files changed (215) hide show
  1. package/adr/2026-07-18-data-migration.md +123 -0
  2. package/guides/async-getting-started.md +687 -0
  3. package/guides/compile-time-resource-safety-with-scope.md +21 -16
  4. package/guides/getting-started-with-mux.md +1395 -0
  5. package/guides/query-dsl-extending.md +161 -102
  6. package/guides/query-dsl-fluent-builder.md +217 -157
  7. package/guides/query-dsl-reified-optics.md +12 -10
  8. package/guides/query-dsl-sql.md +640 -165
  9. package/guides/sql-checked-interpolation.md +173 -0
  10. package/guides/sql-transactions.md +286 -0
  11. package/guides/telemetry-guide.md +1130 -0
  12. package/guides/zio-schema-migration.md +29 -22
  13. package/index.md +248 -389
  14. package/package.json +1 -1
  15. package/plans/config-follow-up-prs.md +188 -0
  16. package/plans/config-pr-assessment-roadmap.md +310 -0
  17. package/reference/MuxDataFlow.jsx +250 -0
  18. package/reference/async.md +1499 -0
  19. package/reference/chunk.md +3533 -308
  20. package/reference/codegen/case-class.md +436 -0
  21. package/reference/codegen/emitter-config.md +383 -0
  22. package/reference/codegen/examples.md +664 -0
  23. package/reference/codegen/field.md +316 -0
  24. package/reference/codegen/index.md +317 -0
  25. package/reference/codegen/scala-emitter.md +392 -0
  26. package/reference/codegen/scala-file.md +276 -0
  27. package/reference/codegen/sealed-trait.md +408 -0
  28. package/reference/codegen/type-definition.md +340 -0
  29. package/reference/codegen/type-ref.md +201 -0
  30. package/reference/combinators.md +347 -117
  31. package/reference/config/config-decoder.md +460 -0
  32. package/reference/config/config-source.md +489 -0
  33. package/reference/config/errors.md +278 -0
  34. package/reference/config/flags.md +369 -0
  35. package/reference/config/formats.md +314 -0
  36. package/reference/config/index.md +304 -0
  37. package/reference/config/rollout.md +336 -0
  38. package/reference/context.md +9 -52
  39. package/reference/data-migration.md +269 -0
  40. package/reference/datastar/attributes.md +302 -0
  41. package/reference/datastar/events.md +234 -0
  42. package/reference/datastar/index.md +256 -0
  43. package/reference/datastar/signals.md +230 -0
  44. package/reference/datastar/sse.md +295 -0
  45. package/reference/datastar.md +346 -0
  46. package/reference/docs.md +1461 -345
  47. package/reference/endpoint/auth-type.md +146 -0
  48. package/reference/endpoint/bulk-creation.md +96 -0
  49. package/reference/endpoint/endpoint.md +297 -0
  50. package/reference/endpoint/http-codec.md +249 -0
  51. package/reference/endpoint/index.md +745 -0
  52. package/reference/endpoint/path-codec.md +225 -0
  53. package/reference/endpoint/route-pattern.md +194 -0
  54. package/reference/endpoint/route-tree.md +111 -0
  55. package/reference/endpoint/segment-codec.md +199 -0
  56. package/reference/html.md +1424 -0
  57. package/reference/htmx/attribute-values.md +359 -0
  58. package/reference/htmx/hx-encoding.md +111 -0
  59. package/reference/htmx/hx-params.md +204 -0
  60. package/reference/htmx/hx-swap.md +276 -0
  61. package/reference/htmx/hx-sync.md +251 -0
  62. package/reference/htmx/hx-target.md +314 -0
  63. package/reference/htmx/hx-trigger.md +457 -0
  64. package/reference/htmx/hx-url-update.md +239 -0
  65. package/reference/htmx/index.md +807 -0
  66. package/reference/htmx/response-headers.md +240 -0
  67. package/reference/http-model/headers.md +735 -0
  68. package/reference/http-model/index.md +49 -0
  69. package/reference/http-model/model.md +1517 -0
  70. package/reference/http-model/schema-codecs.md +522 -0
  71. package/reference/http-model/schema.md +750 -0
  72. package/reference/http-model/server-sent-event.md +341 -0
  73. package/reference/jwt.md +195 -0
  74. package/reference/maybe.md +943 -0
  75. package/reference/media-type.md +2 -2
  76. package/reference/mux.md +254 -0
  77. package/reference/mux.mdx +828 -0
  78. package/reference/openapi.md +1351 -0
  79. package/reference/projection.md +654 -0
  80. package/reference/resource-management/defer-handle.md +1 -1
  81. package/reference/resource-management/resource.md +31 -98
  82. package/reference/resource-management/scope.md +28 -220
  83. package/reference/resource-management/wire.md +5 -55
  84. package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
  85. package/reference/ringbuffer/MpscDiagram.jsx +618 -0
  86. package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
  87. package/reference/ringbuffer/SpscDiagram.jsx +677 -0
  88. package/reference/ringbuffer/advanced.mdx +109 -0
  89. package/reference/ringbuffer/index.mdx +145 -0
  90. package/reference/ringbuffer/mpmc.mdx +185 -0
  91. package/reference/ringbuffer/mpsc.mdx +164 -0
  92. package/reference/ringbuffer/spmc.mdx +108 -0
  93. package/reference/ringbuffer/spsc.mdx +416 -0
  94. package/reference/{allows.md → schema/allows.md} +4 -100
  95. package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
  96. package/reference/{binding.md → schema/binding.md} +3 -4
  97. package/reference/schema/built-in-codecs/avro.md +451 -0
  98. package/reference/schema/built-in-codecs/bson.md +510 -0
  99. package/reference/schema/built-in-codecs/csv.md +564 -0
  100. package/reference/schema/built-in-codecs/index.md +77 -0
  101. package/reference/schema/built-in-codecs/json/index.md +295 -0
  102. package/reference/schema/built-in-codecs/json/json-config.md +217 -0
  103. package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
  104. package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
  105. package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
  106. package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
  107. package/reference/schema/built-in-codecs/messagepack.md +508 -0
  108. package/reference/schema/built-in-codecs/thrift.md +433 -0
  109. package/reference/schema/built-in-codecs/toon.md +1078 -0
  110. package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
  111. package/reference/schema/built-in-codecs/yaml.md +552 -0
  112. package/reference/{codec.md → schema/codec.md} +11 -11
  113. package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +196 -5
  114. package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
  115. package/reference/schema/format.md +92 -0
  116. package/reference/schema/index.md +52 -0
  117. package/reference/schema/migration.md +297 -0
  118. package/reference/{modifier.md → schema/modifier.md} +58 -7
  119. package/reference/{optics.md → schema/optics.md} +2 -2
  120. package/reference/{patch.md → schema/patch.md} +1 -1
  121. package/{path-interpolator.md → reference/schema/path-interpolator.md} +167 -72
  122. package/reference/schema/reflect-transformer.md +140 -0
  123. package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
  124. package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
  125. package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
  126. package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
  127. package/reference/schema/schema-search.md +263 -0
  128. package/reference/{schema.md → schema/schema.md} +22 -2
  129. package/reference/{structural-types.md → schema/structural-types.md} +1 -1
  130. package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
  131. package/reference/smithy.md +1032 -0
  132. package/reference/sql/db-codec-deriver.md +71 -0
  133. package/reference/sql/db-codec.md +687 -0
  134. package/reference/sql/db-con.md +271 -0
  135. package/reference/sql/db-connection.md +153 -0
  136. package/reference/sql/db-param-writer.md +77 -0
  137. package/reference/sql/db-param.md +66 -0
  138. package/reference/sql/db-result-reader.md +148 -0
  139. package/reference/sql/db-tx.md +114 -0
  140. package/reference/sql/db-value.md +41 -0
  141. package/reference/sql/ddl.md +85 -0
  142. package/reference/sql/frag.md +288 -0
  143. package/reference/sql/index.md +341 -0
  144. package/reference/sql/repo.md +600 -0
  145. package/reference/sql/sql-dialect.md +73 -0
  146. package/reference/sql/sql-logger.md +62 -0
  147. package/reference/sql/sql-name-mapper.md +70 -0
  148. package/reference/sql/table-metadata.md +134 -0
  149. package/reference/sql/table.md +448 -0
  150. package/reference/sql/transactor-zio.md +399 -0
  151. package/reference/sql/transactor.md +363 -0
  152. package/reference/sql-zio.md +112 -0
  153. package/reference/streams/core/index.md +32 -0
  154. package/reference/streams/core/pipeline.md +854 -0
  155. package/reference/streams/core/sink.md +1404 -0
  156. package/reference/streams/core/stream.md +3236 -0
  157. package/reference/streams/execution-and-compatibility/async-execution.md +822 -0
  158. package/reference/streams/execution-and-compatibility/index.md +35 -0
  159. package/reference/streams/execution-and-compatibility/platform-differences.md +297 -0
  160. package/reference/streams/execution-and-compatibility/scala-2-compatibility.md +88 -0
  161. package/reference/streams/execution-and-compatibility/zero-boxing.md +393 -0
  162. package/reference/streams/index.md +726 -0
  163. package/reference/streams/primitives/index.md +30 -0
  164. package/reference/streams/primitives/reader.md +1992 -0
  165. package/reference/streams/primitives/writer.md +1201 -0
  166. package/reference/telemetry/common/any-value.md +90 -0
  167. package/reference/telemetry/common/attribute-key.md +87 -0
  168. package/reference/telemetry/common/attributes.md +118 -0
  169. package/reference/telemetry/common/index.md +39 -0
  170. package/reference/telemetry/common/instrumentation-scope.md +24 -0
  171. package/reference/telemetry/common/resource.md +34 -0
  172. package/reference/telemetry/index.md +311 -0
  173. package/reference/telemetry/logging/index.md +197 -0
  174. package/reference/telemetry/logging/log-enrichment.md +72 -0
  175. package/reference/telemetry/logging/log-formatter.md +100 -0
  176. package/reference/telemetry/logging/log-record-processor.md +56 -0
  177. package/reference/telemetry/logging/log-record.md +44 -0
  178. package/reference/telemetry/logging/log-writer.md +64 -0
  179. package/reference/telemetry/logging/logger-provider.md +142 -0
  180. package/reference/telemetry/logging/logger.md +83 -0
  181. package/reference/telemetry/logging/severity.md +62 -0
  182. package/reference/telemetry/metrics/index.md +150 -0
  183. package/reference/telemetry/metrics/instruments.md +183 -0
  184. package/reference/telemetry/metrics/labeled-instruments.md +74 -0
  185. package/reference/telemetry/metrics/meter-provider.md +76 -0
  186. package/reference/telemetry/metrics/meter.md +98 -0
  187. package/reference/telemetry/metrics/metric-data.md +57 -0
  188. package/reference/telemetry/otel/custom-exporter.md +216 -0
  189. package/reference/telemetry/otel/index.md +212 -0
  190. package/reference/telemetry/tracing/index.md +155 -0
  191. package/reference/telemetry/tracing/sampler.md +89 -0
  192. package/reference/telemetry/tracing/span-builder.md +57 -0
  193. package/reference/telemetry/tracing/span-context.md +39 -0
  194. package/reference/telemetry/tracing/span-data.md +32 -0
  195. package/reference/telemetry/tracing/span-kind.md +55 -0
  196. package/reference/telemetry/tracing/span-processor.md +53 -0
  197. package/reference/telemetry/tracing/span-status.md +47 -0
  198. package/reference/telemetry/tracing/span.md +117 -0
  199. package/reference/telemetry/tracing/tracer-provider.md +91 -0
  200. package/reference/telemetry/tracing/tracer.md +52 -0
  201. package/reference/typeid.md +5 -83
  202. package/sidebars.js +376 -43
  203. package/undocumented-report.md +528 -270
  204. package/reference/formats.md +0 -694
  205. package/reference/http-model.md +0 -1716
  206. package/reference/streams.md +0 -989
  207. package/ringbuffer.md +0 -249
  208. /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
  209. /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
  210. /package/reference/{lazy.md → schema/lazy.md} +0 -0
  211. /package/reference/{reflect.md → schema/reflect.md} +0 -0
  212. /package/reference/{registers.md → schema/registers.md} +0 -0
  213. /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
  214. /package/reference/{syntax.md → schema/syntax.md} +0 -0
  215. /package/reference/{validation.md → schema/validation.md} +0 -0
@@ -0,0 +1,363 @@
1
+ ---
2
+ id: transactor
3
+ title: "Transactor"
4
+ description: "Reference for Transactor and JdbcTransactor: the sql module's entry point for connection lifecycle and transaction management."
5
+ keywords:
6
+ - "JdbcTransactor connection lifecycle"
7
+ - "Transactor transaction management"
8
+ - "DbCon connection context"
9
+ - "DbTx transaction scope"
10
+ - "JDBC connection pooling"
11
+ - "SQL commit rollback"
12
+ - "TransactorZIO ZIO integration"
13
+ ---
14
+
15
+ `Transactor` is the entry point for all SQL execution in the `sql` module. It declares two methods that acquire a JDBC connection, execute a provided body, and guarantee the connection is closed on return — whether the body succeeds or throws:
16
+
17
+ - **`Transactor#connect`** — supplies a `DbCon` implicit context for non-transactional queries; auto-commit remains at its default state.
18
+ - **`Transactor#transact`** — supplies a `DbTx` implicit context with auto-commit disabled; commits on success and rolls back on any exception.
19
+
20
+ `DbTx` extends `DbCon`, so every `Frag` execution method and every `Repo` CRUD operation that requires `DbCon` also works inside `transact`. The module's other core types — `Frag`, `Table`, and `Repo` — all depend on the context provided by `Transactor` to reach the database.
21
+
22
+ The structural shape of the trait is:
23
+
24
+ ```scala
25
+ trait Transactor {
26
+ def connect[A](f: DbCon ?=> A): A
27
+ def transact[A](f: DbTx ?=> A): A
28
+ def transact[A](isolation: TransactionIsolation, readOnly: Boolean)(f: DbTx ?=> A): A
29
+ }
30
+ ```
31
+
32
+ The no-arg `transact` preserves the driver’s default isolation level and `readOnly` flag, while the two-arg overload lets callers request an explicit `TransactionIsolation` (`ReadUncommitted(1)`, `ReadCommitted(2)`, `RepeatableRead(4)`, `Serializable(8)`) and read-only mode, plus the savepoint-based nested transaction support described in `DbTx`.
33
+
34
+ `JdbcTransactor` is the concrete JDBC-backed implementation. Its companion object provides factory methods for all common connection strategies:
35
+
36
+ ```scala
37
+ class JdbcTransactor(
38
+ connectionFactory: () => java.sql.Connection,
39
+ val dialect: SqlDialect,
40
+ val sqlLogger: SqlLogger
41
+ ) extends Transactor
42
+
43
+ object JdbcTransactor {
44
+ def fromDataSource(dataSource: javax.sql.DataSource, dialect: SqlDialect): JdbcTransactor
45
+ def fromUrl(url: String, dialect: SqlDialect): JdbcTransactor
46
+ def fromUrl(url: String, user: String, password: String, dialect: SqlDialect): JdbcTransactor
47
+ def postgres(dataSource: javax.sql.DataSource): JdbcTransactor
48
+ def sqlite(dataSource: javax.sql.DataSource): JdbcTransactor
49
+ }
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ The following block demonstrates the complete workflow: create a transactor, open a transactional scope, and execute both `Repo` operations and raw `sql"..."` fragments inside it:
55
+
56
+ ```scala
57
+ import zio.blocks.sql._
58
+ import zio.blocks.schema.Schema
59
+
60
+ case class User(id: Int, name: String, email: String)
61
+ object User { implicit val schema: Schema[User] = Schema.derived }
62
+
63
+ implicit val userCodec: DbCodec[User] = User.schema.deriving(DbCodecDeriver).derive
64
+
65
+ val repo = Repo.derived[User, Int]("users", "id", _.id)
66
+ val transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
67
+
68
+ // transact: auto-commit disabled; commits on success, rolls back on exception
69
+ transactor.transact {
70
+ repo.table.createTable(summon[DbTx].dialect).update
71
+ repo.insert(User(1, "Alice", "alice@example.com"))
72
+ repo.insert(User(2, "Bob", "bob@example.com"))
73
+
74
+ // Raw fragment composes freely with Repo operations inside the same scope
75
+ val active: List[User] =
76
+ sql"SELECT id, name, email FROM users WHERE id > ${0}".query[User]
77
+ }
78
+
79
+ // connect: auto-commit unchanged; no transaction overhead for pure reads
80
+ val users: List[User] = transactor.connect {
81
+ repo.all
82
+ }
83
+ ```
84
+
85
+ ## Construction / Creating Instances
86
+
87
+ We can create a `JdbcTransactor` from a `DataSource`, from a JDBC URL, or using database-specific convenience factories. In every case the third constructor parameter `sqlLogger` defaults to `SqlLogger.noop`, so it can be omitted unless query logging is required.
88
+
89
+ ### `JdbcTransactor.fromDataSource` — Create from a DataSource
90
+
91
+ `JdbcTransactor.fromDataSource` is the recommended factory for production use. It calls `dataSource.getConnection` once per `connect` or `transact` invocation, so connection pooling is fully controlled by the `DataSource` implementation (for example, HikariCP or c3p0):
92
+
93
+ ```scala
94
+ object JdbcTransactor {
95
+ def fromDataSource(dataSource: javax.sql.DataSource, dialect: SqlDialect): JdbcTransactor
96
+ }
97
+ ```
98
+
99
+ Pass the `DataSource` and the `SqlDialect` constant that matches your database. The following shows a typical setup where the data source is provided externally:
100
+
101
+ ```scala
102
+ import zio.blocks.sql._
103
+
104
+ val dataSource: javax.sql.DataSource = ???
105
+ val transactor: JdbcTransactor =
106
+ JdbcTransactor.fromDataSource(dataSource, SqlDialect.PostgreSQL)
107
+ ```
108
+
109
+ ### `JdbcTransactor.fromUrl` — Create from a JDBC URL
110
+
111
+ `JdbcTransactor.fromUrl` creates a transactor that opens each connection via `DriverManager.getConnection`. Two overloads are available: one without credentials and one that accepts a username and password:
112
+
113
+ ```scala
114
+ object JdbcTransactor {
115
+ def fromUrl(url: String, dialect: SqlDialect): JdbcTransactor
116
+ def fromUrl(url: String, user: String, password: String, dialect: SqlDialect): JdbcTransactor
117
+ }
118
+ ```
119
+
120
+ Use the credential-free overload for databases that embed authentication in the URL (for example, SQLite in-memory) or when the JDBC driver handles authentication separately:
121
+
122
+ ```scala
123
+ import zio.blocks.sql._
124
+
125
+ // Without credentials — useful for SQLite or URL-embedded auth
126
+ val sqlite: JdbcTransactor =
127
+ JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
128
+ // sqlite: JdbcTransactor = zio.blocks.sql.JdbcTransactor@7bf83f3d
129
+ ```
130
+
131
+ Use the three-argument overload when the database requires a username and password supplied separately:
132
+
133
+ ```scala
134
+ import zio.blocks.sql._
135
+
136
+ // With credentials — typical for PostgreSQL or MySQL
137
+ val postgres: JdbcTransactor =
138
+ JdbcTransactor.fromUrl(
139
+ "jdbc:postgresql://localhost/mydb",
140
+ "alice",
141
+ "secret",
142
+ SqlDialect.PostgreSQL
143
+ )
144
+ // postgres: JdbcTransactor = zio.blocks.sql.JdbcTransactor@216c12b5
145
+ ```
146
+
147
+ :::caution
148
+ `fromUrl` opens a new physical connection for every `connect` or `transact` call and does no pooling. For applications with concurrent workloads, prefer `fromDataSource` backed by a pooling `DataSource`.
149
+ :::
150
+
151
+ ### `JdbcTransactor.postgres` — PostgreSQL convenience factory
152
+
153
+ `JdbcTransactor.postgres` is shorthand for `fromDataSource(dataSource, SqlDialect.PostgreSQL)`. Use it to reduce boilerplate when working exclusively with PostgreSQL:
154
+
155
+ ```scala
156
+ object JdbcTransactor {
157
+ def postgres(dataSource: javax.sql.DataSource): JdbcTransactor
158
+ }
159
+ ```
160
+
161
+ The factory fixes the dialect to `SqlDialect.PostgreSQL` so DDL type names, parameter placeholders, and dialect-specific SQL all render correctly for PostgreSQL:
162
+
163
+ ```scala
164
+ import zio.blocks.sql._
165
+
166
+ val pgDataSource: javax.sql.DataSource = ???
167
+ val transactor: JdbcTransactor = JdbcTransactor.postgres(pgDataSource)
168
+ ```
169
+
170
+ ### `JdbcTransactor.sqlite` — SQLite convenience factory
171
+
172
+ `JdbcTransactor.sqlite` is shorthand for `fromDataSource(dataSource, SqlDialect.SQLite)`. Use it for SQLite databases where the `DataSource` is already available:
173
+
174
+ ```scala
175
+ object JdbcTransactor {
176
+ def sqlite(dataSource: javax.sql.DataSource): JdbcTransactor
177
+ }
178
+ ```
179
+
180
+ This factory is useful when you wire the `DataSource` through a dependency-injection layer and want to keep dialect selection close to the data source definition rather than at each call site:
181
+
182
+ ```scala
183
+ import zio.blocks.sql._
184
+
185
+ val sqDataSource: javax.sql.DataSource = ???
186
+ val transactor: JdbcTransactor = JdbcTransactor.sqlite(sqDataSource)
187
+ ```
188
+
189
+ ## Core Operations
190
+
191
+ `Transactor` exposes exactly two public methods. Together they cover the two modes of database access: non-transactional connections for reads and transactional connections for writes.
192
+
193
+ ### Connection Management
194
+
195
+ `Transactor#connect` is the lightweight entry point for database access without a transaction. It provides a `DbCon` context, which is the implicit argument required by every `Frag` extension method and every `Repo` CRUD operation.
196
+
197
+ It acquires a connection from the underlying factory, wraps it in a `JdbcConnection`, synthesizes a `DbCon` given value, and executes the provided body. The connection is closed in a `finally` block, so it is released whether the body returns normally or throws:
198
+
199
+ ```scala
200
+ trait Transactor {
201
+ def connect[A](f: DbCon ?=> A): A
202
+ }
203
+ ```
204
+
205
+ Because `DbTx extends DbCon`, a block that compiles under `connect` will also compile under `transact` — so we can promote non-transactional code to transactional scope without changing the body. The following example runs a read query inside `connect` without incurring transaction overhead:
206
+
207
+ ```scala
208
+ import zio.blocks.sql._
209
+ import zio.blocks.schema.Schema
210
+
211
+ case class User(id: Int, name: String, email: String)
212
+ object User { implicit val schema: Schema[User] = Schema.derived }
213
+
214
+ implicit val userCodec: DbCodec[User] = User.schema.deriving(DbCodecDeriver).derive
215
+
216
+ val repo = Repo.derived[User, Int]("users", "id", _.id)
217
+ val transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
218
+
219
+ // The body receives DbCon as a given — no explicit passing required
220
+ val users: List[User] = transactor.connect {
221
+ repo.all
222
+ }
223
+ ```
224
+
225
+ :::caution
226
+ Inside `connect`, auto-commit is left at its default state (typically `true` for JDBC). Any DML statement executed here is committed immediately. If you need atomic multi-statement writes, use `transact` instead.
227
+ :::
228
+
229
+ ### Transaction Management
230
+
231
+ `Transactor#transact` builds on `connect` by adding full transaction semantics: it disables auto-commit before executing the body, commits when the body returns normally, and rolls back when the body throws. The connection is always closed after commit or rollback. Two overloads are available — a no-arg form that preserves the driver’s defaults and a two-arg form that sets isolation and `readOnly` explicitly:
232
+
233
+ ```scala
234
+ trait Transactor {
235
+ def transact[A](f: DbTx ?=> A): A
236
+ def transact[A](isolation: TransactionIsolation, readOnly: Boolean)(f: DbTx ?=> A): A
237
+ }
238
+ ```
239
+
240
+ The two-arg overload acquires a connection, saves the previous isolation level and `readOnly` flag, calls `setTransactionIsolation(isolation.jdbcLevel)` (fail-fast — isolation failures propagate) and best-effort `setReadOnly(readOnly)` (SQLite may throw, which is swallowed), sets `autoCommit = false` (fail-fast), synthesizes a `DbTx` given value, and runs the body. On success it calls `conn.commit()`. On any exception it calls `conn.rollback()`, adds any rollback failure as a suppressed exception, and rethrows the original. Previous isolation, `readOnly`, and `autoCommit` are restored and the connection is closed in the `finally` block regardless of outcome. SQLite natively supports only `SERIALIZABLE` — other levels are accepted via `setTransactionIsolation` but the engine still behaves as serializable.
241
+
242
+ The no-arg overload preserves driver defaults (e.g. PostgreSQL `READ_COMMITTED`) and does not force `SERIALIZABLE`; it simply sets `autoCommit = false` before running the body, with the same commit/rollback and cleanup guarantees.
243
+
244
+ Because `DbTx extends DbCon`, the `DbTx` given satisfies any `DbCon ?=>` requirement inside the block. We can mix `Repo` CRUD calls with raw `sql"..."` fragments freely:
245
+
246
+ ```scala
247
+ import zio.blocks.sql._
248
+ import zio.blocks.schema.Schema
249
+ import zio.blocks.maybe.Maybe
250
+
251
+ case class User(id: Int, name: String, email: String)
252
+ object User { implicit val schema: Schema[User] = Schema.derived }
253
+
254
+ implicit val userCodec: DbCodec[User] = User.schema.deriving(DbCodecDeriver).derive
255
+ // userCodec: DbCodec[User] = zio.blocks.sql.DbCodecDeriver$$anon$10@7425b984
256
+
257
+ val repo = Repo.derived[User, Int]("users", "id", _.id)
258
+ // repo: Repo[User, Int] = zio.blocks.sql.Repo$DerivedRepo@78facd18
259
+ val transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
260
+ // transactor: JdbcTransactor = zio.blocks.sql.JdbcTransactor@26a6d9fe
261
+
262
+ transactor.transact {
263
+ repo.table.createTable(summon[DbTx].dialect).update
264
+ repo.insert(User(1, "Alice", "alice@example.com"))
265
+
266
+ // If this throws, the INSERT above is rolled back
267
+ val existing: Maybe[User] = repo.find(1)
268
+ existing
269
+ }
270
+ // res7: Maybe[User] = User(
271
+ // id = 1,
272
+ // name = "Alice",
273
+ // email = "alice@example.com"
274
+ // )
275
+ ```
276
+
277
+ :::caution
278
+ If `commit` itself throws after a successful body, the transaction is rolled back and the commit exception propagates. The body's return value is discarded in that case.
279
+ :::
280
+
281
+ ### Nested Transactions (Savepoints)
282
+
283
+ Inside `transact`, nested work is emulated via SQL savepoints on the same JDBC connection through `DbTx` — `summon[DbTx].transact { ... }`, `DbTx.transactNested`, or the top-level `transactNested` helper. Savepoints are named `zib_tx_1 .. zib_tx_N` with depth tracked in `DbTx.currentDepth`; inner success issues `RELEASE SAVEPOINT`, failure issues `ROLLBACK TO SAVEPOINT` then rethrows. See [DbTx](db-tx) for full savepoint semantics.
284
+
285
+ ## JdbcTransactor
286
+
287
+ `JdbcTransactor` is the only concrete implementation of `Transactor` in the `sql` module. It holds three constructor parameters: `connectionFactory`, `dialect`, and `sqlLogger`. The factory methods on its companion object cover the most common configurations; the primary constructor is available for custom setups such as test harnesses that inject a pre-existing connection:
288
+
289
+ ```
290
+ Transactor (trait — shared, cross-platform)
291
+ └── JdbcTransactor (class — JVM only, JDBC-backed)
292
+ ```
293
+
294
+ You can subclass `JdbcTransactor` to override `connect` or `transact` — for example, to reuse a single shared connection across multiple calls in a test suite without closing it between calls, as the `TransactorSpec` test helper does internally.
295
+
296
+ ## Transactor vs TransactorZIO
297
+
298
+ `Transactor` and `JdbcTransactor` are synchronous and suitable for code that does not use the ZIO effect system. `TransactorZIO`, provided by the separate `zio-blocks-sql-zio` artifact, wraps a `JdbcTransactor` and exposes two execution models for ZIO applications:
299
+
300
+ | Aspect | `Transactor` / `JdbcTransactor` | `TransactorZIO` (sql-zio module) |
301
+ |--------------------------|------------------------------------------------|---------------------------------------------------------------------------------------------------|
302
+ | **Return type** | `A` (synchronous, blocking) | `Task[A]` (or `ZIO[R, E \| Throwable, A]` for ZIO bodies) |
303
+ | **Thread model** | Blocks the calling thread | `connect`/`transact` run on the blocking thread pool via `ZIO.attemptBlocking` |
304
+ | **Interruption safety** | None — the body runs to completion | `connectZIO`/`transactZIO` use `ZIO.acquireRelease`; connection closes even on fiber interruption |
305
+ | **ZIO dependency** | None — zero ZIO dependency | Requires ZIO runtime |
306
+ | **Dependency injection** | Manual construction | `TransactorZIO.layer` provides a `ZLayer` |
307
+ | **When to use** | Synchronous imperative code, scripts, or tests | ZIO-based applications where effects compose across the entire call stack |
308
+
309
+ The following diagram shows how the two types relate:
310
+
311
+ ```
312
+ JdbcTransactor ──────────── wraps ───────────► TransactorZIO
313
+ │ │
314
+ │ connect { DbCon ?=> A }: A │ connect { DbCon ?=> A }: Task[A]
315
+ │ transact { DbTx ?=> A }: A │ transact { DbTx ?=> A }: Task[A]
316
+ │ │ connectZIO { DbCon ?=> ZIO[R,E,A] }
317
+ │ │ transactZIO { DbTx ?=> ZIO[R,E,A] }
318
+ │ │
319
+ └── (no ZIO dep) ────────────────────────── (ZIO runtime required) ──┘
320
+ ```
321
+
322
+ Choose `JdbcTransactor` when the codebase is synchronous or when ZIO is not on the classpath. Choose `TransactorZIO` when you want connections bracketed by ZIO's `acquireRelease` so they survive fiber interruption, or when you need `ZLayer`-based dependency injection.
323
+
324
+ ## Advanced Usage: Composing the Context
325
+
326
+ `DbCon` carries three members — `connection`, `dialect`, and `logger` — and is passed implicitly through every SQL operation. This means application-level helper methods can declare `(using DbCon)` and they are automatically satisfied anywhere inside `connect` or `transact` with no explicit argument passing. The same pattern composes across multiple layers:
327
+
328
+ ```scala
329
+ import zio.blocks.sql._
330
+ import zio.blocks.schema.Schema
331
+
332
+ case class User(id: Int, name: String, email: String)
333
+ object User { implicit val schema: Schema[User] = Schema.derived }
334
+
335
+ implicit val userCodec: DbCodec[User] = User.schema.deriving(DbCodecDeriver).derive
336
+ // userCodec: DbCodec[User] = zio.blocks.sql.DbCodecDeriver$$anon$10@26afe124
337
+
338
+ val repo = Repo.derived[User, Int]("users", "id", _.id)
339
+ // repo: Repo[User, Int] = zio.blocks.sql.Repo$DerivedRepo@1693a6ca
340
+ val transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
341
+ // transactor: JdbcTransactor = zio.blocks.sql.JdbcTransactor@60ed0082
342
+
343
+ // Helper that composes two Repo calls — requires only DbCon, not Transactor
344
+ def upsertUser(user: User)(using DbCon): Unit = {
345
+ if (repo.exists(user.id)) repo.update(user)
346
+ else repo.insert(user)
347
+ }
348
+
349
+ // The Transactor provides the DbCon; upsertUser picks it up automatically
350
+ transactor.transact {
351
+ repo.table.createTable(summon[DbTx].dialect).update
352
+ upsertUser(User(1, "Alice", "alice@example.com"))
353
+ upsertUser(User(1, "Alice Smith", "alice.smith@example.com"))
354
+ repo.find(1)
355
+ }
356
+ // res9: Maybe[User] = User(
357
+ // id = 1,
358
+ // name = "Alice Smith",
359
+ // email = "alice.smith@example.com"
360
+ // )
361
+ ```
362
+
363
+ Because `DbTx extends DbCon`, `upsertUser` works unchanged inside both `connect` and `transact`. This lets us design helper functions against the minimal context they need and promote them to transactional scope at the call site without modifying their signatures.
@@ -0,0 +1,112 @@
1
+ ---
2
+ id: sql-zio
3
+ title: "SQL — ZIO Integration"
4
+ ---
5
+
6
+ `zio-blocks-sql-zio` is the ZIO adapter for `zio-blocks-sql`. It wraps the
7
+ core JDBC transactor so ZIO applications can use the same SQL layer without
8
+ changing the underlying database API.
9
+
10
+ This guide covers two integration styles: `ZLayer`-based dependency injection
11
+ for the plain synchronous `Transactor` (via `JdbcTransactor.postgresLayer` /
12
+ `sqliteLayer`), and the `TransactorZIO` wrapper class for ZIO-native blocking
13
+ and effect-aware methods. For a full method-by-method reference on
14
+ `TransactorZIO`, see [TransactorZIO](./sql/transactor-zio.md).
15
+
16
+ ## Installation
17
+
18
+ ```scala
19
+ libraryDependencies += "dev.zio" %% "zio-blocks-sql-zio" % "0.0.55"
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ Create a `Transactor` layer from a JDBC `DataSource` and pick the dialect-specific helper that matches your database:
25
+
26
+ ```scala
27
+ import javax.sql.DataSource
28
+ import zio.*
29
+ import zio.blocks.maybe.Maybe
30
+ import zio.blocks.sql.*
31
+ import zio.blocks.sql.zio.*
32
+
33
+ val dataSource: DataSource = ???
34
+ val transactorLayer: ZLayer[Any, Nothing, Transactor] =
35
+ ZLayer.succeed(dataSource) >>> JdbcTransactor.postgresLayer
36
+
37
+ val program: ZIO[Transactor, Throwable, Maybe[Int]] =
38
+ ZIO.serviceWith[Transactor] { transactor =>
39
+ transactor.connect {
40
+ sql"SELECT 1".queryOne[Int]
41
+ }
42
+ }
43
+ ```
44
+
45
+ Use `JdbcTransactor.sqliteLayer` for SQLite databases.
46
+
47
+ ## TransactorZIO
48
+
49
+ `TransactorZIO` wraps the synchronous transactor and exposes ZIO-friendly
50
+ operations.
51
+
52
+ ```scala
53
+ import zio._
54
+ import zio.blocks.sql._
55
+ import zio.blocks.sql.zio._
56
+
57
+ val transactor = TransactorZIO.fromUrl(
58
+ "jdbc:postgresql://localhost/mydb",
59
+ "alice", "secret",
60
+ SqlDialect.PostgreSQL
61
+ )
62
+ ```
63
+
64
+ For production use, prefer `TransactorZIO.fromDataSource(...)` so connection
65
+ pooling is handled outside the library.
66
+
67
+ You can also create a transactor from a `DataSource` when you already have one:
68
+
69
+ ```scala
70
+ val transactor = TransactorZIO.fromDataSource(dataSource, SqlDialect.PostgreSQL)
71
+ ```
72
+
73
+ ## Blocking Wrappers
74
+
75
+ `connect` and `transact` run synchronous code on ZIO's blocking thread pool and
76
+ return `Task`.
77
+
78
+ ```scala
79
+ val users: Task[List[User]] = transactor.connect:
80
+ userRepo.all
81
+
82
+ val result: Task[User] = transactor.transact:
83
+ userRepo.insertReturning(newUser)
84
+ ```
85
+
86
+ ## Effect-Aware Methods
87
+
88
+ `connectZIO` and `transactZIO` let the body return a `ZIO` directly.
89
+
90
+ ```scala
91
+ val program: ZIO[Any, Throwable, User] =
92
+ transactor.transactZIO:
93
+ for
94
+ _ <- ZIO.attemptBlocking(userRepo.insert(newUser))
95
+ user <- ZIO.attemptBlocking(userRepo.find(newUser.id))
96
+ yield user.get
97
+ ```
98
+
99
+ ## ZLayer
100
+
101
+ Use `ZLayer` when you want to provide `TransactorZIO` through dependency
102
+ injection:
103
+
104
+ ```scala
105
+ val transactorLayer: ZLayer[Any, Nothing, TransactorZIO] =
106
+ TransactorZIO.layer("jdbc:postgresql://localhost/mydb", SqlDialect.PostgreSQL)
107
+ ```
108
+
109
+ ## Thread Safety
110
+
111
+ `TransactorZIO` is safe to share. It creates a new connection per
112
+ `connect` / `transact` invocation.
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: index
3
+ title: "Core Types"
4
+ description: "Core Types index: Stream, Pipeline, and Sink, the declarative descriptions you compose into a stream processing pipeline."
5
+ keywords:
6
+ - "Pull-Based Streams"
7
+ - "Stream Composition"
8
+ - "Core Types Overview"
9
+ - "Sink"
10
+ sidebar_label: "Core Types"
11
+ ---
12
+
13
+ `Stream`, `Pipeline`, and `Sink` are the three types you compose to build a pipeline. Each is a lazy, immutable description rather than a running process: you assemble one with ordinary combinators, and nothing executes until a terminal operation such as `stream.runAsync(sink)` — or `stream.run(sink)`, which is JVM-only — compiles and drives it.
14
+
15
+ Compiling is what materializes a description into a [`Reader`](../primitives/reader.md), the stateful cursor a sink pulls from. Those live primitives are documented under [Low-Level Primitives](../primitives/index.md); this section covers the descriptions you write.
16
+
17
+ ## Stream
18
+
19
+ [`Stream[+E, +A]`](./stream.md) describes a source of elements of type `A` that may fail with `E`. Values are produced lazily, so a stream can outlive what fits in memory and can hold an external resource open only while it is being drained.
20
+
21
+ ## Pipeline
22
+
23
+ [`Pipeline[-In, +Out]`](./pipeline.md) describes a reusable transformation from `In` to `Out`. Reach for it when the same steps apply to more than one stream. Pipelines compose with `andThen`, apply to a stream with `stream.via(pipe)`, and to a sink with `pipe.andThenSink(sink)`.
24
+
25
+ ## Sink
26
+
27
+ [`Sink[+E, -A, +Z]`](./sink.md) describes how to consume elements of type `A` into a result `Z`, possibly failing with `E` — the endpoint of a pipeline, built once and reusable across streams.
28
+
29
+ ## See Also
30
+
31
+ - [Streams Reference](../index.md) — module overview
32
+ - [Low-Level Primitives](../primitives/index.md) — the `Reader` and `Writer` cursors these compile into