@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
@@ -0,0 +1,271 @@
1
+ ---
2
+ id: db-con
3
+ title: "DbCon"
4
+ description: "Reference for DbCon, the implicit execution context in the sql module carrying a DbConnection, SqlDialect, and SqlLogger through SQL operations."
5
+ keywords:
6
+ - "DbCon implicit context"
7
+ - "Transactor connection scope"
8
+ - "DbTx transaction scope"
9
+ - "SqlDialect dialect selection"
10
+ - "SqlLogger query observability"
11
+ - "sql module context threading"
12
+ - "DbConnection JDBC abstraction"
13
+ ---
14
+
15
+ `DbCon` is the implicit execution context that threads database connection state through every SQL operation in the `sql` module. It is a plain trait with three abstract members — `connection`, `dialect`, and `logger` — and carries no type parameters:
16
+
17
+ ```scala
18
+ trait DbCon {
19
+ def connection: DbConnection
20
+ def dialect: SqlDialect
21
+ def logger: SqlLogger
22
+ }
23
+ ```
24
+
25
+ Application code never constructs a `DbCon` directly. Instead, `Transactor#connect` and `Transactor#transact` each create one internally and supply it as a Scala 3 context parameter (`?=>`) to the block they receive.
26
+
27
+ All `Frag` execution methods (`query`, `queryOne`, `queryLimit`, `update`, `updateReturningKeys`) and all `Repo` CRUD methods (`all`, `find`, `insert`, `update`, `delete`, and friends) require an implicit `DbCon` in scope — so any code that runs inside a `Transactor#connect` or `Transactor#transact` block automatically has everything it needs to execute SQL.
28
+
29
+ Key properties:
30
+ - **Implicit context type** — carries the active database session without explicit parameter threading.
31
+ - **Three concrete members** — `connection` (the active `DbConnection`), `dialect` (the `SqlDialect`), and `logger` (the `SqlLogger`).
32
+ - **Extended by `DbTx`** — `DbTx` is a subtype of `DbCon` that marks transactional scope; any method that accepts `DbCon` also accepts `DbTx`.
33
+ - **Lifetime managed by `Transactor`** — the connection is closed when the enclosing `connect` or `transact` block returns, whether it succeeds or throws.
34
+
35
+ ## Usage
36
+
37
+ The following example shows how `DbCon` is obtained from a `Transactor`, how the context is propagated into helper methods, and how the three members can be accessed when needed:
38
+
39
+ ```scala
40
+ import zio.blocks.sql._
41
+ import zio.blocks.schema.Schema
42
+
43
+ case class User(id: Int, name: String)
44
+ object User {
45
+ implicit val schema: Schema[User] = Schema.derived
46
+ }
47
+
48
+ val tx: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
49
+ // tx: Transactor = zio.blocks.sql.JdbcTransactor@4c1ffa3c
50
+
51
+ // DbCon is supplied automatically by connect — no explicit argument needed
52
+ tx.connect {
53
+ // Frag execution picks up the given DbCon implicitly
54
+ Frag.literal("CREATE TABLE users (id INTEGER NOT NULL, name TEXT NOT NULL)").update
55
+ sql"INSERT INTO users (id, name) VALUES (${1}, ${"Alice"})".update
56
+ val users: List[User] = sql"SELECT id, name FROM users".query[User]
57
+ // Access the context members directly when needed
58
+ val dialectName: String = summon[DbCon].dialect.toString
59
+ (users, dialectName)
60
+ }
61
+ // res1: Tuple2[List[User], String] = (
62
+ // List(User(id = 1, name = "Alice")),
63
+ // "SQLite"
64
+ // )
65
+ ```
66
+
67
+ ## Entry Points
68
+
69
+ `DbCon` is never instantiated by application code. A `Transactor` creates and supplies the instance automatically. There are two entry points depending on whether transactional behaviour is needed.
70
+
71
+ ### `Transactor#connect` — Non-transactional connection scope
72
+
73
+ `Transactor#connect` acquires a JDBC connection from the underlying source, wraps it in a `DbCon`, and calls the provided context function. The connection is closed when the block returns, whether it completes normally or throws. Auto-commit remains at the driver default (enabled for most JDBC drivers), so each statement issued inside the block commits independently.
74
+
75
+ The signature from `Transactor` is:
76
+
77
+ ```scala
78
+ trait Transactor {
79
+ def connect[A](f: DbCon ?=> A): A
80
+ }
81
+ ```
82
+
83
+ The following example shows a non-transactional read that uses the supplied `DbCon` to execute a query:
84
+
85
+ ```scala
86
+ import zio.blocks.sql._
87
+
88
+ val tx: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
89
+
90
+ // The `DbCon` binding is supplied by `connect` — no manual construction
91
+ val names: List[String] = tx.connect {
92
+ sql"SELECT name FROM users ORDER BY name".query[String]
93
+ }
94
+ ```
95
+
96
+ :::caution
97
+ Do not capture the `DbCon` value or the `DbConnection` it contains and use them outside the `connect` block. The connection is closed when the block returns, and any statement prepared or executed on it afterward will throw.
98
+ :::
99
+
100
+ ### `Transactor#transact` — Transactional connection scope
101
+
102
+ `Transactor#transact` acquires a connection, disables auto-commit, and supplies a `DbTx` context — a subtype of `DbCon` — to the block. On normal return the transaction commits; on any thrown exception it rolls back. The connection is closed after commit or rollback. Because `DbTx extends DbCon`, all `Frag` and `Repo` methods that accept `DbCon` work unchanged inside `transact`.
103
+
104
+ The signature from `Transactor` is:
105
+
106
+ ```scala
107
+ trait Transactor {
108
+ def transact[A](f: DbTx ?=> A): A
109
+ }
110
+ ```
111
+
112
+ The following example shows a transactional write that inserts two rows atomically — if the second insert throws, the first is rolled back:
113
+
114
+ ```scala
115
+ import zio.blocks.sql._
116
+
117
+ val tx: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
118
+
119
+ tx.transact {
120
+ // Both inserts commit together; an exception rolls back both
121
+ sql"INSERT INTO users (id, name) VALUES (${1}, ${"Alice"})".update
122
+ sql"INSERT INTO users (id, name) VALUES (${2}, ${"Bob"})".update
123
+ }
124
+ ```
125
+
126
+ ## Core Operations
127
+
128
+ `DbCon` exposes three read-only members. They are rarely accessed directly in application code — the `Transactor` configures them at construction time and `Frag` / `Repo` consume them implicitly — but they become useful when integrating with lower-level JDBC abstractions, logging frameworks, or custom dialect rendering.
129
+
130
+ ### Context Access
131
+
132
+ The three context-access members return the `DbConnection`, `SqlDialect`, and `SqlLogger` held by the current `DbCon` instance.
133
+
134
+ #### `DbCon#connection` — Underlying JDBC-abstraction connection
135
+
136
+ `DbCon#connection` returns the `DbConnection` wrapping the active JDBC `java.sql.Connection`. `DbConnection` exposes `prepareStatement`, `prepareStatementReturningKeys`, transaction-control methods, and `close`. It is consumed internally by every `Frag` and `Repo` operation that executes a statement. Access it directly only when you need to drop below the `Frag` layer to a raw prepared statement.
137
+
138
+ ```scala
139
+ trait DbCon {
140
+ def connection: DbConnection
141
+ }
142
+ ```
143
+
144
+ The following example shows how to retrieve the `DbConnection` and use it to execute a raw prepared statement — useful for operations that the `Frag` API does not cover directly:
145
+
146
+ ```scala
147
+ import zio.blocks.sql._
148
+
149
+ val tx: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
150
+
151
+ tx.connect {
152
+ val conn: DbConnection = summon[DbCon].connection
153
+ val ps = conn.prepareStatement("SELECT COUNT(*) FROM users")
154
+ try {
155
+ val rs = ps.executeQuery()
156
+ try { rs.next(); rs.reader.getInt(1) }
157
+ finally rs.close()
158
+ } finally ps.close()
159
+ }
160
+ ```
161
+
162
+ :::caution
163
+ Never call `connection.close()` manually. The `Transactor` closes the connection when the enclosing `connect` or `transact` block finishes, whether it returns normally or throws. Closing the connection early will cause all subsequent statements in the block to fail.
164
+ :::
165
+
166
+ #### `DbCon#dialect` — SQL dialect for fragment rendering
167
+
168
+ `DbCon#dialect` returns the `SqlDialect` used to render `Frag` values to parameterized SQL strings. Every `Frag` execution method calls `frag.sql(dialect)` internally to produce the driver-specific SQL before binding parameters. The dialect also governs how DDL type names are spelled when generating `CREATE TABLE` statements from `Table#createTable`.
169
+
170
+ ```scala
171
+ trait DbCon {
172
+ def dialect: SqlDialect
173
+ }
174
+ ```
175
+
176
+ The following example shows reading the dialect from a context to render a `Frag` explicitly — for instance, to log the SQL before execution:
177
+
178
+ ```scala
179
+ import zio.blocks.sql._
180
+
181
+ val tx: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
182
+ // tx: Transactor = zio.blocks.sql.JdbcTransactor@606f8c9a
183
+
184
+ tx.connect {
185
+ val frag = sql"SELECT id FROM users WHERE id = ${42}"
186
+ frag.sql(summon[DbCon].dialect)
187
+ }
188
+ // res6: String = "SELECT id FROM users WHERE id = ?"
189
+ ```
190
+
191
+ #### `DbCon#logger` — Query execution logger
192
+
193
+ `DbCon#logger` returns the `SqlLogger` that the `Transactor` was configured with. After each successful statement `SqlLogger#onSuccess` receives the rendered SQL, the parameter list, the execution duration, and the affected-row count. After a failed statement `SqlLogger#onError` receives the same information plus the thrown exception. The default implementation — `SqlLogger.noop` — discards all events; replace it with a custom `SqlLogger` to integrate with your preferred logging framework.
194
+
195
+ ```scala
196
+ trait DbCon {
197
+ def logger: SqlLogger
198
+ }
199
+ ```
200
+
201
+ The following example shows passing a logging `SqlLogger` to `JdbcTransactor` so that every query executed inside `connect` or `transact` is recorded:
202
+
203
+ ```scala
204
+ import zio.blocks.sql._
205
+
206
+ val loggingLogger: SqlLogger = new SqlLogger {
207
+ def onSuccess(event: SqlLogger.SuccessEvent): Unit =
208
+ println(s"OK [${event.duration.toMillis} ms, ${event.rowCount} rows]: ${event.sql}")
209
+ def onError(event: SqlLogger.ErrorEvent): Unit =
210
+ println(s"ERR [${event.duration.toMillis} ms]: ${event.sql} — ${event.error.getMessage}")
211
+ }
212
+ // loggingLogger: SqlLogger = repl.MdocSession$MdocApp7$$anon$9@1d96b35a
213
+
214
+ val tx: Transactor =
215
+ new JdbcTransactor(
216
+ () => java.sql.DriverManager.getConnection("jdbc:sqlite::memory:"),
217
+ SqlDialect.SQLite,
218
+ loggingLogger
219
+ )
220
+ // tx: Transactor = zio.blocks.sql.JdbcTransactor@7abee0ec
221
+
222
+ tx.connect {
223
+ // Every Frag execution notifies loggingLogger automatically
224
+ Frag.literal("SELECT 1").query[Int]
225
+ }
226
+ // OK [0 ms, 1 rows]: SELECT 1
227
+ // res8: List[Int] = List(1)
228
+ ```
229
+
230
+ ## Transactional Scope — `DbTx`
231
+
232
+ `DbTx` is the only subtype of `DbCon`. It is a marker trait — it adds no new members — whose sole purpose is to distinguish code that runs inside `Transactor#transact` from code that runs inside `Transactor#connect` at the type level:
233
+
234
+ ```scala
235
+ trait DbTx extends DbCon
236
+ ```
237
+
238
+ Because `DbTx` has no additional members, it exists purely to make the transactional / non-transactional boundary visible in method signatures. A method that requires `DbTx` cannot be called from a `connect` block, but a method that requires `DbCon` can be called from either. This asymmetry is enforced by the compiler: `DbTx <: DbCon` so `DbTx` satisfies a `DbCon` requirement, but a plain `DbCon` does not satisfy a `DbTx` requirement.
239
+
240
+ The following example illustrates how to write a helper method that is restricted to transactional scope:
241
+
242
+ ```scala
243
+ import zio.blocks.sql._
244
+
245
+ // This helper compiles only inside a `transact` block, never inside `connect`
246
+ def insertUser(id: Int, name: String)(using DbTx): Unit = {
247
+ sql"INSERT INTO users (id, name) VALUES ($id, $name)".update
248
+ ()
249
+ }
250
+
251
+ val tx: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
252
+
253
+ tx.transact {
254
+ insertUser(1, "Alice") // OK — DbTx satisfies the `using DbTx` requirement
255
+ }
256
+
257
+ // tx.connect {
258
+ // insertUser(1, "Alice") // Compile error — DbCon does not satisfy `using DbTx`
259
+ // }
260
+ ```
261
+
262
+ When a helper only reads data and should work in both contexts, declare it with `using DbCon`:
263
+
264
+ ```scala
265
+ import zio.blocks.sql._
266
+ import zio.blocks.maybe.Maybe
267
+
268
+ // Usable inside both `connect` and `transact` blocks
269
+ def findUser(id: Int)(using DbCon): Maybe[String] =
270
+ sql"SELECT name FROM users WHERE id = $id".queryOne[String]
271
+ ```
@@ -0,0 +1,153 @@
1
+ ---
2
+ id: db-connection
3
+ title: "DbConnection"
4
+ description: "The JDBC Connection abstraction in the sql module"
5
+ keywords:
6
+ - "DbConnection JDBC abstraction"
7
+ - "prepareStatement SQL"
8
+ - "DbPreparedStatement executeQuery"
9
+ - "DbResultSet result reading"
10
+ - "transaction control commit rollback"
11
+ - "AutoCloseable connection lifecycle"
12
+ - "Transactor connection management"
13
+ ---
14
+
15
+ `DbConnection` is a `trait` that extends `AutoCloseable` and abstracts over a JDBC `java.sql.Connection`. It exposes the minimum surface needed to prepare statements, control transaction boundaries, and query connection state.
16
+
17
+ It is part of a three-tier abstraction:
18
+ - `DbConnection` manages the connection itself
19
+ - `DbPreparedStatement` executes statements with parameters
20
+ - `DbResultSet` reads result rows
21
+
22
+ ## Core API
23
+
24
+ Here is the core API which `DbConnection` exposes:
25
+
26
+ ```scala
27
+ trait DbConnection extends AutoCloseable {
28
+ // Statement preparation
29
+ def prepareStatement(sql: String): DbPreparedStatement
30
+ def prepareStatementReturningKeys(sql: String): DbPreparedStatement
31
+
32
+ // Transaction control
33
+ def setAutoCommit(autoCommit: Boolean): Unit
34
+ def getAutoCommit: Boolean
35
+ def commit(): Unit
36
+ def rollback(): Unit
37
+
38
+ // Connection state
39
+ def isClosed: Boolean
40
+ def close(): Unit
41
+ }
42
+ ```
43
+
44
+ ## Creating Instances
45
+
46
+ `DbConnection` has no public constructor. Application code never instantiates it. `Transactor#connect` and `Transactor#transact` create the concrete `JdbcConnection` internally and make it available through `DbCon#connection` inside the block.
47
+
48
+ For testing, implement the trait directly with a mock or use a lightweight in-memory JDBC driver such as SQLite's `:memory:` database.
49
+
50
+ :::caution
51
+ Never call `con.close()` inside a `connect` or `transact` block. The `Transactor` closes the connection after the block returns; closing it early will cause the rest of the block to fail with a "connection already closed" JDBC error.
52
+ :::
53
+
54
+ ## Statement Preparation
55
+
56
+ ### `prepareStatement` — Prepare a SQL statement for execution
57
+
58
+ `prepareStatement(sql: String): DbPreparedStatement` asks the JDBC driver to compile and cache the SQL string and returns a `DbPreparedStatement` that can have parameters bound to it before execution. The `sql` string must use `?` placeholders for parameters.
59
+
60
+ ```scala
61
+ import zio.blocks.sql._
62
+
63
+ val transactor: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
64
+
65
+ // Inside a connect block:
66
+ transactor.connect {
67
+ val con = summon[DbCon].connection
68
+ val stmt = con.prepareStatement("INSERT INTO tags (name) VALUES (?)")
69
+ stmt.paramWriter.setString(1, "scala")
70
+ val rowCount = stmt.executeUpdate()
71
+ stmt.close()
72
+ rowCount
73
+ }
74
+ ```
75
+
76
+ ### `prepareStatementReturningKeys` — Prepare an insert that returns generated keys
77
+
78
+ `prepareStatementReturningKeys(sql: String): DbPreparedStatement` prepares a statement with the JDBC `RETURN_GENERATED_KEYS` hint, enabling `executeUpdateReturningKeys` to return an auto-generated primary key. Use this for `INSERT` statements on tables with a database-generated `SERIAL` or `AUTOINCREMENT` primary key.
79
+
80
+ ```scala
81
+ import zio.blocks.sql._
82
+
83
+ val transactor: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
84
+
85
+ // Inside a connect block:
86
+ transactor.connect {
87
+ val con = summon[DbCon].connection
88
+ val stmt = con.prepareStatementReturningKeys("INSERT INTO orders (amount) VALUES (?)")
89
+ stmt.paramWriter.setBigDecimal(1, new java.math.BigDecimal("99.99"))
90
+ val keyRs = stmt.executeUpdateReturningKeys()
91
+ val genKey = if (keyRs.next()) keyRs.reader.getLong(1) else -1L
92
+ keyRs.close()
93
+ stmt.close()
94
+ genKey
95
+ }
96
+ ```
97
+
98
+ ## Transaction Control
99
+
100
+ `setAutoCommit`, `getAutoCommit`, `commit`, and `rollback` manage the connection's transactional state.
101
+
102
+ `setAutoCommit(autoCommit: Boolean)` switches the connection between auto-commit and manual-commit mode. `getAutoCommit: Boolean` queries the current mode. `commit()` commits the current transaction; `rollback()` rolls it back. These methods wrap the corresponding `java.sql.Connection` calls.
103
+
104
+ `Transactor#transact` calls `setAutoCommit(false)` before the block and calls `commit()` on success or `rollback()` on exception — so within a `transact` block, you should not call these methods yourself. Use them directly only in a `connect` block where you need fine-grained control over transaction boundaries.
105
+
106
+ ```scala
107
+ import zio.blocks.sql._
108
+
109
+ val transactor: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
110
+
111
+ // Manual transaction management inside a connect block (uncommon)
112
+ transactor.connect {
113
+ val con = summon[DbCon].connection
114
+ con.setAutoCommit(false)
115
+ try {
116
+ // ... execute statements ...
117
+ con.commit()
118
+ } catch {
119
+ case t: Throwable =>
120
+ con.rollback()
121
+ throw t
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## Connection State
127
+
128
+ ### `isClosed` — Check whether the connection is still open
129
+
130
+ `isClosed: Boolean` returns `true` if the connection has already been closed. Inside a `connect` or `transact` block the connection is always open; this method is primarily useful in test code that verifies the `Transactor` closes connections correctly.
131
+
132
+ ```scala
133
+ import zio.blocks.sql._
134
+
135
+ val transactor: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
136
+ // transactor: Transactor = zio.blocks.sql.JdbcTransactor@7d102738
137
+
138
+ var capturedCon: DbConnection = null
139
+ // capturedCon: DbConnection = null
140
+
141
+ transactor.connect {
142
+ capturedCon = summon[DbCon].connection
143
+ capturedCon.isClosed // still open inside the block
144
+ }
145
+ // res4: Boolean = false
146
+
147
+ capturedCon.isClosed // closed after the block returned
148
+ // res5: Boolean = true
149
+ ```
150
+
151
+ ### `close` — Close the connection
152
+
153
+ `close(): Unit` closes the connection and releases the underlying JDBC resources. Normally the `Transactor` calls this automatically after the `connect` or `transact` block completes. Calling it manually inside a block will cause subsequent operations to fail with a "connection already closed" error.
@@ -0,0 +1,77 @@
1
+ ---
2
+ id: db-param-writer
3
+ title: "DbParamWriter"
4
+ description: "Reference for DbParamWriter, the interface for binding typed Scala values to SQL prepared-statement parameters."
5
+ keywords:
6
+ - "DbParamWriter Parameter Binding"
7
+ - "Typed SQL Parameters"
8
+ - "Prepared Statement Binding"
9
+ - "JDBC Parameter Binding"
10
+ ---
11
+
12
+ `DbParamWriter` is a trait for binding typed Scala values to the `?` placeholders in a SQL prepared statement. It provides methods to set parameters by their 1-based index (following JDBC convention).
13
+
14
+ Application code does not use `DbParamWriter` directly — the framework calls it internally when executing queries through `Frag` or `Repo`. It is the write-side counterpart to `DbResultReader`, which reads values from result sets.
15
+
16
+ ## Core API
17
+
18
+ ```scala
19
+ trait DbParamWriter {
20
+ // Numeric types
21
+ def setInt(index: Int, value: Int): Unit
22
+ def setLong(index: Int, value: Long): Unit
23
+ def setDouble(index: Int, value: Double): Unit
24
+ def setFloat(index: Int, value: Float): Unit
25
+ def setShort(index: Int, value: Short): Unit
26
+ def setByte(index: Int, value: Byte): Unit
27
+ def setBigDecimal(index: Int, value: java.math.BigDecimal): Unit
28
+
29
+ // Text and binary
30
+ def setString(index: Int, value: String): Unit
31
+ def setBytes(index: Int, value: Array[Byte]): Unit
32
+
33
+ // Date and time
34
+ def setLocalDate(index: Int, value: java.time.LocalDate): Unit
35
+ def setLocalDateTime(index: Int, value: java.time.LocalDateTime): Unit
36
+ def setLocalTime(index: Int, value: java.time.LocalTime): Unit
37
+ def setInstant(index: Int, value: java.time.Instant): Unit
38
+ def setDuration(index: Int, value: java.time.Duration): Unit
39
+
40
+ // Other types
41
+ def setBoolean(index: Int, value: Boolean): Unit
42
+ def setUUID(index: Int, value: java.util.UUID): Unit
43
+ def setArray(index: Int, elementType: String, elements: IndexedSeq[Any]): Unit
44
+
45
+ // Null handling
46
+ def setNull(index: Int, sqlType: Int): Unit
47
+ }
48
+ ```
49
+
50
+ ## Usage
51
+
52
+ You access `DbParamWriter` through `DbPreparedStatement.paramWriter` when using raw prepared statements in a `connect` block:
53
+
54
+ ```scala
55
+ import zio.blocks.sql._
56
+
57
+ val transactor: Transactor = JdbcTransactor.fromUrl("jdbc:sqlite::memory:", SqlDialect.SQLite)
58
+
59
+ transactor.connect {
60
+ val con = summon[DbCon].connection
61
+ val stmt = con.prepareStatement("INSERT INTO users (name, age) VALUES (?, ?)")
62
+
63
+ stmt.paramWriter.setString(1, "Alice") // First ?
64
+ stmt.paramWriter.setInt(2, 30) // Second ?
65
+
66
+ stmt.executeUpdate()
67
+ stmt.close()
68
+ }
69
+ ```
70
+
71
+ Note that indices are 1-based, not 0-based.
72
+
73
+ ## How It Works
74
+
75
+ When you use higher-level operations like `Frag.query` or `Repo.insert`, `DbCodec` internally calls `DbParamWriter` methods to bind your Scala values to SQL parameters. You see this trait only when dropping down to raw prepared statements for advanced use cases like stored procedures or batch operations.
76
+
77
+ See [DbConnection](./db-connection.md) for examples of raw prepared-statement usage, and [DbCodec](./db-codec.md) for how parameter binding integrates with the codec system.
@@ -0,0 +1,66 @@
1
+ ---
2
+ id: db-param
3
+ title: "DbParam"
4
+ description: "Reference for DbParam, the typeclass that converts Scala values to DbValue for the sql interpolator and bound SQL parameters in the sql module."
5
+ keywords:
6
+ - "DbParam typeclass"
7
+ - "sql interpolator parameters"
8
+ - "toDbValue conversion"
9
+ - "DbParam given instances"
10
+ - "fromDbCodec bridge"
11
+ - "Option Maybe nullable parameters"
12
+ - "Compile-time SQL parameters"
13
+ ---
14
+
15
+ `DbParam[A]` is a single-method typeclass that converts a Scala value of type `A` to a `DbValue` for use as a bound SQL parameter. Its sole abstract method is `toDbValue(value: A): DbValue`. The `sql"..."` string interpolator summons a `DbParam[A]` instance at compile time for every interpolated expression and delegates to it during execution to produce the typed `DbValue` that is stored in `Frag#params`.
16
+
17
+ The structural shape of `DbParam` is:
18
+
19
+ ```scala
20
+ trait DbParam[A] {
21
+ def toDbValue(value: A): DbValue
22
+ }
23
+
24
+ object DbParam {
25
+ def apply[A](implicit p: DbParam[A]): DbParam[A]
26
+ // given instances for:
27
+ // Int, Long, Double, Float, Boolean, String, Short, Byte,
28
+ // BigDecimal, Array[Byte], LocalDate, LocalDateTime, LocalTime,
29
+ // Instant, Duration, UUID, DbValue (identity),
30
+ // Option[A], Maybe[A], and fromDbCodec[A]
31
+ }
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ The following example shows the three common entry points for `DbParam`: the `sql"..."` interpolator (which calls `toDbValue` behind the scenes), direct instance summoning for inspection:
37
+
38
+ ```scala
39
+ import zio.blocks.sql._
40
+ import java.time.Instant
41
+ import java.util.UUID
42
+
43
+ // 1. Implicitly used by the sql"..." interpolator — no explicit call needed
44
+ val userId = 42
45
+ // userId: Int = 42
46
+ val active = true
47
+ // active: Boolean = true
48
+ val query = sql"SELECT * FROM users WHERE id = $userId AND active = $active"
49
+ // query: Frag = Frag(
50
+ // parts = ArraySeq("SELECT * FROM users WHERE id = ", " AND active = ", ""),
51
+ // params = Vector(DbInt(42), DbBoolean(true))
52
+ // )
53
+ query.params
54
+ // res0: IndexedSeq[DbValue] = Vector(DbInt(42), DbBoolean(true))
55
+
56
+ // 2. Summon an instance explicitly with DbParam.apply to inspect conversion
57
+ val instant = Instant.parse("2024-01-15T10:00:00Z")
58
+ // instant: Instant = 2024-01-15T10:00:00Z
59
+ DbParam[Instant].toDbValue(instant)
60
+ // res1: DbValue = DbInstant(2024-01-15T10:00:00Z)
61
+
62
+ DbParam[Option[Int]].toDbValue(Some(7))
63
+ // res2: DbValue = DbInt(7)
64
+ DbParam[Option[Int]].toDbValue(None)
65
+ // res3: DbValue = DbNull
66
+ ```