clanka 0.7.0 → 0.7.2
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/dist/CodeChunker.d.ts.map +1 -1
- package/dist/CodeChunker.js +17 -2
- package/dist/CodeChunker.js.map +1 -1
- package/dist/CodeChunker.test.js +49 -2
- package/dist/CodeChunker.test.js.map +1 -1
- package/dist/Compaction.d.ts +2 -1
- package/dist/Compaction.d.ts.map +1 -1
- package/dist/Compaction.js +30 -3
- package/dist/Compaction.js.map +1 -1
- package/dist/CompactionTokens.test.d.ts +2 -0
- package/dist/CompactionTokens.test.d.ts.map +1 -0
- package/dist/CompactionTokens.test.js +152 -0
- package/dist/CompactionTokens.test.js.map +1 -0
- package/dist/ExaSearch.d.ts.map +1 -1
- package/dist/ExaSearch.js +13 -5
- package/dist/ExaSearch.js.map +1 -1
- package/dist/Image.d.ts.map +1 -1
- package/dist/Image.js +10 -18
- package/dist/Image.js.map +1 -1
- package/dist/OutputFormatter.js +1 -1
- package/dist/OutputFormatter.js.map +1 -1
- package/dist/SemanticSearch.js +2 -2
- package/dist/SemanticSearch.js.map +1 -1
- package/dist/bin/McpClient-D6vFD-wP.mjs +16337 -0
- package/dist/bin/McpClient-D6vFD-wP.mjs.map +1 -0
- package/dist/bin/Schema-D6y3R-At.mjs +28728 -0
- package/dist/bin/Schema-D6y3R-At.mjs.map +1 -0
- package/dist/bin/SemanticSearch-D9iZ_Mi9.mjs +3372 -0
- package/dist/bin/SemanticSearch-D9iZ_Mi9.mjs.map +1 -0
- package/dist/bin/Undici-ChB4UBDa.mjs +28 -0
- package/dist/bin/Undici-ChB4UBDa.mjs.map +1 -0
- package/dist/bin/cli.mjs +57559 -0
- package/dist/bin/cli.mjs.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +7 -4
- package/src/CodeChunker.test.ts +62 -2
- package/src/CodeChunker.ts +30 -2
- package/src/Compaction.ts +32 -4
- package/src/CompactionTokens.test.ts +214 -0
- package/src/ExaSearch.ts +18 -5
- package/src/Image.ts +12 -3
- package/src/OutputFormatter.ts +1 -1
- package/src/SemanticSearch.ts +2 -2
- package/src/cli.ts +1 -1
|
@@ -0,0 +1,3372 @@
|
|
|
1
|
+
import { $a as done, B as TaggedError, Bi as void_$1, Bo as onExit$1, Bs as isZero, Co as exitHasInterrupts, Cs as sort, Ct as isSchema, Da as effect, Dc as Prototype, Di as sync, Dr as forEach, Ei as suspend, Er as fnUntraced, Fc as assignProperty, Fo as forkUnsafe, Fr as interrupt, Gc as byReferenceUnsafe, Gn as all, Ha as addFinalizer, Hn as acquireRelease, Hs as minutes, I as String$1, Ia as provide$1, Ii as uninterruptibleMask, Ja as provide, Jc as hash, Ji as Class$2, Jn as annotateLogs, Jo as updateContext, Js as add, Ka as make$8, Kc as equals, Ki as withSpan, Ks as Reference, Kt as evolve, L as Struct$2, La as provideMerge, Lr as isEffect, Ls as fromInputUnsafe, Mi as tryPromise, Mo as fiberJoin, Ni as try_, Nr as gen, O as Number$1, Oa as effectContext, Oi as tap, Oo as fiberInterrupt, Or as forever, Ot as mutable, Pc as withFiber$1, Pr as ignore, Q as brand, Qs as getOrUndefined, Rr as logDebug, Rs as infinity, S as Natural, Sc as some, Si as serviceOption, So as endSpan, Sr as flatMap, Tc as make$10, Tr as fn, Ui as withFiber, Un as acquireUseRelease, Uo as succeed$1, Ur as makeSpanScoped, Us as seconds, Va as Scope, Vr as logInfo, Vs as millis, Wa as close, Wi as withLogSpan, Wr as map, Ws as toMillis, Xc as symbol$1, Xr as matchCauseEager, Xs as get$1, Y as Union$2, Yn as as, Yo as void_$2, Za as TracerTimingEnabled, Zc as hasProperty, Zn as asVoid, Zo as ParentSpan, Zs as getOption, _c as map$1, _i as runForkWith, ai as orDie, ao as makeUnsafe$2, bi as scoped, co as failCause, cr as catchTag, d as Defect, da as NoSuchElementError, dl as constUndefined, do as isFailure, ds as flatMapNullishOr, dt as instanceOf, ec as getUnsafe, eo as doneUnsafe, fo as isSuccess, fr as context, fs as fromIterable, gc as isSome, gi as runFork, gl as identity, hc as isNone, hl as flow, ho as ClockRef, hr as die, it as decodeUnknownEffect, jr as forkScoped, ka as effectDiscard, kc as PipeInspectableProto, kt as optional, la as Clock, li as provideContext, lr as catchTags, ml as dual, mo as void_$3, mr as delay, ms as isArrayNonEmpty, n as ArraySchema, ni as onExitPrimitive, no as into, nr as catchDefect, o as Class$1, oi as orElseSucceed, or as catchNoSuchElement, pi as request$1, po as succeed$2, pr as contextWith, qc as symbol, qn as annotateCurrentSpan, qr as mapError, qs as Service, rc as merge, rs as TaggedError$1, rt as decodeTo, so as fail, ss as empty, st as encodeEffect, tc as make$9, ti as onExit, tr as catchCause, uc as fromNullishOr, ui as provideService, ur as catch_, va as filterInterruptors, vc as match, vl as pipe, wc as Number$2, wi as succeed, wn as transform$1, xa as hasInterruptsOnly, xo as contextWith$1, xr as filterOrFail, yc as none, yi as scope, yl as pipeArguments, yr as fail$1, ys as map$2, zi as useSpan, zo as makeSpanUnsafe, zs as isFinite } from "./Schema-D6y3R-At.mjs";
|
|
2
|
+
import { A as isEmpty, B as getCurrent, C as runCollect, D as empty$1, E as unwrap, F as make$14, G as has, H as join$1, I as makeUnsafe$3, K as toPredicate, L as failCauseUnsafe, M as remove, N as set, O as forEach$1, P as size, R as make$11, S as provideService$1, T as tap$1, U as runIn, V as interruptAs, W as compose, _ as die$1, a as makeGrouped, b as fromArrayEffect, c as SemanticSearch, f as make$13, g as FileSystem, h as Path, i as batchN, j as make$12, k as get$2, l as maybeRemoveFile, m as Console, n as EmbeddingModel, o as setDelay, p as ChildProcessSpawner, r as EmbeddingRequest, s as withSpan$1, t as Dimensions, u as maybeUpdateFile, v as flatMap$1, w as runDrain, x as fromQueue, y as fromArray, z as offerUnsafe } from "./cli.mjs";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import TreeSitter from "tree-sitter";
|
|
5
|
+
import TreeSitterJavaScript from "tree-sitter-javascript";
|
|
6
|
+
import TreeSitterTypeScript from "tree-sitter-typescript";
|
|
7
|
+
import { DatabaseSync, backup } from "node:sqlite";
|
|
8
|
+
import { getLoadablePath } from "sqlite-vec";
|
|
9
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/reactivity/Reactivity.js
|
|
10
|
+
/**
|
|
11
|
+
* Process-local invalidation for connecting writes to dependent reads.
|
|
12
|
+
*
|
|
13
|
+
* This module does not cache values itself. It lets callers register handlers
|
|
14
|
+
* for keys, invalidate those keys, wrap successful mutations so they invalidate
|
|
15
|
+
* keys, and expose effects as queues or streams that rerun when matching keys
|
|
16
|
+
* change. The service can also batch invalidations so handlers run after the
|
|
17
|
+
* batch completes.
|
|
18
|
+
*
|
|
19
|
+
* @since 4.0.0
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Brand for `Reactivity` implementations.
|
|
23
|
+
*
|
|
24
|
+
* @category type IDs
|
|
25
|
+
* @since 4.0.0
|
|
26
|
+
*/
|
|
27
|
+
const TypeId$6 = "~effect/reactivity/Reactivity";
|
|
28
|
+
/**
|
|
29
|
+
* Service key for reactive invalidation.
|
|
30
|
+
*
|
|
31
|
+
* @category services
|
|
32
|
+
* @since 4.0.0
|
|
33
|
+
*/
|
|
34
|
+
const Reactivity = /*#__PURE__*/ Service("effect/reactivity/Reactivity");
|
|
35
|
+
/**
|
|
36
|
+
* Creates an in-memory `Reactivity` service.
|
|
37
|
+
*
|
|
38
|
+
* **Details**
|
|
39
|
+
*
|
|
40
|
+
* The service tracks handlers by hashed keys and runs the registered handlers when
|
|
41
|
+
* matching keys are invalidated.
|
|
42
|
+
*
|
|
43
|
+
* @category constructors
|
|
44
|
+
* @since 4.0.0
|
|
45
|
+
*/
|
|
46
|
+
const make$7 = /*#__PURE__*/ sync(() => {
|
|
47
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
48
|
+
const invalidateUnsafe = (keys) => {
|
|
49
|
+
keysToHashes(keys, (hash) => {
|
|
50
|
+
const set = handlers.get(hash);
|
|
51
|
+
if (set === void 0) return;
|
|
52
|
+
set.forEach((run) => run());
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
const invalidate = (keys) => contextWith((services) => {
|
|
56
|
+
const pending = getOrUndefined(services, PendingInvalidation);
|
|
57
|
+
if (pending) keysToHashes(keys, (hash) => {
|
|
58
|
+
pending.add(hash);
|
|
59
|
+
});
|
|
60
|
+
else invalidateUnsafe(keys);
|
|
61
|
+
return void_$1;
|
|
62
|
+
});
|
|
63
|
+
const mutation = (keys, effect) => tap(effect, invalidate(keys));
|
|
64
|
+
const registerUnsafe = (keys, handler) => {
|
|
65
|
+
const resolvedKeys = [];
|
|
66
|
+
keysToHashes(keys, (hash) => {
|
|
67
|
+
resolvedKeys.push(hash);
|
|
68
|
+
let set = handlers.get(hash);
|
|
69
|
+
if (set === void 0) {
|
|
70
|
+
set = /* @__PURE__ */ new Set();
|
|
71
|
+
handlers.set(hash, set);
|
|
72
|
+
}
|
|
73
|
+
set.add(handler);
|
|
74
|
+
});
|
|
75
|
+
return () => {
|
|
76
|
+
for (let i = 0; i < resolvedKeys.length; i++) {
|
|
77
|
+
const set = handlers.get(resolvedKeys[i]);
|
|
78
|
+
if (set === void 0) continue;
|
|
79
|
+
set.delete(handler);
|
|
80
|
+
if (set.size === 0) handlers.delete(resolvedKeys[i]);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
const query = (keys, effect) => gen(function* () {
|
|
85
|
+
const services = yield* context();
|
|
86
|
+
const scope = get$1(services, Scope);
|
|
87
|
+
const results = yield* make$11();
|
|
88
|
+
const runFork = flow(runForkWith(services), runIn(scope));
|
|
89
|
+
let running = false;
|
|
90
|
+
let pending = false;
|
|
91
|
+
const handleExit = (exit) => {
|
|
92
|
+
if (exit._tag === "Failure") failCauseUnsafe(results, exit.cause);
|
|
93
|
+
else offerUnsafe(results, exit.value);
|
|
94
|
+
if (pending) {
|
|
95
|
+
pending = false;
|
|
96
|
+
runFork(effect).addObserver(handleExit);
|
|
97
|
+
} else running = false;
|
|
98
|
+
};
|
|
99
|
+
function run() {
|
|
100
|
+
if (running) {
|
|
101
|
+
pending = true;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
running = true;
|
|
105
|
+
runFork(effect).addObserver(handleExit);
|
|
106
|
+
}
|
|
107
|
+
const cancel = registerUnsafe(keys, run);
|
|
108
|
+
yield* addFinalizer(scope, sync(cancel));
|
|
109
|
+
run();
|
|
110
|
+
return results;
|
|
111
|
+
});
|
|
112
|
+
const stream = (tables, effect) => query(tables, effect).pipe(map(fromQueue), unwrap);
|
|
113
|
+
const withBatch = (effect) => suspend(() => {
|
|
114
|
+
const pending = /* @__PURE__ */ new Set();
|
|
115
|
+
return effect.pipe(provideService(PendingInvalidation, pending), onExit((_) => sync(() => {
|
|
116
|
+
pending.forEach((hash) => {
|
|
117
|
+
const set = handlers.get(hash);
|
|
118
|
+
if (set === void 0) return;
|
|
119
|
+
set.forEach((run) => run());
|
|
120
|
+
});
|
|
121
|
+
})));
|
|
122
|
+
});
|
|
123
|
+
return Reactivity.of({
|
|
124
|
+
[TypeId$6]: TypeId$6,
|
|
125
|
+
mutation,
|
|
126
|
+
query,
|
|
127
|
+
stream,
|
|
128
|
+
invalidateUnsafe,
|
|
129
|
+
invalidate,
|
|
130
|
+
registerUnsafe,
|
|
131
|
+
withBatch
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
var PendingInvalidation = class extends (/*#__PURE__*/ Service()("effect/reactivity/Reactivity/PendingInvalidation")) {};
|
|
135
|
+
/**
|
|
136
|
+
* The default layer that provides an in-memory `Reactivity` service.
|
|
137
|
+
*
|
|
138
|
+
* @category layers
|
|
139
|
+
* @since 4.0.0
|
|
140
|
+
*/
|
|
141
|
+
const layer$5 = /*#__PURE__*/ effect(Reactivity)(make$7);
|
|
142
|
+
function stringOrHash(u) {
|
|
143
|
+
switch (typeof u) {
|
|
144
|
+
case "string":
|
|
145
|
+
case "number":
|
|
146
|
+
case "bigint":
|
|
147
|
+
case "boolean": return String(u);
|
|
148
|
+
default: return hash(u);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const keysToHashes = (keys, f) => {
|
|
152
|
+
if (Array.isArray(keys)) {
|
|
153
|
+
for (let i = 0; i < keys.length; i++) f(stringOrHash(keys[i]));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
for (const key in keys) {
|
|
157
|
+
f(key);
|
|
158
|
+
const ids = keys[key];
|
|
159
|
+
for (let i = 0; i < ids.length; i++) f(`${key}:${stringOrHash(ids[i])}`);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/sql/Statement.js
|
|
164
|
+
/**
|
|
165
|
+
* Low-level SQL statement and fragment primitives.
|
|
166
|
+
*
|
|
167
|
+
* `SqlClient` uses this module to build executable, parameterized SQL from
|
|
168
|
+
* reusable fragments. A statement can be executed, streamed, run without row
|
|
169
|
+
* transformation, or compiled to SQL text and parameters for a specific
|
|
170
|
+
* dialect. The module also contains helpers for identifiers, parameters,
|
|
171
|
+
* inserts, updates, custom dialect fragments, statement compilation, and row
|
|
172
|
+
* transformation.
|
|
173
|
+
*
|
|
174
|
+
* @since 4.0.0
|
|
175
|
+
*/
|
|
176
|
+
const FragmentTypeId = "~effect/sql/Statement/Fragment";
|
|
177
|
+
/**
|
|
178
|
+
* Constructs a SQL `Fragment` from low-level statement segments.
|
|
179
|
+
*
|
|
180
|
+
* @category constructors
|
|
181
|
+
* @since 4.0.0
|
|
182
|
+
*/
|
|
183
|
+
const fragment = (segments) => ({
|
|
184
|
+
[FragmentTypeId]: FragmentTypeId,
|
|
185
|
+
segments
|
|
186
|
+
});
|
|
187
|
+
/**
|
|
188
|
+
* Context reference for an optional current SQL statement transformer applied
|
|
189
|
+
* before statement execution.
|
|
190
|
+
*
|
|
191
|
+
* @category services
|
|
192
|
+
* @since 4.0.0
|
|
193
|
+
*/
|
|
194
|
+
const CurrentTransformer = /*#__PURE__*/ Reference("effect/sql/CurrentTransformer", { defaultValue: constUndefined });
|
|
195
|
+
/**
|
|
196
|
+
* Parents driver spans under `sql.execute` for every client in the current scope,
|
|
197
|
+
* including acquisition and stream pulls. Defaults to `false`; ignored when tracing is disabled.
|
|
198
|
+
*
|
|
199
|
+
* @category services
|
|
200
|
+
* @since 4.0.0
|
|
201
|
+
*/
|
|
202
|
+
const SpanPropagationEnabled = /*#__PURE__*/ Reference("effect/sql/SpanPropagationEnabled", { defaultValue: () => false });
|
|
203
|
+
/**
|
|
204
|
+
* Returns `true` when a value is a SQL `Fragment`.
|
|
205
|
+
*
|
|
206
|
+
* @category guards
|
|
207
|
+
* @since 4.0.0
|
|
208
|
+
*/
|
|
209
|
+
const isFragment = (u) => hasProperty(u, FragmentTypeId);
|
|
210
|
+
/**
|
|
211
|
+
* Constructs a raw SQL literal segment. The literal text is not escaped, so use
|
|
212
|
+
* bound parameters for untrusted values.
|
|
213
|
+
*
|
|
214
|
+
* @category constructors
|
|
215
|
+
* @since 4.0.0
|
|
216
|
+
*/
|
|
217
|
+
const literal = (value, params) => ({
|
|
218
|
+
_tag: "Literal",
|
|
219
|
+
value,
|
|
220
|
+
params
|
|
221
|
+
});
|
|
222
|
+
/**
|
|
223
|
+
* Constructs a SQL identifier segment that will be escaped by the active
|
|
224
|
+
* compiler.
|
|
225
|
+
*
|
|
226
|
+
* @category constructors
|
|
227
|
+
* @since 4.0.0
|
|
228
|
+
*/
|
|
229
|
+
const identifier = (value) => ({
|
|
230
|
+
_tag: "Identifier",
|
|
231
|
+
value
|
|
232
|
+
});
|
|
233
|
+
/**
|
|
234
|
+
* Constructs a bound parameter segment for a statement value.
|
|
235
|
+
*
|
|
236
|
+
* @category constructors
|
|
237
|
+
* @since 4.0.0
|
|
238
|
+
*/
|
|
239
|
+
const parameter = (value) => ({
|
|
240
|
+
_tag: "Parameter",
|
|
241
|
+
value
|
|
242
|
+
});
|
|
243
|
+
/**
|
|
244
|
+
* Constructs an `ArrayHelper` segment for an array of values or fragments.
|
|
245
|
+
*
|
|
246
|
+
* @category constructors
|
|
247
|
+
* @since 4.0.0
|
|
248
|
+
*/
|
|
249
|
+
const arrayHelper = (value) => ({
|
|
250
|
+
_tag: "ArrayHelper",
|
|
251
|
+
value
|
|
252
|
+
});
|
|
253
|
+
const RecordInsertHelperProto = {
|
|
254
|
+
_tag: "RecordInsertHelper",
|
|
255
|
+
returning(sql) {
|
|
256
|
+
const self = Object.create(Object.getPrototypeOf(this));
|
|
257
|
+
Object.assign(self, this, { returningIdentifier: typeof sql === "string" || isFragment(sql) ? sql : fragment([sql]) });
|
|
258
|
+
return self;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
/**
|
|
262
|
+
* Constructs a `RecordInsertHelper` from one or more row objects.
|
|
263
|
+
*
|
|
264
|
+
* @category constructors
|
|
265
|
+
* @since 4.0.0
|
|
266
|
+
*/
|
|
267
|
+
const recordInsertHelper = (value) => Object.assign(Object.create(RecordInsertHelperProto), {
|
|
268
|
+
value,
|
|
269
|
+
returningIdentifier: void 0
|
|
270
|
+
});
|
|
271
|
+
const RecordUpdateHelperProto = {
|
|
272
|
+
...RecordInsertHelperProto,
|
|
273
|
+
_tag: "RecordUpdateHelper"
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Constructs a `RecordUpdateHelper` for multi-row update compilation using the
|
|
277
|
+
* provided alias.
|
|
278
|
+
*
|
|
279
|
+
* @category constructors
|
|
280
|
+
* @since 4.0.0
|
|
281
|
+
*/
|
|
282
|
+
const recordUpdateHelper = (value, alias) => Object.assign(Object.create(RecordUpdateHelperProto), {
|
|
283
|
+
value,
|
|
284
|
+
alias,
|
|
285
|
+
returningIdentifier: void 0
|
|
286
|
+
});
|
|
287
|
+
const RecordUpdateHelperSingleProto = {
|
|
288
|
+
...RecordInsertHelperProto,
|
|
289
|
+
_tag: "RecordUpdateHelperSingle"
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Constructs a `RecordUpdateHelperSingle` from a record and a list of columns
|
|
293
|
+
* to omit from the update.
|
|
294
|
+
*
|
|
295
|
+
* @category constructors
|
|
296
|
+
* @since 4.0.0
|
|
297
|
+
*/
|
|
298
|
+
const recordUpdateHelperSingle = (value, omit) => Object.assign(Object.create(RecordUpdateHelperSingleProto), {
|
|
299
|
+
value,
|
|
300
|
+
omit,
|
|
301
|
+
returningIdentifier: void 0
|
|
302
|
+
});
|
|
303
|
+
/**
|
|
304
|
+
* Creates a cached SQL statement constructor from a connection acquirer,
|
|
305
|
+
* compiler, tracing attributes, and optional row transformation function.
|
|
306
|
+
*
|
|
307
|
+
* @category constructors
|
|
308
|
+
* @since 4.0.0
|
|
309
|
+
*/
|
|
310
|
+
const make$6 = (acquirer, compiler, spanAttributes, transformRows, borrower) => {
|
|
311
|
+
const cache = transformRows === void 0 ? constructorCache.noTransforms : constructorCache.transforms;
|
|
312
|
+
if (cache.has(acquirer)) return cache.get(acquirer);
|
|
313
|
+
const self = Object.assign(function sql(strings, ...args) {
|
|
314
|
+
if (typeof strings === "string") return identifier(strings);
|
|
315
|
+
else if (Array.isArray(strings) && "raw" in strings) return statement(acquirer, compiler, strings, args, spanAttributes, transformRows, borrower);
|
|
316
|
+
throw "absurd";
|
|
317
|
+
}, {
|
|
318
|
+
unsafe(sql, params) {
|
|
319
|
+
return makeUnsafe$1([literal(sql, params)], acquirer, compiler, spanAttributes, transformRows, borrower);
|
|
320
|
+
},
|
|
321
|
+
literal(sql) {
|
|
322
|
+
return fragment([literal(sql)]);
|
|
323
|
+
},
|
|
324
|
+
in: in_,
|
|
325
|
+
insert(value) {
|
|
326
|
+
return recordInsertHelper(Array.isArray(value) ? value : [value]);
|
|
327
|
+
},
|
|
328
|
+
update(value, omit) {
|
|
329
|
+
return recordUpdateHelperSingle(value, omit ?? []);
|
|
330
|
+
},
|
|
331
|
+
updateValues(value, alias) {
|
|
332
|
+
return recordUpdateHelper(value, alias);
|
|
333
|
+
},
|
|
334
|
+
and,
|
|
335
|
+
or,
|
|
336
|
+
csv,
|
|
337
|
+
join,
|
|
338
|
+
onDialect(options) {
|
|
339
|
+
return options[compiler.dialect]();
|
|
340
|
+
},
|
|
341
|
+
onDialectOrElse(options) {
|
|
342
|
+
return options[compiler.dialect] !== void 0 ? options[compiler.dialect]() : options.orElse();
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
cache.set(acquirer, self);
|
|
346
|
+
return self;
|
|
347
|
+
};
|
|
348
|
+
const constructorCache = {
|
|
349
|
+
transforms: /*#__PURE__*/ new WeakMap(),
|
|
350
|
+
noTransforms: /*#__PURE__*/ new WeakMap()
|
|
351
|
+
};
|
|
352
|
+
/**
|
|
353
|
+
* Builds a `Statement` from template strings and arguments, preserving
|
|
354
|
+
* fragments and helper segments while converting ordinary interpolated values
|
|
355
|
+
* into bound parameters.
|
|
356
|
+
*
|
|
357
|
+
* @category constructors
|
|
358
|
+
* @since 4.0.0
|
|
359
|
+
*/
|
|
360
|
+
const statement = (acquirer, compiler, strings, args, spanAttributes, transformRows, borrower) => {
|
|
361
|
+
const segments = strings[0].length > 0 ? [literal(strings[0])] : [];
|
|
362
|
+
for (let i = 0; i < args.length; i++) {
|
|
363
|
+
const arg = args[i];
|
|
364
|
+
if (isFragment(arg)) segments.push(...arg.segments);
|
|
365
|
+
else if (isSegment(arg)) segments.push(arg);
|
|
366
|
+
else segments.push(parameter(arg));
|
|
367
|
+
if (strings[i + 1].length > 0) segments.push(literal(strings[i + 1]));
|
|
368
|
+
}
|
|
369
|
+
return makeUnsafe$1(segments, acquirer, compiler, spanAttributes, transformRows, borrower);
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* Creates a helper that joins SQL clauses with a literal separator, optionally
|
|
373
|
+
* wrapping multiple clauses in parentheses and using a fallback for an empty
|
|
374
|
+
* list.
|
|
375
|
+
*
|
|
376
|
+
* @category constructors
|
|
377
|
+
* @since 4.0.0
|
|
378
|
+
*/
|
|
379
|
+
function join(lit, addParens = true, fallback = "") {
|
|
380
|
+
const literalStatement = literal(lit);
|
|
381
|
+
const fallbackFragment = fragment([literal(fallback)]);
|
|
382
|
+
return (clauses) => {
|
|
383
|
+
if (clauses.length === 0) return fallbackFragment;
|
|
384
|
+
else if (clauses.length === 1) return fragment(convertLiteralOrFragment(clauses[0]));
|
|
385
|
+
const segments = [];
|
|
386
|
+
if (addParens) segments.push(literal("("));
|
|
387
|
+
segments.push.apply(segments, convertLiteralOrFragment(clauses[0]));
|
|
388
|
+
for (let i = 1; i < clauses.length; i++) {
|
|
389
|
+
segments.push(literalStatement);
|
|
390
|
+
segments.push.apply(segments, convertLiteralOrFragment(clauses[i]));
|
|
391
|
+
}
|
|
392
|
+
if (addParens) segments.push(literal(")"));
|
|
393
|
+
return fragment(segments);
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Combines clauses with `AND`, parenthesizing multiple clauses and returning
|
|
398
|
+
* `1=1` when the list is empty.
|
|
399
|
+
*
|
|
400
|
+
* @category constructors
|
|
401
|
+
* @since 4.0.0
|
|
402
|
+
*/
|
|
403
|
+
const and = /*#__PURE__*/ join(" AND ", true, "1=1");
|
|
404
|
+
/**
|
|
405
|
+
* Combines clauses with `OR`, parenthesizing multiple clauses and returning
|
|
406
|
+
* `1=1` when the list is empty.
|
|
407
|
+
*
|
|
408
|
+
* @category constructors
|
|
409
|
+
* @since 4.0.0
|
|
410
|
+
*/
|
|
411
|
+
const or = /*#__PURE__*/ join(" OR ", true, "1=1");
|
|
412
|
+
/**
|
|
413
|
+
* Creates a comma-separated SQL fragment from values, optionally adding a
|
|
414
|
+
* prefix, and returns an empty fragment when no values are provided.
|
|
415
|
+
*
|
|
416
|
+
* @category constructors
|
|
417
|
+
* @since 4.0.0
|
|
418
|
+
*/
|
|
419
|
+
const csv = function(...args) {
|
|
420
|
+
if (args[args.length - 1].length === 0) return emptyFragment;
|
|
421
|
+
if (args.length === 1) return csvRaw(args[0]);
|
|
422
|
+
return fragment([literal(`${args[0]} `), ...csvRaw(args[1]).segments]);
|
|
423
|
+
};
|
|
424
|
+
const csvRaw = /*#__PURE__*/ join(",", false);
|
|
425
|
+
const emptyFragment = /*#__PURE__*/ fragment([/*#__PURE__*/ literal("")]);
|
|
426
|
+
/**
|
|
427
|
+
* Creates a dialect-specific SQL `Compiler` from rendering callbacks.
|
|
428
|
+
*
|
|
429
|
+
* @category constructors
|
|
430
|
+
* @since 4.0.0
|
|
431
|
+
*/
|
|
432
|
+
const makeCompiler = (options) => {
|
|
433
|
+
const self = Object.create(CompilerProto);
|
|
434
|
+
self.options = options;
|
|
435
|
+
self.dialect = options.dialect;
|
|
436
|
+
self.disableTransforms = false;
|
|
437
|
+
self.statementCache = /* @__PURE__ */ new WeakMap();
|
|
438
|
+
self.statementCacheNoTransform = /* @__PURE__ */ new WeakMap();
|
|
439
|
+
return self;
|
|
440
|
+
};
|
|
441
|
+
const CompilerProto = {
|
|
442
|
+
compile(statement, withoutTransform = false, placeholderOverride) {
|
|
443
|
+
const opts = this.options;
|
|
444
|
+
withoutTransform = withoutTransform || this.disableTransforms;
|
|
445
|
+
const cache = withoutTransform ? this.statementCacheNoTransform : this.statementCache;
|
|
446
|
+
const cached = cache.get(statement);
|
|
447
|
+
if (cached !== void 0 && placeholderOverride === void 0) return cached;
|
|
448
|
+
const segments = statement.segments;
|
|
449
|
+
const len = segments.length;
|
|
450
|
+
let sql = "";
|
|
451
|
+
const binds = [];
|
|
452
|
+
let placeholderCount = 0;
|
|
453
|
+
const placeholder = placeholderOverride ?? ((u) => opts.placeholder(++placeholderCount, u));
|
|
454
|
+
const placeholderNoIncrement = (u) => opts.placeholder(placeholderCount, u);
|
|
455
|
+
const placeholders = makePlaceholdersArray(placeholder);
|
|
456
|
+
for (let i = 0; i < len; i++) {
|
|
457
|
+
const segment = segments[i];
|
|
458
|
+
switch (segment._tag) {
|
|
459
|
+
case "Literal":
|
|
460
|
+
sql += segment.value;
|
|
461
|
+
if (segment.params) binds.push.apply(binds, segment.params);
|
|
462
|
+
break;
|
|
463
|
+
case "Identifier":
|
|
464
|
+
sql += opts.onIdentifier(segment.value, withoutTransform);
|
|
465
|
+
break;
|
|
466
|
+
case "Parameter":
|
|
467
|
+
sql += placeholder(segment.value);
|
|
468
|
+
binds.push(segment.value);
|
|
469
|
+
break;
|
|
470
|
+
case "ArrayHelper":
|
|
471
|
+
sql += `(${placeholders(segment.value)})`;
|
|
472
|
+
binds.push.apply(binds, segment.value);
|
|
473
|
+
break;
|
|
474
|
+
case "RecordInsertHelper": {
|
|
475
|
+
const keys = Object.keys(segment.value[0]);
|
|
476
|
+
if (opts.onInsert) {
|
|
477
|
+
const values = new Array(segment.value.length);
|
|
478
|
+
let placeholders = "";
|
|
479
|
+
for (let i = 0; i < segment.value.length; i++) {
|
|
480
|
+
const row = new Array(keys.length);
|
|
481
|
+
values[i] = row;
|
|
482
|
+
placeholders += i === 0 ? "(" : ",(";
|
|
483
|
+
for (let j = 0; j < keys.length; j++) {
|
|
484
|
+
const key = keys[j];
|
|
485
|
+
const value = segment.value[i][key];
|
|
486
|
+
const primitive = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform);
|
|
487
|
+
row[j] = primitive;
|
|
488
|
+
placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`;
|
|
489
|
+
}
|
|
490
|
+
placeholders += ")";
|
|
491
|
+
}
|
|
492
|
+
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);
|
|
493
|
+
sql += s;
|
|
494
|
+
binds.push.apply(binds, b);
|
|
495
|
+
} else {
|
|
496
|
+
let placeholders = "";
|
|
497
|
+
for (let i = 0; i < segment.value.length; i++) {
|
|
498
|
+
placeholders += i === 0 ? "(" : ",(";
|
|
499
|
+
for (let j = 0; j < keys.length; j++) {
|
|
500
|
+
const value = segment.value[i][keys[j]];
|
|
501
|
+
const primitive = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform);
|
|
502
|
+
binds.push(primitive);
|
|
503
|
+
placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`;
|
|
504
|
+
}
|
|
505
|
+
placeholders += ")";
|
|
506
|
+
}
|
|
507
|
+
sql += `${generateColumns(keys, opts.onIdentifier, withoutTransform)} VALUES ${placeholders}`;
|
|
508
|
+
if (typeof segment.returningIdentifier === "string") sql += ` RETURNING ${segment.returningIdentifier}`;
|
|
509
|
+
else if (segment.returningIdentifier) {
|
|
510
|
+
sql += " RETURNING ";
|
|
511
|
+
const [s, b] = this.compile(segment.returningIdentifier, withoutTransform, placeholder);
|
|
512
|
+
sql += s;
|
|
513
|
+
binds.push.apply(binds, b);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
case "RecordUpdateHelperSingle": {
|
|
519
|
+
let keys = Object.keys(segment.value);
|
|
520
|
+
if (segment.omit.length > 0) keys = keys.filter((key) => !segment.omit.includes(key));
|
|
521
|
+
if (opts.onRecordUpdateSingle) {
|
|
522
|
+
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);
|
|
523
|
+
sql += s;
|
|
524
|
+
binds.push.apply(binds, b);
|
|
525
|
+
} else {
|
|
526
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
527
|
+
const column = opts.onIdentifier(keys[i], withoutTransform);
|
|
528
|
+
if (i === 0) sql += `${column} = ${placeholder(segment.value[keys[i]])}`;
|
|
529
|
+
else sql += `, ${column} = ${placeholder(segment.value[keys[i]])}`;
|
|
530
|
+
binds.push(extractPrimitive(segment.value[keys[i]], opts.onCustom, placeholderNoIncrement, withoutTransform));
|
|
531
|
+
}
|
|
532
|
+
if (typeof segment.returningIdentifier === "string") {
|
|
533
|
+
if (this.dialect === "mssql") sql += ` OUTPUT ${segment.returningIdentifier === "*" ? "INSERTED.*" : segment.returningIdentifier}`;
|
|
534
|
+
else sql += ` RETURNING ${segment.returningIdentifier}`;
|
|
535
|
+
} else if (segment.returningIdentifier) {
|
|
536
|
+
sql += this.dialect === "mssql" ? " OUTPUT " : " RETURNING ";
|
|
537
|
+
const [s, b] = this.compile(segment.returningIdentifier, withoutTransform, placeholder);
|
|
538
|
+
sql += s;
|
|
539
|
+
binds.push.apply(binds, b);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
case "RecordUpdateHelper": {
|
|
545
|
+
const keys = Object.keys(segment.value[0]);
|
|
546
|
+
const values = new Array(segment.value.length);
|
|
547
|
+
let placeholders = "";
|
|
548
|
+
for (let i = 0; i < segment.value.length; i++) {
|
|
549
|
+
const row = new Array(keys.length);
|
|
550
|
+
values[i] = row;
|
|
551
|
+
placeholders += i === 0 ? "(" : ",(";
|
|
552
|
+
for (let j = 0; j < keys.length; j++) {
|
|
553
|
+
const key = keys[j];
|
|
554
|
+
const value = segment.value[i][key];
|
|
555
|
+
row[j] = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform);
|
|
556
|
+
placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`;
|
|
557
|
+
}
|
|
558
|
+
placeholders += ")";
|
|
559
|
+
}
|
|
560
|
+
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);
|
|
561
|
+
sql += s;
|
|
562
|
+
binds.push.apply(binds, b);
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
case "Custom": {
|
|
566
|
+
const [s, b] = opts.onCustom(segment, placeholder, withoutTransform);
|
|
567
|
+
sql += s;
|
|
568
|
+
binds.push.apply(binds, b);
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const result = [sql, binds];
|
|
574
|
+
if (placeholderOverride !== void 0) return result;
|
|
575
|
+
cache.set(statement, result);
|
|
576
|
+
return result;
|
|
577
|
+
},
|
|
578
|
+
get withoutTransform() {
|
|
579
|
+
const self = Object.create(CompilerProto);
|
|
580
|
+
Object.assign(self, this, { disableTransforms: true });
|
|
581
|
+
return self;
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
/**
|
|
585
|
+
* Creates a SQLite compiler that uses `?` placeholders and quoted identifiers,
|
|
586
|
+
* optionally transforming identifier names before escaping.
|
|
587
|
+
*
|
|
588
|
+
* @category constructors
|
|
589
|
+
* @since 4.0.0
|
|
590
|
+
*/
|
|
591
|
+
const makeCompilerSqlite = (transform) => makeCompiler({
|
|
592
|
+
dialect: "sqlite",
|
|
593
|
+
placeholder(_) {
|
|
594
|
+
return "?";
|
|
595
|
+
},
|
|
596
|
+
onIdentifier: transform ? function(value, withoutTransform) {
|
|
597
|
+
return withoutTransform ? escapeSqlite(value) : escapeSqlite(transform(value));
|
|
598
|
+
} : escapeSqlite,
|
|
599
|
+
onRecordUpdate() {
|
|
600
|
+
return ["", []];
|
|
601
|
+
},
|
|
602
|
+
onCustom() {
|
|
603
|
+
return ["", []];
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
/**
|
|
607
|
+
* Creates an identifier escaping function that wraps names in the given
|
|
608
|
+
* delimiter, doubles delimiter characters, and escapes dots between identifier
|
|
609
|
+
* parts.
|
|
610
|
+
*
|
|
611
|
+
* @category constructors
|
|
612
|
+
* @since 4.0.0
|
|
613
|
+
*/
|
|
614
|
+
function defaultEscape(c) {
|
|
615
|
+
const re = new RegExp(c, "g");
|
|
616
|
+
const double = c + c;
|
|
617
|
+
const dot = c + "." + c;
|
|
618
|
+
return function(str) {
|
|
619
|
+
return c + str.replace(re, double).replace(/\./g, dot) + c;
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Builds value, object, and row-array transformers that rename object keys with
|
|
624
|
+
* the supplied function and optionally recurse into nested object arrays.
|
|
625
|
+
*
|
|
626
|
+
* @category transforming
|
|
627
|
+
* @since 4.0.0
|
|
628
|
+
*/
|
|
629
|
+
const defaultTransforms = (transformer, nested = true) => {
|
|
630
|
+
const transformValue = (value) => {
|
|
631
|
+
if (Array.isArray(value)) {
|
|
632
|
+
if (value.length === 0 || value[0].constructor !== Object) return value;
|
|
633
|
+
return array(value);
|
|
634
|
+
} else if (value?.constructor === Object) return transformObject(value);
|
|
635
|
+
return value;
|
|
636
|
+
};
|
|
637
|
+
const transformObject = (obj) => {
|
|
638
|
+
const newObj = {};
|
|
639
|
+
for (const key of Object.keys(obj)) assignProperty(newObj, transformer(key), transformValue(obj[key]));
|
|
640
|
+
return newObj;
|
|
641
|
+
};
|
|
642
|
+
const transformArrayNested = (rows) => {
|
|
643
|
+
const newRows = new Array(rows.length);
|
|
644
|
+
for (let i = 0, len = rows.length; i < len; i++) {
|
|
645
|
+
const row = rows[i];
|
|
646
|
+
if (Array.isArray(row)) newRows[i] = transformArrayNested(row);
|
|
647
|
+
else {
|
|
648
|
+
const obj = {};
|
|
649
|
+
for (const [key, value] of Object.entries(row)) assignProperty(obj, transformer(key), transformValue(value));
|
|
650
|
+
newRows[i] = obj;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return newRows;
|
|
654
|
+
};
|
|
655
|
+
const transformArray = (rows) => {
|
|
656
|
+
const newRows = new Array(rows.length);
|
|
657
|
+
for (let i = 0, len = rows.length; i < len; i++) {
|
|
658
|
+
const row = rows[i];
|
|
659
|
+
if (Array.isArray(row)) newRows[i] = transformArray(row);
|
|
660
|
+
else {
|
|
661
|
+
const obj = {};
|
|
662
|
+
for (const [key, value] of Object.entries(row)) assignProperty(obj, transformer(key), value);
|
|
663
|
+
newRows[i] = obj;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return newRows;
|
|
667
|
+
};
|
|
668
|
+
const array = nested ? transformArrayNested : transformArray;
|
|
669
|
+
return {
|
|
670
|
+
value: transformValue,
|
|
671
|
+
object: transformObject,
|
|
672
|
+
array
|
|
673
|
+
};
|
|
674
|
+
};
|
|
675
|
+
const ATTR_DB_OPERATION_NAME = "db.operation.name";
|
|
676
|
+
const ATTR_DB_QUERY_TEXT = "db.query.text";
|
|
677
|
+
const makeUnsafe$1 = (segments, acquirer, compiler, spanAttributes, transformRows, borrower) => {
|
|
678
|
+
const self = Object.create(StatementProto);
|
|
679
|
+
self.segments = segments;
|
|
680
|
+
self.acquirer = acquirer;
|
|
681
|
+
self.compiler = compiler;
|
|
682
|
+
self.spanAttributes = spanAttributes;
|
|
683
|
+
self.transformRows = transformRows;
|
|
684
|
+
self.borrower = borrower;
|
|
685
|
+
return self;
|
|
686
|
+
};
|
|
687
|
+
const StatementProto = {
|
|
688
|
+
[FragmentTypeId]: FragmentTypeId,
|
|
689
|
+
withConnection(operation, f, withoutTransform = false) {
|
|
690
|
+
return useSpan("sql.execute", { kind: "client" }, (span) => this.withConnectionSpan(operation, f, withoutTransform, span));
|
|
691
|
+
},
|
|
692
|
+
withConnectionSpan(operation, f, withoutTransform, span) {
|
|
693
|
+
return withStatement(this, span, (statement, fiber) => {
|
|
694
|
+
const [sql, params] = statement.compile(withoutTransform);
|
|
695
|
+
for (const [key, value] of this.spanAttributes) span.attribute(key, value);
|
|
696
|
+
span.attribute(ATTR_DB_OPERATION_NAME, operation);
|
|
697
|
+
span.attribute(ATTR_DB_QUERY_TEXT, sql);
|
|
698
|
+
const execute = this.borrower === void 0 ? scoped(flatMap(this.acquirer, (_) => f(_, sql, params))) : this.borrower((connection) => f(connection, sql, params));
|
|
699
|
+
return fiber.cache.tracerEnabled && fiber.getRef(SpanPropagationEnabled) ? provideService(execute, ParentSpan, span) : execute;
|
|
700
|
+
});
|
|
701
|
+
},
|
|
702
|
+
get withoutTransform() {
|
|
703
|
+
return this.withConnection("executeWithoutTransform", (connection, sql, params) => connection.execute(sql, params, void 0), true);
|
|
704
|
+
},
|
|
705
|
+
get raw() {
|
|
706
|
+
return this.withConnection("executeRaw", (connection, sql, params) => connection.executeRaw(sql, params), true);
|
|
707
|
+
},
|
|
708
|
+
get stream() {
|
|
709
|
+
const self = this;
|
|
710
|
+
return unwrap(flatMap(makeSpanScoped("sql.execute", { kind: "client" }), (span) => withStatement(self, span, (statement, fiber) => {
|
|
711
|
+
const [sql, params] = statement.compile();
|
|
712
|
+
for (const [key, value] of self.spanAttributes) span.attribute(key, value);
|
|
713
|
+
span.attribute(ATTR_DB_OPERATION_NAME, "executeStream");
|
|
714
|
+
span.attribute(ATTR_DB_QUERY_TEXT, sql);
|
|
715
|
+
const acquire = map(self.acquirer, (_) => _.executeStream(sql, params, self.transformRows));
|
|
716
|
+
return fiber.cache.tracerEnabled && fiber.getRef(SpanPropagationEnabled) ? succeed(provideService$1(unwrap(acquire), ParentSpan, span)) : acquire;
|
|
717
|
+
})));
|
|
718
|
+
},
|
|
719
|
+
get values() {
|
|
720
|
+
return this.withConnection("executeValues", (connection, sql, params) => connection.executeValues(sql, params));
|
|
721
|
+
},
|
|
722
|
+
get valuesUnprepared() {
|
|
723
|
+
return this.withConnection("executeValuesUnprepared", (connection, sql, params) => connection.executeValuesUnprepared(sql, params));
|
|
724
|
+
},
|
|
725
|
+
get unprepared() {
|
|
726
|
+
const self = this;
|
|
727
|
+
return self.withConnection("executeUnprepared", (connection, sql, params) => connection.executeUnprepared(sql, params, self.transformRows));
|
|
728
|
+
},
|
|
729
|
+
.../*#__PURE__*/ Prototype({
|
|
730
|
+
label: "Statement",
|
|
731
|
+
evaluate(fiber) {
|
|
732
|
+
const span = makeSpanUnsafe(fiber, "sql.execute", { kind: "client" });
|
|
733
|
+
const clock = fiber.getRef(Clock);
|
|
734
|
+
const timingEnabled = fiber.getRef(TracerTimingEnabled);
|
|
735
|
+
return onExit(this.withConnectionSpan("execute", (connection, sql, params) => connection.execute(sql, params, this.transformRows), false, span), (exit) => endSpan(span, exit, clock, timingEnabled));
|
|
736
|
+
}
|
|
737
|
+
}),
|
|
738
|
+
compile(withoutTransform) {
|
|
739
|
+
return this.compiler.compile(this, withoutTransform ?? false);
|
|
740
|
+
},
|
|
741
|
+
toJSON() {
|
|
742
|
+
const [sql, params] = this.compile();
|
|
743
|
+
return {
|
|
744
|
+
_id: "Statement",
|
|
745
|
+
segments: this.segments,
|
|
746
|
+
sql,
|
|
747
|
+
params
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
const withStatement = (self, span, f) => withFiber((fiber) => {
|
|
752
|
+
const transform = fiber.getRef(CurrentTransformer);
|
|
753
|
+
if (transform === void 0) return f(self, fiber);
|
|
754
|
+
return flatMap(transform(self, make$6(self.acquirer, self.compiler, self.spanAttributes, self.transformRows, self.borrower), fiber, span), (statement) => f(statement, fiber));
|
|
755
|
+
});
|
|
756
|
+
const isSegment = (u) => {
|
|
757
|
+
if (!hasProperty(u, "_tag")) return false;
|
|
758
|
+
switch (u._tag) {
|
|
759
|
+
case "Literal":
|
|
760
|
+
case "Parameter":
|
|
761
|
+
case "ArrayHelper":
|
|
762
|
+
case "RecordInsertHelper":
|
|
763
|
+
case "RecordUpdateHelper":
|
|
764
|
+
case "RecordUpdateHelperSingle":
|
|
765
|
+
case "Identifier":
|
|
766
|
+
case "Custom": return true;
|
|
767
|
+
default: return false;
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
function convertLiteralOrFragment(clause) {
|
|
771
|
+
if (typeof clause === "string") return [literal(clause)];
|
|
772
|
+
return clause.segments;
|
|
773
|
+
}
|
|
774
|
+
const makePlaceholdersArray = (evaluate) => (values) => {
|
|
775
|
+
if (values.length === 0) return "";
|
|
776
|
+
let result = evaluate(values[0]);
|
|
777
|
+
for (let i = 1; i < values.length; i++) result += `,${evaluate(values[i])}`;
|
|
778
|
+
return result;
|
|
779
|
+
};
|
|
780
|
+
const generateColumns = (keys, escape, withoutTransform) => {
|
|
781
|
+
if (keys.length === 0) return "()";
|
|
782
|
+
let str = `(${escape(keys[0], withoutTransform)}`;
|
|
783
|
+
for (let i = 1; i < keys.length; i++) str += `,${escape(keys[i], withoutTransform)}`;
|
|
784
|
+
return str + ")";
|
|
785
|
+
};
|
|
786
|
+
const extractPrimitive = (value, onCustom, placeholder, withoutTransform) => {
|
|
787
|
+
if (value === void 0) return null;
|
|
788
|
+
else if (isFragment(value)) {
|
|
789
|
+
const head = value.segments[0];
|
|
790
|
+
if (head._tag === "Custom") return onCustom(head, placeholder, withoutTransform)[1][0] ?? null;
|
|
791
|
+
else if (head._tag === "Parameter") return head.value;
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
return value;
|
|
795
|
+
};
|
|
796
|
+
const escapeSqlite = /*#__PURE__*/ defaultEscape("\"");
|
|
797
|
+
function in_() {
|
|
798
|
+
if (arguments.length === 1) return arrayHelper(arguments[0]);
|
|
799
|
+
const column = arguments[0];
|
|
800
|
+
const values = arguments[1];
|
|
801
|
+
return values.length === 0 ? neverFragment : fragment([
|
|
802
|
+
identifier(column),
|
|
803
|
+
literal(" IN "),
|
|
804
|
+
arrayHelper(values)
|
|
805
|
+
]);
|
|
806
|
+
}
|
|
807
|
+
const neverFragment = /*#__PURE__*/ fragment([/*#__PURE__*/ literal("1=0")]);
|
|
808
|
+
//#endregion
|
|
809
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/sql/SqlClient.js
|
|
810
|
+
/**
|
|
811
|
+
* Main SQL client service for tagged-template queries.
|
|
812
|
+
*
|
|
813
|
+
* `SqlClient` combines the tagged-template statement constructor with
|
|
814
|
+
* connection acquisition, dialect compilation, transactions, row transforms,
|
|
815
|
+
* tracing, and reactive query helpers. Driver integrations build this service
|
|
816
|
+
* from their connection and compiler pieces.
|
|
817
|
+
*
|
|
818
|
+
* @since 4.0.0
|
|
819
|
+
*/
|
|
820
|
+
const TypeId$5 = "~effect/sql/SqlClient";
|
|
821
|
+
/**
|
|
822
|
+
* Service tag for the active SQL client service.
|
|
823
|
+
*
|
|
824
|
+
* **When to use**
|
|
825
|
+
*
|
|
826
|
+
* Use to access or provide the SQL client used to build statements, stream
|
|
827
|
+
* rows, reserve connections, and run transactions.
|
|
828
|
+
*
|
|
829
|
+
* @category services
|
|
830
|
+
* @since 4.0.0
|
|
831
|
+
*/
|
|
832
|
+
const SqlClient = /*#__PURE__*/ Service("effect/sql/SqlClient");
|
|
833
|
+
let clientIdCounter = 0;
|
|
834
|
+
let transactionSemaphoreIdCounter = 0;
|
|
835
|
+
/**
|
|
836
|
+
* Constructs a `SqlClient` from connection acquirers, a compiler, transaction
|
|
837
|
+
* commands, tracing attributes, optional row transforms, and reactive query
|
|
838
|
+
* integration.
|
|
839
|
+
*
|
|
840
|
+
* @category constructors
|
|
841
|
+
* @since 4.0.0
|
|
842
|
+
*/
|
|
843
|
+
const make$5 = /*#__PURE__*/ fnUntraced(function* (options) {
|
|
844
|
+
const transactionService = options.transactionService ?? TransactionConnection(clientIdCounter++);
|
|
845
|
+
const getConnection = flatMap(serviceOption(transactionService), match({
|
|
846
|
+
onNone: () => options.acquirer,
|
|
847
|
+
onSome: ([conn]) => succeed(conn)
|
|
848
|
+
}));
|
|
849
|
+
const beginTransaction = options.beginTransaction ?? "BEGIN";
|
|
850
|
+
const commit = options.commit ?? "COMMIT";
|
|
851
|
+
const savepoint = options.savepoint ?? ((name) => `SAVEPOINT ${name}`);
|
|
852
|
+
const rollback = options.rollback ?? "ROLLBACK";
|
|
853
|
+
const rollbackSavepoint = options.rollbackSavepoint ?? ((name) => `ROLLBACK TO SAVEPOINT ${name}`);
|
|
854
|
+
const transactionAcquirer = options.transactionAcquirer ?? options.acquirer;
|
|
855
|
+
const control = options.prepareTransactionControls === true ? (conn, sql) => conn.execute(sql, [], void 0) : (conn, sql) => conn.executeUnprepared(sql, [], void 0);
|
|
856
|
+
const withTransaction = makeWithTransaction({
|
|
857
|
+
transactionService,
|
|
858
|
+
spanAttributes: options.spanAttributes,
|
|
859
|
+
acquireConnection: flatMap(make$8(), (scope) => map(provide(transactionAcquirer, scope), (conn) => [scope, conn])),
|
|
860
|
+
begin: (conn) => control(conn, beginTransaction),
|
|
861
|
+
savepoint: (conn, id) => control(conn, savepoint(`effect_sql_${id}`)),
|
|
862
|
+
commit: (conn) => control(conn, commit),
|
|
863
|
+
rollback: (conn) => control(conn, rollback),
|
|
864
|
+
rollbackSavepoint: (conn, id) => control(conn, rollbackSavepoint(`effect_sql_${id}`))
|
|
865
|
+
});
|
|
866
|
+
const reactivity = yield* Reactivity;
|
|
867
|
+
const borrower = options.borrower === void 0 ? void 0 : (f) => flatMap(serviceOption(transactionService), match({
|
|
868
|
+
onNone: () => options.borrower(f),
|
|
869
|
+
onSome: ([conn]) => f(conn)
|
|
870
|
+
}));
|
|
871
|
+
const client = Object.assign(make$6(getConnection, options.compiler, options.spanAttributes, options.transformRows, borrower), {
|
|
872
|
+
[TypeId$5]: TypeId$5,
|
|
873
|
+
safe: void 0,
|
|
874
|
+
withTransaction,
|
|
875
|
+
transactionService,
|
|
876
|
+
reserve: transactionAcquirer,
|
|
877
|
+
withoutTransforms() {
|
|
878
|
+
if (options.transformRows === void 0) return this;
|
|
879
|
+
const statement = make$6(getConnection, options.compiler.withoutTransform, options.spanAttributes, void 0, borrower);
|
|
880
|
+
const client = Object.assign(statement, {
|
|
881
|
+
...this,
|
|
882
|
+
...statement
|
|
883
|
+
});
|
|
884
|
+
client.safe = client;
|
|
885
|
+
client.withoutTransforms = () => client;
|
|
886
|
+
return client;
|
|
887
|
+
},
|
|
888
|
+
reactive: options.reactiveQueue ? (keys, effect) => options.reactiveQueue(keys, effect).pipe(map(fromQueue), unwrap) : reactivity.stream,
|
|
889
|
+
reactiveMailbox: options.reactiveQueue ?? reactivity.query
|
|
890
|
+
});
|
|
891
|
+
client.safe = client;
|
|
892
|
+
return client;
|
|
893
|
+
});
|
|
894
|
+
/**
|
|
895
|
+
* Builds a transaction wrapper that begins top-level transactions, uses
|
|
896
|
+
* savepoints for nested transactions, commits on success, and rolls back on
|
|
897
|
+
* failure or interruption.
|
|
898
|
+
*
|
|
899
|
+
* @category transactions
|
|
900
|
+
* @since 4.0.0
|
|
901
|
+
*/
|
|
902
|
+
const makeWithTransaction = (options) => {
|
|
903
|
+
const transactionSemaphore = Service(`effect/sql/SqlClient/TransactionSemaphore/${transactionSemaphoreIdCounter++}`);
|
|
904
|
+
return (effect) => uninterruptibleMask((restore) => useSpan("sql.transaction", { kind: "client" }, (span) => withFiber((fiber) => {
|
|
905
|
+
for (const [key, value] of options.spanAttributes) span.attribute(key, value);
|
|
906
|
+
const services = fiber.context;
|
|
907
|
+
const clock = fiber.getRef(Clock);
|
|
908
|
+
const connOption = getOption(services, options.transactionService);
|
|
909
|
+
const conn = connOption._tag === "Some" ? succeed([void 0, connOption.value[0]]) : options.acquireConnection;
|
|
910
|
+
const id = connOption._tag === "Some" ? connOption.value[1] + 1 : 0;
|
|
911
|
+
const transaction = flatMap(conn, ([scope, conn]) => (id === 0 ? options.begin(conn) : options.savepoint(conn, id)).pipe(flatMap(() => onExitPrimitive(provideContext(restore(effect), services.pipe(add(options.transactionService, [conn, id]), add(transactionSemaphore, makeUnsafe$3(1)), add(ParentSpan, span))), (exit) => {
|
|
912
|
+
let effect;
|
|
913
|
+
if (isSuccess(exit)) {
|
|
914
|
+
if (id === 0) {
|
|
915
|
+
span.event("db.transaction.commit", clock.currentTimeNanosUnsafe());
|
|
916
|
+
effect = orDie(options.commit(conn));
|
|
917
|
+
} else {
|
|
918
|
+
span.event("db.transaction.savepoint", clock.currentTimeNanosUnsafe());
|
|
919
|
+
effect = void_$1;
|
|
920
|
+
}
|
|
921
|
+
} else {
|
|
922
|
+
span.event("db.transaction.rollback", clock.currentTimeNanosUnsafe());
|
|
923
|
+
effect = orDie(id > 0 ? options.rollbackSavepoint(conn, id) : options.rollback(conn));
|
|
924
|
+
}
|
|
925
|
+
return flatMap(effect, () => exit);
|
|
926
|
+
}, true)), scope ? (eff) => onExitPrimitive(eff, (exit) => close(scope, exit), true) : identity));
|
|
927
|
+
return id === 0 ? transaction : getUnsafe(services, transactionSemaphore).withPermit(transaction);
|
|
928
|
+
})));
|
|
929
|
+
};
|
|
930
|
+
/**
|
|
931
|
+
* Creates a unique context service tag for the active transaction connection of
|
|
932
|
+
* a specific SQL client.
|
|
933
|
+
*
|
|
934
|
+
* @category services
|
|
935
|
+
* @since 4.0.0
|
|
936
|
+
*/
|
|
937
|
+
const TransactionConnection = (clientId) => Service(`effect/sql/SqlClient/TransactionConnection/${clientId}`);
|
|
938
|
+
/**
|
|
939
|
+
* Context reference used by SQL integrations to opt in to safe integer
|
|
940
|
+
* handling; defaults to `false`.
|
|
941
|
+
*
|
|
942
|
+
* @category services
|
|
943
|
+
* @since 4.0.0
|
|
944
|
+
*/
|
|
945
|
+
const SafeIntegers = /*#__PURE__*/ Reference("effect/sql/SqlClient/SafeIntegers", { defaultValue: () => false });
|
|
946
|
+
//#endregion
|
|
947
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/Cache.js
|
|
948
|
+
/**
|
|
949
|
+
* Caches values loaded by an Effect lookup function.
|
|
950
|
+
*
|
|
951
|
+
* A cache stores successful and failed lookup results, shares an in-progress
|
|
952
|
+
* lookup when multiple callers request the same missing key, and limits entries
|
|
953
|
+
* by capacity and optional time-to-live rules. This module includes helpers for
|
|
954
|
+
* reading, setting, refreshing, invalidating, and inspecting cache contents.
|
|
955
|
+
*
|
|
956
|
+
* @since 4.0.0
|
|
957
|
+
*/
|
|
958
|
+
const TypeId$4 = "~effect/Cache";
|
|
959
|
+
/**
|
|
960
|
+
* Creates a cache with dynamic time-to-live based on the result and key.
|
|
961
|
+
*
|
|
962
|
+
* **When to use**
|
|
963
|
+
*
|
|
964
|
+
* Use when you need different cache entry lifetimes based on the lookup result
|
|
965
|
+
* or key characteristics.
|
|
966
|
+
*
|
|
967
|
+
* **Details**
|
|
968
|
+
*
|
|
969
|
+
* The timeToLive function receives both the exit result and the key, allowing
|
|
970
|
+
* for flexible TTL policies based on success/failure state and key characteristics.
|
|
971
|
+
*
|
|
972
|
+
* **Example** (Configuring dynamic time to live)
|
|
973
|
+
*
|
|
974
|
+
* ```ts import.meta.vitest
|
|
975
|
+
* import { Cache, Effect, Exit } from "effect"
|
|
976
|
+
*
|
|
977
|
+
* // Cache with TTL based on computed value
|
|
978
|
+
* const program = Effect.gen(function*() {
|
|
979
|
+
* const cache = yield* Cache.makeWith(
|
|
980
|
+
* (id: number) => Effect.succeed({ id, active: id % 2 === 0 }),
|
|
981
|
+
* {
|
|
982
|
+
* capacity: 1000,
|
|
983
|
+
* timeToLive(exit) {
|
|
984
|
+
* if (Exit.isSuccess(exit)) {
|
|
985
|
+
* const user = exit.value
|
|
986
|
+
* return user.active ? "1 hour" : "5 minutes"
|
|
987
|
+
* }
|
|
988
|
+
* return "30 seconds"
|
|
989
|
+
* }
|
|
990
|
+
* }
|
|
991
|
+
* )
|
|
992
|
+
*
|
|
993
|
+
* return cache.capacity
|
|
994
|
+
* })
|
|
995
|
+
*
|
|
996
|
+
* const actual = await Effect.runPromise(program)
|
|
997
|
+
* actual // => 1000
|
|
998
|
+
* ```
|
|
999
|
+
*
|
|
1000
|
+
* @see {@link make} for a simpler cache constructor with a fixed time-to-live for all entries
|
|
1001
|
+
* @category constructors
|
|
1002
|
+
* @since 2.0.0
|
|
1003
|
+
*/
|
|
1004
|
+
const makeWith = (lookup, options) => contextWith$1((context) => {
|
|
1005
|
+
const self = Object.create(Proto$1);
|
|
1006
|
+
self.lookup = (key) => updateContext(lookup(key), (input) => merge(context, input));
|
|
1007
|
+
self.map = make$12();
|
|
1008
|
+
self.capacity = options.capacity;
|
|
1009
|
+
self.timeToLive = options.timeToLive ? (exit, key) => fromInputUnsafe(options.timeToLive(exit, key)) : defaultTimeToLive;
|
|
1010
|
+
return succeed$1(self);
|
|
1011
|
+
});
|
|
1012
|
+
/**
|
|
1013
|
+
* Creates a cache with a fixed time-to-live for all entries.
|
|
1014
|
+
*
|
|
1015
|
+
* **Details**
|
|
1016
|
+
*
|
|
1017
|
+
* This is the basic cache constructor where all entries share the same TTL.
|
|
1018
|
+
* The lookup function will be called when a key is not found or has expired.
|
|
1019
|
+
*
|
|
1020
|
+
* **Example** (Creating a basic cache)
|
|
1021
|
+
*
|
|
1022
|
+
* ```ts import.meta.vitest
|
|
1023
|
+
* import { Cache, Effect } from "effect"
|
|
1024
|
+
*
|
|
1025
|
+
* // Basic cache with string keys
|
|
1026
|
+
* const program = Effect.gen(function*() {
|
|
1027
|
+
* const cache = yield* Cache.make<string, number>({
|
|
1028
|
+
* capacity: 100,
|
|
1029
|
+
* lookup: (key) => Effect.succeed(key.length)
|
|
1030
|
+
* })
|
|
1031
|
+
*
|
|
1032
|
+
* const result1 = yield* Cache.get(cache, "hello")
|
|
1033
|
+
* const result2 = yield* Cache.get(cache, "world")
|
|
1034
|
+
* return { result1, result2 }
|
|
1035
|
+
* })
|
|
1036
|
+
*
|
|
1037
|
+
* const actual = await Effect.runPromise(program)
|
|
1038
|
+
* actual // => { result1: 5, result2: 5 }
|
|
1039
|
+
* ```
|
|
1040
|
+
*
|
|
1041
|
+
* **Example** (Creating a cache with TTL)
|
|
1042
|
+
*
|
|
1043
|
+
* ```ts import.meta.vitest
|
|
1044
|
+
* import { Cache, Effect } from "effect"
|
|
1045
|
+
*
|
|
1046
|
+
* const program = Effect.gen(function*() {
|
|
1047
|
+
* const users = new Map([
|
|
1048
|
+
* [123, { name: "Ada", email: "ada@example.com" }],
|
|
1049
|
+
* [456, { name: "Grace", email: "grace@example.com" }]
|
|
1050
|
+
* ])
|
|
1051
|
+
*
|
|
1052
|
+
* const cache = yield* Cache.make<
|
|
1053
|
+
* number,
|
|
1054
|
+
* { name: string; email: string },
|
|
1055
|
+
* string
|
|
1056
|
+
* >({
|
|
1057
|
+
* capacity: 500,
|
|
1058
|
+
* lookup: (userId) =>
|
|
1059
|
+
* Effect.suspend(() => {
|
|
1060
|
+
* const user = users.get(userId)
|
|
1061
|
+
* return user === undefined
|
|
1062
|
+
* ? Effect.fail(`User ${userId} not found`)
|
|
1063
|
+
* : Effect.succeed(user)
|
|
1064
|
+
* }),
|
|
1065
|
+
* timeToLive: "15 minutes"
|
|
1066
|
+
* })
|
|
1067
|
+
*
|
|
1068
|
+
* const user1 = yield* Cache.get(cache, 123)
|
|
1069
|
+
* const user2 = yield* Cache.get(cache, 123)
|
|
1070
|
+
* return [user1, user2, user1 === user2] as const
|
|
1071
|
+
* })
|
|
1072
|
+
*
|
|
1073
|
+
* const actual = await Effect.runPromise(program)
|
|
1074
|
+
* actual // => [{ name: "Ada", email: "ada@example.com" }, { name: "Ada", email: "ada@example.com" }, true]
|
|
1075
|
+
* ```
|
|
1076
|
+
*
|
|
1077
|
+
* @category constructors
|
|
1078
|
+
* @since 2.0.0
|
|
1079
|
+
*/
|
|
1080
|
+
const make$4 = (options) => makeWith(options.lookup, {
|
|
1081
|
+
...options,
|
|
1082
|
+
timeToLive: options.timeToLive !== void 0 ? () => options.timeToLive : defaultTimeToLive
|
|
1083
|
+
});
|
|
1084
|
+
const Proto$1 = {
|
|
1085
|
+
...PipeInspectableProto,
|
|
1086
|
+
[TypeId$4]: TypeId$4,
|
|
1087
|
+
toJSON() {
|
|
1088
|
+
return {
|
|
1089
|
+
_id: "Cache",
|
|
1090
|
+
capacity: this.capacity,
|
|
1091
|
+
map: this.map
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
const defaultTimeToLive = (_, _key) => infinity;
|
|
1096
|
+
/**
|
|
1097
|
+
* Retrieves the value for a key, invoking the lookup function on a cache miss
|
|
1098
|
+
* or expired entry.
|
|
1099
|
+
*
|
|
1100
|
+
* **Details**
|
|
1101
|
+
*
|
|
1102
|
+
* Concurrent `get` calls for the same missing key share the same pending
|
|
1103
|
+
* lookup. The cache stores the lookup `Exit`, so failed lookups are cached and
|
|
1104
|
+
* will fail again until the entry expires, is invalidated, or is refreshed.
|
|
1105
|
+
*
|
|
1106
|
+
* **Example** (Getting cached values)
|
|
1107
|
+
*
|
|
1108
|
+
* ```ts import.meta.vitest
|
|
1109
|
+
* import { Cache, Effect } from "effect"
|
|
1110
|
+
*
|
|
1111
|
+
* const program = Effect.gen(function*() {
|
|
1112
|
+
* const cache = yield* Cache.make({
|
|
1113
|
+
* capacity: 10,
|
|
1114
|
+
* lookup: (key: string) => Effect.succeed(key.length)
|
|
1115
|
+
* })
|
|
1116
|
+
*
|
|
1117
|
+
* // Cache miss - triggers lookup function
|
|
1118
|
+
* const result1 = yield* Cache.get(cache, "hello")
|
|
1119
|
+
*
|
|
1120
|
+
* // Cache hit - returns cached value without lookup
|
|
1121
|
+
* const result2 = yield* Cache.get(cache, "hello")
|
|
1122
|
+
*
|
|
1123
|
+
* return { result1, result2 }
|
|
1124
|
+
* })
|
|
1125
|
+
*
|
|
1126
|
+
* const actual = await Effect.runPromise(program)
|
|
1127
|
+
* actual // => { result1: 5, result2: 5 }
|
|
1128
|
+
* ```
|
|
1129
|
+
*
|
|
1130
|
+
* **Example** (Handling lookup failures)
|
|
1131
|
+
*
|
|
1132
|
+
* ```ts import.meta.vitest
|
|
1133
|
+
* import { Cache, Effect, Exit } from "effect"
|
|
1134
|
+
*
|
|
1135
|
+
* // Error handling when lookup fails
|
|
1136
|
+
* const program = Effect.gen(function*() {
|
|
1137
|
+
* const cache = yield* Cache.make<string, number, string>({
|
|
1138
|
+
* capacity: 10,
|
|
1139
|
+
* lookup: (key: string) =>
|
|
1140
|
+
* key === "error"
|
|
1141
|
+
* ? Effect.fail("Lookup failed")
|
|
1142
|
+
* : Effect.succeed(key.length)
|
|
1143
|
+
* })
|
|
1144
|
+
*
|
|
1145
|
+
* // Successful lookup
|
|
1146
|
+
* const success = yield* Cache.get(cache, "hello")
|
|
1147
|
+
*
|
|
1148
|
+
* // Failed lookup - returns error
|
|
1149
|
+
* const failure = yield* Effect.exit(Cache.get(cache, "error"))
|
|
1150
|
+
* return [success, failure] as const
|
|
1151
|
+
* })
|
|
1152
|
+
*
|
|
1153
|
+
* const actual = await Effect.runPromise(program)
|
|
1154
|
+
* actual // => [5, Exit.fail("Lookup failed")]
|
|
1155
|
+
* ```
|
|
1156
|
+
*
|
|
1157
|
+
* **Example** (Sharing concurrent lookups)
|
|
1158
|
+
*
|
|
1159
|
+
* ```ts import.meta.vitest
|
|
1160
|
+
* import { Cache, Effect } from "effect"
|
|
1161
|
+
*
|
|
1162
|
+
* // Concurrent access - multiple gets of same key only invoke lookup once
|
|
1163
|
+
* const program = Effect.gen(function*() {
|
|
1164
|
+
* let lookupCount = 0
|
|
1165
|
+
* const cache = yield* Cache.make({
|
|
1166
|
+
* capacity: 10,
|
|
1167
|
+
* lookup: (key: string) =>
|
|
1168
|
+
* Effect.sync(() => {
|
|
1169
|
+
* lookupCount++
|
|
1170
|
+
* return key.length
|
|
1171
|
+
* })
|
|
1172
|
+
* })
|
|
1173
|
+
*
|
|
1174
|
+
* // Multiple concurrent gets
|
|
1175
|
+
* const results = yield* Effect.all([
|
|
1176
|
+
* Cache.get(cache, "hello"),
|
|
1177
|
+
* Cache.get(cache, "hello"),
|
|
1178
|
+
* Cache.get(cache, "hello")
|
|
1179
|
+
* ], { concurrency: "unbounded" })
|
|
1180
|
+
*
|
|
1181
|
+
* return { results, lookupCount }
|
|
1182
|
+
* })
|
|
1183
|
+
*
|
|
1184
|
+
* const actual = await Effect.runPromise(program)
|
|
1185
|
+
* actual // => { results: [5, 5, 5], lookupCount: 1 }
|
|
1186
|
+
* ```
|
|
1187
|
+
*
|
|
1188
|
+
* @category combinators
|
|
1189
|
+
* @since 4.0.0
|
|
1190
|
+
*/
|
|
1191
|
+
const get = /*#__PURE__*/ dual(2, (self, key) => withFiber$1((fiber) => {
|
|
1192
|
+
const oentry = get$2(self.map, key);
|
|
1193
|
+
if (isSome(oentry) && !hasExpired(oentry.value, fiber)) {
|
|
1194
|
+
remove(self.map, key);
|
|
1195
|
+
set(self.map, key, oentry.value);
|
|
1196
|
+
return oentry.value.await();
|
|
1197
|
+
}
|
|
1198
|
+
const entry = new EntryImpl(fiber, self.lookup(key));
|
|
1199
|
+
entry.fiber.addObserver((exit) => {
|
|
1200
|
+
if (exitHasInterrupts(exit)) {
|
|
1201
|
+
const current = get$2(self.map, key);
|
|
1202
|
+
if (isSome(current) && current.value === entry) remove(self.map, key);
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
const ttl = self.timeToLive(exit, key);
|
|
1206
|
+
if (isFinite(ttl)) entry.expiresAt = fiber.getRef(ClockRef).currentTimeMillisUnsafe() + toMillis(ttl);
|
|
1207
|
+
else if (isZero(ttl)) remove(self.map, key);
|
|
1208
|
+
});
|
|
1209
|
+
const exit = entry.fiber.pollUnsafe();
|
|
1210
|
+
if (exit === void 0 || !exitHasInterrupts(exit)) set(self.map, key, entry);
|
|
1211
|
+
if (Number.isFinite(self.capacity)) checkCapacity(self);
|
|
1212
|
+
return entry.await();
|
|
1213
|
+
}));
|
|
1214
|
+
var EntryImpl = class {
|
|
1215
|
+
expiresAt;
|
|
1216
|
+
awaiters;
|
|
1217
|
+
fiber;
|
|
1218
|
+
constructor(parent, valueEffect) {
|
|
1219
|
+
this.fiber = forkUnsafe(parent, valueEffect, true, true);
|
|
1220
|
+
this.awaiters = 0;
|
|
1221
|
+
this.expiresAt = void 0;
|
|
1222
|
+
}
|
|
1223
|
+
await() {
|
|
1224
|
+
const exit = this.fiber.pollUnsafe();
|
|
1225
|
+
if (exit) return exit;
|
|
1226
|
+
this.awaiters++;
|
|
1227
|
+
return onExit$1(fiberJoin(this.fiber), () => {
|
|
1228
|
+
this.awaiters--;
|
|
1229
|
+
if (this.awaiters > 0 || this.fiber.pollUnsafe()) return void_$2;
|
|
1230
|
+
return fiberInterrupt(this.fiber);
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
const hasExpired = (entry, fiber) => {
|
|
1235
|
+
if (entry.expiresAt === void 0) return false;
|
|
1236
|
+
return fiber.getRef(ClockRef).currentTimeMillisUnsafe() >= entry.expiresAt;
|
|
1237
|
+
};
|
|
1238
|
+
const checkCapacity = (self) => {
|
|
1239
|
+
let diff = size(self.map) - self.capacity;
|
|
1240
|
+
if (diff <= 0) return;
|
|
1241
|
+
for (const [key] of self.map) {
|
|
1242
|
+
remove(self.map, key);
|
|
1243
|
+
diff--;
|
|
1244
|
+
if (diff === 0) return;
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
//#endregion
|
|
1248
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/schema/VariantSchema.js
|
|
1249
|
+
/**
|
|
1250
|
+
* Runtime type identifier attached to variant schema structs.
|
|
1251
|
+
*
|
|
1252
|
+
* @category type IDs
|
|
1253
|
+
* @since 4.0.0
|
|
1254
|
+
*/
|
|
1255
|
+
const TypeId$3 = "~effect/schema/VariantSchema";
|
|
1256
|
+
const cacheSymbol = /*#__PURE__*/ Symbol.for(`${TypeId$3}/cache`);
|
|
1257
|
+
const defaultCacheSymbol = /*#__PURE__*/ Symbol.for(`${TypeId$3}/defaultCache`);
|
|
1258
|
+
/**
|
|
1259
|
+
* Returns `true` when a value is a variant schema struct.
|
|
1260
|
+
*
|
|
1261
|
+
* @category guards
|
|
1262
|
+
* @since 4.0.0
|
|
1263
|
+
*/
|
|
1264
|
+
const isStruct = (u) => hasProperty(u, TypeId$3);
|
|
1265
|
+
const FieldTypeId = "~effect/schema/VariantSchema/Field";
|
|
1266
|
+
/**
|
|
1267
|
+
* Returns `true` when a value is a variant schema field.
|
|
1268
|
+
*
|
|
1269
|
+
* @category guards
|
|
1270
|
+
* @since 4.0.0
|
|
1271
|
+
*/
|
|
1272
|
+
const isField = (u) => hasProperty(u, FieldTypeId);
|
|
1273
|
+
const extract$1 = /*#__PURE__*/ dual((args) => isStruct(args[0]), (self, variant, options) => {
|
|
1274
|
+
if (options?.isDefault === true && isSchema(self)) return self;
|
|
1275
|
+
const cache = options?.isDefault === true ? self[defaultCacheSymbol] ?? (self[defaultCacheSymbol] = Object.create(null)) : self[cacheSymbol] ?? (self[cacheSymbol] = Object.create(null));
|
|
1276
|
+
if (Object.hasOwn(cache, variant)) return cache[variant];
|
|
1277
|
+
const fields = {};
|
|
1278
|
+
for (const key of Object.keys(self[TypeId$3])) {
|
|
1279
|
+
const value = self[TypeId$3][key];
|
|
1280
|
+
if (value === void 0) continue;
|
|
1281
|
+
if ("~effect/schema/VariantSchema" in value) {
|
|
1282
|
+
if (options?.isDefault === true && isSchema(value)) assignProperty(fields, key, value);
|
|
1283
|
+
else assignProperty(fields, key, extract$1(value, variant));
|
|
1284
|
+
} else if (FieldTypeId in value) {
|
|
1285
|
+
if (Object.hasOwn(value.schemas, variant)) {
|
|
1286
|
+
const schema = value.schemas[variant];
|
|
1287
|
+
if (schema !== void 0) assignProperty(fields, key, schema);
|
|
1288
|
+
}
|
|
1289
|
+
} else assignProperty(fields, key, value);
|
|
1290
|
+
}
|
|
1291
|
+
const schema = Struct$2(fields);
|
|
1292
|
+
cache[variant] = schema;
|
|
1293
|
+
return schema;
|
|
1294
|
+
});
|
|
1295
|
+
/**
|
|
1296
|
+
* Creates a variant schema toolkit for a fixed set of variant names and a default
|
|
1297
|
+
* variant.
|
|
1298
|
+
*
|
|
1299
|
+
* @category constructors
|
|
1300
|
+
* @since 4.0.0
|
|
1301
|
+
*/
|
|
1302
|
+
const make$3 = (options) => {
|
|
1303
|
+
function Class(identifier) {
|
|
1304
|
+
return function(fields, annotations) {
|
|
1305
|
+
const variantStruct = Struct$1(fields);
|
|
1306
|
+
const schema = extract$1(variantStruct, options.defaultVariant, { isDefault: true });
|
|
1307
|
+
const SClass = Class$1;
|
|
1308
|
+
class Base extends SClass(identifier)(schema.fields, annotations) {
|
|
1309
|
+
static [TypeId$3] = fields;
|
|
1310
|
+
}
|
|
1311
|
+
for (const variant of options.variants) Object.defineProperty(Base, variant, { value: extract$1(variantStruct, variant).annotate({
|
|
1312
|
+
id: `${identifier}.${variant}`,
|
|
1313
|
+
title: `${identifier}.${variant}`
|
|
1314
|
+
}) });
|
|
1315
|
+
return Base;
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
function FieldOnly(keys) {
|
|
1319
|
+
return function(schema) {
|
|
1320
|
+
const obj = {};
|
|
1321
|
+
for (const key of keys) assignProperty(obj, key, schema);
|
|
1322
|
+
return Field$1(obj);
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function FieldExcept(keys) {
|
|
1326
|
+
return function(schema) {
|
|
1327
|
+
const obj = {};
|
|
1328
|
+
for (const variant of options.variants) if (!keys.includes(variant)) assignProperty(obj, variant, schema);
|
|
1329
|
+
return Field$1(obj);
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
function UnionVariants(members) {
|
|
1333
|
+
return Union$1(members, options.defaultVariant, options.variants);
|
|
1334
|
+
}
|
|
1335
|
+
const fieldEvolve = dual(2, (self, f) => {
|
|
1336
|
+
const field = isField(self) ? self : Field$1(Object.fromEntries(options.variants.map((variant) => [variant, self])));
|
|
1337
|
+
return Field$1(evolve(field.schemas, f));
|
|
1338
|
+
});
|
|
1339
|
+
const extractVariants = dual(2, (self, variant) => extract$1(self, variant, { isDefault: variant === options.defaultVariant }));
|
|
1340
|
+
return {
|
|
1341
|
+
Struct: Struct$1,
|
|
1342
|
+
Field: Field$1,
|
|
1343
|
+
FieldOnly,
|
|
1344
|
+
FieldExcept,
|
|
1345
|
+
Class,
|
|
1346
|
+
Union: UnionVariants,
|
|
1347
|
+
fieldEvolve,
|
|
1348
|
+
extract: extractVariants
|
|
1349
|
+
};
|
|
1350
|
+
};
|
|
1351
|
+
const StructProto = { pipe() {
|
|
1352
|
+
return pipeArguments(this, arguments);
|
|
1353
|
+
} };
|
|
1354
|
+
const Struct$1 = (fields) => {
|
|
1355
|
+
const self = Object.create(StructProto);
|
|
1356
|
+
self[TypeId$3] = fields;
|
|
1357
|
+
return self;
|
|
1358
|
+
};
|
|
1359
|
+
const FieldProto = {
|
|
1360
|
+
[FieldTypeId]: FieldTypeId,
|
|
1361
|
+
pipe() {
|
|
1362
|
+
return pipeArguments(this, arguments);
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
const Field$1 = (schemas) => {
|
|
1366
|
+
const self = Object.create(FieldProto);
|
|
1367
|
+
self.schemas = schemas;
|
|
1368
|
+
return self;
|
|
1369
|
+
};
|
|
1370
|
+
const Union$1 = (members, defaultVariant, variants) => {
|
|
1371
|
+
const VariantUnion = Union$2(members.map((member) => isSchema(member) ? member : extract$1(member, defaultVariant, { isDefault: true })));
|
|
1372
|
+
for (const variant of variants) Object.defineProperty(VariantUnion, variant, { value: Union$2(members.map((member) => extract$1(member, variant))) });
|
|
1373
|
+
return VariantUnion;
|
|
1374
|
+
};
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/schema/Model.js
|
|
1377
|
+
const { Class, Field, FieldExcept, FieldOnly, Struct, Union, extract, fieldEvolve } = /*#__PURE__*/ make$3({
|
|
1378
|
+
variants: [
|
|
1379
|
+
"select",
|
|
1380
|
+
"insert",
|
|
1381
|
+
"update",
|
|
1382
|
+
"json",
|
|
1383
|
+
"jsonCreate",
|
|
1384
|
+
"jsonUpdate"
|
|
1385
|
+
],
|
|
1386
|
+
defaultVariant: "select"
|
|
1387
|
+
});
|
|
1388
|
+
//#endregion
|
|
1389
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/sql/SqlError.js
|
|
1390
|
+
/**
|
|
1391
|
+
* Defines structured failures for SQL clients and driver integrations.
|
|
1392
|
+
*
|
|
1393
|
+
* `SqlError` wraps the different reasons a SQL operation can fail, such as
|
|
1394
|
+
* connection, authentication, authorization, syntax, constraint, or transaction
|
|
1395
|
+
* problems. Each reason keeps the original cause, optional message and
|
|
1396
|
+
* operation metadata, and whether retrying may succeed. This module also
|
|
1397
|
+
* includes schemas, guards, a SQLite error classifier, and the
|
|
1398
|
+
* `ResultLengthMismatch` error used by ordered batched SQL resolvers.
|
|
1399
|
+
*
|
|
1400
|
+
* @since 4.0.0
|
|
1401
|
+
*/
|
|
1402
|
+
const TypeId$2 = "~effect/sql/SqlError";
|
|
1403
|
+
const ReasonTypeId = "~effect/sql/SqlError/Reason";
|
|
1404
|
+
const ReasonFields = {
|
|
1405
|
+
cause: /*#__PURE__*/ Defect(),
|
|
1406
|
+
message: /*#__PURE__*/ optional(String$1),
|
|
1407
|
+
operation: /*#__PURE__*/ optional(String$1)
|
|
1408
|
+
};
|
|
1409
|
+
/**
|
|
1410
|
+
* SQL error reason for connection or open failures; marked retryable.
|
|
1411
|
+
*
|
|
1412
|
+
* @category errors
|
|
1413
|
+
* @since 4.0.0
|
|
1414
|
+
*/
|
|
1415
|
+
var ConnectionError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/ConnectionError")("ConnectionError", ReasonFields)) {
|
|
1416
|
+
/**
|
|
1417
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1418
|
+
*
|
|
1419
|
+
* @since 4.0.0
|
|
1420
|
+
*/
|
|
1421
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1422
|
+
/**
|
|
1423
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1424
|
+
*
|
|
1425
|
+
* @since 4.0.0
|
|
1426
|
+
*/
|
|
1427
|
+
get isRetryable() {
|
|
1428
|
+
return true;
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
/**
|
|
1432
|
+
* SQL error reason for authentication failures such as invalid credentials; not
|
|
1433
|
+
* marked retryable.
|
|
1434
|
+
*
|
|
1435
|
+
* @category errors
|
|
1436
|
+
* @since 4.0.0
|
|
1437
|
+
*/
|
|
1438
|
+
var AuthenticationError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/AuthenticationError")("AuthenticationError", ReasonFields)) {
|
|
1439
|
+
/**
|
|
1440
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1441
|
+
*
|
|
1442
|
+
* @since 4.0.0
|
|
1443
|
+
*/
|
|
1444
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1445
|
+
/**
|
|
1446
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1447
|
+
*
|
|
1448
|
+
* @since 4.0.0
|
|
1449
|
+
*/
|
|
1450
|
+
get isRetryable() {
|
|
1451
|
+
return false;
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
/**
|
|
1455
|
+
* SQL error reason for authorization or permission failures; not marked
|
|
1456
|
+
* retryable.
|
|
1457
|
+
*
|
|
1458
|
+
* @category errors
|
|
1459
|
+
* @since 4.0.0
|
|
1460
|
+
*/
|
|
1461
|
+
var AuthorizationError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/AuthorizationError")("AuthorizationError", ReasonFields)) {
|
|
1462
|
+
/**
|
|
1463
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1464
|
+
*
|
|
1465
|
+
* @since 4.0.0
|
|
1466
|
+
*/
|
|
1467
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1468
|
+
/**
|
|
1469
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1470
|
+
*
|
|
1471
|
+
* @since 4.0.0
|
|
1472
|
+
*/
|
|
1473
|
+
get isRetryable() {
|
|
1474
|
+
return false;
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
/**
|
|
1478
|
+
* SQL error reason for invalid SQL syntax; not marked retryable.
|
|
1479
|
+
*
|
|
1480
|
+
* @category errors
|
|
1481
|
+
* @since 4.0.0
|
|
1482
|
+
*/
|
|
1483
|
+
var SqlSyntaxError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/SqlSyntaxError")("SqlSyntaxError", ReasonFields)) {
|
|
1484
|
+
/**
|
|
1485
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1486
|
+
*
|
|
1487
|
+
* @since 4.0.0
|
|
1488
|
+
*/
|
|
1489
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1490
|
+
/**
|
|
1491
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1492
|
+
*
|
|
1493
|
+
* @since 4.0.0
|
|
1494
|
+
*/
|
|
1495
|
+
get isRetryable() {
|
|
1496
|
+
return false;
|
|
1497
|
+
}
|
|
1498
|
+
};
|
|
1499
|
+
const UniqueViolationFields = {
|
|
1500
|
+
...ReasonFields,
|
|
1501
|
+
constraint: String$1
|
|
1502
|
+
};
|
|
1503
|
+
/**
|
|
1504
|
+
* SQL error reason for a unique constraint violation, including the violated
|
|
1505
|
+
* constraint identifier; not marked retryable.
|
|
1506
|
+
*
|
|
1507
|
+
* @category errors
|
|
1508
|
+
* @since 4.0.0
|
|
1509
|
+
*/
|
|
1510
|
+
var UniqueViolation = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/UniqueViolation")("UniqueViolation", UniqueViolationFields)) {
|
|
1511
|
+
/**
|
|
1512
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1513
|
+
*
|
|
1514
|
+
* @since 4.0.0
|
|
1515
|
+
*/
|
|
1516
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1517
|
+
/**
|
|
1518
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1519
|
+
*
|
|
1520
|
+
* @since 4.0.0
|
|
1521
|
+
*/
|
|
1522
|
+
get isRetryable() {
|
|
1523
|
+
return false;
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
/**
|
|
1527
|
+
* SQL error reason for a non-unique constraint violation; not marked retryable.
|
|
1528
|
+
*
|
|
1529
|
+
* @category errors
|
|
1530
|
+
* @since 4.0.0
|
|
1531
|
+
*/
|
|
1532
|
+
var ConstraintError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/ConstraintError")("ConstraintError", ReasonFields)) {
|
|
1533
|
+
/**
|
|
1534
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1535
|
+
*
|
|
1536
|
+
* @since 4.0.0
|
|
1537
|
+
*/
|
|
1538
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1539
|
+
/**
|
|
1540
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1541
|
+
*
|
|
1542
|
+
* @since 4.0.0
|
|
1543
|
+
*/
|
|
1544
|
+
get isRetryable() {
|
|
1545
|
+
return false;
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
/**
|
|
1549
|
+
* SQL error reason for a database deadlock; marked retryable.
|
|
1550
|
+
*
|
|
1551
|
+
* @category errors
|
|
1552
|
+
* @since 4.0.0
|
|
1553
|
+
*/
|
|
1554
|
+
var DeadlockError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/DeadlockError")("DeadlockError", ReasonFields)) {
|
|
1555
|
+
/**
|
|
1556
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1557
|
+
*
|
|
1558
|
+
* @since 4.0.0
|
|
1559
|
+
*/
|
|
1560
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1561
|
+
/**
|
|
1562
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1563
|
+
*
|
|
1564
|
+
* @since 4.0.0
|
|
1565
|
+
*/
|
|
1566
|
+
get isRetryable() {
|
|
1567
|
+
return true;
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
/**
|
|
1571
|
+
* SQL error reason for a transaction serialization or isolation conflict;
|
|
1572
|
+
* marked retryable.
|
|
1573
|
+
*
|
|
1574
|
+
* @category errors
|
|
1575
|
+
* @since 4.0.0
|
|
1576
|
+
*/
|
|
1577
|
+
var SerializationError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/SerializationError")("SerializationError", ReasonFields)) {
|
|
1578
|
+
/**
|
|
1579
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1580
|
+
*
|
|
1581
|
+
* @since 4.0.0
|
|
1582
|
+
*/
|
|
1583
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1584
|
+
/**
|
|
1585
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1586
|
+
*
|
|
1587
|
+
* @since 4.0.0
|
|
1588
|
+
*/
|
|
1589
|
+
get isRetryable() {
|
|
1590
|
+
return true;
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
/**
|
|
1594
|
+
* SQL error reason for timing out while waiting on a database lock; marked
|
|
1595
|
+
* retryable.
|
|
1596
|
+
*
|
|
1597
|
+
* @category errors
|
|
1598
|
+
* @since 4.0.0
|
|
1599
|
+
*/
|
|
1600
|
+
var LockTimeoutError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/LockTimeoutError")("LockTimeoutError", ReasonFields)) {
|
|
1601
|
+
/**
|
|
1602
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1603
|
+
*
|
|
1604
|
+
* @since 4.0.0
|
|
1605
|
+
*/
|
|
1606
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1607
|
+
/**
|
|
1608
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1609
|
+
*
|
|
1610
|
+
* @since 4.0.0
|
|
1611
|
+
*/
|
|
1612
|
+
get isRetryable() {
|
|
1613
|
+
return true;
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
/**
|
|
1617
|
+
* SQL error reason for a statement or query timeout; marked retryable.
|
|
1618
|
+
*
|
|
1619
|
+
* @category errors
|
|
1620
|
+
* @since 4.0.0
|
|
1621
|
+
*/
|
|
1622
|
+
var StatementTimeoutError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/StatementTimeoutError")("StatementTimeoutError", ReasonFields)) {
|
|
1623
|
+
/**
|
|
1624
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1625
|
+
*
|
|
1626
|
+
* @since 4.0.0
|
|
1627
|
+
*/
|
|
1628
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1629
|
+
/**
|
|
1630
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1631
|
+
*
|
|
1632
|
+
* @since 4.0.0
|
|
1633
|
+
*/
|
|
1634
|
+
get isRetryable() {
|
|
1635
|
+
return true;
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1638
|
+
/**
|
|
1639
|
+
* SQL error reason for an unclassified database failure; not marked retryable.
|
|
1640
|
+
*
|
|
1641
|
+
* @category errors
|
|
1642
|
+
* @since 4.0.0
|
|
1643
|
+
*/
|
|
1644
|
+
var UnknownError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError/UnknownError")("UnknownError", ReasonFields)) {
|
|
1645
|
+
/**
|
|
1646
|
+
* Marks this value as a structured SQL error reason for runtime guards.
|
|
1647
|
+
*
|
|
1648
|
+
* @since 4.0.0
|
|
1649
|
+
*/
|
|
1650
|
+
[ReasonTypeId] = ReasonTypeId;
|
|
1651
|
+
/**
|
|
1652
|
+
* Indicates whether retrying the failed SQL operation may succeed.
|
|
1653
|
+
*
|
|
1654
|
+
* @since 4.0.0
|
|
1655
|
+
*/
|
|
1656
|
+
get isRetryable() {
|
|
1657
|
+
return false;
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
/**
|
|
1661
|
+
* Schema for encoding and decoding SQL error reasons.
|
|
1662
|
+
*
|
|
1663
|
+
* @category schemas
|
|
1664
|
+
* @since 4.0.0
|
|
1665
|
+
*/
|
|
1666
|
+
const SqlErrorReason = /*#__PURE__*/ Union$2([
|
|
1667
|
+
ConnectionError,
|
|
1668
|
+
AuthenticationError,
|
|
1669
|
+
AuthorizationError,
|
|
1670
|
+
SqlSyntaxError,
|
|
1671
|
+
UniqueViolation,
|
|
1672
|
+
ConstraintError,
|
|
1673
|
+
DeadlockError,
|
|
1674
|
+
SerializationError,
|
|
1675
|
+
LockTimeoutError,
|
|
1676
|
+
StatementTimeoutError,
|
|
1677
|
+
UnknownError
|
|
1678
|
+
]);
|
|
1679
|
+
/**
|
|
1680
|
+
* Error wrapper for SQL failures whose `message`, `cause`, and `isRetryable`
|
|
1681
|
+
* values are derived from its `SqlErrorReason`.
|
|
1682
|
+
*
|
|
1683
|
+
* @category errors
|
|
1684
|
+
* @since 4.0.0
|
|
1685
|
+
*/
|
|
1686
|
+
var SqlError = class extends (/*#__PURE__*/ TaggedError("effect/sql/SqlError")("SqlError", { reason: SqlErrorReason })) {
|
|
1687
|
+
/**
|
|
1688
|
+
* Marks this value as the top-level SQL error wrapper for runtime guards.
|
|
1689
|
+
*
|
|
1690
|
+
* @since 4.0.0
|
|
1691
|
+
*/
|
|
1692
|
+
[TypeId$2] = TypeId$2;
|
|
1693
|
+
/**
|
|
1694
|
+
* Exposes the structured SQL reason as the JavaScript error cause.
|
|
1695
|
+
*
|
|
1696
|
+
* @since 4.0.0
|
|
1697
|
+
*/
|
|
1698
|
+
cause = this.reason;
|
|
1699
|
+
/**
|
|
1700
|
+
* Uses the reason message when present, otherwise falls back to the reason tag.
|
|
1701
|
+
*
|
|
1702
|
+
* @since 4.0.0
|
|
1703
|
+
*/
|
|
1704
|
+
get message() {
|
|
1705
|
+
return this.reason.message || this.reason._tag;
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Delegates retryability to the underlying SQL error reason.
|
|
1709
|
+
*
|
|
1710
|
+
* @since 4.0.0
|
|
1711
|
+
*/
|
|
1712
|
+
get isRetryable() {
|
|
1713
|
+
return this.reason.isRetryable;
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
const sqliteCodeFromCause = (cause) => {
|
|
1717
|
+
if (!hasProperty(cause, "code")) return;
|
|
1718
|
+
const code = cause.code;
|
|
1719
|
+
return typeof code === "string" || typeof code === "number" ? code : void 0;
|
|
1720
|
+
};
|
|
1721
|
+
const sqliteNumericCodeFromCause = (cause) => {
|
|
1722
|
+
const code = sqliteCodeFromCause(cause);
|
|
1723
|
+
if (typeof code === "number") return code;
|
|
1724
|
+
if (!hasProperty(cause, "errno")) return;
|
|
1725
|
+
const errno = cause.errno;
|
|
1726
|
+
return typeof errno === "number" ? errno : void 0;
|
|
1727
|
+
};
|
|
1728
|
+
const matchesSqliteNumericCode = (cause, expected) => {
|
|
1729
|
+
if (sqliteCodeFromCause(cause) === expected) return true;
|
|
1730
|
+
if (!hasProperty(cause, "errno")) return false;
|
|
1731
|
+
return cause.errno === expected;
|
|
1732
|
+
};
|
|
1733
|
+
const matchesSqliteCode = (code, expected) => code === expected || code.startsWith(expected + "_");
|
|
1734
|
+
const UNKNOWN_CONSTRAINT = "unknown";
|
|
1735
|
+
const SQLITE_CONSTRAINT_UNIQUE = "SQLITE_CONSTRAINT_UNIQUE";
|
|
1736
|
+
const SQLITE_CONSTRAINT_UNIQUE_CODE = 2067;
|
|
1737
|
+
const normalizeConstraintIdentifier = (identifier) => {
|
|
1738
|
+
if (typeof identifier !== "string") return UNKNOWN_CONSTRAINT;
|
|
1739
|
+
const trimmed = identifier.trim();
|
|
1740
|
+
return trimmed.length === 0 ? UNKNOWN_CONSTRAINT : trimmed;
|
|
1741
|
+
};
|
|
1742
|
+
const sqliteUniqueConstraintFromCause = (cause) => {
|
|
1743
|
+
if (hasProperty(cause, "constraint")) return normalizeConstraintIdentifier(cause.constraint);
|
|
1744
|
+
if (!hasProperty(cause, "message")) return UNKNOWN_CONSTRAINT;
|
|
1745
|
+
const message = cause.message;
|
|
1746
|
+
if (typeof message !== "string") return UNKNOWN_CONSTRAINT;
|
|
1747
|
+
const index = message.indexOf("UNIQUE constraint failed:");
|
|
1748
|
+
return index === -1 ? UNKNOWN_CONSTRAINT : normalizeConstraintIdentifier(message.slice(index + 25));
|
|
1749
|
+
};
|
|
1750
|
+
/**
|
|
1751
|
+
* Classifies a native SQLite error cause into a `SqlErrorReason` using its
|
|
1752
|
+
* `code` or `errno`, with optional message and operation metadata.
|
|
1753
|
+
*
|
|
1754
|
+
* @category converting
|
|
1755
|
+
* @since 4.0.0
|
|
1756
|
+
*/
|
|
1757
|
+
const classifySqliteError = (cause, { message, operation } = {}) => {
|
|
1758
|
+
const props = {
|
|
1759
|
+
cause,
|
|
1760
|
+
message,
|
|
1761
|
+
operation
|
|
1762
|
+
};
|
|
1763
|
+
const code = sqliteCodeFromCause(cause);
|
|
1764
|
+
const numericCode = sqliteNumericCodeFromCause(cause);
|
|
1765
|
+
if (code === SQLITE_CONSTRAINT_UNIQUE || matchesSqliteNumericCode(cause, SQLITE_CONSTRAINT_UNIQUE_CODE)) return new UniqueViolation({
|
|
1766
|
+
...props,
|
|
1767
|
+
constraint: sqliteUniqueConstraintFromCause(cause)
|
|
1768
|
+
});
|
|
1769
|
+
if (typeof code === "string") {
|
|
1770
|
+
if (matchesSqliteCode(code, "SQLITE_AUTH")) return new AuthenticationError(props);
|
|
1771
|
+
if (matchesSqliteCode(code, "SQLITE_PERM")) return new AuthorizationError(props);
|
|
1772
|
+
if (matchesSqliteCode(code, "SQLITE_CONSTRAINT")) return new ConstraintError(props);
|
|
1773
|
+
if (matchesSqliteCode(code, "SQLITE_BUSY") || matchesSqliteCode(code, "SQLITE_LOCKED")) return new LockTimeoutError(props);
|
|
1774
|
+
if (matchesSqliteCode(code, "SQLITE_CANTOPEN")) return new ConnectionError(props);
|
|
1775
|
+
}
|
|
1776
|
+
if (typeof numericCode === "number") switch (numericCode & 255) {
|
|
1777
|
+
case 23: return new AuthenticationError(props);
|
|
1778
|
+
case 3: return new AuthorizationError(props);
|
|
1779
|
+
case 19: return new ConstraintError(props);
|
|
1780
|
+
case 5:
|
|
1781
|
+
case 6: return new LockTimeoutError(props);
|
|
1782
|
+
case 14: return new ConnectionError(props);
|
|
1783
|
+
default: return new UnknownError(props);
|
|
1784
|
+
}
|
|
1785
|
+
return new UnknownError(props);
|
|
1786
|
+
};
|
|
1787
|
+
/**
|
|
1788
|
+
* Error raised when an ordered batched SQL resolver receives a different number
|
|
1789
|
+
* of result rows than requests.
|
|
1790
|
+
*
|
|
1791
|
+
* @category errors
|
|
1792
|
+
* @since 4.0.0
|
|
1793
|
+
*/
|
|
1794
|
+
var ResultLengthMismatch = class extends (/*#__PURE__*/ TaggedError("effect/sql/ResultLengthMismatch")("ResultLengthMismatch", {
|
|
1795
|
+
expected: Natural,
|
|
1796
|
+
actual: Natural
|
|
1797
|
+
})) {
|
|
1798
|
+
/**
|
|
1799
|
+
* Explains the mismatch between expected and actual batched SQL result counts.
|
|
1800
|
+
*
|
|
1801
|
+
* @since 4.0.0
|
|
1802
|
+
*/
|
|
1803
|
+
get message() {
|
|
1804
|
+
return `Expected ${this.expected} results but got ${this.actual}`;
|
|
1805
|
+
}
|
|
1806
|
+
};
|
|
1807
|
+
//#endregion
|
|
1808
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/sql/SqlResolver.js
|
|
1809
|
+
/**
|
|
1810
|
+
* Schema-aware `RequestResolver` helpers for SQL-backed data loading.
|
|
1811
|
+
*
|
|
1812
|
+
* This module represents each lookup or mutation as a `SqlRequest` and batches
|
|
1813
|
+
* concurrent requests into SQL operations. Request payloads are encoded with the
|
|
1814
|
+
* request schema before `execute` is called, and returned rows are decoded with
|
|
1815
|
+
* the result schema before requests are completed. It provides ordered,
|
|
1816
|
+
* grouped, id-based, and side-effect-only resolver constructors, and keeps
|
|
1817
|
+
* batches separated by the active SQL transaction connection.
|
|
1818
|
+
*
|
|
1819
|
+
* @since 4.0.0
|
|
1820
|
+
*/
|
|
1821
|
+
const SqlRequestProto = {
|
|
1822
|
+
...Class$2.prototype,
|
|
1823
|
+
[symbol](that) {
|
|
1824
|
+
return equals(this.payload, that.payload);
|
|
1825
|
+
},
|
|
1826
|
+
[symbol$1]() {
|
|
1827
|
+
return hash(this.payload);
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1830
|
+
/**
|
|
1831
|
+
* Runs a payload as a `SqlRequest` through a request resolver, either directly
|
|
1832
|
+
* with a payload and resolver or curried by resolver.
|
|
1833
|
+
*
|
|
1834
|
+
* @category running
|
|
1835
|
+
* @since 4.0.0
|
|
1836
|
+
*/
|
|
1837
|
+
const request = function() {
|
|
1838
|
+
if (arguments.length === 1) {
|
|
1839
|
+
const resolver = arguments[0];
|
|
1840
|
+
return (payload) => request$1(SqlRequest(payload), resolver);
|
|
1841
|
+
}
|
|
1842
|
+
return request$1(SqlRequest(arguments[0]), arguments[1]);
|
|
1843
|
+
};
|
|
1844
|
+
/**
|
|
1845
|
+
* Constructs a `SqlRequest` from a payload. Equality and hashing are based on
|
|
1846
|
+
* the payload so equal requests can be batched and deduplicated.
|
|
1847
|
+
*
|
|
1848
|
+
* @category constructors
|
|
1849
|
+
* @since 4.0.0
|
|
1850
|
+
*/
|
|
1851
|
+
const SqlRequest = (payload) => {
|
|
1852
|
+
const self = Object.create(SqlRequestProto);
|
|
1853
|
+
self.payload = payload;
|
|
1854
|
+
return self;
|
|
1855
|
+
};
|
|
1856
|
+
/**
|
|
1857
|
+
* Creates a resolver for a SQL query with a request schema and a result schema.
|
|
1858
|
+
*
|
|
1859
|
+
* **Details**
|
|
1860
|
+
*
|
|
1861
|
+
* The request schema is used to validate the input of the query, and the result
|
|
1862
|
+
* schema is used to validate the output of the query. Results are mapped to the
|
|
1863
|
+
* requests in order, so the length of the results must match the length of the
|
|
1864
|
+
* requests.
|
|
1865
|
+
*
|
|
1866
|
+
* @category resolvers
|
|
1867
|
+
* @since 4.0.0
|
|
1868
|
+
*/
|
|
1869
|
+
const ordered = (options) => {
|
|
1870
|
+
const decodeArray = decodeUnknownEffect(ArraySchema(options.Result));
|
|
1871
|
+
return makeGrouped({
|
|
1872
|
+
key: transactionKey,
|
|
1873
|
+
resolver: fnUntraced(function* (entries) {
|
|
1874
|
+
const [inputs, encodedEntries] = yield* partitionRequests(entries, options.Request);
|
|
1875
|
+
if (!isArrayNonEmpty(inputs)) return;
|
|
1876
|
+
const results = yield* options.execute(inputs).pipe(provideContext(entries[0].context));
|
|
1877
|
+
if (results.length !== inputs.length) return yield* new ResultLengthMismatch({
|
|
1878
|
+
expected: inputs.length,
|
|
1879
|
+
actual: results.length
|
|
1880
|
+
});
|
|
1881
|
+
const decodedResults = yield* decodeArray(results).pipe(provideContext(entries[0].context));
|
|
1882
|
+
for (let i = 0; i < encodedEntries.length; i++) encodedEntries[i].completeUnsafe(succeed$2(decodedResults[i]));
|
|
1883
|
+
})
|
|
1884
|
+
});
|
|
1885
|
+
};
|
|
1886
|
+
/**
|
|
1887
|
+
* Creates a batched resolver that fetches rows for encoded ids, decodes
|
|
1888
|
+
* results, completes each matching request using `ResultId`, and fails missing
|
|
1889
|
+
* ids with `NoSuchElementError`.
|
|
1890
|
+
*
|
|
1891
|
+
* @category resolvers
|
|
1892
|
+
* @since 4.0.0
|
|
1893
|
+
*/
|
|
1894
|
+
const findById = (options) => {
|
|
1895
|
+
const decodeResults = decodeUnknownEffect(ArraySchema(options.Result));
|
|
1896
|
+
return makeGrouped({
|
|
1897
|
+
key: transactionKey,
|
|
1898
|
+
resolver: fnUntraced(function* (entries) {
|
|
1899
|
+
const [inputs, idMap] = yield* partitionRequestsById(entries, options.Id);
|
|
1900
|
+
if (!isArrayNonEmpty(inputs)) return;
|
|
1901
|
+
const results = yield* options.execute(inputs).pipe(provideContext(entries[0].context));
|
|
1902
|
+
const decodedResults = yield* decodeResults(results).pipe(provideContext(entries[0].context));
|
|
1903
|
+
for (let i = 0; i < decodedResults.length; i++) {
|
|
1904
|
+
const result = decodedResults[i];
|
|
1905
|
+
const id = options.ResultId(result, results[i]);
|
|
1906
|
+
const request = get$2(idMap, id);
|
|
1907
|
+
if (request._tag === "None") continue;
|
|
1908
|
+
remove(idMap, id);
|
|
1909
|
+
request.value.completeUnsafe(succeed$2(result));
|
|
1910
|
+
}
|
|
1911
|
+
if (isEmpty(idMap)) return;
|
|
1912
|
+
forEach$1(idMap, (request) => {
|
|
1913
|
+
request.completeUnsafe(constNoSuchElement);
|
|
1914
|
+
});
|
|
1915
|
+
})
|
|
1916
|
+
});
|
|
1917
|
+
};
|
|
1918
|
+
const void_ = (options) => makeGrouped({
|
|
1919
|
+
key: transactionKey,
|
|
1920
|
+
resolver: fnUntraced(function* (entries) {
|
|
1921
|
+
const [inputs] = yield* partitionRequests(entries, options.Request);
|
|
1922
|
+
if (!isArrayNonEmpty(inputs)) return;
|
|
1923
|
+
yield* options.execute(inputs).pipe(provideContext(entries[0].context));
|
|
1924
|
+
for (let i = 0; i < entries.length; i++) entries[i].completeUnsafe(void_$3);
|
|
1925
|
+
})
|
|
1926
|
+
});
|
|
1927
|
+
const constNoSuchElement = /*#__PURE__*/ fail(/*#__PURE__*/ new NoSuchElementError());
|
|
1928
|
+
const partitionRequests = function* (requests, schema) {
|
|
1929
|
+
const len = requests.length;
|
|
1930
|
+
const inputs = empty();
|
|
1931
|
+
const encodedEntries = empty();
|
|
1932
|
+
let entry;
|
|
1933
|
+
const encode = encodeEffect(schema);
|
|
1934
|
+
const handle = matchCauseEager({
|
|
1935
|
+
onFailure(cause) {
|
|
1936
|
+
entry.completeUnsafe(failCause(cause));
|
|
1937
|
+
},
|
|
1938
|
+
onSuccess(value) {
|
|
1939
|
+
inputs.push(value);
|
|
1940
|
+
encodedEntries.push(entry);
|
|
1941
|
+
}
|
|
1942
|
+
});
|
|
1943
|
+
for (let i = 0; i < len; i++) {
|
|
1944
|
+
entry = requests[i];
|
|
1945
|
+
yield provideContext(handle(encode(entry.request.payload)), entry.context);
|
|
1946
|
+
}
|
|
1947
|
+
return [inputs, encodedEntries];
|
|
1948
|
+
};
|
|
1949
|
+
const partitionRequestsById = function* (requests, schema) {
|
|
1950
|
+
const len = requests.length;
|
|
1951
|
+
const inputs = empty();
|
|
1952
|
+
const byIdMap = empty$1();
|
|
1953
|
+
for (let i = 0; i < len; i++) {
|
|
1954
|
+
const entry = requests[i];
|
|
1955
|
+
const existing = get$2(byIdMap, entry.request.payload);
|
|
1956
|
+
if (isSome(existing)) {
|
|
1957
|
+
const previous = existing.value;
|
|
1958
|
+
set(byIdMap, entry.request.payload, {
|
|
1959
|
+
...previous,
|
|
1960
|
+
completeUnsafe(exit) {
|
|
1961
|
+
previous.completeUnsafe(exit);
|
|
1962
|
+
entry.completeUnsafe(exit);
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
} else set(byIdMap, entry.request.payload, entry);
|
|
1966
|
+
}
|
|
1967
|
+
const encode = encodeEffect(schema);
|
|
1968
|
+
for (const [, entry] of byIdMap) yield* provideContext(matchCauseEager(encode(entry.request.payload), {
|
|
1969
|
+
onFailure(cause) {
|
|
1970
|
+
entry.completeUnsafe(failCause(cause));
|
|
1971
|
+
},
|
|
1972
|
+
onSuccess(value) {
|
|
1973
|
+
inputs.push(value);
|
|
1974
|
+
}
|
|
1975
|
+
}), entry.context);
|
|
1976
|
+
return [inputs, byIdMap];
|
|
1977
|
+
};
|
|
1978
|
+
function transactionKey(entry) {
|
|
1979
|
+
const client = getOrUndefined(entry.context, SqlClient);
|
|
1980
|
+
if (!client) return void 0;
|
|
1981
|
+
const conn = getOrUndefined(entry.context, client.transactionService);
|
|
1982
|
+
if (!conn) return void 0;
|
|
1983
|
+
return byReferenceUnsafe(conn);
|
|
1984
|
+
}
|
|
1985
|
+
//#endregion
|
|
1986
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/sql/SqlSchema.js
|
|
1987
|
+
/**
|
|
1988
|
+
* Builds a query function that encodes the request and decodes all result rows,
|
|
1989
|
+
* allowing an empty result set.
|
|
1990
|
+
*
|
|
1991
|
+
* **When to use**
|
|
1992
|
+
*
|
|
1993
|
+
* Use when you need to run a query that may return zero or more rows and
|
|
1994
|
+
* represent an empty result as an empty array.
|
|
1995
|
+
*
|
|
1996
|
+
* @see {@link findNonEmpty} for queries where an empty result is a failure
|
|
1997
|
+
*
|
|
1998
|
+
* @category constructors
|
|
1999
|
+
* @since 4.0.0
|
|
2000
|
+
*/
|
|
2001
|
+
const findAll = (options) => {
|
|
2002
|
+
const encodeRequest = encodeEffect(options.Request);
|
|
2003
|
+
const decode = decodeUnknownEffect(mutable(ArraySchema(options.Result)));
|
|
2004
|
+
return (request) => flatMap(flatMap(encodeRequest(request), options.execute), decode);
|
|
2005
|
+
};
|
|
2006
|
+
//#endregion
|
|
2007
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/unstable/sql/SqlModel.js
|
|
2008
|
+
/**
|
|
2009
|
+
* Creates batched request resolvers for a schema model's insert, insert-void,
|
|
2010
|
+
* find-by-id, and delete operations, honoring the optional soft-delete column.
|
|
2011
|
+
*
|
|
2012
|
+
* @category constructors
|
|
2013
|
+
* @since 4.0.0
|
|
2014
|
+
*/
|
|
2015
|
+
const makeResolvers = (Model, options) => gen(function* () {
|
|
2016
|
+
const sql = yield* SqlClient;
|
|
2017
|
+
const idSchema = Model.fields[options.idColumn];
|
|
2018
|
+
const idColumn = options.idColumn;
|
|
2019
|
+
const softDeleteColumn = options.softDeleteColumn;
|
|
2020
|
+
const withSoftDeleteFilter = (where) => softDeleteColumn === void 0 ? where : sql.and([where, sql`${sql(softDeleteColumn)} is null`]);
|
|
2021
|
+
const setSoftDeleted = softDeleteColumn === void 0 ? void 0 : sql`${sql(softDeleteColumn)} = CURRENT_TIMESTAMP`;
|
|
2022
|
+
return {
|
|
2023
|
+
insert: ordered({
|
|
2024
|
+
Request: Model.insert,
|
|
2025
|
+
Result: Model,
|
|
2026
|
+
execute: (request) => sql.onDialectOrElse({
|
|
2027
|
+
mysql: () => forEach(request, (request) => sql`insert into ${sql(options.tableName)} ${sql.insert(request)};
|
|
2028
|
+
select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql`${sql(idColumn)} = LAST_INSERT_ID()`)};`.unprepared.pipe(map(([, results]) => results[0])), { concurrency: 10 }),
|
|
2029
|
+
orElse: () => sql`insert into ${sql(options.tableName)} ${sql.insert(request).returning("*")}`
|
|
2030
|
+
})
|
|
2031
|
+
}).pipe(withSpan$1(`${options.spanPrefix}.insertResolver`)),
|
|
2032
|
+
insertVoid: void_({
|
|
2033
|
+
Request: Model.insert,
|
|
2034
|
+
execute: (request) => sql`insert into ${sql(options.tableName)} ${sql.insert(request)}`
|
|
2035
|
+
}).pipe(withSpan$1(`${options.spanPrefix}.insertVoidResolver`)),
|
|
2036
|
+
findById: findById({
|
|
2037
|
+
Id: idSchema,
|
|
2038
|
+
Result: Model,
|
|
2039
|
+
ResultId(request) {
|
|
2040
|
+
return request[idColumn];
|
|
2041
|
+
},
|
|
2042
|
+
execute: (ids) => sql`select * from ${sql(options.tableName)} where ${withSoftDeleteFilter(sql.in(idColumn, ids))}`
|
|
2043
|
+
}).pipe(withSpan$1(`${options.spanPrefix}.findByIdResolver`)),
|
|
2044
|
+
delete: void_({
|
|
2045
|
+
Request: idSchema,
|
|
2046
|
+
execute: (ids) => softDeleteColumn === void 0 ? sql`delete from ${sql(options.tableName)} where ${sql.in(idColumn, ids)}` : sql`update ${sql(options.tableName)} set ${setSoftDeleted} where ${withSoftDeleteFilter(sql.in(idColumn, ids))}`
|
|
2047
|
+
}).pipe(withSpan$1(`${options.spanPrefix}.deleteResolver`))
|
|
2048
|
+
};
|
|
2049
|
+
});
|
|
2050
|
+
//#endregion
|
|
2051
|
+
//#region src/ChunkRepo.ts
|
|
2052
|
+
/** @effect-diagnostics schemaNumber:off */
|
|
2053
|
+
/**
|
|
2054
|
+
* @since 1.0.0
|
|
2055
|
+
* @category Models
|
|
2056
|
+
*/
|
|
2057
|
+
const ChunkId = Number$1.pipe(brand("ChunkRepo/ChunkId"));
|
|
2058
|
+
/**
|
|
2059
|
+
* @since 1.0.0
|
|
2060
|
+
* @category Models
|
|
2061
|
+
*/
|
|
2062
|
+
const SyncId = String$1.pipe(brand("ChunkRepo/SyncId"));
|
|
2063
|
+
/**
|
|
2064
|
+
* @since 1.0.0
|
|
2065
|
+
* @category Models
|
|
2066
|
+
*/
|
|
2067
|
+
const Float32ArraySchema = instanceOf(Float32Array);
|
|
2068
|
+
/**
|
|
2069
|
+
* @since 1.0.0
|
|
2070
|
+
* @category Models
|
|
2071
|
+
*/
|
|
2072
|
+
const Float32ArrayFromArray = ArraySchema(Number$1).pipe(decodeTo(Float32ArraySchema, transform$1({
|
|
2073
|
+
decode: (arr) => new Float32Array(arr),
|
|
2074
|
+
encode: (array) => Array.from(array)
|
|
2075
|
+
})));
|
|
2076
|
+
/**
|
|
2077
|
+
* @since 1.0.0
|
|
2078
|
+
* @category Models
|
|
2079
|
+
*/
|
|
2080
|
+
const Float32ArrayField = Field({
|
|
2081
|
+
insert: Float32ArraySchema,
|
|
2082
|
+
update: Float32ArraySchema,
|
|
2083
|
+
jsonCreate: Float32ArrayFromArray,
|
|
2084
|
+
jsonUpdate: Float32ArrayFromArray
|
|
2085
|
+
});
|
|
2086
|
+
/**
|
|
2087
|
+
* @since 1.0.0
|
|
2088
|
+
* @category Models
|
|
2089
|
+
*/
|
|
2090
|
+
var Chunk = class extends Class("Chunk")({
|
|
2091
|
+
id: ChunkId.pipe(FieldExcept(["insert", "jsonCreate"])),
|
|
2092
|
+
path: String$1,
|
|
2093
|
+
content: String$1,
|
|
2094
|
+
hash: String$1,
|
|
2095
|
+
vector: Float32ArrayField,
|
|
2096
|
+
syncId: SyncId
|
|
2097
|
+
}) {};
|
|
2098
|
+
/**
|
|
2099
|
+
* @since 1.0.0
|
|
2100
|
+
* @category Services
|
|
2101
|
+
*/
|
|
2102
|
+
var ChunkRepo = class extends Service()("clanka/ChunkRepo") {};
|
|
2103
|
+
/**
|
|
2104
|
+
* @since 1.0.0
|
|
2105
|
+
* @category Errors
|
|
2106
|
+
*/
|
|
2107
|
+
var ChunkRepoError = class extends TaggedError()("ChunkRepoError", { reason: Union$2([SqlError]) }) {
|
|
2108
|
+
cause = this.reason;
|
|
2109
|
+
message = this.reason.message;
|
|
2110
|
+
};
|
|
2111
|
+
/**
|
|
2112
|
+
* @since 1.0.0
|
|
2113
|
+
* @category Layers
|
|
2114
|
+
*/
|
|
2115
|
+
const layer$4 = effect(ChunkRepo, gen(function* () {
|
|
2116
|
+
const sql = yield* SqlClient;
|
|
2117
|
+
const dimensions = yield* Dimensions;
|
|
2118
|
+
yield* gen(function* () {
|
|
2119
|
+
yield* sql`CREATE VIRTUAL TABLE IF NOT EXISTS chunk_vectors USING vec0(
|
|
2120
|
+
vector float[${sql.literal(String(dimensions))}]
|
|
2121
|
+
)`;
|
|
2122
|
+
yield* sql`CREATE TRIGGER IF NOT EXISTS chunks_vector_insert
|
|
2123
|
+
AFTER INSERT ON chunks
|
|
2124
|
+
BEGIN
|
|
2125
|
+
INSERT INTO chunk_vectors(rowid, vector) VALUES (new.id, new.vector);
|
|
2126
|
+
END`;
|
|
2127
|
+
yield* sql`CREATE TRIGGER IF NOT EXISTS chunks_vector_update
|
|
2128
|
+
AFTER UPDATE OF vector ON chunks
|
|
2129
|
+
BEGIN
|
|
2130
|
+
DELETE FROM chunk_vectors WHERE rowid = old.id;
|
|
2131
|
+
INSERT INTO chunk_vectors(rowid, vector) VALUES (new.id, new.vector);
|
|
2132
|
+
END`;
|
|
2133
|
+
yield* sql`CREATE TRIGGER IF NOT EXISTS chunks_vector_delete
|
|
2134
|
+
AFTER DELETE ON chunks
|
|
2135
|
+
BEGIN
|
|
2136
|
+
DELETE FROM chunk_vectors WHERE rowid = old.id;
|
|
2137
|
+
END`;
|
|
2138
|
+
yield* sql`DELETE FROM chunk_vectors
|
|
2139
|
+
WHERE rowid NOT IN (SELECT id FROM chunks)`;
|
|
2140
|
+
yield* sql`INSERT INTO chunk_vectors(rowid, vector)
|
|
2141
|
+
SELECT id, vector FROM chunks
|
|
2142
|
+
WHERE id NOT IN (SELECT rowid FROM chunk_vectors)`;
|
|
2143
|
+
}).pipe(sql.withTransaction);
|
|
2144
|
+
const loaders = yield* makeResolvers(Chunk, {
|
|
2145
|
+
tableName: "chunks",
|
|
2146
|
+
idColumn: "id",
|
|
2147
|
+
spanPrefix: "ChunkRepo"
|
|
2148
|
+
});
|
|
2149
|
+
const search = findAll({
|
|
2150
|
+
Request: Struct$2({
|
|
2151
|
+
vector: Float32ArraySchema,
|
|
2152
|
+
limit: Number$1
|
|
2153
|
+
}),
|
|
2154
|
+
Result: Chunk,
|
|
2155
|
+
execute: ({ vector, limit }) => sql`
|
|
2156
|
+
select chunks.id, chunks.path, chunks.content, chunks.hash, chunks.syncId
|
|
2157
|
+
from chunk_vectors
|
|
2158
|
+
JOIN chunks ON chunks.id = chunk_vectors.rowid
|
|
2159
|
+
WHERE chunk_vectors.vector MATCH ${vector}
|
|
2160
|
+
AND k = CAST(${limit} AS INTEGER)
|
|
2161
|
+
ORDER BY chunk_vectors.distance
|
|
2162
|
+
`
|
|
2163
|
+
});
|
|
2164
|
+
const exists = findById({
|
|
2165
|
+
Id: String$1,
|
|
2166
|
+
Result: Struct$2({
|
|
2167
|
+
id: ChunkId,
|
|
2168
|
+
hash: String$1
|
|
2169
|
+
}),
|
|
2170
|
+
ResultId(result) {
|
|
2171
|
+
return result.hash;
|
|
2172
|
+
},
|
|
2173
|
+
execute: (hashes) => sql`select id, hash from chunks where ${sql.in("hash", hashes)}`
|
|
2174
|
+
}).pipe(setDelay(5));
|
|
2175
|
+
const insertResolver = loaders.insert.pipe(setDelay(5));
|
|
2176
|
+
const findByIdResolver = loaders.findById.pipe(setDelay(5));
|
|
2177
|
+
return ChunkRepo.of({
|
|
2178
|
+
insert: (insert) => request(insert, insertResolver).pipe(catchTags({
|
|
2179
|
+
SchemaError: die,
|
|
2180
|
+
ResultLengthMismatch: die
|
|
2181
|
+
}, (reason) => fail$1(new ChunkRepoError({ reason })))),
|
|
2182
|
+
findById: (id) => request(id, findByIdResolver).pipe(catchTags({
|
|
2183
|
+
SchemaError: die,
|
|
2184
|
+
SqlError: (reason) => fail$1(new ChunkRepoError({ reason }))
|
|
2185
|
+
})),
|
|
2186
|
+
exists: (hash) => request(hash, exists).pipe(map((result) => result.id), catchNoSuchElement, catchTags({
|
|
2187
|
+
SqlError: (reason) => fail$1(new ChunkRepoError({ reason })),
|
|
2188
|
+
SchemaError: die
|
|
2189
|
+
})),
|
|
2190
|
+
search: fn("ChunkRepo.search")(function* (options) {
|
|
2191
|
+
return yield* search(options).pipe(catchTags({
|
|
2192
|
+
SqlError: (reason) => fail$1(new ChunkRepoError({ reason })),
|
|
2193
|
+
SchemaError: die
|
|
2194
|
+
}));
|
|
2195
|
+
}),
|
|
2196
|
+
quantize: void_$1,
|
|
2197
|
+
setSyncId: (chunkId, syncId) => sql`update chunks set syncId = ${syncId} where id = ${chunkId}`.pipe(mapError((reason) => new ChunkRepoError({ reason }))),
|
|
2198
|
+
deleteByPath: (path) => sql`delete from chunks where path = ${path}`.pipe(mapError((reason) => new ChunkRepoError({ reason }))),
|
|
2199
|
+
deleteForSyncId: (syncId) => sql`delete from chunks where syncId != ${syncId}`.pipe(mapError((reason) => new ChunkRepoError({ reason })))
|
|
2200
|
+
});
|
|
2201
|
+
}));
|
|
2202
|
+
//#endregion
|
|
2203
|
+
//#region src/CodeChunker.ts
|
|
2204
|
+
/**
|
|
2205
|
+
* @since 1.0.0
|
|
2206
|
+
*/
|
|
2207
|
+
/**
|
|
2208
|
+
* @since 1.0.0
|
|
2209
|
+
* @category Services
|
|
2210
|
+
*/
|
|
2211
|
+
var CodeChunker = class extends Service()("clanka/CodeChunker") {};
|
|
2212
|
+
const sourceExtensions = /* @__PURE__ */ new Set([
|
|
2213
|
+
"c",
|
|
2214
|
+
"cc",
|
|
2215
|
+
"cpp",
|
|
2216
|
+
"cs",
|
|
2217
|
+
"css",
|
|
2218
|
+
"cts",
|
|
2219
|
+
"cxx",
|
|
2220
|
+
"go",
|
|
2221
|
+
"gql",
|
|
2222
|
+
"graphql",
|
|
2223
|
+
"h",
|
|
2224
|
+
"hpp",
|
|
2225
|
+
"html",
|
|
2226
|
+
"ini",
|
|
2227
|
+
"java",
|
|
2228
|
+
"js",
|
|
2229
|
+
"jsx",
|
|
2230
|
+
"kt",
|
|
2231
|
+
"kts",
|
|
2232
|
+
"less",
|
|
2233
|
+
"lua",
|
|
2234
|
+
"mjs",
|
|
2235
|
+
"mts",
|
|
2236
|
+
"php",
|
|
2237
|
+
"py",
|
|
2238
|
+
"rb",
|
|
2239
|
+
"rs",
|
|
2240
|
+
"sass",
|
|
2241
|
+
"scala",
|
|
2242
|
+
"scss",
|
|
2243
|
+
"sh",
|
|
2244
|
+
"sql",
|
|
2245
|
+
"svelte",
|
|
2246
|
+
"swift",
|
|
2247
|
+
"ts",
|
|
2248
|
+
"tsx",
|
|
2249
|
+
"vue",
|
|
2250
|
+
"xml",
|
|
2251
|
+
"zsh"
|
|
2252
|
+
]);
|
|
2253
|
+
const documentationExtensions = /* @__PURE__ */ new Set([
|
|
2254
|
+
"adoc",
|
|
2255
|
+
"asciidoc",
|
|
2256
|
+
"md",
|
|
2257
|
+
"mdx",
|
|
2258
|
+
"rst",
|
|
2259
|
+
"txt"
|
|
2260
|
+
]);
|
|
2261
|
+
const ignoredDirectories = /* @__PURE__ */ new Set([
|
|
2262
|
+
".git",
|
|
2263
|
+
".next",
|
|
2264
|
+
".nuxt",
|
|
2265
|
+
".svelte-kit",
|
|
2266
|
+
".turbo",
|
|
2267
|
+
"build",
|
|
2268
|
+
"coverage",
|
|
2269
|
+
"dist",
|
|
2270
|
+
"node_modules",
|
|
2271
|
+
"target"
|
|
2272
|
+
]);
|
|
2273
|
+
const normalizePath$1 = (path) => path.replace(/\\/g, "/");
|
|
2274
|
+
const normalizeText = (content) => content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2275
|
+
const meaningfulLinePattern = /[^\s\p{P}]/u;
|
|
2276
|
+
const isMeaningfulLine = (line) => meaningfulLinePattern.test(line);
|
|
2277
|
+
const languageByExtension = /* @__PURE__ */ new Map([
|
|
2278
|
+
["js", TreeSitterJavaScript],
|
|
2279
|
+
["jsx", TreeSitterJavaScript],
|
|
2280
|
+
["ts", TreeSitterTypeScript.typescript],
|
|
2281
|
+
["tsx", TreeSitterTypeScript.tsx]
|
|
2282
|
+
]);
|
|
2283
|
+
/**
|
|
2284
|
+
* @since 1.0.0
|
|
2285
|
+
* @category Predicates
|
|
2286
|
+
*/
|
|
2287
|
+
const isProbablyMinified = (content) => {
|
|
2288
|
+
const normalized = normalizeText(content);
|
|
2289
|
+
if (normalized.length < 2e3) return false;
|
|
2290
|
+
const lines = normalized.split("\n");
|
|
2291
|
+
if (lines.length <= 2) return true;
|
|
2292
|
+
let longLines = 0;
|
|
2293
|
+
for (const line of lines) if (line.length >= 300) longLines++;
|
|
2294
|
+
return lines.length <= 20 && longLines / lines.length >= .8;
|
|
2295
|
+
};
|
|
2296
|
+
/**
|
|
2297
|
+
* @since 1.0.0
|
|
2298
|
+
* @category Predicates
|
|
2299
|
+
*/
|
|
2300
|
+
const isMeaningfulFile = (path) => {
|
|
2301
|
+
const parts = normalizePath$1(path).toLowerCase().split("/");
|
|
2302
|
+
const fileName = parts.at(-1);
|
|
2303
|
+
if (fileName === void 0 || fileName.length === 0) return false;
|
|
2304
|
+
if (parts.some((part) => ignoredDirectories.has(part))) return false;
|
|
2305
|
+
if (/\.min\.(?:css|js)$/i.test(fileName)) return false;
|
|
2306
|
+
const extensionIndex = fileName.lastIndexOf(".");
|
|
2307
|
+
if (extensionIndex === -1) return false;
|
|
2308
|
+
const extension = fileName.slice(extensionIndex + 1);
|
|
2309
|
+
return sourceExtensions.has(extension) || documentationExtensions.has(extension);
|
|
2310
|
+
};
|
|
2311
|
+
const resolveChunkSettings = (options) => {
|
|
2312
|
+
const chunkSize = Math.max(1, options.chunkSize);
|
|
2313
|
+
return {
|
|
2314
|
+
chunkSize,
|
|
2315
|
+
chunkOverlap: Math.max(0, Math.min(chunkSize - 1, options.chunkOverlap)),
|
|
2316
|
+
chunkMaxCharacters: options.chunkMaxCharacters !== void 0 && Number.isFinite(options.chunkMaxCharacters) ? Math.max(1, Math.floor(options.chunkMaxCharacters)) : Number.POSITIVE_INFINITY
|
|
2317
|
+
};
|
|
2318
|
+
};
|
|
2319
|
+
const getPathExtension = (path) => {
|
|
2320
|
+
const fileName = path.split("/").at(-1);
|
|
2321
|
+
if (fileName === void 0) return;
|
|
2322
|
+
const extensionIndex = fileName.lastIndexOf(".");
|
|
2323
|
+
if (extensionIndex === -1) return;
|
|
2324
|
+
return fileName.slice(extensionIndex + 1).toLowerCase();
|
|
2325
|
+
};
|
|
2326
|
+
const resolveAstLanguage = (path) => {
|
|
2327
|
+
const extension = getPathExtension(path);
|
|
2328
|
+
if (extension === void 0) return;
|
|
2329
|
+
return languageByExtension.get(extension);
|
|
2330
|
+
};
|
|
2331
|
+
const lineRangeFromNode = (node) => {
|
|
2332
|
+
const startLine = node.startPosition.row + 1;
|
|
2333
|
+
return {
|
|
2334
|
+
startLine,
|
|
2335
|
+
endLine: Math.max(startLine, node.endPosition.row + 1)
|
|
2336
|
+
};
|
|
2337
|
+
};
|
|
2338
|
+
const hasOnlyWhitespaceLines = (lines, startLine, endLine) => {
|
|
2339
|
+
if (startLine > endLine) return true;
|
|
2340
|
+
for (let lineIndex = startLine; lineIndex <= endLine; lineIndex++) if ((lines[lineIndex - 1] ?? "").trim().length > 0) return false;
|
|
2341
|
+
return true;
|
|
2342
|
+
};
|
|
2343
|
+
const lineRangeWithLeadingComments = (node, siblings, nodeIndex, lines) => {
|
|
2344
|
+
const baseRange = lineRangeFromNode(node);
|
|
2345
|
+
let startLine = baseRange.startLine;
|
|
2346
|
+
for (let index = nodeIndex - 1; index >= 0; index--) {
|
|
2347
|
+
const sibling = siblings[index];
|
|
2348
|
+
if (sibling.type !== "comment") break;
|
|
2349
|
+
const commentRange = lineRangeFromNode(sibling);
|
|
2350
|
+
if (!hasOnlyWhitespaceLines(lines, commentRange.endLine + 1, startLine - 1)) break;
|
|
2351
|
+
startLine = commentRange.startLine;
|
|
2352
|
+
}
|
|
2353
|
+
return {
|
|
2354
|
+
startLine,
|
|
2355
|
+
endLine: baseRange.endLine
|
|
2356
|
+
};
|
|
2357
|
+
};
|
|
2358
|
+
const normalizeLineRange = (range, lineCount) => {
|
|
2359
|
+
const startLine = Math.max(1, Math.min(lineCount, range.startLine));
|
|
2360
|
+
const endLine = Math.max(1, Math.min(lineCount, range.endLine));
|
|
2361
|
+
if (endLine < startLine) return;
|
|
2362
|
+
return {
|
|
2363
|
+
startLine,
|
|
2364
|
+
endLine
|
|
2365
|
+
};
|
|
2366
|
+
};
|
|
2367
|
+
const lineLengthPrefixSums = (lines) => {
|
|
2368
|
+
const sums = [0];
|
|
2369
|
+
for (let index = 0; index < lines.length; index++) sums.push(sums[index] + lines[index].length);
|
|
2370
|
+
return sums;
|
|
2371
|
+
};
|
|
2372
|
+
const lineRangeCharacterLength = (prefixSums, range) => prefixSums[range.endLine] - prefixSums[range.startLine - 1] + (range.endLine - range.startLine);
|
|
2373
|
+
const resolveSegmentEndLine = (options) => {
|
|
2374
|
+
if (options.settings.chunkMaxCharacters === Number.POSITIVE_INFINITY) return options.maxEndLine;
|
|
2375
|
+
let endLine = options.maxEndLine;
|
|
2376
|
+
while (endLine > options.startLine && lineRangeCharacterLength(options.prefixSums, {
|
|
2377
|
+
startLine: options.startLine,
|
|
2378
|
+
endLine
|
|
2379
|
+
}) > options.settings.chunkMaxCharacters) endLine--;
|
|
2380
|
+
return endLine;
|
|
2381
|
+
};
|
|
2382
|
+
const splitRange = (range, settings, prefixSums) => {
|
|
2383
|
+
if (range.endLine - range.startLine + 1 <= settings.chunkSize && lineRangeCharacterLength(prefixSums, range) <= settings.chunkMaxCharacters) return [range];
|
|
2384
|
+
const out = [];
|
|
2385
|
+
for (let startLine = range.startLine; startLine <= range.endLine;) {
|
|
2386
|
+
const maxEndLine = Math.min(range.endLine, startLine + settings.chunkSize - 1);
|
|
2387
|
+
const endLine = resolveSegmentEndLine({
|
|
2388
|
+
startLine,
|
|
2389
|
+
maxEndLine,
|
|
2390
|
+
settings,
|
|
2391
|
+
prefixSums
|
|
2392
|
+
});
|
|
2393
|
+
out.push({
|
|
2394
|
+
startLine,
|
|
2395
|
+
endLine
|
|
2396
|
+
});
|
|
2397
|
+
if (endLine >= range.endLine) break;
|
|
2398
|
+
startLine = Math.max(startLine + 1, endLine - settings.chunkOverlap + 1);
|
|
2399
|
+
}
|
|
2400
|
+
return out;
|
|
2401
|
+
};
|
|
2402
|
+
const nodeText = (node) => {
|
|
2403
|
+
if (node === null) return;
|
|
2404
|
+
const value = node.text.trim().replace(/\s+/g, " ");
|
|
2405
|
+
return value.length === 0 ? void 0 : value;
|
|
2406
|
+
};
|
|
2407
|
+
const nodeFieldText = (node, fieldName) => nodeText(node.childForFieldName(fieldName));
|
|
2408
|
+
const isNamespaceNode = (node) => node.type === "internal_module" || node.type === "module";
|
|
2409
|
+
const unwrapDeclarationNode = (node) => {
|
|
2410
|
+
let current = node;
|
|
2411
|
+
while (true) {
|
|
2412
|
+
if (current.type === "export_statement") {
|
|
2413
|
+
const declaration = current.childForFieldName("declaration") ?? current.namedChildren[0];
|
|
2414
|
+
if (declaration === void 0) return current;
|
|
2415
|
+
current = declaration;
|
|
2416
|
+
continue;
|
|
2417
|
+
}
|
|
2418
|
+
if (current.type === "ambient_declaration") {
|
|
2419
|
+
const declaration = current.namedChildren.find((child) => child.type.endsWith("_declaration") || isNamespaceNode(child));
|
|
2420
|
+
if (declaration === void 0) return current;
|
|
2421
|
+
current = declaration;
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
return current;
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
const variableDeclarators = (node) => node.namedChildren.filter((child) => child.type === "variable_declarator");
|
|
2428
|
+
const variableTypeFromDeclarator = (node) => {
|
|
2429
|
+
const value = node.childForFieldName("value");
|
|
2430
|
+
if (value !== null && value.type.includes("function")) return "function";
|
|
2431
|
+
return "variable";
|
|
2432
|
+
};
|
|
2433
|
+
const variableTypeFromDeclaration = (node) => {
|
|
2434
|
+
if (variableDeclarators(node).some((declarator) => variableTypeFromDeclarator(declarator) === "function")) return "function";
|
|
2435
|
+
return "variable";
|
|
2436
|
+
};
|
|
2437
|
+
const chunkTypeFromNode = (node) => {
|
|
2438
|
+
switch (node.type) {
|
|
2439
|
+
case "class_declaration": return "class";
|
|
2440
|
+
case "enum_declaration": return "enum";
|
|
2441
|
+
case "function_declaration":
|
|
2442
|
+
case "generator_function_declaration": return "function";
|
|
2443
|
+
case "internal_module":
|
|
2444
|
+
case "module": return "namespace";
|
|
2445
|
+
case "interface_declaration": return "interface";
|
|
2446
|
+
case "generator_method_definition":
|
|
2447
|
+
case "method_definition": return "method";
|
|
2448
|
+
case "type_alias_declaration": return "type-alias";
|
|
2449
|
+
case "lexical_declaration":
|
|
2450
|
+
case "variable_declaration": return variableTypeFromDeclaration(node);
|
|
2451
|
+
case "variable_declarator": return variableTypeFromDeclarator(node);
|
|
2452
|
+
default: return;
|
|
2453
|
+
}
|
|
2454
|
+
};
|
|
2455
|
+
const variableNamesFromDeclaration = (node) => {
|
|
2456
|
+
const names = variableDeclarators(node).map((declarator) => nodeFieldText(declarator, "name")).filter((name) => name !== void 0);
|
|
2457
|
+
if (names.length === 0) return;
|
|
2458
|
+
return names.join(", ");
|
|
2459
|
+
};
|
|
2460
|
+
const nameFromNode = (node) => {
|
|
2461
|
+
switch (node.type) {
|
|
2462
|
+
case "class_declaration":
|
|
2463
|
+
case "enum_declaration":
|
|
2464
|
+
case "function_declaration":
|
|
2465
|
+
case "generator_function_declaration":
|
|
2466
|
+
case "internal_module":
|
|
2467
|
+
case "interface_declaration":
|
|
2468
|
+
case "module":
|
|
2469
|
+
case "generator_method_definition":
|
|
2470
|
+
case "method_definition":
|
|
2471
|
+
case "type_alias_declaration":
|
|
2472
|
+
case "variable_declarator": return nodeFieldText(node, "name");
|
|
2473
|
+
case "lexical_declaration":
|
|
2474
|
+
case "variable_declaration": return variableNamesFromDeclaration(node);
|
|
2475
|
+
default: return;
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
const formatParent = (type, name) => {
|
|
2479
|
+
if (type === void 0 && name === void 0) return;
|
|
2480
|
+
if (type === void 0) return name;
|
|
2481
|
+
if (name === void 0) return type;
|
|
2482
|
+
return type + " " + name;
|
|
2483
|
+
};
|
|
2484
|
+
const collectClassMethodRanges = (classNode, parent, lines) => {
|
|
2485
|
+
const body = classNode.childForFieldName("body");
|
|
2486
|
+
if (body === null) return [];
|
|
2487
|
+
const out = [];
|
|
2488
|
+
for (let index = 0; index < body.namedChildren.length; index++) {
|
|
2489
|
+
const child = body.namedChildren[index];
|
|
2490
|
+
if (!child.type.includes("method")) continue;
|
|
2491
|
+
out.push({
|
|
2492
|
+
...lineRangeWithLeadingComments(child, body.namedChildren, index, lines),
|
|
2493
|
+
name: nameFromNode(child),
|
|
2494
|
+
type: chunkTypeFromNode(child),
|
|
2495
|
+
parent
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
return out;
|
|
2499
|
+
};
|
|
2500
|
+
const collectAstRanges = (path, content, lines) => {
|
|
2501
|
+
const language = resolveAstLanguage(path);
|
|
2502
|
+
if (language === void 0) return [];
|
|
2503
|
+
try {
|
|
2504
|
+
const parser = new TreeSitter();
|
|
2505
|
+
parser.setLanguage(language);
|
|
2506
|
+
const tree = parser.parse(content, void 0, { bufferSize: 1048576 });
|
|
2507
|
+
const collectDeclarationRanges = (siblings, parent) => {
|
|
2508
|
+
const out = [];
|
|
2509
|
+
for (let index = 0; index < siblings.length; index++) {
|
|
2510
|
+
const sibling = siblings[index];
|
|
2511
|
+
if (sibling.type === "comment" || sibling.type.includes("import")) continue;
|
|
2512
|
+
const declarationNode = unwrapDeclarationNode(sibling);
|
|
2513
|
+
const type = chunkTypeFromNode(declarationNode);
|
|
2514
|
+
const name = nameFromNode(declarationNode);
|
|
2515
|
+
if (type === void 0 && name === void 0) continue;
|
|
2516
|
+
out.push({
|
|
2517
|
+
...lineRangeWithLeadingComments(sibling, siblings, index, lines),
|
|
2518
|
+
name,
|
|
2519
|
+
type,
|
|
2520
|
+
parent
|
|
2521
|
+
});
|
|
2522
|
+
if (declarationNode.type === "class_declaration") out.push(...collectClassMethodRanges(declarationNode, formatParent(type, name), lines));
|
|
2523
|
+
if (isNamespaceNode(declarationNode)) {
|
|
2524
|
+
const body = declarationNode.childForFieldName("body");
|
|
2525
|
+
if (body !== null) out.push(...collectDeclarationRanges(body.namedChildren, formatParent(type, name)));
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
return out;
|
|
2529
|
+
};
|
|
2530
|
+
return collectDeclarationRanges(tree.rootNode.namedChildren, void 0);
|
|
2531
|
+
} catch {
|
|
2532
|
+
return [];
|
|
2533
|
+
}
|
|
2534
|
+
};
|
|
2535
|
+
const chunksFromRanges = (path, lines, ranges, settings) => {
|
|
2536
|
+
const hasMethodChildRange = (classRange) => {
|
|
2537
|
+
const parent = formatParent("class", classRange.name);
|
|
2538
|
+
return ranges.some((range) => range.type === "method" && range.parent === parent && range.startLine >= classRange.startLine && range.endLine <= classRange.endLine);
|
|
2539
|
+
};
|
|
2540
|
+
const out = [];
|
|
2541
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2542
|
+
const prefixSums = lineLengthPrefixSums(lines);
|
|
2543
|
+
for (const range of ranges) {
|
|
2544
|
+
const normalizedRange = normalizeLineRange(range, lines.length);
|
|
2545
|
+
if (normalizedRange === void 0) continue;
|
|
2546
|
+
const allSegments = splitRange(normalizedRange, settings, prefixSums);
|
|
2547
|
+
const segments = range.type === "class" && allSegments.length > 1 && hasMethodChildRange({
|
|
2548
|
+
...normalizedRange,
|
|
2549
|
+
name: range.name
|
|
2550
|
+
}) ? [allSegments[0]] : allSegments;
|
|
2551
|
+
for (const segment of segments) {
|
|
2552
|
+
const key = String(segment.startLine) + ":" + String(segment.endLine) + ":" + (range.name ?? "") + ":" + (range.type ?? "") + ":" + (range.parent ?? "");
|
|
2553
|
+
if (seen.has(key)) continue;
|
|
2554
|
+
seen.add(key);
|
|
2555
|
+
const chunkLines = lines.slice(segment.startLine - 1, segment.endLine);
|
|
2556
|
+
if (!chunkLines.some(isMeaningfulLine)) continue;
|
|
2557
|
+
out.push({
|
|
2558
|
+
path,
|
|
2559
|
+
startLine: segment.startLine,
|
|
2560
|
+
endLine: segment.endLine,
|
|
2561
|
+
name: range.name,
|
|
2562
|
+
type: range.type,
|
|
2563
|
+
parent: range.parent,
|
|
2564
|
+
content: chunkLines.join("\n")
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
return out.toSorted((left, right) => left.startLine - right.startLine || left.endLine - right.endLine || (left.name ?? "").localeCompare(right.name ?? ""));
|
|
2569
|
+
};
|
|
2570
|
+
const chunkWithLineWindows = (path, lines, settings) => {
|
|
2571
|
+
const out = [];
|
|
2572
|
+
const prefixSums = lineLengthPrefixSums(lines);
|
|
2573
|
+
for (let index = 0; index < lines.length;) {
|
|
2574
|
+
if (!isMeaningfulLine(lines[index])) {
|
|
2575
|
+
index++;
|
|
2576
|
+
continue;
|
|
2577
|
+
}
|
|
2578
|
+
const startLine = index + 1;
|
|
2579
|
+
const maxEndLine = Math.min(lines.length, startLine + settings.chunkSize - 1);
|
|
2580
|
+
const endLine = resolveSegmentEndLine({
|
|
2581
|
+
startLine,
|
|
2582
|
+
maxEndLine,
|
|
2583
|
+
settings,
|
|
2584
|
+
prefixSums
|
|
2585
|
+
});
|
|
2586
|
+
const chunkLines = lines.slice(startLine - 1, endLine);
|
|
2587
|
+
out.push({
|
|
2588
|
+
path,
|
|
2589
|
+
startLine,
|
|
2590
|
+
endLine,
|
|
2591
|
+
name: void 0,
|
|
2592
|
+
type: void 0,
|
|
2593
|
+
parent: void 0,
|
|
2594
|
+
content: chunkLines.join("\n")
|
|
2595
|
+
});
|
|
2596
|
+
if (endLine >= lines.length) break;
|
|
2597
|
+
index = Math.max(startLine + 1, endLine - settings.chunkOverlap + 1) - 1;
|
|
2598
|
+
}
|
|
2599
|
+
return out;
|
|
2600
|
+
};
|
|
2601
|
+
const splitOversizedChunks = (chunks, maxCharacters) => chunks.flatMap((chunk) => {
|
|
2602
|
+
if (chunk.content.length <= maxCharacters) return [chunk];
|
|
2603
|
+
const pieces = [];
|
|
2604
|
+
for (let offset = 0; offset < chunk.content.length; offset += maxCharacters) pieces.push({
|
|
2605
|
+
...chunk,
|
|
2606
|
+
content: chunk.content.slice(offset, offset + maxCharacters)
|
|
2607
|
+
});
|
|
2608
|
+
return pieces;
|
|
2609
|
+
});
|
|
2610
|
+
/**
|
|
2611
|
+
* @since 1.0.0
|
|
2612
|
+
* @category Constructors
|
|
2613
|
+
*/
|
|
2614
|
+
const chunkFileContent = (path, content, options) => {
|
|
2615
|
+
if (content.trim().length === 0 || isProbablyMinified(content)) return [];
|
|
2616
|
+
const normalizedPath = normalizePath$1(path);
|
|
2617
|
+
const normalizedContent = normalizeText(content);
|
|
2618
|
+
const lines = normalizedContent.split("\n");
|
|
2619
|
+
if (lines.at(-1) === "") lines.pop();
|
|
2620
|
+
if (lines.length === 0) return [];
|
|
2621
|
+
const settings = resolveChunkSettings(options);
|
|
2622
|
+
const astRanges = collectAstRanges(normalizedPath, normalizedContent, lines);
|
|
2623
|
+
if (astRanges.length > 0) {
|
|
2624
|
+
const astChunks = chunksFromRanges(normalizedPath, lines, astRanges, settings);
|
|
2625
|
+
if (astChunks.length > 0) return splitOversizedChunks(astChunks, settings.chunkMaxCharacters);
|
|
2626
|
+
}
|
|
2627
|
+
return splitOversizedChunks(chunkWithLineWindows(normalizedPath, lines, settings), settings.chunkMaxCharacters);
|
|
2628
|
+
};
|
|
2629
|
+
/**
|
|
2630
|
+
* @since 1.0.0
|
|
2631
|
+
* @category Layers
|
|
2632
|
+
*/
|
|
2633
|
+
const layer$3 = effect(CodeChunker, gen(function* () {
|
|
2634
|
+
const spawner = yield* ChildProcessSpawner;
|
|
2635
|
+
const fs = yield* FileSystem;
|
|
2636
|
+
const pathService = yield* Path;
|
|
2637
|
+
const listFiles = fn("CodeChunker.listFiles")(function* (options) {
|
|
2638
|
+
const root = pathService.resolve(options.root);
|
|
2639
|
+
const maxFileSize = options.maxFileSize ?? "1M";
|
|
2640
|
+
return yield* pipe(spawner.streamLines(make$13("rg", [
|
|
2641
|
+
"--files",
|
|
2642
|
+
"--hidden",
|
|
2643
|
+
"--max-filesize",
|
|
2644
|
+
maxFileSize,
|
|
2645
|
+
"--glob",
|
|
2646
|
+
"!.git"
|
|
2647
|
+
], {
|
|
2648
|
+
cwd: root,
|
|
2649
|
+
stdin: "ignore"
|
|
2650
|
+
})), runCollect, map(fromIterable), map((entries) => entries.map((entry) => normalizePath$1(entry.trim())).filter((entry) => entry.length > 0 && isMeaningfulFile(entry)).toSorted((left, right) => left.localeCompare(right))), orDie);
|
|
2651
|
+
});
|
|
2652
|
+
const chunkFile = fn("CodeChunker.chunkFile")(function* (options) {
|
|
2653
|
+
const root = pathService.resolve(options.root);
|
|
2654
|
+
const absolutePath = pathService.resolve(root, options.path);
|
|
2655
|
+
const path = normalizePath$1(pathService.relative(root, absolutePath));
|
|
2656
|
+
if (path.length === 0 || path === ".." || path.startsWith("../") || !isMeaningfulFile(path)) return [];
|
|
2657
|
+
return yield* pipe(fs.readFileString(absolutePath), map((content) => chunkFileContent(path, content, options)), orElseSucceed(() => []));
|
|
2658
|
+
});
|
|
2659
|
+
const chunkFiles = (options) => fromArray(options.paths).pipe(flatMap$1((path) => pipe(chunkFile({
|
|
2660
|
+
root: options.root,
|
|
2661
|
+
path,
|
|
2662
|
+
chunkSize: options.chunkSize,
|
|
2663
|
+
chunkOverlap: options.chunkOverlap,
|
|
2664
|
+
...options.chunkMaxCharacters === void 0 ? {} : { chunkMaxCharacters: options.chunkMaxCharacters }
|
|
2665
|
+
}), fromArrayEffect), { concurrency: 5 }));
|
|
2666
|
+
const chunkCodebase = fnUntraced(function* (options) {
|
|
2667
|
+
const root = pathService.resolve(options.root);
|
|
2668
|
+
const files = yield* listFiles({
|
|
2669
|
+
root,
|
|
2670
|
+
...options.maxFileSize === void 0 ? {} : { maxFileSize: options.maxFileSize }
|
|
2671
|
+
});
|
|
2672
|
+
return chunkFiles({
|
|
2673
|
+
root,
|
|
2674
|
+
paths: files,
|
|
2675
|
+
chunkSize: options.chunkSize,
|
|
2676
|
+
chunkOverlap: options.chunkOverlap,
|
|
2677
|
+
...options.chunkMaxCharacters === void 0 ? {} : { chunkMaxCharacters: options.chunkMaxCharacters }
|
|
2678
|
+
});
|
|
2679
|
+
}, unwrap);
|
|
2680
|
+
return CodeChunker.of({
|
|
2681
|
+
listFiles,
|
|
2682
|
+
chunkFile,
|
|
2683
|
+
chunkFiles,
|
|
2684
|
+
chunkCodebase
|
|
2685
|
+
});
|
|
2686
|
+
}));
|
|
2687
|
+
//#endregion
|
|
2688
|
+
//#region node_modules/.pnpm/effect@4.0.0-rc.115/node_modules/effect/dist/FiberHandle.js
|
|
2689
|
+
/**
|
|
2690
|
+
* Manages at most one fiber inside a scope.
|
|
2691
|
+
*
|
|
2692
|
+
* A `FiberHandle<A, E>` can hold one `Fiber<A, E>`. Installing a new fiber
|
|
2693
|
+
* interrupts the previous one unless the operation is configured with
|
|
2694
|
+
* `onlyIfMissing`, and closing the owning scope interrupts the current fiber.
|
|
2695
|
+
* This module includes constructors for handles and scoped runtimes, helpers
|
|
2696
|
+
* for setting, reading, clearing, and running fibers, and operations for joining
|
|
2697
|
+
* the current fiber or waiting until the handle is empty.
|
|
2698
|
+
*
|
|
2699
|
+
* @since 2.0.0
|
|
2700
|
+
*/
|
|
2701
|
+
const TypeId$1 = "~effect/FiberHandle";
|
|
2702
|
+
/**
|
|
2703
|
+
* Returns `true` if a value is a `FiberHandle` by checking for the
|
|
2704
|
+
* `FiberHandle` runtime marker.
|
|
2705
|
+
*
|
|
2706
|
+
* **Example** (Checking fiber handles)
|
|
2707
|
+
*
|
|
2708
|
+
* ```ts import.meta.vitest
|
|
2709
|
+
* import { Effect, FiberHandle } from "effect"
|
|
2710
|
+
*
|
|
2711
|
+
* const program = Effect.gen(function*() {
|
|
2712
|
+
* const handle = yield* FiberHandle.make()
|
|
2713
|
+
*
|
|
2714
|
+
* return [FiberHandle.isFiberHandle(handle), FiberHandle.isFiberHandle("not a handle")]
|
|
2715
|
+
* })
|
|
2716
|
+
*
|
|
2717
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
2718
|
+
* actual // => [true, false]
|
|
2719
|
+
* ```
|
|
2720
|
+
*
|
|
2721
|
+
* @category guards
|
|
2722
|
+
* @since 2.0.0
|
|
2723
|
+
*/
|
|
2724
|
+
const isFiberHandle = (u) => hasProperty(u, TypeId$1);
|
|
2725
|
+
const Proto = {
|
|
2726
|
+
[TypeId$1]: TypeId$1,
|
|
2727
|
+
...PipeInspectableProto,
|
|
2728
|
+
toJSON() {
|
|
2729
|
+
return {
|
|
2730
|
+
_id: "FiberHandle",
|
|
2731
|
+
state: this.state
|
|
2732
|
+
};
|
|
2733
|
+
}
|
|
2734
|
+
};
|
|
2735
|
+
const makeUnsafe = () => {
|
|
2736
|
+
const self = Object.create(Proto);
|
|
2737
|
+
self.state = {
|
|
2738
|
+
_tag: "Open",
|
|
2739
|
+
fiber: void 0
|
|
2740
|
+
};
|
|
2741
|
+
self.deferred = makeUnsafe$2();
|
|
2742
|
+
return self;
|
|
2743
|
+
};
|
|
2744
|
+
/**
|
|
2745
|
+
* Creates a scoped `FiberHandle` that can store a single fiber.
|
|
2746
|
+
*
|
|
2747
|
+
* **Details**
|
|
2748
|
+
*
|
|
2749
|
+
* When the associated `Scope` is closed, the contained fiber will be
|
|
2750
|
+
* interrupted. You can add a fiber to the handle using `FiberHandle.run`, and
|
|
2751
|
+
* the fiber will be automatically removed from the `FiberHandle` when it
|
|
2752
|
+
* completes.
|
|
2753
|
+
*
|
|
2754
|
+
* **Example** (Creating a scoped fiber handle)
|
|
2755
|
+
*
|
|
2756
|
+
* ```ts import.meta.vitest
|
|
2757
|
+
* import { Effect, FiberHandle } from "effect"
|
|
2758
|
+
*
|
|
2759
|
+
* const program = Effect.gen(function*() {
|
|
2760
|
+
* const handle = yield* FiberHandle.make()
|
|
2761
|
+
*
|
|
2762
|
+
* // run some effects
|
|
2763
|
+
* yield* FiberHandle.run(handle, Effect.never)
|
|
2764
|
+
* // this will interrupt the previous fiber
|
|
2765
|
+
* yield* FiberHandle.run(handle, Effect.never)
|
|
2766
|
+
*
|
|
2767
|
+
* yield* Effect.yieldNow
|
|
2768
|
+
* return handle.state._tag === "Open" && handle.state.fiber !== undefined
|
|
2769
|
+
* }).pipe(
|
|
2770
|
+
* Effect.scoped // The fiber will be interrupted when the scope is closed
|
|
2771
|
+
* )
|
|
2772
|
+
*
|
|
2773
|
+
* const actual = await Effect.runPromise(program)
|
|
2774
|
+
* actual // => true
|
|
2775
|
+
* ```
|
|
2776
|
+
*
|
|
2777
|
+
* @category constructors
|
|
2778
|
+
* @since 2.0.0
|
|
2779
|
+
*/
|
|
2780
|
+
const make$2 = () => acquireRelease(sync(() => makeUnsafe()), (handle) => {
|
|
2781
|
+
const state = handle.state;
|
|
2782
|
+
if (state._tag === "Closed") return void_$1;
|
|
2783
|
+
handle.state = { _tag: "Closed" };
|
|
2784
|
+
return state.fiber ? into(asVoid(interruptAs(state.fiber, internalFiberId)), handle.deferred) : done(handle.deferred, void_$3);
|
|
2785
|
+
});
|
|
2786
|
+
const internalFiberId = -1;
|
|
2787
|
+
const isInternalInterruption = /*#__PURE__*/ toPredicate(/*#__PURE__*/ compose(filterInterruptors, /*#__PURE__*/ has(internalFiberId)));
|
|
2788
|
+
/**
|
|
2789
|
+
* Sets the fiber in a FiberHandle. When the fiber completes, it will be removed from the FiberHandle.
|
|
2790
|
+
* If a fiber is already running, it will be interrupted unless `options.onlyIfMissing` is set.
|
|
2791
|
+
*
|
|
2792
|
+
* **When to use**
|
|
2793
|
+
*
|
|
2794
|
+
* Use when an existing forked fiber must be installed synchronously into a
|
|
2795
|
+
* handle and immediate interruption of replaced or closed fibers is acceptable.
|
|
2796
|
+
*
|
|
2797
|
+
* **Example** (Setting a fiber unsafely)
|
|
2798
|
+
*
|
|
2799
|
+
* ```ts import.meta.vitest
|
|
2800
|
+
* import { Effect, Fiber, FiberHandle } from "effect"
|
|
2801
|
+
*
|
|
2802
|
+
* const program = Effect.gen(function*() {
|
|
2803
|
+
* const handle = yield* FiberHandle.make()
|
|
2804
|
+
* const fiber = Effect.runFork(Effect.succeed("hello"))
|
|
2805
|
+
*
|
|
2806
|
+
* // Set the fiber directly (unsafe)
|
|
2807
|
+
* FiberHandle.setUnsafe(handle, fiber)
|
|
2808
|
+
*
|
|
2809
|
+
* // The fiber is now managed by the handle
|
|
2810
|
+
* return yield* Fiber.join(fiber)
|
|
2811
|
+
* })
|
|
2812
|
+
*
|
|
2813
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
2814
|
+
* actual // => "hello"
|
|
2815
|
+
* ```
|
|
2816
|
+
*
|
|
2817
|
+
* @category combinators
|
|
2818
|
+
* @since 4.0.0
|
|
2819
|
+
*/
|
|
2820
|
+
const setUnsafe = /*#__PURE__*/ dual((args) => isFiberHandle(args[0]), (self, fiber, options) => {
|
|
2821
|
+
if (self.state._tag === "Closed") {
|
|
2822
|
+
fiber.interruptUnsafe(internalFiberId);
|
|
2823
|
+
return;
|
|
2824
|
+
} else if (self.state.fiber !== void 0) {
|
|
2825
|
+
if (self.state.fiber === fiber) return;
|
|
2826
|
+
else if (options?.onlyIfMissing === true) {
|
|
2827
|
+
fiber.interruptUnsafe(internalFiberId);
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2830
|
+
self.state.fiber.interruptUnsafe(internalFiberId);
|
|
2831
|
+
self.state.fiber = void 0;
|
|
2832
|
+
}
|
|
2833
|
+
self.state.fiber = fiber;
|
|
2834
|
+
fiber.addObserver((exit) => {
|
|
2835
|
+
if (self.state._tag === "Open" && fiber === self.state.fiber) self.state.fiber = void 0;
|
|
2836
|
+
if (isFailure(exit) && (options?.propagateInterruption === true ? !isInternalInterruption(exit.cause) : !hasInterruptsOnly(exit.cause))) doneUnsafe(self.deferred, exit);
|
|
2837
|
+
});
|
|
2838
|
+
});
|
|
2839
|
+
const constInterruptedFiber = /*#__PURE__*/ function() {
|
|
2840
|
+
let fiber = void 0;
|
|
2841
|
+
return () => {
|
|
2842
|
+
if (fiber === void 0) fiber = runFork(interrupt);
|
|
2843
|
+
return fiber;
|
|
2844
|
+
};
|
|
2845
|
+
}();
|
|
2846
|
+
/**
|
|
2847
|
+
* Forks an Effect and stores the resulting fiber in the `FiberHandle`.
|
|
2848
|
+
*
|
|
2849
|
+
* **Details**
|
|
2850
|
+
*
|
|
2851
|
+
* The handle manages only one fiber: running a new effect interrupts the
|
|
2852
|
+
* previous fiber unless `onlyIfMissing` is set. When the managed fiber
|
|
2853
|
+
* completes, it is removed from the handle.
|
|
2854
|
+
*
|
|
2855
|
+
* **Example** (Running an effect in a fiber handle)
|
|
2856
|
+
*
|
|
2857
|
+
* ```ts import.meta.vitest
|
|
2858
|
+
* import { Effect, Fiber, FiberHandle } from "effect"
|
|
2859
|
+
*
|
|
2860
|
+
* const program = Effect.gen(function*() {
|
|
2861
|
+
* const handle = yield* FiberHandle.make()
|
|
2862
|
+
*
|
|
2863
|
+
* // Run an effect and get the fiber
|
|
2864
|
+
* const fiber = yield* FiberHandle.run(handle, Effect.succeed("hello"))
|
|
2865
|
+
* const result = yield* Fiber.join(fiber)
|
|
2866
|
+
*
|
|
2867
|
+
* // Running another effect will interrupt the previous one
|
|
2868
|
+
* const fiber2 = yield* FiberHandle.run(handle, Effect.succeed("world"))
|
|
2869
|
+
* const result2 = yield* Fiber.join(fiber2)
|
|
2870
|
+
* return [result, result2]
|
|
2871
|
+
* })
|
|
2872
|
+
*
|
|
2873
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
2874
|
+
* actual // => ["hello", "world"]
|
|
2875
|
+
* ```
|
|
2876
|
+
*
|
|
2877
|
+
* @category combinators
|
|
2878
|
+
* @since 2.0.0
|
|
2879
|
+
*/
|
|
2880
|
+
const run$1 = function() {
|
|
2881
|
+
const self = arguments[0];
|
|
2882
|
+
if (isEffect(arguments[1])) return runImpl(self, arguments[1], arguments[2]);
|
|
2883
|
+
const options = arguments[1];
|
|
2884
|
+
return (effect) => runImpl(self, effect, options);
|
|
2885
|
+
};
|
|
2886
|
+
const runImpl = (self, effect, options) => withFiber((parent) => {
|
|
2887
|
+
if (self.state._tag === "Closed") return interrupt;
|
|
2888
|
+
else if (self.state.fiber !== void 0 && options?.onlyIfMissing === true) return sync(constInterruptedFiber);
|
|
2889
|
+
const fiber = runForkWith(parent.context)(effect);
|
|
2890
|
+
setUnsafe(self, fiber, options);
|
|
2891
|
+
return succeed(fiber);
|
|
2892
|
+
});
|
|
2893
|
+
//#endregion
|
|
2894
|
+
//#region node_modules/.pnpm/@effect+sql-sqlite-node@4.0.0-rc.115_effect@4.0.0-rc.115/node_modules/@effect/sql-sqlite-node/dist/SqliteClient.js
|
|
2895
|
+
/**
|
|
2896
|
+
* Connects Effect SQL to SQLite on Node.js using `node:sqlite`.
|
|
2897
|
+
*
|
|
2898
|
+
* This module opens a SQLite database and exposes it as both `SqliteClient` and
|
|
2899
|
+
* the generic Effect SQL client. It serializes access through one connection,
|
|
2900
|
+
* caches prepared statements, enables WAL mode unless disabled, and waits up
|
|
2901
|
+
* to five seconds for busy databases by default. Explicit transactions on
|
|
2902
|
+
* writable connections use `BEGIN IMMEDIATE` to avoid read-to-write lock
|
|
2903
|
+
* upgrades, which serializes them behind other writers even when they only
|
|
2904
|
+
* read. Clients opened with `readonly: true` are unaffected. Busy waits block
|
|
2905
|
+
* the Node.js event loop because `node:sqlite` is synchronous. Database backup
|
|
2906
|
+
* and extension loading are supported; streaming queries and `updateValues`
|
|
2907
|
+
* are not.
|
|
2908
|
+
*
|
|
2909
|
+
* @since 4.0.0
|
|
2910
|
+
*/
|
|
2911
|
+
const ATTR_DB_SYSTEM_NAME = "db.system.name";
|
|
2912
|
+
const MAX_BUSY_TIMEOUT = 2147483647;
|
|
2913
|
+
/**
|
|
2914
|
+
* Runtime type identifier used to mark Node `SqliteClient` values.
|
|
2915
|
+
*
|
|
2916
|
+
* @category type IDs
|
|
2917
|
+
* @since 4.0.0
|
|
2918
|
+
*/
|
|
2919
|
+
const TypeId = "~@effect/sql-sqlite-node/SqliteClient";
|
|
2920
|
+
/**
|
|
2921
|
+
* Service tag for the node SQLite client implementation.
|
|
2922
|
+
*
|
|
2923
|
+
* @category services
|
|
2924
|
+
* @since 4.0.0
|
|
2925
|
+
*/
|
|
2926
|
+
const SqliteClient = /*#__PURE__*/ Service("@effect/sql-sqlite-node/SqliteClient");
|
|
2927
|
+
/**
|
|
2928
|
+
* Creates a scoped node SQLite client from the supplied configuration, using a single serialized connection with WAL and a 5-second busy timeout enabled by default. Explicit transactions on writable connections take the write lock for their duration, even when they only read; clients opened with `readonly: true` are unaffected.
|
|
2929
|
+
*
|
|
2930
|
+
* @category constructors
|
|
2931
|
+
* @since 4.0.0
|
|
2932
|
+
*/
|
|
2933
|
+
const make$1 = (options) => gen(function* () {
|
|
2934
|
+
const compiler = makeCompilerSqlite(options.transformQueryNames);
|
|
2935
|
+
const transformRows = options.transformResultNames ? defaultTransforms(options.transformResultNames).array : void 0;
|
|
2936
|
+
const makeConnection = gen(function* () {
|
|
2937
|
+
const scope$1 = yield* scope;
|
|
2938
|
+
const db = new DatabaseSync(options.filename, {
|
|
2939
|
+
readOnly: options.readonly ?? false,
|
|
2940
|
+
allowExtension: true
|
|
2941
|
+
});
|
|
2942
|
+
yield* addFinalizer(scope$1, sync(() => db.close()));
|
|
2943
|
+
db.enableLoadExtension(false);
|
|
2944
|
+
const busyTimeout = Math.min(MAX_BUSY_TIMEOUT, Math.max(0, Math.round(toMillis(options.busyTimeout ?? seconds(5)))));
|
|
2945
|
+
db.exec(`PRAGMA busy_timeout = ${busyTimeout}`);
|
|
2946
|
+
if (options.disableWAL !== true) db.exec("PRAGMA journal_mode = WAL");
|
|
2947
|
+
const prepare = (sql) => try_({
|
|
2948
|
+
try: () => db.prepare(sql),
|
|
2949
|
+
catch: (cause) => new SqlError({ reason: classifyError(cause, "Failed to prepare statement", "prepare") })
|
|
2950
|
+
});
|
|
2951
|
+
const prepareCache = yield* make$4({
|
|
2952
|
+
capacity: options.prepareCacheSize ?? 200,
|
|
2953
|
+
timeToLive: options.prepareCacheTTL ?? minutes(10),
|
|
2954
|
+
lookup: prepare
|
|
2955
|
+
});
|
|
2956
|
+
const runStatement = (statement, params, raw) => withFiber((fiber) => {
|
|
2957
|
+
const useSafeIntegers = get$1(fiber.context, SafeIntegers);
|
|
2958
|
+
return try_({
|
|
2959
|
+
try: () => {
|
|
2960
|
+
statement.setReadBigInts(useSafeIntegers);
|
|
2961
|
+
if (statement.columns().length > 0) return statement.all(...params);
|
|
2962
|
+
const result = statement.run(...params);
|
|
2963
|
+
return raw ? {
|
|
2964
|
+
changes: result.changes,
|
|
2965
|
+
lastInsertRowid: result.lastInsertRowid
|
|
2966
|
+
} : [];
|
|
2967
|
+
},
|
|
2968
|
+
catch: (cause) => new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") })
|
|
2969
|
+
});
|
|
2970
|
+
});
|
|
2971
|
+
const runStatementValues = (statement, params) => withFiber((fiber) => {
|
|
2972
|
+
const useSafeIntegers = get$1(fiber.context, SafeIntegers);
|
|
2973
|
+
return try_({
|
|
2974
|
+
try: () => {
|
|
2975
|
+
statement.setReadBigInts(useSafeIntegers);
|
|
2976
|
+
if (statement.columns().length > 0) return statement.all(...params);
|
|
2977
|
+
statement.run(...params);
|
|
2978
|
+
return [];
|
|
2979
|
+
},
|
|
2980
|
+
catch: (cause) => new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") })
|
|
2981
|
+
});
|
|
2982
|
+
});
|
|
2983
|
+
const runStatementValuesUnprepared = (statement, params) => withFiber((fiber) => {
|
|
2984
|
+
const useSafeIntegers = get$1(fiber.context, SafeIntegers);
|
|
2985
|
+
return try_({
|
|
2986
|
+
try: () => {
|
|
2987
|
+
statement.setReadBigInts(useSafeIntegers);
|
|
2988
|
+
statement.setReturnArrays(true);
|
|
2989
|
+
if (statement.columns().length > 0) return statement.all(...params);
|
|
2990
|
+
statement.run(...params);
|
|
2991
|
+
return [];
|
|
2992
|
+
},
|
|
2993
|
+
catch: (cause) => new SqlError({ reason: classifyError(cause, "Failed to execute statement", "execute") })
|
|
2994
|
+
});
|
|
2995
|
+
});
|
|
2996
|
+
const run = (sql, params, raw = false) => flatMap(get(prepareCache, sql), (s) => runStatement(s, params, raw));
|
|
2997
|
+
const runValues = (sql, params) => acquireUseRelease(get(prepareCache, sql), (statement) => {
|
|
2998
|
+
statement.setReturnArrays(true);
|
|
2999
|
+
return runStatementValues(statement, params);
|
|
3000
|
+
}, (statement) => sync(() => statement.setReturnArrays(false)));
|
|
3001
|
+
const runValuesUnprepared = (sql, params) => flatMap(prepare(sql), (statement) => runStatementValuesUnprepared(statement, params));
|
|
3002
|
+
return identity({
|
|
3003
|
+
execute(sql, params, transformRows) {
|
|
3004
|
+
return transformRows ? map(run(sql, params), transformRows) : run(sql, params);
|
|
3005
|
+
},
|
|
3006
|
+
executeRaw(sql, params) {
|
|
3007
|
+
return run(sql, params, true);
|
|
3008
|
+
},
|
|
3009
|
+
executeValues(sql, params) {
|
|
3010
|
+
return runValues(sql, params);
|
|
3011
|
+
},
|
|
3012
|
+
executeValuesUnprepared(sql, params) {
|
|
3013
|
+
return runValuesUnprepared(sql, params);
|
|
3014
|
+
},
|
|
3015
|
+
executeUnprepared(sql, params, transformRows) {
|
|
3016
|
+
const effect = flatMap(prepare(sql), (statement) => runStatement(statement, params ?? [], false));
|
|
3017
|
+
return transformRows ? map(effect, transformRows) : effect;
|
|
3018
|
+
},
|
|
3019
|
+
executeStream(_sql, _params) {
|
|
3020
|
+
return die$1("executeStream not implemented");
|
|
3021
|
+
},
|
|
3022
|
+
backup(destination) {
|
|
3023
|
+
return suspend(() => {
|
|
3024
|
+
let totalPages = 0;
|
|
3025
|
+
return tryPromise({
|
|
3026
|
+
try: () => backup(db, destination, { progress: (progress) => {
|
|
3027
|
+
totalPages = progress.totalPages;
|
|
3028
|
+
} }).then((pages) => ({
|
|
3029
|
+
totalPages: totalPages || pages,
|
|
3030
|
+
remainingPages: 0
|
|
3031
|
+
})),
|
|
3032
|
+
catch: (cause) => new SqlError({ reason: classifyError(cause, "Failed to backup database", "backup") })
|
|
3033
|
+
});
|
|
3034
|
+
});
|
|
3035
|
+
},
|
|
3036
|
+
loadExtension(path) {
|
|
3037
|
+
return acquireUseRelease(sync(() => db.enableLoadExtension(true)), () => try_({
|
|
3038
|
+
try: () => db.loadExtension(path),
|
|
3039
|
+
catch: (cause) => new SqlError({ reason: classifyError(cause, "Failed to load extension", "loadExtension") })
|
|
3040
|
+
}), () => sync(() => db.enableLoadExtension(false)));
|
|
3041
|
+
}
|
|
3042
|
+
});
|
|
3043
|
+
});
|
|
3044
|
+
const semaphore = yield* make$14(1);
|
|
3045
|
+
const connection = yield* makeConnection;
|
|
3046
|
+
const acquirer = semaphore.withPermits(1)(succeed(connection));
|
|
3047
|
+
const transactionAcquirer = uninterruptibleMask((restore) => {
|
|
3048
|
+
const fiber = getCurrent();
|
|
3049
|
+
const scope = getUnsafe(fiber.context, Scope);
|
|
3050
|
+
return as(tap(restore(semaphore.take(1)), () => addFinalizer(scope, semaphore.release(1))), connection);
|
|
3051
|
+
});
|
|
3052
|
+
return Object.assign(yield* make$5({
|
|
3053
|
+
acquirer,
|
|
3054
|
+
compiler,
|
|
3055
|
+
transactionAcquirer,
|
|
3056
|
+
beginTransaction: options.readonly === true ? "BEGIN" : "BEGIN IMMEDIATE",
|
|
3057
|
+
spanAttributes: [...options.spanAttributes ? Object.entries(options.spanAttributes) : [], [ATTR_DB_SYSTEM_NAME, "sqlite"]],
|
|
3058
|
+
transformRows
|
|
3059
|
+
}), {
|
|
3060
|
+
[TypeId]: TypeId,
|
|
3061
|
+
config: options,
|
|
3062
|
+
backup: (destination) => flatMap(acquirer, (_) => _.backup(destination)),
|
|
3063
|
+
loadExtension: (path) => flatMap(acquirer, (_) => _.loadExtension(path))
|
|
3064
|
+
});
|
|
3065
|
+
});
|
|
3066
|
+
/**
|
|
3067
|
+
* Builds a layer from a node SQLite client configuration, providing both `SqliteClient` and the generic `SqlClient` service.
|
|
3068
|
+
*
|
|
3069
|
+
* @category layers
|
|
3070
|
+
* @since 4.0.0
|
|
3071
|
+
*/
|
|
3072
|
+
const layer$2 = (config) => effectContext(map(make$1(config), (client) => make$9(SqliteClient, client).pipe(add(SqlClient, client)))).pipe(provide$1(layer$5));
|
|
3073
|
+
const classifyError = (cause, message, operation) => classifySqliteError(sqliteCauseWithErrno(cause), {
|
|
3074
|
+
message,
|
|
3075
|
+
operation
|
|
3076
|
+
});
|
|
3077
|
+
const sqliteCauseWithErrno = (cause) => {
|
|
3078
|
+
if (typeof cause !== "object" || cause === null || !("errcode" in cause) || "errno" in cause) return cause;
|
|
3079
|
+
const errcode = cause.errcode;
|
|
3080
|
+
if (typeof errcode !== "number") return cause;
|
|
3081
|
+
return Object.assign(cause, { errno: errcode });
|
|
3082
|
+
};
|
|
3083
|
+
/**
|
|
3084
|
+
* Error raised while loading, validating, locking, or running SQL migrations.
|
|
3085
|
+
*
|
|
3086
|
+
* @category errors
|
|
3087
|
+
* @since 4.0.0
|
|
3088
|
+
*/
|
|
3089
|
+
var MigrationError = class extends (/*#__PURE__*/ TaggedError$1("MigrationError")) {};
|
|
3090
|
+
/**
|
|
3091
|
+
* Creates a migrator that ensures the migrations table exists, runs pending
|
|
3092
|
+
* migrations in a transaction, and optionally dumps the schema after successful
|
|
3093
|
+
* migrations.
|
|
3094
|
+
*
|
|
3095
|
+
* @category constructors
|
|
3096
|
+
* @since 4.0.0
|
|
3097
|
+
*/
|
|
3098
|
+
const make = ({ dumpSchema = () => void_$1 }) => ({ loader, schemaDirectory, table = "effect_sql_migrations" }) => gen(function* () {
|
|
3099
|
+
const sql = yield* SqlClient;
|
|
3100
|
+
const ensureMigrationsTable = sql.onDialectOrElse({
|
|
3101
|
+
mssql: () => sql`IF OBJECT_ID(N'${sql.literal(table)}', N'U') IS NULL
|
|
3102
|
+
CREATE TABLE ${sql(table)} (
|
|
3103
|
+
migration_id INT NOT NULL PRIMARY KEY,
|
|
3104
|
+
name VARCHAR(255) NOT NULL,
|
|
3105
|
+
created_at DATETIME NOT NULL DEFAULT GETDATE()
|
|
3106
|
+
)`,
|
|
3107
|
+
mysql: () => sql`CREATE TABLE IF NOT EXISTS ${sql(table)} (
|
|
3108
|
+
migration_id INTEGER UNSIGNED NOT NULL,
|
|
3109
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
3110
|
+
name VARCHAR(255) NOT NULL,
|
|
3111
|
+
PRIMARY KEY (migration_id)
|
|
3112
|
+
)`,
|
|
3113
|
+
pg: () => catch_(sql`select ${table}::regclass`, () => sql`CREATE TABLE ${sql(table)} (
|
|
3114
|
+
migration_id integer primary key,
|
|
3115
|
+
created_at timestamp with time zone not null default now(),
|
|
3116
|
+
name text not null
|
|
3117
|
+
)`),
|
|
3118
|
+
orElse: () => sql`CREATE TABLE IF NOT EXISTS ${sql(table)} (
|
|
3119
|
+
migration_id integer PRIMARY KEY NOT NULL,
|
|
3120
|
+
created_at datetime NOT NULL DEFAULT current_timestamp,
|
|
3121
|
+
name VARCHAR(255) NOT NULL
|
|
3122
|
+
)`
|
|
3123
|
+
});
|
|
3124
|
+
const insertMigrations = (rows) => sql`INSERT INTO ${sql(table)} ${sql.insert(rows.map(([migration_id, name]) => ({
|
|
3125
|
+
migration_id,
|
|
3126
|
+
name
|
|
3127
|
+
})))}`.withoutTransform;
|
|
3128
|
+
const latestMigration = map(sql`SELECT migration_id, name, created_at FROM ${sql(table)} ORDER BY migration_id DESC`.withoutTransform, (_) => map$1(fromNullishOr(_[0]), ({ created_at, migration_id, name }) => ({
|
|
3129
|
+
id: migration_id,
|
|
3130
|
+
name,
|
|
3131
|
+
createdAt: created_at
|
|
3132
|
+
})));
|
|
3133
|
+
const loadMigration = ([id, name, load]) => catchDefect(load, (_) => fail$1(new MigrationError({
|
|
3134
|
+
kind: "ImportError",
|
|
3135
|
+
message: `Could not import migration "${id}_${name}"\n\n${_}`
|
|
3136
|
+
}))).pipe(flatMap((_) => isEffect(_) ? succeed(_) : _.default ? succeed(_.default?.default ?? _.default) : fail$1(new MigrationError({
|
|
3137
|
+
kind: "ImportError",
|
|
3138
|
+
message: `Default export not found for migration "${id}_${name}"`
|
|
3139
|
+
}))), filterOrFail(isEffect, () => new MigrationError({
|
|
3140
|
+
kind: "ImportError",
|
|
3141
|
+
message: `Default export was not an Effect for migration "${id}_${name}"`
|
|
3142
|
+
})));
|
|
3143
|
+
const runMigration = (id, name, effect) => catch_(effect, (error) => die(new MigrationError({
|
|
3144
|
+
cause: error,
|
|
3145
|
+
kind: "Failed",
|
|
3146
|
+
message: `Migration "${id}_${name}" failed`
|
|
3147
|
+
})));
|
|
3148
|
+
const run = gen(function* () {
|
|
3149
|
+
yield* sql.onDialectOrElse({
|
|
3150
|
+
pg: () => sql`LOCK TABLE ${sql(table)} IN ACCESS EXCLUSIVE MODE`,
|
|
3151
|
+
orElse: () => void_$1
|
|
3152
|
+
});
|
|
3153
|
+
const [latestMigrationId, current] = yield* all([map(latestMigration, match({
|
|
3154
|
+
onNone: () => 0,
|
|
3155
|
+
onSome: (_) => _.id
|
|
3156
|
+
})), loader]);
|
|
3157
|
+
if (new Set(current.map(([id]) => id)).size !== current.length) return yield* new MigrationError({
|
|
3158
|
+
kind: "Duplicates",
|
|
3159
|
+
message: "Found duplicate migration id's"
|
|
3160
|
+
});
|
|
3161
|
+
const required = [];
|
|
3162
|
+
for (const resolved of current) {
|
|
3163
|
+
const [currentId, currentName] = resolved;
|
|
3164
|
+
if (currentId <= latestMigrationId) continue;
|
|
3165
|
+
required.push([
|
|
3166
|
+
currentId,
|
|
3167
|
+
currentName,
|
|
3168
|
+
yield* loadMigration(resolved)
|
|
3169
|
+
]);
|
|
3170
|
+
}
|
|
3171
|
+
if (required.length > 0) yield* pipe(insertMigrations(required.map(([id, name]) => [id, name])), mapError((error) => isConstraintConflict(error) ? new MigrationError({
|
|
3172
|
+
kind: "Locked",
|
|
3173
|
+
message: "Migrations already running"
|
|
3174
|
+
}) : error));
|
|
3175
|
+
yield* forEach(required, ([id, name, effect]) => logDebug(`Running migration`).pipe(flatMap(() => runMigration(id, name, effect)), annotateLogs("migration_id", String(id)), annotateLogs("migration_name", name), withSpan(`Migrator ${id}_${name}`)), { discard: true });
|
|
3176
|
+
yield* pipe(latestMigration, flatMap(match({
|
|
3177
|
+
onNone: () => logDebug(`Migrations complete`),
|
|
3178
|
+
onSome: (_) => logDebug(`Migrations complete`).pipe(annotateLogs("latest_migration_id", _.id.toString()), annotateLogs("latest_migration_name", _.name))
|
|
3179
|
+
})));
|
|
3180
|
+
return required.map(([id, name]) => [id, name]);
|
|
3181
|
+
});
|
|
3182
|
+
yield* ensureMigrationsTable;
|
|
3183
|
+
const completed = yield* pipe(sql.withTransaction(run), catchTag("MigrationError", (_) => _.kind === "Locked" ? as(logDebug(_.message), []) : fail$1(_)));
|
|
3184
|
+
if (schemaDirectory && completed.length > 0) yield* dumpSchema(`${schemaDirectory}/_schema.sql`, table).pipe(catchCause((cause) => logInfo("Could not dump schema", cause)));
|
|
3185
|
+
return completed;
|
|
3186
|
+
});
|
|
3187
|
+
const migrationOrder = /*#__PURE__*/ make$10(([a], [b]) => Number$2(a, b));
|
|
3188
|
+
const isConstraintConflict = (error) => error.reason._tag === "ConstraintError" || error.reason._tag === "UniqueViolation";
|
|
3189
|
+
/**
|
|
3190
|
+
* Creates a migration loader from a record of migration effects keyed by
|
|
3191
|
+
* `<id>_<name>`, sorted by migration id.
|
|
3192
|
+
*
|
|
3193
|
+
* @category loaders
|
|
3194
|
+
* @since 4.0.0
|
|
3195
|
+
*/
|
|
3196
|
+
const fromRecord = (migrations) => pipe(Object.keys(migrations), flatMapNullishOr((_) => _.match(/^(\d+)_(.+)$/)), map$2(([key, id, name]) => [
|
|
3197
|
+
Number(id),
|
|
3198
|
+
name,
|
|
3199
|
+
succeed(migrations[key])
|
|
3200
|
+
]), sort(migrationOrder), succeed);
|
|
3201
|
+
//#endregion
|
|
3202
|
+
//#region node_modules/.pnpm/@effect+sql-sqlite-node@4.0.0-rc.115_effect@4.0.0-rc.115/node_modules/@effect/sql-sqlite-node/dist/SqliteMigrator.js
|
|
3203
|
+
/**
|
|
3204
|
+
* Runs SQL migrations for a SQLite database using the shared `Migrator` implementation and the current `SqlClient`.
|
|
3205
|
+
*
|
|
3206
|
+
* @category running
|
|
3207
|
+
* @since 4.0.0
|
|
3208
|
+
*/
|
|
3209
|
+
const run = /*#__PURE__*/ make({});
|
|
3210
|
+
/**
|
|
3211
|
+
* Creates a layer that runs the configured SQLite migrations during layer construction and provides no services.
|
|
3212
|
+
*
|
|
3213
|
+
* @category layers
|
|
3214
|
+
* @since 4.0.0
|
|
3215
|
+
*/
|
|
3216
|
+
const layer$1 = (options) => effectDiscard(run(options));
|
|
3217
|
+
//#endregion
|
|
3218
|
+
//#region src/Sqlite.ts
|
|
3219
|
+
/**
|
|
3220
|
+
* @since 1.0.0
|
|
3221
|
+
*/
|
|
3222
|
+
/**
|
|
3223
|
+
* @since 1.0.0
|
|
3224
|
+
* @category Layers
|
|
3225
|
+
*/
|
|
3226
|
+
const SqliteLayer = (database) => layer$1({ loader: fromRecord({ "0001_create_chunks": gen(function* () {
|
|
3227
|
+
const sql = yield* SqlClient;
|
|
3228
|
+
yield* sql`CREATE TABLE IF NOT EXISTS chunks (
|
|
3229
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3230
|
+
path TEXT NOT NULL,
|
|
3231
|
+
content TEXT NOT NULL,
|
|
3232
|
+
hash TEXT NOT NULL,
|
|
3233
|
+
vector BLOB NOT NULL,
|
|
3234
|
+
syncId TEXT NOT NULL
|
|
3235
|
+
)`;
|
|
3236
|
+
yield* sql`CREATE INDEX IF NOT EXISTS idx_chunks_hash ON chunks (hash)`;
|
|
3237
|
+
}) }) }).pipe(provide$1(effectDiscard(gen(function* () {
|
|
3238
|
+
yield* (yield* SqliteClient).loadExtension(getLoadablePath());
|
|
3239
|
+
}))), provideMerge(layer$2({ filename: database })), provide$1(effectDiscard(gen(function* () {
|
|
3240
|
+
const fs = yield* FileSystem;
|
|
3241
|
+
const directory = (yield* Path).dirname(database);
|
|
3242
|
+
if (directory === ".") return;
|
|
3243
|
+
yield* fs.makeDirectory(directory, { recursive: true });
|
|
3244
|
+
}))));
|
|
3245
|
+
//#endregion
|
|
3246
|
+
//#region src/SemanticSearch.ts
|
|
3247
|
+
/**
|
|
3248
|
+
* @since 1.0.0
|
|
3249
|
+
*/
|
|
3250
|
+
const normalizePath = (path) => path.replace(/\\/g, "/");
|
|
3251
|
+
const resolveChunkConfig = (options) => ({
|
|
3252
|
+
chunkSize: 30,
|
|
3253
|
+
chunkOverlap: 0,
|
|
3254
|
+
chunkMaxCharacters: options.chunkMaxCharacters ?? 15e3
|
|
3255
|
+
});
|
|
3256
|
+
const makeEmbeddingResolver = (resolver, options) => resolver.pipe(setDelay(options.embeddingRequestDelay ?? millis(50)), batchN(options.embeddingBatchSize ?? 32));
|
|
3257
|
+
const chunkEmbeddingInput = (chunk) => {
|
|
3258
|
+
const headerLines = ["---", "file: " + chunk.path];
|
|
3259
|
+
if (chunk.name !== void 0) headerLines.push("name: " + chunk.name);
|
|
3260
|
+
if (chunk.type !== void 0) headerLines.push("type: " + chunk.type);
|
|
3261
|
+
if (chunk.parent !== void 0) headerLines.push("parent: " + chunk.parent);
|
|
3262
|
+
headerLines.push("---");
|
|
3263
|
+
const contentLines = chunk.content.split("\n");
|
|
3264
|
+
let contentWithLines = "";
|
|
3265
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
3266
|
+
if (i > 0) contentWithLines += "\n";
|
|
3267
|
+
contentWithLines += `${chunk.startLine + i}: ${contentLines[i]}`;
|
|
3268
|
+
}
|
|
3269
|
+
return headerLines.join("\n") + "\n\n" + contentWithLines;
|
|
3270
|
+
};
|
|
3271
|
+
const hashChunkInput = (input) => createHash("sha256").update(input).digest("hex");
|
|
3272
|
+
/**
|
|
3273
|
+
* @since 1.0.0
|
|
3274
|
+
* @category Layers
|
|
3275
|
+
*/
|
|
3276
|
+
const layer = (options) => effect(SemanticSearch, gen(function* () {
|
|
3277
|
+
const chunker = yield* CodeChunker;
|
|
3278
|
+
const repo = yield* ChunkRepo;
|
|
3279
|
+
const embeddings = yield* EmbeddingModel;
|
|
3280
|
+
const pathService = yield* Path;
|
|
3281
|
+
const root = pathService.resolve(options.directory);
|
|
3282
|
+
const resolver = makeEmbeddingResolver(embeddings.resolver, options);
|
|
3283
|
+
const concurrency = options.concurrency ?? 2e3;
|
|
3284
|
+
const chunkConfig = resolveChunkConfig(options);
|
|
3285
|
+
const indexHandle = yield* make$2();
|
|
3286
|
+
const console = yield* Console;
|
|
3287
|
+
const resolveIndexedPath = (path) => {
|
|
3288
|
+
const absolutePath = pathService.resolve(root, path);
|
|
3289
|
+
const relativePath = normalizePath(pathService.relative(root, absolutePath));
|
|
3290
|
+
if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith("../")) return none();
|
|
3291
|
+
return some(relativePath);
|
|
3292
|
+
};
|
|
3293
|
+
const processChunk = fnUntraced(function* (options) {
|
|
3294
|
+
const input = chunkEmbeddingInput(options.chunk);
|
|
3295
|
+
const hash = hashChunkInput(input);
|
|
3296
|
+
if (options.checkExisting) {
|
|
3297
|
+
const id = yield* repo.exists(hash);
|
|
3298
|
+
if (isSome(id)) {
|
|
3299
|
+
yield* repo.setSyncId(id.value, options.syncId);
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
const result = yield* request$1(new EmbeddingRequest({ input }), resolver);
|
|
3304
|
+
const vector = new Float32Array(result.vector);
|
|
3305
|
+
yield* repo.insert(Chunk.insert.make({
|
|
3306
|
+
path: options.chunk.path,
|
|
3307
|
+
hash,
|
|
3308
|
+
content: input,
|
|
3309
|
+
vector,
|
|
3310
|
+
syncId: options.syncId
|
|
3311
|
+
}));
|
|
3312
|
+
}, ignore({
|
|
3313
|
+
log: "Warn",
|
|
3314
|
+
message: "Failed to process chunk for embedding"
|
|
3315
|
+
}), (effect, options) => annotateLogs(effect, { chunk: `${options.chunk.path}/${options.chunk.startLine}` }));
|
|
3316
|
+
const index = gen(function* () {
|
|
3317
|
+
const syncId = SyncId.make(crypto.randomUUID());
|
|
3318
|
+
yield* logInfo("Starting SemanticSearch index");
|
|
3319
|
+
yield* pipe(chunker.chunkCodebase({
|
|
3320
|
+
root,
|
|
3321
|
+
...chunkConfig
|
|
3322
|
+
}), tap$1((chunk) => processChunk({
|
|
3323
|
+
chunk,
|
|
3324
|
+
syncId,
|
|
3325
|
+
checkExisting: true
|
|
3326
|
+
}), { concurrency }), runDrain);
|
|
3327
|
+
yield* repo.deleteForSyncId(syncId);
|
|
3328
|
+
yield* logInfo("Finished SemanticSearch index");
|
|
3329
|
+
}).pipe(withSpan("SemanticSearch.index"), withLogSpan("SemanticSearch.index"), provideService(Console, console));
|
|
3330
|
+
const runIndex = run$1(indexHandle, index, { onlyIfMissing: true });
|
|
3331
|
+
const initialIndex = yield* runIndex;
|
|
3332
|
+
yield* runIndex.pipe(delay(minutes(3)), forever, forkScoped);
|
|
3333
|
+
return SemanticSearch.of({
|
|
3334
|
+
search: fn("SemanticSearch.search")(function* (options) {
|
|
3335
|
+
yield* join$1(initialIndex);
|
|
3336
|
+
yield* annotateCurrentSpan(options);
|
|
3337
|
+
const { vector } = yield* embeddings.embed(options.query);
|
|
3338
|
+
return (yield* repo.search({
|
|
3339
|
+
vector: new Float32Array(vector),
|
|
3340
|
+
limit: options.limit
|
|
3341
|
+
})).map((r) => r.content).join("\n\n");
|
|
3342
|
+
}, orDie),
|
|
3343
|
+
updateFile: fn("SemanticSearch.updateFile")(function* (path) {
|
|
3344
|
+
yield* join$1(initialIndex);
|
|
3345
|
+
const indexedPath = resolveIndexedPath(path);
|
|
3346
|
+
if (isNone(indexedPath)) return;
|
|
3347
|
+
yield* repo.deleteByPath(indexedPath.value);
|
|
3348
|
+
const chunks = yield* chunker.chunkFile({
|
|
3349
|
+
root,
|
|
3350
|
+
path: indexedPath.value,
|
|
3351
|
+
...chunkConfig
|
|
3352
|
+
});
|
|
3353
|
+
if (chunks.length === 0) return;
|
|
3354
|
+
const syncId = SyncId.make(crypto.randomUUID());
|
|
3355
|
+
yield* pipe(fromArray(chunks), tap$1((chunk) => processChunk({
|
|
3356
|
+
chunk,
|
|
3357
|
+
syncId,
|
|
3358
|
+
checkExisting: false
|
|
3359
|
+
}), { concurrency }), runDrain);
|
|
3360
|
+
}, orDie),
|
|
3361
|
+
removeFile: fn("SemanticSearch.removeFile")(function* (path) {
|
|
3362
|
+
yield* join$1(initialIndex);
|
|
3363
|
+
const indexedPath = resolveIndexedPath(path);
|
|
3364
|
+
if (isNone(indexedPath)) return;
|
|
3365
|
+
yield* repo.deleteByPath(indexedPath.value);
|
|
3366
|
+
}, orDie)
|
|
3367
|
+
});
|
|
3368
|
+
})).pipe(provide$1([layer$3, layer$4.pipe(provide$1(SqliteLayer(options.database ?? ".clanka/search.sqlite")))]));
|
|
3369
|
+
//#endregion
|
|
3370
|
+
export { SemanticSearch, chunkEmbeddingInput, layer, makeEmbeddingResolver, maybeRemoveFile, maybeUpdateFile };
|
|
3371
|
+
|
|
3372
|
+
//# sourceMappingURL=SemanticSearch-D9iZ_Mi9.mjs.map
|