@zio.dev/zio-blocks 0.0.29 → 0.0.30
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 +997 -0
- package/guides/query-dsl-extending.md +1 -1
- package/guides/query-dsl-fluent-builder.md +203 -203
- package/guides/query-dsl-reified-optics.md +1 -1
- package/guides/query-dsl-sql.md +1 -1
- package/guides/zio-schema-migration.md +6 -6
- package/index.md +20 -14
- package/package.json +1 -1
- package/reference/codec.md +7 -7
- package/reference/context.md +1 -1
- package/reference/docs.md +1 -1
- package/reference/dynamic-schema.md +39 -42
- package/reference/media-type.md +2 -2
- package/reference/resource-management/defer-handle.md +246 -0
- package/reference/resource-management/finalization.md +286 -0
- package/reference/resource-management/finalizer.md +167 -0
- package/reference/{resource-management-di → resource-management}/index.md +3 -8
- package/reference/{resource-management-di → resource-management}/resource.md +532 -50
- package/reference/resource-management/scope.md +3026 -0
- package/reference/resource-management/unscoped.md +125 -0
- package/reference/{resource-management-di → resource-management}/wire.md +74 -28
- package/reference/schema-evolution/as.md +4 -4
- package/reference/schema-evolution/into.md +2 -2
- package/reference/schema-expr.md +2 -2
- package/reference/streams.md +989 -0
- package/reference/type-class-derivation.md +1 -1
- package/ringbuffer.md +1 -1
- package/sidebars.js +9 -4
- package/reference/resource-management-di/scope.md +0 -1423
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: unscoped
|
|
3
|
+
title: "Unscoped"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`Unscoped[A]` is a marker typeclass for types that can safely escape a scope without tracking. Types with an `Unscoped` instance are considered "safe data"—they don't hold resources and can be freely extracted from a scope. Here's the definition:
|
|
7
|
+
|
|
8
|
+
```scala
|
|
9
|
+
trait Unscoped[A]
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The `Unscoped` typeclass distinguishes between two categories of types:
|
|
13
|
+
|
|
14
|
+
1. **Unscoped types** (have an instance): Primitives, strings, collections, value types, and pure data. These can leave a scope without risk.
|
|
15
|
+
2. **Scoped types** (no instance): Resources like streams, connections, handles. These must remain tracked within a scope.
|
|
16
|
+
|
|
17
|
+
When the `$` operator is used to access a scoped value, if the result type has an `Unscoped` instance, it returns the value directly (unwrapped). Otherwise, it returns the value still wrapped in `$`.
|
|
18
|
+
|
|
19
|
+
## Motivation / Use Case
|
|
20
|
+
|
|
21
|
+
The exact problem: A `scoped` block automatically closes all resources when it exits. If you accidentally returned a resource (like a database connection or file handle) from the block, it would be closed—but you might try to use it later, causing a **use-after-close** crash. Here's an example (this would fail without `Unscoped`):
|
|
22
|
+
|
|
23
|
+
```scala
|
|
24
|
+
import zio.blocks.scope.{Scope, Resource}
|
|
25
|
+
|
|
26
|
+
final class Database {
|
|
27
|
+
def query(sql: String) = s"result: $sql"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Without Unscoped constraint, this compiles (BAD):
|
|
31
|
+
// val db: Database = Scope.global.scoped { scope =>
|
|
32
|
+
// val db = allocate(Resource(new Database()))
|
|
33
|
+
// db // BUG: returns the resource itself, not data extracted from it
|
|
34
|
+
// }
|
|
35
|
+
// db.query("SELECT 1") // CRASH: use-after-close (scope already closed it)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The solution: `Unscoped` makes this a **compile error** instead of a runtime bug. When a `scoped` block returns a value, that value's type must have an `Unscoped` instance—meaning the type checker verifies you're only extracting *computed results* (like `Int`, `String`, or aggregate data), not resources themselves.
|
|
39
|
+
|
|
40
|
+
You can still extract computed results by using the `$` operator to unwrap scoped values *within* the scope:
|
|
41
|
+
|
|
42
|
+
```scala
|
|
43
|
+
import zio.blocks.scope.{Scope, Resource}
|
|
44
|
+
|
|
45
|
+
Scope.global.scoped { scope =>
|
|
46
|
+
import scope._
|
|
47
|
+
|
|
48
|
+
val intValue = allocate(Resource(42))
|
|
49
|
+
// Extract the Int value (not the Resource), computed inside the scope
|
|
50
|
+
val n: Int = $(intValue)(x => x + 1)
|
|
51
|
+
|
|
52
|
+
val text = allocate(Resource("hello"))
|
|
53
|
+
// Extract the String value (not the Resource), computed inside the scope
|
|
54
|
+
val s: String = $(text)(x => x.toUpperCase)
|
|
55
|
+
|
|
56
|
+
(n, s) // Tuple of pure data: safe to return
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Returning Unscoped Data from Scopes
|
|
61
|
+
|
|
62
|
+
Extract computed results that don't hold resources:
|
|
63
|
+
|
|
64
|
+
```scala
|
|
65
|
+
import zio.blocks.scope.{Scope, Resource, Unscoped}
|
|
66
|
+
import scala.concurrent.duration.{Duration, FiniteDuration}
|
|
67
|
+
|
|
68
|
+
case class ProcessingResult(count: Int, elapsed: FiniteDuration)
|
|
69
|
+
|
|
70
|
+
object ProcessingResult {
|
|
71
|
+
implicit val unscoped: Unscoped[ProcessingResult] = new Unscoped[ProcessingResult] {}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
def processData(): ProcessingResult = Scope.global.scoped { scope =>
|
|
75
|
+
import scope._
|
|
76
|
+
|
|
77
|
+
val startTime = java.time.Instant.now()
|
|
78
|
+
val input = allocate(Resource(Seq(1, 2, 3, 4, 5)))
|
|
79
|
+
val count = $(input)(_.length)
|
|
80
|
+
|
|
81
|
+
val endTime = java.time.Instant.now()
|
|
82
|
+
val elapsed = java.time.Duration.between(startTime, endTime).toNanos
|
|
83
|
+
|
|
84
|
+
ProcessingResult(count, FiniteDuration(elapsed, java.util.concurrent.TimeUnit.NANOSECONDS))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
val result = processData()
|
|
88
|
+
println(result)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Only create instances for **pure data types** that don't hold resources. Never create instances for types that contain connections, streams, handles, or any resource-like fields.
|
|
92
|
+
|
|
93
|
+
## Predefined Instances
|
|
94
|
+
|
|
95
|
+
All built-in instances follow a simple principle: **if a type cannot hold resources, it gets an `Unscoped` instance**. Collections inherit this property from their elements — `List[Int]` is unscoped because `Int` is unscoped.
|
|
96
|
+
|
|
97
|
+
**Primitive and atomic values** (cannot hold resources by nature):
|
|
98
|
+
- `Int`, `Long`, `Short`, `Byte`, `Char`, `Boolean`, `Float`, `Double`, `Unit`
|
|
99
|
+
- `String`, `BigInt`, `BigDecimal`
|
|
100
|
+
- `java.util.UUID`
|
|
101
|
+
|
|
102
|
+
**Collections with conditional instances** (safe when elements/entries are unscoped):
|
|
103
|
+
- Sequences: `Array[A]`, `List[A]`, `Vector[A]`, `Seq[A]`, `IndexedSeq[A]`, `Iterable[A]`
|
|
104
|
+
- Sets: `Set[A]`
|
|
105
|
+
- Maps: `Map[K, V]` (when both `K` and `V` are unscoped)
|
|
106
|
+
- Wrappers: `Option[A]`, `Either[A, B]`, `Tuple2[A, B]` through `Tuple4[A, B, C, D]`
|
|
107
|
+
- ZIO types: `zio.blocks.chunk.Chunk[A]`
|
|
108
|
+
|
|
109
|
+
**Standard library time types** (immutable, cannot hold resources):
|
|
110
|
+
- `java.time.Instant`, `LocalDate`, `LocalTime`, `LocalDateTime`, `ZonedDateTime`, `OffsetDateTime`
|
|
111
|
+
- `java.time.Duration`, `Period`, `ZoneId`, `ZoneOffset`
|
|
112
|
+
- `scala.concurrent.duration.Duration`, `FiniteDuration`
|
|
113
|
+
|
|
114
|
+
All other types (resources, handles, connections) must be manually defined if needed.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
## Thread Safety
|
|
118
|
+
|
|
119
|
+
`Unscoped` instances themselves are immutable and thread-safe. However, the types they mark must be truly immutable for safe concurrent use. For example, `Array[Int]` is mutable—if shared across threads without synchronization, it could cause data races.
|
|
120
|
+
|
|
121
|
+
## Integration
|
|
122
|
+
|
|
123
|
+
- [`Scope.$`](./scope.md) — the operator that uses `Unscoped`
|
|
124
|
+
- [`Resource`](./resource.md) — types that provide `Unscoped` may be wrapped in resources
|
|
125
|
+
- [`Scope`](./scope.md) — manages the lifecycle of resources
|
|
@@ -3,7 +3,7 @@ id: wire
|
|
|
3
3
|
title: "Wire"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
`Wire[-In, +Out]` is a **compile-time safe recipe for constructing a service and its dependencies**. Wires describe how to construct an `Out` value given access to its dependencies via a `Context[In]` and a `Scope` for finalization
|
|
6
|
+
`Wire[-In, +Out]` is a **compile-time safe recipe for constructing a service and its dependencies**. Wires describe how to construct an `Out` value given access to its dependencies via a `Context[In]` and a `Scope` for finalization:
|
|
7
7
|
|
|
8
8
|
```scala
|
|
9
9
|
sealed trait Wire[-In, +Out] {
|
|
@@ -60,7 +60,7 @@ final class App(service: UserService) {
|
|
|
60
60
|
|
|
61
61
|
// Manual wiring:
|
|
62
62
|
Scope.global.scoped { scope =>
|
|
63
|
-
import scope
|
|
63
|
+
import scope._
|
|
64
64
|
val config = Config("jdbc:postgres://localhost/db")
|
|
65
65
|
val db = Resource.fromAutoCloseable(new Database(config)).allocate
|
|
66
66
|
val service = new UserService($(db)(identity))
|
|
@@ -73,7 +73,7 @@ With `Wire` + `Resource.from`, the macro handles the dependency graph:
|
|
|
73
73
|
|
|
74
74
|
```scala
|
|
75
75
|
Scope.global.scoped { scope =>
|
|
76
|
-
import scope
|
|
76
|
+
import scope._
|
|
77
77
|
val app = Resource.from[App](
|
|
78
78
|
Wire(Config("jdbc:postgres://localhost/db"))
|
|
79
79
|
).allocate
|
|
@@ -89,23 +89,27 @@ Scope.global.scoped { scope =>
|
|
|
89
89
|
|
|
90
90
|
## Installation
|
|
91
91
|
|
|
92
|
+
Add the following dependency to your `build.sbt`:
|
|
93
|
+
|
|
92
94
|
```scala
|
|
93
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-scope" % "
|
|
95
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-scope" % "0.0.30"
|
|
94
96
|
```
|
|
95
97
|
|
|
96
98
|
For cross-platform (Scala.js):
|
|
97
99
|
|
|
98
100
|
```scala
|
|
99
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-scope" % "
|
|
101
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-scope" % "0.0.30"
|
|
100
102
|
```
|
|
101
103
|
|
|
102
104
|
Supported Scala versions: 2.13.x and 3.x.
|
|
103
105
|
|
|
104
106
|
## Construction
|
|
105
107
|
|
|
108
|
+
`Wire` provides multiple ways to create instances, ranging from automatic macro-based derivation to manual construction for custom logic. Here are the main construction methods:
|
|
109
|
+
|
|
106
110
|
### Wire.shared[T] — derive a shared wire
|
|
107
111
|
|
|
108
|
-
The `Wire.shared[T]` macro inspects `T`'s primary constructor and generates a shared wire that reuses the same instance across dependents
|
|
112
|
+
The `Wire.shared[T]` macro inspects `T`'s primary constructor and generates a shared wire that reuses the same instance across dependents:
|
|
109
113
|
|
|
110
114
|
```scala
|
|
111
115
|
import zio.blocks.scope._
|
|
@@ -121,7 +125,7 @@ final class Database(config: Config) extends AutoCloseable {
|
|
|
121
125
|
val wire: Wire.Shared[Config, Database] = Wire.shared[Database]
|
|
122
126
|
|
|
123
127
|
Scope.global.scoped { scope =>
|
|
124
|
-
import scope
|
|
128
|
+
import scope._
|
|
125
129
|
val config = Config(debug = true)
|
|
126
130
|
val deps = Context[Config](config)
|
|
127
131
|
val db = allocate(wire.toResource(deps))
|
|
@@ -131,7 +135,7 @@ Scope.global.scoped { scope =>
|
|
|
131
135
|
|
|
132
136
|
### Wire.unique[T] — derive a unique wire
|
|
133
137
|
|
|
134
|
-
Like `shared[T]`, but creates a fresh instance each time the wire is used. Use for request-scoped or per-call services
|
|
138
|
+
Like `Wire.shared[T]`, but creates a fresh instance each time the wire is used. Use for request-scoped or per-call services:
|
|
135
139
|
|
|
136
140
|
```scala
|
|
137
141
|
import zio.blocks.scope._
|
|
@@ -144,7 +148,7 @@ final class RequestHandler {
|
|
|
144
148
|
val wire: Wire.Unique[Any, RequestHandler] = Wire.unique[RequestHandler]
|
|
145
149
|
|
|
146
150
|
Scope.global.scoped { scope =>
|
|
147
|
-
import scope
|
|
151
|
+
import scope._
|
|
148
152
|
val deps = Context.empty[Any]
|
|
149
153
|
val resource = wire.toResource(deps)
|
|
150
154
|
|
|
@@ -161,7 +165,7 @@ Scope.global.scoped { scope =>
|
|
|
161
165
|
|
|
162
166
|
### Wire.apply[T] — lift a pre-existing value
|
|
163
167
|
|
|
164
|
-
Creates a shared wire that injects a value you already have. If the value is `AutoCloseable`, its `close()` method is automatically registered as a finalizer
|
|
168
|
+
Creates a shared wire that injects a value you already have. If the value is `AutoCloseable`, its `close()` method is automatically registered as a finalizer:
|
|
165
169
|
|
|
166
170
|
```scala
|
|
167
171
|
import zio.blocks.scope._
|
|
@@ -172,7 +176,7 @@ val config = Config("jdbc:postgres://localhost/db")
|
|
|
172
176
|
val wire: Wire.Shared[Any, Config] = Wire(config)
|
|
173
177
|
|
|
174
178
|
Scope.global.scoped { scope =>
|
|
175
|
-
import scope
|
|
179
|
+
import scope._
|
|
176
180
|
val cfg = allocate(wire.toResource(Context.empty[Any]))
|
|
177
181
|
$(cfg)(_.dbUrl)
|
|
178
182
|
}
|
|
@@ -180,7 +184,7 @@ Scope.global.scoped { scope =>
|
|
|
180
184
|
|
|
181
185
|
### Wire.Shared.fromFunction — manual shared wire construction
|
|
182
186
|
|
|
183
|
-
Use this for custom construction logic when macro derivation doesn't fit
|
|
187
|
+
Use this for custom construction logic when macro derivation doesn't fit:
|
|
184
188
|
|
|
185
189
|
```scala
|
|
186
190
|
import zio.blocks.scope._
|
|
@@ -199,7 +203,7 @@ val wire: Wire.Shared[Config, Client] =
|
|
|
199
203
|
}
|
|
200
204
|
|
|
201
205
|
Scope.global.scoped { scope =>
|
|
202
|
-
import scope
|
|
206
|
+
import scope._
|
|
203
207
|
val config = Config(30)
|
|
204
208
|
val deps = Context[Config](config)
|
|
205
209
|
val client = allocate(wire.toResource(deps))
|
|
@@ -209,7 +213,7 @@ Scope.global.scoped { scope =>
|
|
|
209
213
|
|
|
210
214
|
### Wire.Unique.fromFunction — manual unique wire construction
|
|
211
215
|
|
|
212
|
-
Like `fromFunction`, but for unique wires
|
|
216
|
+
Like `Wire.Shared.fromFunction`, but for unique wires:
|
|
213
217
|
|
|
214
218
|
```scala
|
|
215
219
|
import zio.blocks.scope._
|
|
@@ -225,7 +229,7 @@ val wire: Wire.Unique[Any, RequestContext] =
|
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
Scope.global.scoped { scope =>
|
|
228
|
-
import scope
|
|
232
|
+
import scope._
|
|
229
233
|
val deps = Context.empty[Any]
|
|
230
234
|
val resource = wire.toResource(deps)
|
|
231
235
|
|
|
@@ -249,7 +253,7 @@ The fundamental difference is **reuse semantics**:
|
|
|
249
253
|
| **Instance reuse** | Same instance across entire dependency graph | New instance per allocation |
|
|
250
254
|
| **Finalization** | Runs when last referencing scope closes | Runs when each scope closes |
|
|
251
255
|
|
|
252
|
-
In the diamond pattern (where `App` depends on both `UserService` and `OrderService`, both of which depend on `Database`), a shared wire ensures `Database` is constructed once and both services receive the same instance
|
|
256
|
+
In the diamond pattern (where `App` depends on both `UserService` and `OrderService`, both of which depend on `Database`), a shared wire ensures `Database` is constructed once and both services receive the same instance:
|
|
253
257
|
|
|
254
258
|
```scala
|
|
255
259
|
import zio.blocks.scope._
|
|
@@ -281,7 +285,7 @@ val resource = Resource.from[App](
|
|
|
281
285
|
)
|
|
282
286
|
|
|
283
287
|
Scope.global.scoped { scope =>
|
|
284
|
-
import scope
|
|
288
|
+
import scope._
|
|
285
289
|
val app = resource.allocate
|
|
286
290
|
$(app)(_.check()) // true: Database is shared
|
|
287
291
|
}
|
|
@@ -289,10 +293,21 @@ Scope.global.scoped { scope =>
|
|
|
289
293
|
|
|
290
294
|
## Core Operations
|
|
291
295
|
|
|
296
|
+
The `Wire` interface provides a set of operations for inspecting and transforming wires:
|
|
297
|
+
|
|
292
298
|
### `Wire#isShared` and `Wire#isUnique`
|
|
293
299
|
|
|
294
300
|
Check the sharing strategy of a wire:
|
|
295
301
|
|
|
302
|
+
```scala
|
|
303
|
+
trait Wire[-In, +Out] {
|
|
304
|
+
def isShared: Boolean
|
|
305
|
+
def isUnique: Boolean = !isShared
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Here's how to use these methods:
|
|
310
|
+
|
|
296
311
|
```scala
|
|
297
312
|
import zio.blocks.scope._
|
|
298
313
|
|
|
@@ -309,6 +324,15 @@ println(s"uniqueWire.isUnique: ${uniqueWire.isUnique}") // true
|
|
|
309
324
|
|
|
310
325
|
Convert a wire to the opposite strategy:
|
|
311
326
|
|
|
327
|
+
```scala
|
|
328
|
+
trait Wire[-In, +Out] {
|
|
329
|
+
def shared: Wire.Shared[In, Out]
|
|
330
|
+
def unique: Wire.Unique[In, Out]
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Here's how to convert between sharing strategies:
|
|
335
|
+
|
|
312
336
|
```scala
|
|
313
337
|
import zio.blocks.scope._
|
|
314
338
|
|
|
@@ -329,6 +353,14 @@ Calling `shared` on an already-shared wire returns `this` (identity); likewise `
|
|
|
329
353
|
|
|
330
354
|
Converts the wire to a lazy `Resource` by providing the dependency context:
|
|
331
355
|
|
|
356
|
+
```scala
|
|
357
|
+
trait Wire[-In, +Out] {
|
|
358
|
+
def toResource(deps: Context[In]): Resource[Out]
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Here's how to use this method:
|
|
363
|
+
|
|
332
364
|
```scala
|
|
333
365
|
import zio.blocks.scope._
|
|
334
366
|
import zio.blocks.context.Context
|
|
@@ -341,7 +373,7 @@ val deps = Context[Config](Config("hello"))
|
|
|
341
373
|
val resource: Resource[Config] = wire.toResource(deps)
|
|
342
374
|
|
|
343
375
|
Scope.global.scoped { scope =>
|
|
344
|
-
import scope
|
|
376
|
+
import scope._
|
|
345
377
|
val cfg = allocate(resource)
|
|
346
378
|
$(cfg)(_.value)
|
|
347
379
|
}
|
|
@@ -349,7 +381,15 @@ Scope.global.scoped { scope =>
|
|
|
349
381
|
|
|
350
382
|
### `Wire#make` — construct directly from a wire
|
|
351
383
|
|
|
352
|
-
Directly construct a value without going through `Resource.toResource`. This is a low-level operation; prefer `allocate(wire.toResource(...))` for safety
|
|
384
|
+
Directly construct a value without going through `Resource.toResource`. This is a low-level operation; prefer `allocate(wire.toResource(...))` for safety:
|
|
385
|
+
|
|
386
|
+
```scala
|
|
387
|
+
trait Wire.Shared[-In, +Out] {
|
|
388
|
+
def make(scope: Scope, context: Context[In]): Out
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Here's how to use this method:
|
|
353
393
|
|
|
354
394
|
```scala
|
|
355
395
|
import zio.blocks.scope._
|
|
@@ -362,7 +402,7 @@ final class Service {
|
|
|
362
402
|
val wire = Wire.shared[Service]
|
|
363
403
|
|
|
364
404
|
Scope.global.scoped { scope =>
|
|
365
|
-
import scope
|
|
405
|
+
import scope._
|
|
366
406
|
val service = wire.asInstanceOf[Wire.Shared[Any, Service]].make(scope, Context.empty[Any])
|
|
367
407
|
println(service.getName)
|
|
368
408
|
}
|
|
@@ -384,11 +424,11 @@ import zio.blocks.scope._
|
|
|
384
424
|
|
|
385
425
|
final case class Config(dbUrl: String)
|
|
386
426
|
|
|
387
|
-
final class Logger(
|
|
427
|
+
final class Logger(implicit finalizer: Finalizer) {
|
|
388
428
|
def log(msg: String): Unit = println(msg)
|
|
389
429
|
}
|
|
390
430
|
|
|
391
|
-
final class Database(config: Config)(
|
|
431
|
+
final class Database(config: Config)(implicit scope: Scope) extends AutoCloseable {
|
|
392
432
|
def connect(): Unit = {
|
|
393
433
|
scope.defer(println("database connection closed"))
|
|
394
434
|
println(s"connecting to ${config.dbUrl}")
|
|
@@ -492,7 +532,7 @@ cd zio-blocks
|
|
|
492
532
|
|
|
493
533
|
**2. Run individual examples with sbt:**
|
|
494
534
|
|
|
495
|
-
|
|
535
|
+
Basic wire construction demonstrates how to create and use `Wire` for dependency injection. View the example source code:
|
|
496
536
|
|
|
497
537
|
```scala title="scope-examples/src/main/scala/wire/WireBasicExample.scala"
|
|
498
538
|
package wire
|
|
@@ -589,11 +629,13 @@ final class BasicApp(service: UserService) {
|
|
|
589
629
|
|
|
590
630
|
([source](https://github.com/zio/zio-blocks/blob/main/scope-examples/src/main/scala/wire/WireBasicExample.scala))
|
|
591
631
|
|
|
632
|
+
Run this example with:
|
|
633
|
+
|
|
592
634
|
```bash
|
|
593
|
-
sbt "scope-examples/runMain wire.
|
|
635
|
+
sbt "scope-examples/runMain wire.wireBasicExample"
|
|
594
636
|
```
|
|
595
637
|
|
|
596
|
-
|
|
638
|
+
Comparing shared vs unique semantics shows how shared wires reuse the same instance across dependents, while unique wires create fresh instances. View the example:
|
|
597
639
|
|
|
598
640
|
```scala title="scope-examples/src/main/scala/wire/WireSharedUniqueExample.scala"
|
|
599
641
|
package wire
|
|
@@ -692,11 +734,13 @@ final class UniqueDependencyApp(a: ServiceA, b: ServiceB) {
|
|
|
692
734
|
|
|
693
735
|
([source](https://github.com/zio/zio-blocks/blob/main/scope-examples/src/main/scala/wire/WireSharedUniqueExample.scala))
|
|
694
736
|
|
|
737
|
+
Run this example with:
|
|
738
|
+
|
|
695
739
|
```bash
|
|
696
|
-
sbt "scope-examples/runMain wire.
|
|
740
|
+
sbt "scope-examples/runMain wire.wireSharedUniqueExample"
|
|
697
741
|
```
|
|
698
742
|
|
|
699
|
-
|
|
743
|
+
Manual wire construction demonstrates how to use `fromFunction` for custom construction logic. View the example:
|
|
700
744
|
|
|
701
745
|
```scala title="scope-examples/src/main/scala/wire/WireFromFunctionExample.scala"
|
|
702
746
|
package wire
|
|
@@ -827,6 +871,8 @@ final class ManualWireApp(client: HttpClient, auth: Authenticator) {
|
|
|
827
871
|
|
|
828
872
|
([source](https://github.com/zio/zio-blocks/blob/main/scope-examples/src/main/scala/wire/WireFromFunctionExample.scala))
|
|
829
873
|
|
|
874
|
+
Run this example with:
|
|
875
|
+
|
|
830
876
|
```bash
|
|
831
|
-
sbt "scope-examples/runMain wire.
|
|
877
|
+
sbt "scope-examples/runMain wire.wireFromFunctionExample"
|
|
832
878
|
```
|
|
@@ -39,13 +39,13 @@ The bidirectional data flow looks like this:
|
|
|
39
39
|
`As` is part of `zio-blocks-schema`:
|
|
40
40
|
|
|
41
41
|
```scala
|
|
42
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.
|
|
42
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.30"
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
For Scala.js and Scala Native, use `%%%`:
|
|
46
46
|
|
|
47
47
|
```scala
|
|
48
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.
|
|
48
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.30"
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
Supported Scala versions: 2.13.x and 3.x.
|
|
@@ -240,7 +240,7 @@ trait As[A, B] {
|
|
|
240
240
|
|
|
241
241
|
```scala
|
|
242
242
|
val revAs: As[LongBox, IntBox] = boxAs.reverse
|
|
243
|
-
// revAs: As[LongBox, IntBox] = zio.blocks.schema.As$$anon$1@
|
|
243
|
+
// revAs: As[LongBox, IntBox] = zio.blocks.schema.As$$anon$1@c044a8b
|
|
244
244
|
|
|
245
245
|
revAs.into(LongBox(5L))
|
|
246
246
|
// res11: Either[SchemaError, IntBox] = Right(IntBox(5))
|
|
@@ -302,7 +302,7 @@ We import `As.reverseInto` and use it to obtain the reverse `Into[Int, String]`:
|
|
|
302
302
|
import As.reverseInto
|
|
303
303
|
|
|
304
304
|
val intToStr: Into[Int, String] = reverseInto[String, Int]
|
|
305
|
-
// intToStr: Into[Int, String] = zio.blocks.schema.AsLowPriorityImplicits$$Lambda$
|
|
305
|
+
// intToStr: Into[Int, String] = zio.blocks.schema.AsLowPriorityImplicits$$Lambda$17407/0x00007f6106975350@5d23723e
|
|
306
306
|
intToStr.into(42)
|
|
307
307
|
// res14: Either[SchemaError, String] = Right("42")
|
|
308
308
|
```
|
|
@@ -69,13 +69,13 @@ Compare this to a manual implementation:
|
|
|
69
69
|
`Into` is part of the `zio-blocks-schema` module:
|
|
70
70
|
|
|
71
71
|
```scala
|
|
72
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.
|
|
72
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.30"
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
For Scala.js:
|
|
76
76
|
|
|
77
77
|
```scala
|
|
78
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.
|
|
78
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.30"
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
Supported Scala versions: 2.13.x and 3.x.
|
package/reference/schema-expr.md
CHANGED
|
@@ -70,13 +70,13 @@ val result: Either[OpticCheck, Seq[Boolean]] = combined.eval(alice)
|
|
|
70
70
|
## Installation
|
|
71
71
|
|
|
72
72
|
```scala
|
|
73
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.
|
|
73
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-schema" % "0.0.30"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
For cross-platform (Scala.js):
|
|
77
77
|
|
|
78
78
|
```scala
|
|
79
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.
|
|
79
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-schema" % "0.0.30"
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
Supported Scala versions: 2.13.x and 3.x.
|