alink-cli 0.7.2 → 0.7.4
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/README.md +3 -6
- package/bin/agentlink-account.js +133 -0
- package/bin/agentlink.js +95 -12
- package/dist/Config-Bj2ZPCsP.mjs +1221 -0
- package/dist/Config-Bj2ZPCsP.mjs.map +1 -0
- package/dist/NodeHttpServer-BGJlR_Kf.mjs +826 -0
- package/dist/NodeHttpServer-BGJlR_Kf.mjs.map +1 -0
- package/dist/NodeServices-DDZTiw5K.mjs +1984 -0
- package/dist/NodeServices-DDZTiw5K.mjs.map +1 -0
- package/dist/NodeSocket-08w4osAf.mjs +11198 -0
- package/dist/NodeSocket-08w4osAf.mjs.map +1 -0
- package/dist/NodeSqliteClient-Byu521pt.mjs +578 -0
- package/dist/NodeSqliteClient-Byu521pt.mjs.map +1 -0
- package/dist/Schema-B3i-HrZQ.mjs +40423 -0
- package/dist/Schema-B3i-HrZQ.mjs.map +1 -0
- package/dist/SqlClient-DcM69ZvI.mjs +1554 -0
- package/dist/SqlClient-DcM69ZvI.mjs.map +1 -0
- package/dist/bin.mjs +47577 -26766
- package/dist/bin.mjs.map +1 -1
- package/package.json +4 -3
- package/dist/NodeSqliteClient-BUlNQAY0.mjs +0 -191
- package/dist/NodeSqliteClient-BUlNQAY0.mjs.map +0 -1
|
@@ -0,0 +1,1554 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Bl as void_, Bo as provideContext, Cc as make$6, Cd as match, Cl as asSome, Cs as void_$1, Dl as exitHasInterrupts, El as endSpan, Es as withFiber$1, Fi as failCauseUnsafe, Fl as succeed, Gc as isSuccess, Ha as context, Hu as failVoid, Id as withFiber, Ii as make$5, Il as succeedNone, Io as orDie, Ja as exit, Jd as hash, Ju as succeed$1, Ld as assignProperty, Ll as sync, Md as Prototype, Ml as makeSpanUnsafe, Mo as onExit$1, Nd as PipeInspectableProto, Nl as onExit, Oc as TracerTimingEnabled, Ol as fiberInterrupt, Pd as exitSucceed, Qa as flatMap, Qd as hasProperty, Qu as add, Ru as filterMap, So as map, Ss as useSpan, Tc as provide, Tl as contextWith, Ua as contextWith$1, Vo as provideService, Wl as ParentSpan, Xu as Reference, Zo as scoped, Zu as Service, _c as Scope, aa as runIn, as as suspend, bc as close, bd as isNone, bl as ClockRef, bs as uninterruptibleMask, df as constUndefined, di as make$4, ed as get$2, es as serviceOption, eu as fromInputUnsafe, fi as remove, hf as flow, iu as isZero, jl as forkUnsafe, kl as fiberJoin, lo as gen, mf as dual, mi as size, ni as unwrap, no as fnUntraced, ns as succeed$2, nu as infinity, os as sync$1, pi as set$1, qa as ensuring, qo as runForkWith, qs as Clock, rc as effect, ru as isFinite, sd as merge, ss as tap, td as getOption$1, ui as get$1, uu as toMillis, vc as addFinalizer, xd as isSome, xo as makeSpanScoped, xr as fromQueue, zi as offerUnsafe, zl as updateContext } from "./Schema-B3i-HrZQ.mjs";
|
|
4
|
+
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9/node_modules/effect/dist/Cache.js
|
|
5
|
+
/**
|
|
6
|
+
* Caches values loaded by an Effect lookup function.
|
|
7
|
+
*
|
|
8
|
+
* A cache stores successful and failed lookup results, shares an in-progress
|
|
9
|
+
* lookup when multiple callers request the same missing key, and limits entries
|
|
10
|
+
* by capacity and optional time-to-live rules. This module includes helpers for
|
|
11
|
+
* reading, setting, refreshing, invalidating, and inspecting cache contents.
|
|
12
|
+
*
|
|
13
|
+
* @since 4.0.0
|
|
14
|
+
*/
|
|
15
|
+
const TypeId$1 = "~effect/Cache";
|
|
16
|
+
/**
|
|
17
|
+
* Creates a cache with dynamic time-to-live based on the result and key.
|
|
18
|
+
*
|
|
19
|
+
* **When to use**
|
|
20
|
+
*
|
|
21
|
+
* Use when you need different cache entry lifetimes based on the lookup result
|
|
22
|
+
* or key characteristics.
|
|
23
|
+
*
|
|
24
|
+
* **Details**
|
|
25
|
+
*
|
|
26
|
+
* The timeToLive function receives both the exit result and the key, allowing
|
|
27
|
+
* for flexible TTL policies based on success/failure state and key characteristics.
|
|
28
|
+
*
|
|
29
|
+
* **Example** (Configuring dynamic time to live)
|
|
30
|
+
*
|
|
31
|
+
* ```ts import.meta.vitest
|
|
32
|
+
* import { Cache, Effect, Exit } from "effect"
|
|
33
|
+
*
|
|
34
|
+
* // Cache with TTL based on computed value
|
|
35
|
+
* const program = Effect.gen(function*() {
|
|
36
|
+
* const cache = yield* Cache.makeWith(
|
|
37
|
+
* (id: number) => Effect.succeed({ id, active: id % 2 === 0 }),
|
|
38
|
+
* {
|
|
39
|
+
* capacity: 1000,
|
|
40
|
+
* timeToLive(exit) {
|
|
41
|
+
* if (Exit.isSuccess(exit)) {
|
|
42
|
+
* const user = exit.value
|
|
43
|
+
* return user.active ? "1 hour" : "5 minutes"
|
|
44
|
+
* }
|
|
45
|
+
* return "30 seconds"
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* )
|
|
49
|
+
*
|
|
50
|
+
* return cache.capacity
|
|
51
|
+
* })
|
|
52
|
+
*
|
|
53
|
+
* const actual = await Effect.runPromise(program)
|
|
54
|
+
* actual // => 1000
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @see {@link make} for a simpler cache constructor with a fixed time-to-live for all entries
|
|
58
|
+
* @category constructors
|
|
59
|
+
* @since 2.0.0
|
|
60
|
+
*/
|
|
61
|
+
const makeWith = (lookup, options) => contextWith((context) => {
|
|
62
|
+
const self = Object.create(Proto);
|
|
63
|
+
self.lookup = (key) => updateContext(lookup(key), (input) => merge(context, input));
|
|
64
|
+
self.map = make$4();
|
|
65
|
+
self.capacity = options.capacity;
|
|
66
|
+
self.timeToLive = options.timeToLive ? (exit, key) => fromInputUnsafe(options.timeToLive(exit, key)) : defaultTimeToLive;
|
|
67
|
+
return succeed(self);
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Creates a cache with a fixed time-to-live for all entries.
|
|
71
|
+
*
|
|
72
|
+
* **Details**
|
|
73
|
+
*
|
|
74
|
+
* This is the basic cache constructor where all entries share the same TTL.
|
|
75
|
+
* The lookup function will be called when a key is not found or has expired.
|
|
76
|
+
*
|
|
77
|
+
* **Example** (Creating a basic cache)
|
|
78
|
+
*
|
|
79
|
+
* ```ts import.meta.vitest
|
|
80
|
+
* import { Cache, Effect } from "effect"
|
|
81
|
+
*
|
|
82
|
+
* // Basic cache with string keys
|
|
83
|
+
* const program = Effect.gen(function*() {
|
|
84
|
+
* const cache = yield* Cache.make<string, number>({
|
|
85
|
+
* capacity: 100,
|
|
86
|
+
* lookup: (key) => Effect.succeed(key.length)
|
|
87
|
+
* })
|
|
88
|
+
*
|
|
89
|
+
* const result1 = yield* Cache.get(cache, "hello")
|
|
90
|
+
* const result2 = yield* Cache.get(cache, "world")
|
|
91
|
+
* return { result1, result2 }
|
|
92
|
+
* })
|
|
93
|
+
*
|
|
94
|
+
* const actual = await Effect.runPromise(program)
|
|
95
|
+
* actual // => { result1: 5, result2: 5 }
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* **Example** (Creating a cache with TTL)
|
|
99
|
+
*
|
|
100
|
+
* ```ts import.meta.vitest
|
|
101
|
+
* import { Cache, Effect } from "effect"
|
|
102
|
+
*
|
|
103
|
+
* const program = Effect.gen(function*() {
|
|
104
|
+
* const users = new Map([
|
|
105
|
+
* [123, { name: "Ada", email: "ada@example.com" }],
|
|
106
|
+
* [456, { name: "Grace", email: "grace@example.com" }]
|
|
107
|
+
* ])
|
|
108
|
+
*
|
|
109
|
+
* const cache = yield* Cache.make<
|
|
110
|
+
* number,
|
|
111
|
+
* { name: string; email: string },
|
|
112
|
+
* string
|
|
113
|
+
* >({
|
|
114
|
+
* capacity: 500,
|
|
115
|
+
* lookup: (userId) =>
|
|
116
|
+
* Effect.suspend(() => {
|
|
117
|
+
* const user = users.get(userId)
|
|
118
|
+
* return user === undefined
|
|
119
|
+
* ? Effect.fail(`User ${userId} not found`)
|
|
120
|
+
* : Effect.succeed(user)
|
|
121
|
+
* }),
|
|
122
|
+
* timeToLive: "15 minutes"
|
|
123
|
+
* })
|
|
124
|
+
*
|
|
125
|
+
* const user1 = yield* Cache.get(cache, 123)
|
|
126
|
+
* const user2 = yield* Cache.get(cache, 123)
|
|
127
|
+
* return [user1, user2, user1 === user2] as const
|
|
128
|
+
* })
|
|
129
|
+
*
|
|
130
|
+
* const actual = await Effect.runPromise(program)
|
|
131
|
+
* actual // => [{ name: "Ada", email: "ada@example.com" }, { name: "Ada", email: "ada@example.com" }, true]
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @category constructors
|
|
135
|
+
* @since 2.0.0
|
|
136
|
+
*/
|
|
137
|
+
const make$3 = (options) => makeWith(options.lookup, {
|
|
138
|
+
...options,
|
|
139
|
+
timeToLive: options.timeToLive ? () => options.timeToLive : defaultTimeToLive
|
|
140
|
+
});
|
|
141
|
+
const Proto = {
|
|
142
|
+
...PipeInspectableProto,
|
|
143
|
+
[TypeId$1]: TypeId$1,
|
|
144
|
+
toJSON() {
|
|
145
|
+
return {
|
|
146
|
+
_id: "Cache",
|
|
147
|
+
capacity: this.capacity,
|
|
148
|
+
map: this.map
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const defaultTimeToLive = (_, _key) => infinity;
|
|
153
|
+
/**
|
|
154
|
+
* Retrieves the value for a key, invoking the lookup function on a cache miss
|
|
155
|
+
* or expired entry.
|
|
156
|
+
*
|
|
157
|
+
* **Details**
|
|
158
|
+
*
|
|
159
|
+
* Concurrent `get` calls for the same missing key share the same pending
|
|
160
|
+
* lookup. The cache stores the lookup `Exit`, so failed lookups are cached and
|
|
161
|
+
* will fail again until the entry expires, is invalidated, or is refreshed.
|
|
162
|
+
*
|
|
163
|
+
* **Example** (Getting cached values)
|
|
164
|
+
*
|
|
165
|
+
* ```ts import.meta.vitest
|
|
166
|
+
* import { Cache, Effect } from "effect"
|
|
167
|
+
*
|
|
168
|
+
* const program = Effect.gen(function*() {
|
|
169
|
+
* const cache = yield* Cache.make({
|
|
170
|
+
* capacity: 10,
|
|
171
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
172
|
+
* })
|
|
173
|
+
*
|
|
174
|
+
* // Cache miss - triggers lookup function
|
|
175
|
+
* const result1 = yield* Cache.get(cache, "hello")
|
|
176
|
+
*
|
|
177
|
+
* // Cache hit - returns cached value without lookup
|
|
178
|
+
* const result2 = yield* Cache.get(cache, "hello")
|
|
179
|
+
*
|
|
180
|
+
* return { result1, result2 }
|
|
181
|
+
* })
|
|
182
|
+
*
|
|
183
|
+
* const actual = await Effect.runPromise(program)
|
|
184
|
+
* actual // => { result1: 5, result2: 5 }
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* **Example** (Handling lookup failures)
|
|
188
|
+
*
|
|
189
|
+
* ```ts import.meta.vitest
|
|
190
|
+
* import { Cache, Effect, Exit } from "effect"
|
|
191
|
+
*
|
|
192
|
+
* // Error handling when lookup fails
|
|
193
|
+
* const program = Effect.gen(function*() {
|
|
194
|
+
* const cache = yield* Cache.make<string, number, string>({
|
|
195
|
+
* capacity: 10,
|
|
196
|
+
* lookup: (key: string) =>
|
|
197
|
+
* key === "error"
|
|
198
|
+
* ? Effect.fail("Lookup failed")
|
|
199
|
+
* : Effect.succeed(key.length)
|
|
200
|
+
* })
|
|
201
|
+
*
|
|
202
|
+
* // Successful lookup
|
|
203
|
+
* const success = yield* Cache.get(cache, "hello")
|
|
204
|
+
*
|
|
205
|
+
* // Failed lookup - returns error
|
|
206
|
+
* const failure = yield* Effect.exit(Cache.get(cache, "error"))
|
|
207
|
+
* return [success, failure] as const
|
|
208
|
+
* })
|
|
209
|
+
*
|
|
210
|
+
* const actual = await Effect.runPromise(program)
|
|
211
|
+
* actual // => [5, Exit.fail("Lookup failed")]
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* **Example** (Sharing concurrent lookups)
|
|
215
|
+
*
|
|
216
|
+
* ```ts import.meta.vitest
|
|
217
|
+
* import { Cache, Effect } from "effect"
|
|
218
|
+
*
|
|
219
|
+
* // Concurrent access - multiple gets of same key only invoke lookup once
|
|
220
|
+
* const program = Effect.gen(function*() {
|
|
221
|
+
* let lookupCount = 0
|
|
222
|
+
* const cache = yield* Cache.make({
|
|
223
|
+
* capacity: 10,
|
|
224
|
+
* lookup: (key: string) =>
|
|
225
|
+
* Effect.sync(() => {
|
|
226
|
+
* lookupCount++
|
|
227
|
+
* return key.length
|
|
228
|
+
* })
|
|
229
|
+
* })
|
|
230
|
+
*
|
|
231
|
+
* // Multiple concurrent gets
|
|
232
|
+
* const results = yield* Effect.all([
|
|
233
|
+
* Cache.get(cache, "hello"),
|
|
234
|
+
* Cache.get(cache, "hello"),
|
|
235
|
+
* Cache.get(cache, "hello")
|
|
236
|
+
* ], { concurrency: "unbounded" })
|
|
237
|
+
*
|
|
238
|
+
* return { results, lookupCount }
|
|
239
|
+
* })
|
|
240
|
+
*
|
|
241
|
+
* const actual = await Effect.runPromise(program)
|
|
242
|
+
* actual // => { results: [5, 5, 5], lookupCount: 1 }
|
|
243
|
+
* ```
|
|
244
|
+
*
|
|
245
|
+
* @category combinators
|
|
246
|
+
* @since 4.0.0
|
|
247
|
+
*/
|
|
248
|
+
const get = /*#__PURE__*/ dual(2, (self, key) => withFiber((fiber) => {
|
|
249
|
+
const oentry = get$1(self.map, key);
|
|
250
|
+
if (isSome(oentry) && !hasExpired(oentry.value, fiber)) {
|
|
251
|
+
remove(self.map, key);
|
|
252
|
+
set$1(self.map, key, oentry.value);
|
|
253
|
+
return oentry.value.await();
|
|
254
|
+
}
|
|
255
|
+
const entry = new EntryImpl(fiber, self.lookup(key));
|
|
256
|
+
entry.fiber.addObserver((exit) => {
|
|
257
|
+
if (exitHasInterrupts(exit)) {
|
|
258
|
+
const current = get$1(self.map, key);
|
|
259
|
+
if (isSome(current) && current.value === entry) remove(self.map, key);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const ttl = self.timeToLive(exit, key);
|
|
263
|
+
if (isFinite(ttl)) entry.expiresAt = fiber.getRef(ClockRef).currentTimeMillisUnsafe() + toMillis(ttl);
|
|
264
|
+
else if (isZero(ttl)) remove(self.map, key);
|
|
265
|
+
});
|
|
266
|
+
set$1(self.map, key, entry);
|
|
267
|
+
if (Number.isFinite(self.capacity)) checkCapacity(self);
|
|
268
|
+
return entry.await();
|
|
269
|
+
}));
|
|
270
|
+
var EntryImpl = class {
|
|
271
|
+
expiresAt;
|
|
272
|
+
awaiters;
|
|
273
|
+
fiber;
|
|
274
|
+
constructor(parent, valueEffect) {
|
|
275
|
+
this.fiber = forkUnsafe(parent, valueEffect, true, true);
|
|
276
|
+
this.awaiters = 0;
|
|
277
|
+
this.expiresAt = void 0;
|
|
278
|
+
}
|
|
279
|
+
await() {
|
|
280
|
+
const exit = this.fiber.pollUnsafe();
|
|
281
|
+
if (exit) return exit;
|
|
282
|
+
this.awaiters++;
|
|
283
|
+
return onExit(fiberJoin(this.fiber), () => {
|
|
284
|
+
this.awaiters--;
|
|
285
|
+
if (this.awaiters > 0 || this.fiber.pollUnsafe()) return void_;
|
|
286
|
+
return fiberInterrupt(this.fiber);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const hasExpired = (entry, fiber) => {
|
|
291
|
+
if (entry.expiresAt === void 0) return false;
|
|
292
|
+
return fiber.getRef(ClockRef).currentTimeMillisUnsafe() >= entry.expiresAt;
|
|
293
|
+
};
|
|
294
|
+
const checkCapacity = (self) => {
|
|
295
|
+
let diff = size(self.map) - self.capacity;
|
|
296
|
+
if (diff <= 0) return;
|
|
297
|
+
for (const [key] of self.map) {
|
|
298
|
+
remove(self.map, key);
|
|
299
|
+
diff--;
|
|
300
|
+
if (diff === 0) return;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Reads an existing cache entry without invoking the lookup function.
|
|
305
|
+
*
|
|
306
|
+
* **Details**
|
|
307
|
+
*
|
|
308
|
+
* Returns `Option.none()` when the key is missing or expired, and `Option.some`
|
|
309
|
+
* when a cached lookup has succeeded. If the entry is still pending, waits for
|
|
310
|
+
* it to complete. If the cached or pending lookup fails, this effect fails with
|
|
311
|
+
* the same error.
|
|
312
|
+
*
|
|
313
|
+
* **Example** (Reading cached values without lookup)
|
|
314
|
+
*
|
|
315
|
+
* ```ts import.meta.vitest
|
|
316
|
+
* import { Cache, Effect, Option } from "effect"
|
|
317
|
+
*
|
|
318
|
+
* const program = Effect.gen(function*() {
|
|
319
|
+
* const cache = yield* Cache.make({
|
|
320
|
+
* capacity: 10,
|
|
321
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
322
|
+
* })
|
|
323
|
+
*
|
|
324
|
+
* // No value in cache yet - returns None without lookup
|
|
325
|
+
* const empty = yield* Cache.getOption(cache, "hello")
|
|
326
|
+
*
|
|
327
|
+
* // Populate cache using get
|
|
328
|
+
* yield* Cache.get(cache, "hello")
|
|
329
|
+
*
|
|
330
|
+
* // Now getOption returns the cached value
|
|
331
|
+
* const cached = yield* Cache.getOption(cache, "hello")
|
|
332
|
+
* return [empty, cached] as const
|
|
333
|
+
* })
|
|
334
|
+
*
|
|
335
|
+
* const actual = await Effect.runPromise(program)
|
|
336
|
+
* actual // => [Option.none(), Option.some(5)]
|
|
337
|
+
* ```
|
|
338
|
+
*
|
|
339
|
+
* **Example** (Skipping expired entries)
|
|
340
|
+
*
|
|
341
|
+
* ```ts import.meta.vitest
|
|
342
|
+
* import { Cache, Effect, Option } from "effect"
|
|
343
|
+
* import { TestClock } from "effect/testing"
|
|
344
|
+
*
|
|
345
|
+
* // Expired entries return None
|
|
346
|
+
* const program = Effect.gen(function*() {
|
|
347
|
+
* const cache = yield* Cache.make({
|
|
348
|
+
* capacity: 10,
|
|
349
|
+
* lookup: (key: string) => Effect.succeed(key.length),
|
|
350
|
+
* timeToLive: "1 hour"
|
|
351
|
+
* })
|
|
352
|
+
*
|
|
353
|
+
* // Add value to cache
|
|
354
|
+
* yield* Cache.get(cache, "hello")
|
|
355
|
+
*
|
|
356
|
+
* // Value exists before expiration
|
|
357
|
+
* const beforeExpiry = yield* Cache.getOption(cache, "hello")
|
|
358
|
+
*
|
|
359
|
+
* // Simulate time passing
|
|
360
|
+
* yield* TestClock.adjust("2 hours")
|
|
361
|
+
*
|
|
362
|
+
* // Value expired - returns None
|
|
363
|
+
* const afterExpiry = yield* Cache.getOption(cache, "hello")
|
|
364
|
+
* return [beforeExpiry, afterExpiry] as const
|
|
365
|
+
* })
|
|
366
|
+
*
|
|
367
|
+
* const actual = await Effect.runPromise(Effect.provide(program, TestClock.layer()))
|
|
368
|
+
* actual // => [Option.some(5), Option.none()]
|
|
369
|
+
* ```
|
|
370
|
+
*
|
|
371
|
+
* **Example** (Waiting for pending lookups)
|
|
372
|
+
*
|
|
373
|
+
* ```ts import.meta.vitest
|
|
374
|
+
* import { Cache, Deferred, Effect, Fiber, Option } from "effect"
|
|
375
|
+
*
|
|
376
|
+
* // Waits for ongoing computation to complete
|
|
377
|
+
* const program = Effect.gen(function*() {
|
|
378
|
+
* const deferred = yield* Deferred.make<void>()
|
|
379
|
+
* const cache = yield* Cache.make({
|
|
380
|
+
* capacity: 10,
|
|
381
|
+
* lookup: (_key: string) => Deferred.await(deferred).pipe(Effect.as(42))
|
|
382
|
+
* })
|
|
383
|
+
*
|
|
384
|
+
* // Start lookup in background
|
|
385
|
+
* const getFiber = yield* Effect.forkChild(Cache.get(cache, "key"))
|
|
386
|
+
*
|
|
387
|
+
* // getOption waits for ongoing computation
|
|
388
|
+
* const optionFiber = yield* Effect.forkChild(Cache.getOption(cache, "key"))
|
|
389
|
+
*
|
|
390
|
+
* // Complete the computation
|
|
391
|
+
* yield* Deferred.succeed(deferred, void 0)
|
|
392
|
+
*
|
|
393
|
+
* const result = yield* Fiber.join(optionFiber)
|
|
394
|
+
* const value = yield* Fiber.join(getFiber)
|
|
395
|
+
* return [result, value] as const
|
|
396
|
+
* })
|
|
397
|
+
*
|
|
398
|
+
* const actual = await Effect.runPromise(program)
|
|
399
|
+
* actual // => [Option.some(42), 42]
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* @category combinators
|
|
403
|
+
* @since 4.0.0
|
|
404
|
+
*/
|
|
405
|
+
const getOption = /*#__PURE__*/ dual(2, (self, key) => withFiber((fiber) => {
|
|
406
|
+
const entry = getImpl(self, key, fiber);
|
|
407
|
+
return entry ? asSome(entry.await()) : succeedNone;
|
|
408
|
+
}));
|
|
409
|
+
const getImpl = (self, key, fiber, isRead = true) => {
|
|
410
|
+
const oentry = get$1(self.map, key);
|
|
411
|
+
if (isNone(oentry)) return;
|
|
412
|
+
else if (hasExpired(oentry.value, fiber)) {
|
|
413
|
+
remove(self.map, key);
|
|
414
|
+
return;
|
|
415
|
+
} else if (isRead) {
|
|
416
|
+
remove(self.map, key);
|
|
417
|
+
set$1(self.map, key, oentry.value);
|
|
418
|
+
}
|
|
419
|
+
return oentry.value;
|
|
420
|
+
};
|
|
421
|
+
/**
|
|
422
|
+
* Sets the value associated with the specified key in the cache. This will
|
|
423
|
+
* overwrite any existing value for that key, skipping the lookup function.
|
|
424
|
+
*
|
|
425
|
+
* **Example** (Setting values directly)
|
|
426
|
+
*
|
|
427
|
+
* ```ts import.meta.vitest
|
|
428
|
+
* import { Cache, Effect } from "effect"
|
|
429
|
+
*
|
|
430
|
+
* const program = Effect.gen(function*() {
|
|
431
|
+
* const cache = yield* Cache.make({
|
|
432
|
+
* capacity: 100,
|
|
433
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
434
|
+
* })
|
|
435
|
+
*
|
|
436
|
+
* // Set a value directly without invoking lookup
|
|
437
|
+
* yield* Cache.set(cache, "hello", 42)
|
|
438
|
+
* return yield* Cache.get(cache, "hello")
|
|
439
|
+
* })
|
|
440
|
+
*
|
|
441
|
+
* const actual = await Effect.runPromise(program)
|
|
442
|
+
* actual // => 42
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* **Example** (Overwriting cached values)
|
|
446
|
+
*
|
|
447
|
+
* ```ts import.meta.vitest
|
|
448
|
+
* import { Cache, Effect } from "effect"
|
|
449
|
+
*
|
|
450
|
+
* // Overwriting existing cached values
|
|
451
|
+
* const program = Effect.gen(function*() {
|
|
452
|
+
* const cache = yield* Cache.make({
|
|
453
|
+
* capacity: 100,
|
|
454
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
455
|
+
* })
|
|
456
|
+
*
|
|
457
|
+
* // First get populates via lookup
|
|
458
|
+
* const original = yield* Cache.get(cache, "test") // 4
|
|
459
|
+
*
|
|
460
|
+
* // Set overwrites the cached value
|
|
461
|
+
* yield* Cache.set(cache, "test", 999)
|
|
462
|
+
* const updated = yield* Cache.get(cache, "test") // 999
|
|
463
|
+
*
|
|
464
|
+
* return { original, updated }
|
|
465
|
+
* })
|
|
466
|
+
*
|
|
467
|
+
* const actual = await Effect.runPromise(program)
|
|
468
|
+
* actual // => { original: 4, updated: 999 }
|
|
469
|
+
* ```
|
|
470
|
+
*
|
|
471
|
+
* **Example** (Applying TTL to set values)
|
|
472
|
+
*
|
|
473
|
+
* ```ts import.meta.vitest
|
|
474
|
+
* import { Cache, Effect } from "effect"
|
|
475
|
+
* import { TestClock } from "effect/testing"
|
|
476
|
+
*
|
|
477
|
+
* // TTL behavior with set operations
|
|
478
|
+
* const program = Effect.gen(function*() {
|
|
479
|
+
* const cache = yield* Cache.make({
|
|
480
|
+
* capacity: 100,
|
|
481
|
+
* lookup: (key: string) => Effect.succeed(key.length),
|
|
482
|
+
* timeToLive: "1 hour"
|
|
483
|
+
* })
|
|
484
|
+
*
|
|
485
|
+
* // Set value with TTL applied
|
|
486
|
+
* yield* Cache.set(cache, "temporary", 123)
|
|
487
|
+
* const beforeExpiry = yield* Cache.has(cache, "temporary")
|
|
488
|
+
*
|
|
489
|
+
* // Advance time past TTL
|
|
490
|
+
* yield* TestClock.adjust("2 hours")
|
|
491
|
+
* const afterExpiry = yield* Cache.has(cache, "temporary")
|
|
492
|
+
* return [beforeExpiry, afterExpiry]
|
|
493
|
+
* })
|
|
494
|
+
*
|
|
495
|
+
* const actual = await Effect.runPromise(Effect.provide(program, TestClock.layer()))
|
|
496
|
+
* actual // => [true, false]
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* **Example** (Enforcing capacity when setting values)
|
|
500
|
+
*
|
|
501
|
+
* ```ts import.meta.vitest
|
|
502
|
+
* import { Cache, Effect } from "effect"
|
|
503
|
+
*
|
|
504
|
+
* // Capacity enforcement with set operations
|
|
505
|
+
* const program = Effect.gen(function*() {
|
|
506
|
+
* const cache = yield* Cache.make({
|
|
507
|
+
* capacity: 2,
|
|
508
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
509
|
+
* })
|
|
510
|
+
*
|
|
511
|
+
* // Fill cache to capacity
|
|
512
|
+
* yield* Cache.set(cache, "a", 1)
|
|
513
|
+
* yield* Cache.set(cache, "b", 2)
|
|
514
|
+
* const sizeBeforeEviction = yield* Cache.size(cache)
|
|
515
|
+
*
|
|
516
|
+
* // Adding another entry evicts oldest
|
|
517
|
+
* yield* Cache.set(cache, "c", 3)
|
|
518
|
+
* const sizeAfterEviction = yield* Cache.size(cache)
|
|
519
|
+
* const hasOldest = yield* Cache.has(cache, "a")
|
|
520
|
+
* const hasNewest = yield* Cache.has(cache, "c")
|
|
521
|
+
* return [sizeBeforeEviction, sizeAfterEviction, hasOldest, hasNewest]
|
|
522
|
+
* })
|
|
523
|
+
*
|
|
524
|
+
* const actual = await Effect.runPromise(program)
|
|
525
|
+
* actual // => [2, 2, false, true]
|
|
526
|
+
* ```
|
|
527
|
+
*
|
|
528
|
+
* @category combinators
|
|
529
|
+
* @since 4.0.0
|
|
530
|
+
*/
|
|
531
|
+
const set = /*#__PURE__*/ dual(3, (self, key, value) => withFiber((fiber) => {
|
|
532
|
+
const exit = exitSucceed(value);
|
|
533
|
+
const entry = new EntryImpl(fiber, exit);
|
|
534
|
+
const ttl = self.timeToLive(exit, key);
|
|
535
|
+
if (isZero(ttl)) {
|
|
536
|
+
remove(self.map, key);
|
|
537
|
+
return void_;
|
|
538
|
+
}
|
|
539
|
+
entry.expiresAt = isFinite(ttl) ? fiber.getRef(ClockRef).currentTimeMillisUnsafe() + toMillis(ttl) : void 0;
|
|
540
|
+
set$1(self.map, key, entry);
|
|
541
|
+
checkCapacity(self);
|
|
542
|
+
return void_;
|
|
543
|
+
}));
|
|
544
|
+
/**
|
|
545
|
+
* Invalidates the entry associated with the specified key in the cache.
|
|
546
|
+
*
|
|
547
|
+
* **Example** (Invalidating cached entries)
|
|
548
|
+
*
|
|
549
|
+
* ```ts import.meta.vitest
|
|
550
|
+
* import { Cache, Effect } from "effect"
|
|
551
|
+
*
|
|
552
|
+
* const program = Effect.gen(function*() {
|
|
553
|
+
* const cache = yield* Cache.make({
|
|
554
|
+
* capacity: 10,
|
|
555
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
556
|
+
* })
|
|
557
|
+
*
|
|
558
|
+
* // Add a value to the cache
|
|
559
|
+
* yield* Cache.get(cache, "hello")
|
|
560
|
+
* const beforeInvalidation = yield* Cache.has(cache, "hello")
|
|
561
|
+
*
|
|
562
|
+
* // Invalidate the entry
|
|
563
|
+
* yield* Cache.invalidate(cache, "hello")
|
|
564
|
+
* const afterInvalidation = yield* Cache.has(cache, "hello")
|
|
565
|
+
*
|
|
566
|
+
* // Invalidating non-existent keys doesn't error
|
|
567
|
+
* yield* Cache.invalidate(cache, "nonexistent")
|
|
568
|
+
*
|
|
569
|
+
* // Get after invalidation will invoke lookup again
|
|
570
|
+
* let lookupCount = 0
|
|
571
|
+
* const cache2 = yield* Cache.make({
|
|
572
|
+
* capacity: 10,
|
|
573
|
+
* lookup: (key: string) =>
|
|
574
|
+
* Effect.sync(() => {
|
|
575
|
+
* lookupCount++
|
|
576
|
+
* return key.length
|
|
577
|
+
* })
|
|
578
|
+
* })
|
|
579
|
+
*
|
|
580
|
+
* yield* Cache.get(cache2, "test") // lookupCount = 1
|
|
581
|
+
* yield* Cache.invalidate(cache2, "test")
|
|
582
|
+
* yield* Cache.get(cache2, "test") // lookupCount = 2 (lookup called again)
|
|
583
|
+
* return { beforeInvalidation, afterInvalidation, lookupCount }
|
|
584
|
+
* })
|
|
585
|
+
*
|
|
586
|
+
* const actual = await Effect.runPromise(program)
|
|
587
|
+
* actual // => { beforeInvalidation: true, afterInvalidation: false, lookupCount: 2 }
|
|
588
|
+
* ```
|
|
589
|
+
*
|
|
590
|
+
* @category combinators
|
|
591
|
+
* @since 4.0.0
|
|
592
|
+
*/
|
|
593
|
+
const invalidate = /*#__PURE__*/ dual(2, (self, key) => sync(() => {
|
|
594
|
+
remove(self.map, key);
|
|
595
|
+
}));
|
|
596
|
+
/**
|
|
597
|
+
* Retrieves all active keys from the cache, automatically filtering out expired entries.
|
|
598
|
+
*
|
|
599
|
+
* **Example** (Reading active keys)
|
|
600
|
+
*
|
|
601
|
+
* ```ts import.meta.vitest
|
|
602
|
+
* import { Cache, Effect } from "effect"
|
|
603
|
+
*
|
|
604
|
+
* // Basic key enumeration
|
|
605
|
+
* const program = Effect.gen(function*() {
|
|
606
|
+
* const cache = yield* Cache.make({
|
|
607
|
+
* capacity: 10,
|
|
608
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
609
|
+
* })
|
|
610
|
+
*
|
|
611
|
+
* // Add some entries to the cache
|
|
612
|
+
* yield* Cache.get(cache, "hello")
|
|
613
|
+
* yield* Cache.get(cache, "world")
|
|
614
|
+
* yield* Cache.get(cache, "cache")
|
|
615
|
+
*
|
|
616
|
+
* // Retrieve all active keys
|
|
617
|
+
* const keys = yield* Cache.keys(cache)
|
|
618
|
+
* return Array.from(keys).sort()
|
|
619
|
+
* })
|
|
620
|
+
*
|
|
621
|
+
* const actual = await Effect.runPromise(program)
|
|
622
|
+
* actual // => ["cache", "hello", "world"]
|
|
623
|
+
* ```
|
|
624
|
+
*
|
|
625
|
+
* @category combinators
|
|
626
|
+
* @since 4.0.0
|
|
627
|
+
*/
|
|
628
|
+
const keys = (self) => withFiber((fiber) => {
|
|
629
|
+
const now = fiber.getRef(ClockRef).currentTimeMillisUnsafe();
|
|
630
|
+
return succeed(filterMap(self.map, ([key, entry]) => {
|
|
631
|
+
if (entry.expiresAt === void 0 || entry.expiresAt > now) return succeed$1(key);
|
|
632
|
+
remove(self.map, key);
|
|
633
|
+
return failVoid;
|
|
634
|
+
}));
|
|
635
|
+
});
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9/node_modules/effect/dist/unstable/reactivity/Reactivity.js
|
|
638
|
+
/**
|
|
639
|
+
* Process-local invalidation for connecting writes to dependent reads.
|
|
640
|
+
*
|
|
641
|
+
* This module does not cache values itself. It lets callers register handlers
|
|
642
|
+
* for keys, invalidate those keys, wrap successful mutations so they invalidate
|
|
643
|
+
* keys, and expose effects as queues or streams that rerun when matching keys
|
|
644
|
+
* change. The service can also batch invalidations so handlers run after the
|
|
645
|
+
* batch completes.
|
|
646
|
+
*
|
|
647
|
+
* @since 4.0.0
|
|
648
|
+
*/
|
|
649
|
+
/**
|
|
650
|
+
* Service for key-based reactive invalidation.
|
|
651
|
+
*
|
|
652
|
+
* **When to use**
|
|
653
|
+
*
|
|
654
|
+
* Use to provide the invalidation service that refreshes queries, streams, and
|
|
655
|
+
* atoms when application keys change.
|
|
656
|
+
*
|
|
657
|
+
* **Details**
|
|
658
|
+
*
|
|
659
|
+
* The service can register handlers for keys, invalidate those keys, wrap
|
|
660
|
+
* mutations so successful effects invalidate keys, and turn query effects into
|
|
661
|
+
* queues or streams that rerun when keys are invalidated.
|
|
662
|
+
*
|
|
663
|
+
* @category services
|
|
664
|
+
* @since 4.0.0
|
|
665
|
+
*/
|
|
666
|
+
var Reactivity = class extends Service()("effect/reactivity/Reactivity") {};
|
|
667
|
+
/**
|
|
668
|
+
* Creates an in-memory `Reactivity` service.
|
|
669
|
+
*
|
|
670
|
+
* **Details**
|
|
671
|
+
*
|
|
672
|
+
* The service tracks handlers by hashed keys and runs the registered handlers when
|
|
673
|
+
* matching keys are invalidated.
|
|
674
|
+
*
|
|
675
|
+
* @category constructors
|
|
676
|
+
* @since 4.0.0
|
|
677
|
+
*/
|
|
678
|
+
const make$2 = /*#__PURE__*/ sync$1(() => {
|
|
679
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
680
|
+
const invalidateUnsafe = (keys) => {
|
|
681
|
+
keysToHashes(keys, (hash) => {
|
|
682
|
+
const set = handlers.get(hash);
|
|
683
|
+
if (set === void 0) return;
|
|
684
|
+
set.forEach((run) => run());
|
|
685
|
+
});
|
|
686
|
+
};
|
|
687
|
+
const invalidate = (keys) => contextWith$1((services) => {
|
|
688
|
+
const pending = services.mapUnsafe.get(PendingInvalidation.key);
|
|
689
|
+
if (pending) keysToHashes(keys, (hash) => {
|
|
690
|
+
pending.add(hash);
|
|
691
|
+
});
|
|
692
|
+
else invalidateUnsafe(keys);
|
|
693
|
+
return void_$1;
|
|
694
|
+
});
|
|
695
|
+
const mutation = (keys, effect) => tap(effect, invalidate(keys));
|
|
696
|
+
const registerUnsafe = (keys, handler) => {
|
|
697
|
+
const resolvedKeys = [];
|
|
698
|
+
keysToHashes(keys, (hash) => {
|
|
699
|
+
resolvedKeys.push(hash);
|
|
700
|
+
let set = handlers.get(hash);
|
|
701
|
+
if (set === void 0) {
|
|
702
|
+
set = /* @__PURE__ */ new Set();
|
|
703
|
+
handlers.set(hash, set);
|
|
704
|
+
}
|
|
705
|
+
set.add(handler);
|
|
706
|
+
});
|
|
707
|
+
return () => {
|
|
708
|
+
for (let i = 0; i < resolvedKeys.length; i++) {
|
|
709
|
+
const set = handlers.get(resolvedKeys[i]);
|
|
710
|
+
set.delete(handler);
|
|
711
|
+
if (set.size === 0) handlers.delete(resolvedKeys[i]);
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
};
|
|
715
|
+
const query = (keys, effect) => gen(function* () {
|
|
716
|
+
const services = yield* context();
|
|
717
|
+
const scope = get$2(services, Scope);
|
|
718
|
+
const results = yield* make$5();
|
|
719
|
+
const runFork = flow(runForkWith(services), runIn(scope));
|
|
720
|
+
let running = false;
|
|
721
|
+
let pending = false;
|
|
722
|
+
const handleExit = (exit) => {
|
|
723
|
+
if (exit._tag === "Failure") failCauseUnsafe(results, exit.cause);
|
|
724
|
+
else offerUnsafe(results, exit.value);
|
|
725
|
+
if (pending) {
|
|
726
|
+
pending = false;
|
|
727
|
+
runFork(effect).addObserver(handleExit);
|
|
728
|
+
} else running = false;
|
|
729
|
+
};
|
|
730
|
+
function run() {
|
|
731
|
+
if (running) {
|
|
732
|
+
pending = true;
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
running = true;
|
|
736
|
+
runFork(effect).addObserver(handleExit);
|
|
737
|
+
}
|
|
738
|
+
yield* addFinalizer(scope, sync$1(registerUnsafe(keys, run)));
|
|
739
|
+
run();
|
|
740
|
+
return results;
|
|
741
|
+
});
|
|
742
|
+
const stream = (tables, effect) => query(tables, effect).pipe(map(fromQueue), unwrap);
|
|
743
|
+
const withBatch = (effect) => suspend(() => {
|
|
744
|
+
const pending = /* @__PURE__ */ new Set();
|
|
745
|
+
return effect.pipe(provideService(PendingInvalidation, pending), onExit$1((_) => sync$1(() => {
|
|
746
|
+
pending.forEach((hash) => {
|
|
747
|
+
const set = handlers.get(hash);
|
|
748
|
+
if (set === void 0) return;
|
|
749
|
+
set.forEach((run) => run());
|
|
750
|
+
});
|
|
751
|
+
})));
|
|
752
|
+
});
|
|
753
|
+
return Reactivity.of({
|
|
754
|
+
mutation,
|
|
755
|
+
query,
|
|
756
|
+
stream,
|
|
757
|
+
invalidateUnsafe,
|
|
758
|
+
invalidate,
|
|
759
|
+
registerUnsafe,
|
|
760
|
+
withBatch
|
|
761
|
+
});
|
|
762
|
+
});
|
|
763
|
+
var PendingInvalidation = class extends Service()("effect/reactivity/Reactivity/PendingInvalidation") {};
|
|
764
|
+
/**
|
|
765
|
+
* The default layer that provides an in-memory `Reactivity` service.
|
|
766
|
+
*
|
|
767
|
+
* @category layers
|
|
768
|
+
* @since 4.0.0
|
|
769
|
+
*/
|
|
770
|
+
const layer = /*#__PURE__*/ effect(Reactivity)(make$2);
|
|
771
|
+
function stringOrHash(u) {
|
|
772
|
+
switch (typeof u) {
|
|
773
|
+
case "string":
|
|
774
|
+
case "number":
|
|
775
|
+
case "bigint":
|
|
776
|
+
case "boolean": return String(u);
|
|
777
|
+
default: return hash(u);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
const keysToHashes = (keys, f) => {
|
|
781
|
+
if (Array.isArray(keys)) {
|
|
782
|
+
for (let i = 0; i < keys.length; i++) f(stringOrHash(keys[i]));
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
for (const key in keys) {
|
|
786
|
+
f(key);
|
|
787
|
+
const ids = keys[key];
|
|
788
|
+
for (let i = 0; i < ids.length; i++) f(`${key}:${stringOrHash(ids[i])}`);
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
//#endregion
|
|
792
|
+
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9/node_modules/effect/dist/unstable/sql/Statement.js
|
|
793
|
+
/**
|
|
794
|
+
* Low-level SQL statement and fragment primitives.
|
|
795
|
+
*
|
|
796
|
+
* `SqlClient` uses this module to build executable, parameterized SQL from
|
|
797
|
+
* reusable fragments. A statement can be executed, streamed, run without row
|
|
798
|
+
* transformation, or compiled to SQL text and parameters for a specific
|
|
799
|
+
* dialect. The module also contains helpers for identifiers, parameters,
|
|
800
|
+
* inserts, updates, custom dialect fragments, statement compilation, and row
|
|
801
|
+
* transformation.
|
|
802
|
+
*
|
|
803
|
+
* @since 4.0.0
|
|
804
|
+
*/
|
|
805
|
+
const FragmentTypeId = "~effect/sql/Fragment";
|
|
806
|
+
/**
|
|
807
|
+
* Constructs a SQL `Fragment` from low-level statement segments.
|
|
808
|
+
*
|
|
809
|
+
* @category constructors
|
|
810
|
+
* @since 4.0.0
|
|
811
|
+
*/
|
|
812
|
+
const fragment = (segments) => ({
|
|
813
|
+
[FragmentTypeId]: FragmentTypeId,
|
|
814
|
+
segments
|
|
815
|
+
});
|
|
816
|
+
/**
|
|
817
|
+
* Context reference for an optional current SQL statement transformer applied
|
|
818
|
+
* before statement execution.
|
|
819
|
+
*
|
|
820
|
+
* @category services
|
|
821
|
+
* @since 4.0.0
|
|
822
|
+
*/
|
|
823
|
+
const CurrentTransformer = /*#__PURE__*/ Reference("effect/sql/CurrentTransformer", { defaultValue: constUndefined });
|
|
824
|
+
/**
|
|
825
|
+
* Returns `true` when a value is a SQL `Fragment`.
|
|
826
|
+
*
|
|
827
|
+
* @category guards
|
|
828
|
+
* @since 4.0.0
|
|
829
|
+
*/
|
|
830
|
+
const isFragment = (u) => hasProperty(u, FragmentTypeId);
|
|
831
|
+
/**
|
|
832
|
+
* Constructs a raw SQL literal segment. The literal text is not escaped, so use
|
|
833
|
+
* bound parameters for untrusted values.
|
|
834
|
+
*
|
|
835
|
+
* @category constructors
|
|
836
|
+
* @since 4.0.0
|
|
837
|
+
*/
|
|
838
|
+
const literal = (value, params) => ({
|
|
839
|
+
_tag: "Literal",
|
|
840
|
+
value,
|
|
841
|
+
params
|
|
842
|
+
});
|
|
843
|
+
/**
|
|
844
|
+
* Constructs a SQL identifier segment that will be escaped by the active
|
|
845
|
+
* compiler.
|
|
846
|
+
*
|
|
847
|
+
* @category constructors
|
|
848
|
+
* @since 4.0.0
|
|
849
|
+
*/
|
|
850
|
+
const identifier = (value) => ({
|
|
851
|
+
_tag: "Identifier",
|
|
852
|
+
value
|
|
853
|
+
});
|
|
854
|
+
/**
|
|
855
|
+
* Constructs a bound parameter segment for a statement value.
|
|
856
|
+
*
|
|
857
|
+
* @category constructors
|
|
858
|
+
* @since 4.0.0
|
|
859
|
+
*/
|
|
860
|
+
const parameter = (value) => ({
|
|
861
|
+
_tag: "Parameter",
|
|
862
|
+
value
|
|
863
|
+
});
|
|
864
|
+
/**
|
|
865
|
+
* Constructs an `ArrayHelper` segment for an array of values or fragments.
|
|
866
|
+
*
|
|
867
|
+
* @category constructors
|
|
868
|
+
* @since 4.0.0
|
|
869
|
+
*/
|
|
870
|
+
const arrayHelper = (value) => ({
|
|
871
|
+
_tag: "ArrayHelper",
|
|
872
|
+
value
|
|
873
|
+
});
|
|
874
|
+
const RecordInsertHelperProto = {
|
|
875
|
+
_tag: "RecordInsertHelper",
|
|
876
|
+
returning(sql) {
|
|
877
|
+
const self = Object.create(Object.getPrototypeOf(this));
|
|
878
|
+
Object.assign(self, this, { returningIdentifier: sql });
|
|
879
|
+
return self;
|
|
880
|
+
}
|
|
881
|
+
};
|
|
882
|
+
/**
|
|
883
|
+
* Constructs a `RecordInsertHelper` from one or more row objects.
|
|
884
|
+
*
|
|
885
|
+
* @category constructors
|
|
886
|
+
* @since 4.0.0
|
|
887
|
+
*/
|
|
888
|
+
const recordInsertHelper = (value) => Object.assign(Object.create(RecordInsertHelperProto), {
|
|
889
|
+
value,
|
|
890
|
+
returningIdentifier: void 0
|
|
891
|
+
});
|
|
892
|
+
const RecordUpdateHelperProto = {
|
|
893
|
+
...RecordInsertHelperProto,
|
|
894
|
+
_tag: "RecordUpdateHelper"
|
|
895
|
+
};
|
|
896
|
+
/**
|
|
897
|
+
* Constructs a `RecordUpdateHelper` for multi-row update compilation using the
|
|
898
|
+
* provided alias.
|
|
899
|
+
*
|
|
900
|
+
* @category constructors
|
|
901
|
+
* @since 4.0.0
|
|
902
|
+
*/
|
|
903
|
+
const recordUpdateHelper = (value, alias) => Object.assign(Object.create(RecordUpdateHelperProto), {
|
|
904
|
+
value,
|
|
905
|
+
alias,
|
|
906
|
+
returningIdentifier: void 0
|
|
907
|
+
});
|
|
908
|
+
const RecordUpdateHelperSingleProto = {
|
|
909
|
+
...RecordInsertHelperProto,
|
|
910
|
+
_tag: "RecordUpdateHelperSingle"
|
|
911
|
+
};
|
|
912
|
+
/**
|
|
913
|
+
* Constructs a `RecordUpdateHelperSingle` from a record and a list of columns
|
|
914
|
+
* to omit from the update.
|
|
915
|
+
*
|
|
916
|
+
* @category constructors
|
|
917
|
+
* @since 4.0.0
|
|
918
|
+
*/
|
|
919
|
+
const recordUpdateHelperSingle = (value, omit) => Object.assign(Object.create(RecordUpdateHelperSingleProto), {
|
|
920
|
+
value,
|
|
921
|
+
omit,
|
|
922
|
+
returningIdentifier: void 0
|
|
923
|
+
});
|
|
924
|
+
/**
|
|
925
|
+
* Creates a cached SQL statement constructor from a connection acquirer,
|
|
926
|
+
* compiler, tracing attributes, and optional row transformation function.
|
|
927
|
+
*
|
|
928
|
+
* @category constructors
|
|
929
|
+
* @since 4.0.0
|
|
930
|
+
*/
|
|
931
|
+
const make$1 = (acquirer, compiler, spanAttributes, transformRows) => {
|
|
932
|
+
const cache = transformRows === void 0 ? constructorCache.noTransforms : constructorCache.transforms;
|
|
933
|
+
if (cache.has(acquirer)) return cache.get(acquirer);
|
|
934
|
+
const self = Object.assign(function sql(strings, ...args) {
|
|
935
|
+
if (typeof strings === "string") return identifier(strings);
|
|
936
|
+
else if (Array.isArray(strings) && "raw" in strings) return statement(acquirer, compiler, strings, args, spanAttributes, transformRows);
|
|
937
|
+
throw "absurd";
|
|
938
|
+
}, {
|
|
939
|
+
unsafe(sql, params) {
|
|
940
|
+
return makeUnsafe([literal(sql, params)], acquirer, compiler, spanAttributes, transformRows);
|
|
941
|
+
},
|
|
942
|
+
literal(sql) {
|
|
943
|
+
return fragment([literal(sql)]);
|
|
944
|
+
},
|
|
945
|
+
in: in_,
|
|
946
|
+
insert(value) {
|
|
947
|
+
return recordInsertHelper(Array.isArray(value) ? value : [value]);
|
|
948
|
+
},
|
|
949
|
+
update(value, omit) {
|
|
950
|
+
return recordUpdateHelperSingle(value, omit ?? []);
|
|
951
|
+
},
|
|
952
|
+
updateValues(value, alias) {
|
|
953
|
+
return recordUpdateHelper(value, alias);
|
|
954
|
+
},
|
|
955
|
+
and,
|
|
956
|
+
or,
|
|
957
|
+
csv,
|
|
958
|
+
join,
|
|
959
|
+
onDialect(options) {
|
|
960
|
+
return options[compiler.dialect]();
|
|
961
|
+
},
|
|
962
|
+
onDialectOrElse(options) {
|
|
963
|
+
return options[compiler.dialect] !== void 0 ? options[compiler.dialect]() : options.orElse();
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
cache.set(acquirer, self);
|
|
967
|
+
return self;
|
|
968
|
+
};
|
|
969
|
+
const constructorCache = {
|
|
970
|
+
transforms: /*#__PURE__*/ new WeakMap(),
|
|
971
|
+
noTransforms: /*#__PURE__*/ new WeakMap()
|
|
972
|
+
};
|
|
973
|
+
/**
|
|
974
|
+
* Builds a `Statement` from template strings and arguments, preserving
|
|
975
|
+
* fragments and helper segments while converting ordinary interpolated values
|
|
976
|
+
* into bound parameters.
|
|
977
|
+
*
|
|
978
|
+
* @category constructors
|
|
979
|
+
* @since 4.0.0
|
|
980
|
+
*/
|
|
981
|
+
const statement = (acquirer, compiler, strings, args, spanAttributes, transformRows) => {
|
|
982
|
+
const segments = strings[0].length > 0 ? [literal(strings[0])] : [];
|
|
983
|
+
for (let i = 0; i < args.length; i++) {
|
|
984
|
+
const arg = args[i];
|
|
985
|
+
if (isFragment(arg)) segments.push(...arg.segments);
|
|
986
|
+
else if (isSegment(arg)) segments.push(arg);
|
|
987
|
+
else segments.push(parameter(arg));
|
|
988
|
+
if (strings[i + 1].length > 0) segments.push(literal(strings[i + 1]));
|
|
989
|
+
}
|
|
990
|
+
return makeUnsafe(segments, acquirer, compiler, spanAttributes, transformRows);
|
|
991
|
+
};
|
|
992
|
+
/**
|
|
993
|
+
* Creates a helper that joins SQL clauses with a literal separator, optionally
|
|
994
|
+
* wrapping multiple clauses in parentheses and using a fallback for an empty
|
|
995
|
+
* list.
|
|
996
|
+
*
|
|
997
|
+
* @category constructors
|
|
998
|
+
* @since 4.0.0
|
|
999
|
+
*/
|
|
1000
|
+
function join(lit, addParens = true, fallback = "") {
|
|
1001
|
+
const literalStatement = literal(lit);
|
|
1002
|
+
const fallbackFragment = fragment([literal(fallback)]);
|
|
1003
|
+
return (clauses) => {
|
|
1004
|
+
if (clauses.length === 0) return fallbackFragment;
|
|
1005
|
+
else if (clauses.length === 1) return fragment(convertLiteralOrFragment(clauses[0]));
|
|
1006
|
+
const segments = [];
|
|
1007
|
+
if (addParens) segments.push(literal("("));
|
|
1008
|
+
segments.push.apply(segments, convertLiteralOrFragment(clauses[0]));
|
|
1009
|
+
for (let i = 1; i < clauses.length; i++) {
|
|
1010
|
+
segments.push(literalStatement);
|
|
1011
|
+
segments.push.apply(segments, convertLiteralOrFragment(clauses[i]));
|
|
1012
|
+
}
|
|
1013
|
+
if (addParens) segments.push(literal(")"));
|
|
1014
|
+
return fragment(segments);
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Combines clauses with `AND`, parenthesizing multiple clauses and returning
|
|
1019
|
+
* `1=1` when the list is empty.
|
|
1020
|
+
*
|
|
1021
|
+
* @category constructors
|
|
1022
|
+
* @since 4.0.0
|
|
1023
|
+
*/
|
|
1024
|
+
const and = /*#__PURE__*/ join(" AND ", true, "1=1");
|
|
1025
|
+
/**
|
|
1026
|
+
* Combines clauses with `OR`, parenthesizing multiple clauses and returning
|
|
1027
|
+
* `1=1` when the list is empty.
|
|
1028
|
+
*
|
|
1029
|
+
* @category constructors
|
|
1030
|
+
* @since 4.0.0
|
|
1031
|
+
*/
|
|
1032
|
+
const or = /*#__PURE__*/ join(" OR ", true, "1=1");
|
|
1033
|
+
/**
|
|
1034
|
+
* Creates a comma-separated SQL fragment from values, optionally adding a
|
|
1035
|
+
* prefix, and returns an empty fragment when no values are provided.
|
|
1036
|
+
*
|
|
1037
|
+
* @category constructors
|
|
1038
|
+
* @since 4.0.0
|
|
1039
|
+
*/
|
|
1040
|
+
const csv = function(...args) {
|
|
1041
|
+
if (args[args.length - 1].length === 0) return emptyFragment;
|
|
1042
|
+
if (args.length === 1) return csvRaw(args[0]);
|
|
1043
|
+
return fragment([literal(`${args[0]} `), ...csvRaw(args[1]).segments]);
|
|
1044
|
+
};
|
|
1045
|
+
const csvRaw = /*#__PURE__*/ join(",", false);
|
|
1046
|
+
const emptyFragment = /*#__PURE__*/ fragment([/*#__PURE__*/ literal("")]);
|
|
1047
|
+
/**
|
|
1048
|
+
* Creates a dialect-specific SQL `Compiler` from rendering callbacks.
|
|
1049
|
+
*
|
|
1050
|
+
* @category constructors
|
|
1051
|
+
* @since 4.0.0
|
|
1052
|
+
*/
|
|
1053
|
+
const makeCompiler = (options) => {
|
|
1054
|
+
const self = Object.create(CompilerProto);
|
|
1055
|
+
self.options = options;
|
|
1056
|
+
self.dialect = options.dialect;
|
|
1057
|
+
self.disableTransforms = false;
|
|
1058
|
+
return self;
|
|
1059
|
+
};
|
|
1060
|
+
const statementCacheSymbol = /*#__PURE__*/ Symbol.for("effect/unstable/sql/Statement/statementCache");
|
|
1061
|
+
const statementCacheNoTransformSymbol = /*#__PURE__*/ Symbol.for("effect/unstable/sql/Statement/statementCacheNoTransform");
|
|
1062
|
+
const CompilerProto = {
|
|
1063
|
+
compile(statement, withoutTransform = false, placeholderOverride) {
|
|
1064
|
+
const opts = this.options;
|
|
1065
|
+
withoutTransform = withoutTransform || this.disableTransforms;
|
|
1066
|
+
const cacheSymbol = withoutTransform ? statementCacheNoTransformSymbol : statementCacheSymbol;
|
|
1067
|
+
if (cacheSymbol in statement) return statement[cacheSymbol];
|
|
1068
|
+
const segments = statement.segments;
|
|
1069
|
+
const len = segments.length;
|
|
1070
|
+
let sql = "";
|
|
1071
|
+
const binds = [];
|
|
1072
|
+
let placeholderCount = 0;
|
|
1073
|
+
const placeholder = placeholderOverride ?? ((u) => opts.placeholder(++placeholderCount, u));
|
|
1074
|
+
const placeholderNoIncrement = (u) => opts.placeholder(placeholderCount, u);
|
|
1075
|
+
const placeholders = makePlaceholdersArray(placeholder);
|
|
1076
|
+
for (let i = 0; i < len; i++) {
|
|
1077
|
+
const segment = segments[i];
|
|
1078
|
+
switch (segment._tag) {
|
|
1079
|
+
case "Literal":
|
|
1080
|
+
sql += segment.value;
|
|
1081
|
+
if (segment.params) binds.push.apply(binds, segment.params);
|
|
1082
|
+
break;
|
|
1083
|
+
case "Identifier":
|
|
1084
|
+
sql += opts.onIdentifier(segment.value, withoutTransform);
|
|
1085
|
+
break;
|
|
1086
|
+
case "Parameter":
|
|
1087
|
+
sql += placeholder(segment.value);
|
|
1088
|
+
binds.push(segment.value);
|
|
1089
|
+
break;
|
|
1090
|
+
case "ArrayHelper":
|
|
1091
|
+
sql += `(${placeholders(segment.value)})`;
|
|
1092
|
+
binds.push.apply(binds, segment.value);
|
|
1093
|
+
break;
|
|
1094
|
+
case "RecordInsertHelper": {
|
|
1095
|
+
const keys = Object.keys(segment.value[0]);
|
|
1096
|
+
if (opts.onInsert) {
|
|
1097
|
+
const values = new Array(segment.value.length);
|
|
1098
|
+
let placeholders = "";
|
|
1099
|
+
for (let i = 0; i < segment.value.length; i++) {
|
|
1100
|
+
const row = new Array(keys.length);
|
|
1101
|
+
values[i] = row;
|
|
1102
|
+
placeholders += i === 0 ? "(" : ",(";
|
|
1103
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1104
|
+
const key = keys[j];
|
|
1105
|
+
const value = segment.value[i][key];
|
|
1106
|
+
row[j] = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform);
|
|
1107
|
+
placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`;
|
|
1108
|
+
}
|
|
1109
|
+
placeholders += ")";
|
|
1110
|
+
}
|
|
1111
|
+
const [s, b] = opts.onInsert(keys.map((_) => opts.onIdentifier(_, withoutTransform)), placeholders, values, typeof segment.returningIdentifier === "string" ? [segment.returningIdentifier, []] : segment.returningIdentifier ? this.compile(segment.returningIdentifier, withoutTransform, placeholder) : void 0);
|
|
1112
|
+
sql += s;
|
|
1113
|
+
binds.push.apply(binds, b);
|
|
1114
|
+
} else {
|
|
1115
|
+
let placeholders = "";
|
|
1116
|
+
for (let i = 0; i < segment.value.length; i++) {
|
|
1117
|
+
placeholders += i === 0 ? "(" : ",(";
|
|
1118
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1119
|
+
const value = segment.value[i][keys[j]];
|
|
1120
|
+
const primitive = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform);
|
|
1121
|
+
binds.push(primitive);
|
|
1122
|
+
placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`;
|
|
1123
|
+
}
|
|
1124
|
+
placeholders += ")";
|
|
1125
|
+
}
|
|
1126
|
+
sql += `${generateColumns(keys, opts.onIdentifier, withoutTransform)} VALUES ${placeholders}`;
|
|
1127
|
+
if (typeof segment.returningIdentifier === "string") sql += ` RETURNING ${segment.returningIdentifier}`;
|
|
1128
|
+
else if (segment.returningIdentifier) {
|
|
1129
|
+
sql += " RETURNING ";
|
|
1130
|
+
const [s, b] = this.compile(segment.returningIdentifier, withoutTransform, placeholder);
|
|
1131
|
+
sql += s;
|
|
1132
|
+
binds.push.apply(binds, b);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
break;
|
|
1136
|
+
}
|
|
1137
|
+
case "RecordUpdateHelperSingle": {
|
|
1138
|
+
let keys = Object.keys(segment.value);
|
|
1139
|
+
if (segment.omit.length > 0) keys = keys.filter((key) => !segment.omit.includes(key));
|
|
1140
|
+
if (opts.onRecordUpdateSingle) {
|
|
1141
|
+
const [s, b] = opts.onRecordUpdateSingle(keys.map((_) => opts.onIdentifier(_, withoutTransform)), keys.map((key) => extractPrimitive(segment.value[key], opts.onCustom, placeholderNoIncrement, withoutTransform)), typeof segment.returningIdentifier === "string" ? [segment.returningIdentifier, []] : segment.returningIdentifier ? this.compile(segment.returningIdentifier, withoutTransform, placeholder) : void 0);
|
|
1142
|
+
sql += s;
|
|
1143
|
+
binds.push.apply(binds, b);
|
|
1144
|
+
} else {
|
|
1145
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
1146
|
+
const column = opts.onIdentifier(keys[i], withoutTransform);
|
|
1147
|
+
if (i === 0) sql += `${column} = ${placeholder(segment.value[keys[i]])}`;
|
|
1148
|
+
else sql += `, ${column} = ${placeholder(segment.value[keys[i]])}`;
|
|
1149
|
+
binds.push(extractPrimitive(segment.value[keys[i]], opts.onCustom, placeholderNoIncrement, withoutTransform));
|
|
1150
|
+
}
|
|
1151
|
+
if (typeof segment.returningIdentifier === "string") if (this.dialect === "mssql") sql += ` OUTPUT ${segment.returningIdentifier === "*" ? "INSERTED.*" : segment.returningIdentifier}`;
|
|
1152
|
+
else sql += ` RETURNING ${segment.returningIdentifier}`;
|
|
1153
|
+
else if (segment.returningIdentifier) {
|
|
1154
|
+
sql += this.dialect === "mssql" ? " OUTPUT " : " RETURNING ";
|
|
1155
|
+
const [s, b] = this.compile(segment.returningIdentifier, withoutTransform, placeholder);
|
|
1156
|
+
sql += s;
|
|
1157
|
+
binds.push.apply(binds, b);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
break;
|
|
1161
|
+
}
|
|
1162
|
+
case "RecordUpdateHelper": {
|
|
1163
|
+
const keys = Object.keys(segment.value[0]);
|
|
1164
|
+
const values = new Array(segment.value.length);
|
|
1165
|
+
let placeholders = "";
|
|
1166
|
+
for (let i = 0; i < segment.value.length; i++) {
|
|
1167
|
+
const row = new Array(keys.length);
|
|
1168
|
+
values[i] = row;
|
|
1169
|
+
placeholders += i === 0 ? "(" : ",(";
|
|
1170
|
+
for (let j = 0; j < keys.length; j++) {
|
|
1171
|
+
const key = keys[j];
|
|
1172
|
+
const value = segment.value[i][key];
|
|
1173
|
+
row[j] = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform);
|
|
1174
|
+
placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`;
|
|
1175
|
+
}
|
|
1176
|
+
placeholders += ")";
|
|
1177
|
+
}
|
|
1178
|
+
const [s, b] = opts.onRecordUpdate(placeholders, segment.alias, generateColumns(keys, opts.onIdentifier, withoutTransform), values, typeof segment.returningIdentifier === "string" ? [segment.returningIdentifier, []] : segment.returningIdentifier ? this.compile(segment.returningIdentifier, withoutTransform, placeholder) : void 0);
|
|
1179
|
+
sql += s;
|
|
1180
|
+
binds.push.apply(binds, b);
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
case "Custom": {
|
|
1184
|
+
const [s, b] = opts.onCustom(segment, placeholder, withoutTransform);
|
|
1185
|
+
sql += s;
|
|
1186
|
+
binds.push.apply(binds, b);
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
const result = [sql, binds];
|
|
1192
|
+
if (placeholderOverride !== void 0) return result;
|
|
1193
|
+
return statement[cacheSymbol] = result;
|
|
1194
|
+
},
|
|
1195
|
+
get withoutTransform() {
|
|
1196
|
+
const self = Object.create(CompilerProto);
|
|
1197
|
+
Object.assign(self, this, { disableTransforms: true });
|
|
1198
|
+
return self;
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
/**
|
|
1202
|
+
* Creates a SQLite compiler that uses `?` placeholders and quoted identifiers,
|
|
1203
|
+
* optionally transforming identifier names before escaping.
|
|
1204
|
+
*
|
|
1205
|
+
* @category constructors
|
|
1206
|
+
* @since 4.0.0
|
|
1207
|
+
*/
|
|
1208
|
+
const makeCompilerSqlite = (transform) => makeCompiler({
|
|
1209
|
+
dialect: "sqlite",
|
|
1210
|
+
placeholder(_) {
|
|
1211
|
+
return "?";
|
|
1212
|
+
},
|
|
1213
|
+
onIdentifier: transform ? function(value, withoutTransform) {
|
|
1214
|
+
return withoutTransform ? escapeSqlite(value) : escapeSqlite(transform(value));
|
|
1215
|
+
} : escapeSqlite,
|
|
1216
|
+
onRecordUpdate() {
|
|
1217
|
+
return ["", []];
|
|
1218
|
+
},
|
|
1219
|
+
onCustom() {
|
|
1220
|
+
return ["", []];
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
/**
|
|
1224
|
+
* Creates an identifier escaping function that wraps names in the given
|
|
1225
|
+
* delimiter, doubles delimiter characters, and escapes dots between identifier
|
|
1226
|
+
* parts.
|
|
1227
|
+
*
|
|
1228
|
+
* @category constructors
|
|
1229
|
+
* @since 4.0.0
|
|
1230
|
+
*/
|
|
1231
|
+
function defaultEscape(c) {
|
|
1232
|
+
const re = new RegExp(c, "g");
|
|
1233
|
+
const double = c + c;
|
|
1234
|
+
const dot = c + "." + c;
|
|
1235
|
+
return function(str) {
|
|
1236
|
+
return c + str.replace(re, double).replace(/\./g, dot) + c;
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Builds value, object, and row-array transformers that rename object keys with
|
|
1241
|
+
* the supplied function and optionally recurse into nested object arrays.
|
|
1242
|
+
*
|
|
1243
|
+
* @category transforming
|
|
1244
|
+
* @since 4.0.0
|
|
1245
|
+
*/
|
|
1246
|
+
const defaultTransforms = (transformer, nested = true) => {
|
|
1247
|
+
const transformValue = (value) => {
|
|
1248
|
+
if (Array.isArray(value)) {
|
|
1249
|
+
if (value.length === 0 || value[0].constructor !== Object) return value;
|
|
1250
|
+
return array(value);
|
|
1251
|
+
} else if (value?.constructor === Object) return transformObject(value);
|
|
1252
|
+
return value;
|
|
1253
|
+
};
|
|
1254
|
+
const transformObject = (obj) => {
|
|
1255
|
+
const newObj = {};
|
|
1256
|
+
for (const key of Object.keys(obj)) assignProperty(newObj, transformer(key), transformValue(obj[key]));
|
|
1257
|
+
return newObj;
|
|
1258
|
+
};
|
|
1259
|
+
const transformArrayNested = (rows) => {
|
|
1260
|
+
const newRows = new Array(rows.length);
|
|
1261
|
+
for (let i = 0, len = rows.length; i < len; i++) {
|
|
1262
|
+
const row = rows[i];
|
|
1263
|
+
if (Array.isArray(row)) newRows[i] = transformArrayNested(row);
|
|
1264
|
+
else {
|
|
1265
|
+
const obj = {};
|
|
1266
|
+
for (const [key, value] of Object.entries(row)) assignProperty(obj, transformer(key), transformValue(value));
|
|
1267
|
+
newRows[i] = obj;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return newRows;
|
|
1271
|
+
};
|
|
1272
|
+
const transformArray = (rows) => {
|
|
1273
|
+
const newRows = new Array(rows.length);
|
|
1274
|
+
for (let i = 0, len = rows.length; i < len; i++) {
|
|
1275
|
+
const row = rows[i];
|
|
1276
|
+
if (Array.isArray(row)) newRows[i] = transformArray(row);
|
|
1277
|
+
else {
|
|
1278
|
+
const obj = {};
|
|
1279
|
+
for (const [key, value] of Object.entries(row)) assignProperty(obj, transformer(key), value);
|
|
1280
|
+
newRows[i] = obj;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
return newRows;
|
|
1284
|
+
};
|
|
1285
|
+
const array = nested ? transformArrayNested : transformArray;
|
|
1286
|
+
return {
|
|
1287
|
+
value: transformValue,
|
|
1288
|
+
object: transformObject,
|
|
1289
|
+
array
|
|
1290
|
+
};
|
|
1291
|
+
};
|
|
1292
|
+
const ATTR_DB_OPERATION_NAME = "db.operation.name";
|
|
1293
|
+
const ATTR_DB_QUERY_TEXT = "db.query.text";
|
|
1294
|
+
const makeUnsafe = (segments, acquirer, compiler, spanAttributes, transformRows) => {
|
|
1295
|
+
const self = Object.create(StatementProto);
|
|
1296
|
+
self.segments = segments;
|
|
1297
|
+
self.acquirer = acquirer;
|
|
1298
|
+
self.compiler = compiler;
|
|
1299
|
+
self.spanAttributes = spanAttributes;
|
|
1300
|
+
self.transformRows = transformRows;
|
|
1301
|
+
return self;
|
|
1302
|
+
};
|
|
1303
|
+
const StatementProto = {
|
|
1304
|
+
[FragmentTypeId]: FragmentTypeId,
|
|
1305
|
+
withConnection(operation, f, withoutTransform = false) {
|
|
1306
|
+
return useSpan("sql.execute", { kind: "client" }, (span) => this.withConnectionSpan(operation, f, withoutTransform, span));
|
|
1307
|
+
},
|
|
1308
|
+
withConnectionSpan(operation, f, withoutTransform, span) {
|
|
1309
|
+
return withStatement(this, span, (statement) => {
|
|
1310
|
+
const [sql, params] = statement.compile(withoutTransform);
|
|
1311
|
+
for (const [key, value] of this.spanAttributes) span.attribute(key, value);
|
|
1312
|
+
span.attribute(ATTR_DB_OPERATION_NAME, operation);
|
|
1313
|
+
span.attribute(ATTR_DB_QUERY_TEXT, sql);
|
|
1314
|
+
return scoped(flatMap(this.acquirer, (_) => f(_, sql, params)));
|
|
1315
|
+
});
|
|
1316
|
+
},
|
|
1317
|
+
get withoutTransform() {
|
|
1318
|
+
return this.withConnection("executeWithoutTransform", (connection, sql, params) => connection.execute(sql, params, void 0), true);
|
|
1319
|
+
},
|
|
1320
|
+
get raw() {
|
|
1321
|
+
return this.withConnection("executeRaw", (connection, sql, params) => connection.executeRaw(sql, params), true);
|
|
1322
|
+
},
|
|
1323
|
+
get stream() {
|
|
1324
|
+
const self = this;
|
|
1325
|
+
return unwrap(flatMap(makeSpanScoped("sql.execute", { kind: "client" }), (span) => withStatement(self, span, (statement) => {
|
|
1326
|
+
const [sql, params] = statement.compile();
|
|
1327
|
+
for (const [key, value] of self.spanAttributes) span.attribute(key, value);
|
|
1328
|
+
span.attribute(ATTR_DB_OPERATION_NAME, "executeStream");
|
|
1329
|
+
span.attribute(ATTR_DB_QUERY_TEXT, sql);
|
|
1330
|
+
return map(self.acquirer, (_) => _.executeStream(sql, params, self.transformRows));
|
|
1331
|
+
})));
|
|
1332
|
+
},
|
|
1333
|
+
get values() {
|
|
1334
|
+
return this.withConnection("executeValues", (connection, sql, params) => connection.executeValues(sql, params));
|
|
1335
|
+
},
|
|
1336
|
+
get valuesUnprepared() {
|
|
1337
|
+
return this.withConnection("executeValuesUnprepared", (connection, sql, params) => connection.executeValuesUnprepared(sql, params));
|
|
1338
|
+
},
|
|
1339
|
+
get unprepared() {
|
|
1340
|
+
const self = this;
|
|
1341
|
+
return self.withConnection("executeUnprepared", (connection, sql, params) => connection.executeUnprepared(sql, params, self.transformRows));
|
|
1342
|
+
},
|
|
1343
|
+
.../*#__PURE__*/ Prototype({
|
|
1344
|
+
label: "Statement",
|
|
1345
|
+
evaluate(fiber) {
|
|
1346
|
+
const span = makeSpanUnsafe(fiber, "sql.execute", { kind: "client" });
|
|
1347
|
+
const clock = fiber.getRef(Clock);
|
|
1348
|
+
const timingEnabled = fiber.getRef(TracerTimingEnabled);
|
|
1349
|
+
return onExit$1(this.withConnectionSpan("execute", (connection, sql, params) => connection.execute(sql, params, this.transformRows), false, span), (exit) => endSpan(span, exit, clock, timingEnabled));
|
|
1350
|
+
}
|
|
1351
|
+
}),
|
|
1352
|
+
compile(withoutTransform) {
|
|
1353
|
+
return this.compiler.compile(this, withoutTransform ?? false);
|
|
1354
|
+
},
|
|
1355
|
+
toJSON() {
|
|
1356
|
+
const [sql, params] = this.compile();
|
|
1357
|
+
return {
|
|
1358
|
+
_id: "Statement",
|
|
1359
|
+
segments: this.segments,
|
|
1360
|
+
sql,
|
|
1361
|
+
params
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
const withStatement = (self, span, f) => withFiber$1((fiber) => {
|
|
1366
|
+
const transform = fiber.getRef(CurrentTransformer);
|
|
1367
|
+
if (transform === void 0) return f(self);
|
|
1368
|
+
return flatMap(transform(self, make$1(self.acquirer, self.compiler, self.spanAttributes, self.transformRows), fiber, span), f);
|
|
1369
|
+
});
|
|
1370
|
+
const isSegment = (u) => {
|
|
1371
|
+
if (!hasProperty(u, "_tag")) return false;
|
|
1372
|
+
switch (u._tag) {
|
|
1373
|
+
case "Literal":
|
|
1374
|
+
case "Parameter":
|
|
1375
|
+
case "ArrayHelper":
|
|
1376
|
+
case "RecordInsertHelper":
|
|
1377
|
+
case "RecordUpdateHelper":
|
|
1378
|
+
case "RecordUpdateHelperSingle":
|
|
1379
|
+
case "Identifier":
|
|
1380
|
+
case "Custom": return true;
|
|
1381
|
+
default: return false;
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
function convertLiteralOrFragment(clause) {
|
|
1385
|
+
if (typeof clause === "string") return [literal(clause)];
|
|
1386
|
+
return clause.segments;
|
|
1387
|
+
}
|
|
1388
|
+
const makePlaceholdersArray = (evaluate) => (values) => {
|
|
1389
|
+
if (values.length === 0) return "";
|
|
1390
|
+
let result = evaluate(values[0]);
|
|
1391
|
+
for (let i = 1; i < values.length; i++) result += `,${evaluate(values[i])}`;
|
|
1392
|
+
return result;
|
|
1393
|
+
};
|
|
1394
|
+
const generateColumns = (keys, escape, withoutTransform) => {
|
|
1395
|
+
if (keys.length === 0) return "()";
|
|
1396
|
+
let str = `(${escape(keys[0], withoutTransform)}`;
|
|
1397
|
+
for (let i = 1; i < keys.length; i++) str += `,${escape(keys[i], withoutTransform)}`;
|
|
1398
|
+
return str + ")";
|
|
1399
|
+
};
|
|
1400
|
+
const extractPrimitive = (value, onCustom, placeholder, withoutTransform) => {
|
|
1401
|
+
if (value === void 0) return null;
|
|
1402
|
+
else if (isFragment(value)) {
|
|
1403
|
+
const head = value.segments[0];
|
|
1404
|
+
if (head._tag === "Custom") return onCustom(head, placeholder, withoutTransform)[1][0] ?? null;
|
|
1405
|
+
else if (head._tag === "Parameter") return head.value;
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
return value;
|
|
1409
|
+
};
|
|
1410
|
+
const escapeSqlite = /*#__PURE__*/ defaultEscape("\"");
|
|
1411
|
+
function in_() {
|
|
1412
|
+
if (arguments.length === 1) return arrayHelper(arguments[0]);
|
|
1413
|
+
const column = arguments[0];
|
|
1414
|
+
const values = arguments[1];
|
|
1415
|
+
return values.length === 0 ? neverFragment : fragment([
|
|
1416
|
+
identifier(column),
|
|
1417
|
+
literal(" IN "),
|
|
1418
|
+
arrayHelper(values)
|
|
1419
|
+
]);
|
|
1420
|
+
}
|
|
1421
|
+
const neverFragment = /*#__PURE__*/ fragment([/*#__PURE__*/ literal("1=0")]);
|
|
1422
|
+
//#endregion
|
|
1423
|
+
//#region ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9/node_modules/effect/dist/unstable/sql/SqlClient.js
|
|
1424
|
+
/**
|
|
1425
|
+
* Main SQL client service for tagged-template queries.
|
|
1426
|
+
*
|
|
1427
|
+
* `SqlClient` combines the tagged-template statement constructor with
|
|
1428
|
+
* connection acquisition, dialect compilation, transactions, row transforms,
|
|
1429
|
+
* tracing, and reactive query helpers. Driver integrations build this service
|
|
1430
|
+
* from their connection and compiler pieces.
|
|
1431
|
+
*
|
|
1432
|
+
* @since 4.0.0
|
|
1433
|
+
*/
|
|
1434
|
+
const TypeId = "~effect/sql/SqlClient";
|
|
1435
|
+
/**
|
|
1436
|
+
* Service tag for the active SQL client service.
|
|
1437
|
+
*
|
|
1438
|
+
* **When to use**
|
|
1439
|
+
*
|
|
1440
|
+
* Use to access or provide the SQL client used to build statements, stream
|
|
1441
|
+
* rows, reserve connections, and run transactions.
|
|
1442
|
+
*
|
|
1443
|
+
* @category services
|
|
1444
|
+
* @since 4.0.0
|
|
1445
|
+
*/
|
|
1446
|
+
const SqlClient = /*#__PURE__*/ Service("effect/sql/SqlClient");
|
|
1447
|
+
let clientIdCounter = 0;
|
|
1448
|
+
/**
|
|
1449
|
+
* Constructs a `SqlClient` from connection acquirers, a compiler, transaction
|
|
1450
|
+
* commands, tracing attributes, optional row transforms, and reactive query
|
|
1451
|
+
* integration.
|
|
1452
|
+
*
|
|
1453
|
+
* @category constructors
|
|
1454
|
+
* @since 4.0.0
|
|
1455
|
+
*/
|
|
1456
|
+
const make = /*#__PURE__*/ fnUntraced(function* (options) {
|
|
1457
|
+
const transactionService = options.transactionService ?? TransactionConnection(clientIdCounter++);
|
|
1458
|
+
const getConnection = flatMap(serviceOption(transactionService), match({
|
|
1459
|
+
onNone: () => options.acquirer,
|
|
1460
|
+
onSome: ([conn]) => succeed$2(conn)
|
|
1461
|
+
}));
|
|
1462
|
+
const beginTransaction = options.beginTransaction ?? "BEGIN";
|
|
1463
|
+
const commit = options.commit ?? "COMMIT";
|
|
1464
|
+
const savepoint = options.savepoint ?? ((name) => `SAVEPOINT ${name}`);
|
|
1465
|
+
const rollback = options.rollback ?? "ROLLBACK";
|
|
1466
|
+
const rollbackSavepoint = options.rollbackSavepoint ?? ((name) => `ROLLBACK TO SAVEPOINT ${name}`);
|
|
1467
|
+
const transactionAcquirer = options.transactionAcquirer ?? options.acquirer;
|
|
1468
|
+
const withTransaction = makeWithTransaction({
|
|
1469
|
+
transactionService,
|
|
1470
|
+
spanAttributes: options.spanAttributes,
|
|
1471
|
+
acquireConnection: flatMap(make$6(), (scope) => map(provide(transactionAcquirer, scope), (conn) => [scope, conn])),
|
|
1472
|
+
begin: (conn) => conn.executeUnprepared(beginTransaction, [], void 0),
|
|
1473
|
+
savepoint: (conn, id) => conn.executeUnprepared(savepoint(`effect_sql_${id}`), [], void 0),
|
|
1474
|
+
commit: (conn) => conn.executeUnprepared(commit, [], void 0),
|
|
1475
|
+
rollback: (conn) => conn.executeUnprepared(rollback, [], void 0),
|
|
1476
|
+
rollbackSavepoint: (conn, id) => conn.executeUnprepared(rollbackSavepoint(`effect_sql_${id}`), [], void 0)
|
|
1477
|
+
});
|
|
1478
|
+
const reactivity = yield* Reactivity;
|
|
1479
|
+
const client = Object.assign(make$1(getConnection, options.compiler, options.spanAttributes, options.transformRows), {
|
|
1480
|
+
[TypeId]: TypeId,
|
|
1481
|
+
safe: void 0,
|
|
1482
|
+
withTransaction,
|
|
1483
|
+
transactionService,
|
|
1484
|
+
reserve: transactionAcquirer,
|
|
1485
|
+
withoutTransforms() {
|
|
1486
|
+
if (options.transformRows === void 0) return this;
|
|
1487
|
+
const statement = make$1(getConnection, options.compiler.withoutTransform, options.spanAttributes, void 0);
|
|
1488
|
+
const client = Object.assign(statement, {
|
|
1489
|
+
...this,
|
|
1490
|
+
...statement
|
|
1491
|
+
});
|
|
1492
|
+
client.safe = client;
|
|
1493
|
+
client.withoutTransforms = () => client;
|
|
1494
|
+
return client;
|
|
1495
|
+
},
|
|
1496
|
+
reactive: options.reactiveQueue ? (keys, effect) => options.reactiveQueue(keys, effect).pipe(map(fromQueue), unwrap) : reactivity.stream,
|
|
1497
|
+
reactiveMailbox: options.reactiveQueue ?? reactivity.query
|
|
1498
|
+
});
|
|
1499
|
+
client.safe = client;
|
|
1500
|
+
return client;
|
|
1501
|
+
});
|
|
1502
|
+
/**
|
|
1503
|
+
* Builds a transaction wrapper that begins top-level transactions, uses
|
|
1504
|
+
* savepoints for nested transactions, commits on success, and rolls back on
|
|
1505
|
+
* failure or interruption.
|
|
1506
|
+
*
|
|
1507
|
+
* @category transactions
|
|
1508
|
+
* @since 4.0.0
|
|
1509
|
+
*/
|
|
1510
|
+
const makeWithTransaction = (options) => (effect) => {
|
|
1511
|
+
return uninterruptibleMask((restore) => useSpan("sql.transaction", { kind: "client" }, (span) => withFiber$1((fiber) => {
|
|
1512
|
+
for (const [key, value] of options.spanAttributes) span.attribute(key, value);
|
|
1513
|
+
const services = fiber.context;
|
|
1514
|
+
const clock = fiber.getRef(Clock);
|
|
1515
|
+
const connOption = getOption$1(services, options.transactionService);
|
|
1516
|
+
const conn = connOption._tag === "Some" ? succeed$2([void 0, connOption.value[0]]) : options.acquireConnection;
|
|
1517
|
+
const id = connOption._tag === "Some" ? connOption.value[1] + 1 : 0;
|
|
1518
|
+
return flatMap(conn, ([scope, conn]) => (id === 0 ? options.begin(conn) : options.savepoint(conn, id)).pipe(flatMap(() => provideContext(restore(effect), services.pipe(add(options.transactionService, [conn, id]), add(ParentSpan, span)))), exit, flatMap((exit) => {
|
|
1519
|
+
let effect;
|
|
1520
|
+
if (isSuccess(exit)) if (id === 0) {
|
|
1521
|
+
span.event("db.transaction.commit", clock.currentTimeNanosUnsafe());
|
|
1522
|
+
effect = orDie(options.commit(conn));
|
|
1523
|
+
} else {
|
|
1524
|
+
span.event("db.transaction.savepoint", clock.currentTimeNanosUnsafe());
|
|
1525
|
+
effect = void_$1;
|
|
1526
|
+
}
|
|
1527
|
+
else {
|
|
1528
|
+
span.event("db.transaction.rollback", clock.currentTimeNanosUnsafe());
|
|
1529
|
+
effect = orDie(id > 0 ? options.rollbackSavepoint(conn, id) : options.rollback(conn));
|
|
1530
|
+
}
|
|
1531
|
+
return flatMap(scope !== void 0 ? ensuring(effect, close(scope, exit)) : effect, () => exit);
|
|
1532
|
+
})));
|
|
1533
|
+
})));
|
|
1534
|
+
};
|
|
1535
|
+
/**
|
|
1536
|
+
* Creates a unique context service tag for the active transaction connection of
|
|
1537
|
+
* a specific SQL client.
|
|
1538
|
+
*
|
|
1539
|
+
* @category services
|
|
1540
|
+
* @since 4.0.0
|
|
1541
|
+
*/
|
|
1542
|
+
const TransactionConnection = (clientId) => Service(`effect/sql/SqlClient/TransactionConnection/${clientId}`);
|
|
1543
|
+
/**
|
|
1544
|
+
* Context reference used by SQL integrations to opt in to safe integer
|
|
1545
|
+
* handling; defaults to `false`.
|
|
1546
|
+
*
|
|
1547
|
+
* @category services
|
|
1548
|
+
* @since 4.0.0
|
|
1549
|
+
*/
|
|
1550
|
+
const SafeIntegers = /*#__PURE__*/ Reference("effect/sql/SqlClient/SafeIntegers", { defaultValue: () => false });
|
|
1551
|
+
//#endregion
|
|
1552
|
+
export { makeCompilerSqlite as a, getOption as c, make$3 as d, makeWith as f, defaultTransforms as i, invalidate as l, SqlClient as n, layer as o, set as p, make as r, get as s, SafeIntegers as t, keys as u };
|
|
1553
|
+
|
|
1554
|
+
//# sourceMappingURL=SqlClient-DcM69ZvI.mjs.map
|