sqlite-zod-orm 3.26.0 → 3.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/index.js +79 -30
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -228,6 +228,21 @@ db.exec('UPDATE users SET score = 0 WHERE role = ?', 'guest');
|
|
|
228
228
|
- Debug mode (SQL logging)
|
|
229
229
|
- Raw SQL escape hatch
|
|
230
230
|
|
|
231
|
+
## Contributing
|
|
232
|
+
|
|
233
|
+
SatiDB is opinionated by design. Before proposing new features, understand what it intentionally does **not** do:
|
|
234
|
+
|
|
235
|
+
| ❌ Don't add | Why |
|
|
236
|
+
|---|---|
|
|
237
|
+
| Tagged SQL templates | The whole point is "zero SQL" — `db.raw()` is the escape hatch |
|
|
238
|
+
| FTS5 wrapper | Wrapping it poorly is worse than not wrapping it — use `db.raw()` |
|
|
239
|
+
| Query middleware | `measure-fn` handles observability, `hooks` handle lifecycle |
|
|
240
|
+
| Cursor pagination | Offset pagination covers SQLite's single-process use case |
|
|
241
|
+
| Schema introspection API | Zod schemas are compile-time known — runtime reflection invites dynamic queries |
|
|
242
|
+
| Migration CLI | Auto-migration handles additive changes; use `db.exec()` for destructive ones |
|
|
243
|
+
|
|
244
|
+
**The rule:** if the query builder can already do it, don't add a new API surface for it.
|
|
245
|
+
|
|
231
246
|
## Requirements
|
|
232
247
|
|
|
233
248
|
- **Bun** ≥ 1.0 (uses `bun:sqlite` native bindings)
|
package/dist/index.js
CHANGED
|
@@ -23,8 +23,9 @@ var toAlpha = (num) => {
|
|
|
23
23
|
} while (n >= 0);
|
|
24
24
|
return result;
|
|
25
25
|
};
|
|
26
|
-
var maxResultLen =
|
|
27
|
-
var safeStringify = (value) => {
|
|
26
|
+
var maxResultLen = 0;
|
|
27
|
+
var safeStringify = (value, limit) => {
|
|
28
|
+
const cap = limit ?? maxResultLen;
|
|
28
29
|
if (value === undefined)
|
|
29
30
|
return "";
|
|
30
31
|
if (value === null)
|
|
@@ -37,7 +38,9 @@ var safeStringify = (value) => {
|
|
|
37
38
|
return value.toString();
|
|
38
39
|
if (typeof value === "string") {
|
|
39
40
|
const q = JSON.stringify(value);
|
|
40
|
-
|
|
41
|
+
if (cap === 0)
|
|
42
|
+
return q;
|
|
43
|
+
return q.length > cap ? q.slice(0, cap - 1) + '\u2026"' : q;
|
|
41
44
|
}
|
|
42
45
|
try {
|
|
43
46
|
const seen = new WeakSet;
|
|
@@ -53,7 +56,9 @@ var safeStringify = (value) => {
|
|
|
53
56
|
return `${val}n`;
|
|
54
57
|
return val;
|
|
55
58
|
});
|
|
56
|
-
|
|
59
|
+
if (cap === 0)
|
|
60
|
+
return str;
|
|
61
|
+
return str.length > cap ? str.slice(0, cap) + "\u2026" : str;
|
|
57
62
|
} catch {
|
|
58
63
|
return String(value);
|
|
59
64
|
}
|
|
@@ -67,7 +72,7 @@ var formatDuration = (ms) => {
|
|
|
67
72
|
const secs = Math.round(ms % 60000 / 1000);
|
|
68
73
|
return `${mins}m ${secs}s`;
|
|
69
74
|
};
|
|
70
|
-
var timestamps = process.env.MEASURE_TIMESTAMPS === "1" || process.env.MEASURE_TIMESTAMPS === "true";
|
|
75
|
+
var timestamps = typeof process !== "undefined" && (process.env.MEASURE_TIMESTAMPS === "1" || process.env.MEASURE_TIMESTAMPS === "true");
|
|
71
76
|
var ts = () => {
|
|
72
77
|
if (!timestamps)
|
|
73
78
|
return "";
|
|
@@ -78,7 +83,9 @@ var ts = () => {
|
|
|
78
83
|
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
79
84
|
return `[${h}:${m}:${s}.${ms}] `;
|
|
80
85
|
};
|
|
81
|
-
var silent = process.env.MEASURE_SILENT === "1" || process.env.MEASURE_SILENT === "true";
|
|
86
|
+
var silent = typeof process !== "undefined" && (process.env.MEASURE_SILENT === "1" || process.env.MEASURE_SILENT === "true");
|
|
87
|
+
var dotEndLabel = true;
|
|
88
|
+
var dotChar = "\xB7";
|
|
82
89
|
var logger = null;
|
|
83
90
|
var buildActionLabel = (actionInternal) => {
|
|
84
91
|
return typeof actionInternal === "object" && actionInternal !== null && "label" in actionInternal ? String(actionInternal.label) : String(actionInternal);
|
|
@@ -90,6 +97,20 @@ var extractBudget = (actionInternal) => {
|
|
|
90
97
|
return Number(actionInternal.budget);
|
|
91
98
|
return;
|
|
92
99
|
};
|
|
100
|
+
var extractTimeout = (actionInternal) => {
|
|
101
|
+
if (typeof actionInternal !== "object" || actionInternal === null)
|
|
102
|
+
return;
|
|
103
|
+
if ("timeout" in actionInternal)
|
|
104
|
+
return Number(actionInternal.timeout);
|
|
105
|
+
return;
|
|
106
|
+
};
|
|
107
|
+
var extractMaxResultLength = (actionInternal) => {
|
|
108
|
+
if (typeof actionInternal !== "object" || actionInternal === null)
|
|
109
|
+
return;
|
|
110
|
+
if ("maxResultLength" in actionInternal)
|
|
111
|
+
return Number(actionInternal.maxResultLength);
|
|
112
|
+
return;
|
|
113
|
+
};
|
|
93
114
|
var extractMeta = (actionInternal) => {
|
|
94
115
|
if (typeof actionInternal !== "object" || actionInternal === null)
|
|
95
116
|
return;
|
|
@@ -98,6 +119,8 @@ var extractMeta = (actionInternal) => {
|
|
|
98
119
|
delete details.label;
|
|
99
120
|
if ("budget" in details)
|
|
100
121
|
delete details.budget;
|
|
122
|
+
if ("maxResultLength" in details)
|
|
123
|
+
delete details.maxResultLength;
|
|
101
124
|
if (Object.keys(details).length === 0)
|
|
102
125
|
return;
|
|
103
126
|
return details;
|
|
@@ -126,16 +149,18 @@ var defaultLogger = (event, prefix) => {
|
|
|
126
149
|
console.log(`${t}${id} ... ${event.label}${formatMeta(event.meta)}`);
|
|
127
150
|
break;
|
|
128
151
|
case "success": {
|
|
129
|
-
const
|
|
152
|
+
const endLabel = dotEndLabel ? dotChar.repeat(event.label.length) : event.label;
|
|
153
|
+
const resultStr = event.result !== undefined ? safeStringify(event.result, event.maxResultLength) : "";
|
|
130
154
|
const arrow = resultStr ? ` \u2192 ${resultStr}` : "";
|
|
131
155
|
const budgetWarn = event.budget && event.duration > event.budget ? ` \u26A0 OVER BUDGET (${formatDuration(event.budget)})` : "";
|
|
132
|
-
console.log(`${t}${id}
|
|
156
|
+
console.log(`${t}${id} ${endLabel} ${formatDuration(event.duration)}${arrow}${budgetWarn}`);
|
|
133
157
|
break;
|
|
134
158
|
}
|
|
135
159
|
case "error": {
|
|
160
|
+
const endLabel = dotEndLabel ? dotChar.repeat(event.label.length) : event.label;
|
|
136
161
|
const errorMsg = event.error instanceof Error ? event.error.message : String(event.error);
|
|
137
162
|
const budgetWarn = event.budget && event.duration > event.budget ? ` \u26A0 OVER BUDGET (${formatDuration(event.budget)})` : "";
|
|
138
|
-
console.log(`${t}${id} \u2717 ${
|
|
163
|
+
console.log(`${t}${id} \u2717 ${endLabel} ${formatDuration(event.duration)} (${errorMsg})${budgetWarn}`);
|
|
139
164
|
if (event.error instanceof Error) {
|
|
140
165
|
console.error(`${id}`, event.error.stack ?? event.error.message);
|
|
141
166
|
if (event.error.cause) {
|
|
@@ -151,13 +176,14 @@ var defaultLogger = (event, prefix) => {
|
|
|
151
176
|
break;
|
|
152
177
|
}
|
|
153
178
|
};
|
|
154
|
-
var createNestedResolver = (isAsync, fullIdChain, childCounterRef, depth, resolver, prefix) => {
|
|
179
|
+
var createNestedResolver = (isAsync, fullIdChain, childCounterRef, depth, resolver, prefix, inheritedMaxLen) => {
|
|
155
180
|
return (...args) => {
|
|
156
181
|
const label = args[0];
|
|
157
182
|
const fn = args[1];
|
|
183
|
+
const onError = args[2];
|
|
158
184
|
if (typeof fn === "function") {
|
|
159
185
|
const childParentChain = [...fullIdChain, childCounterRef.value++];
|
|
160
|
-
return resolver(fn, label, childParentChain, depth + 1);
|
|
186
|
+
return resolver(fn, label, childParentChain, depth + 1, typeof onError === "function" ? onError : undefined, inheritedMaxLen);
|
|
161
187
|
} else {
|
|
162
188
|
emit({
|
|
163
189
|
type: "annotation",
|
|
@@ -171,20 +197,24 @@ var createNestedResolver = (isAsync, fullIdChain, childCounterRef, depth, resolv
|
|
|
171
197
|
};
|
|
172
198
|
};
|
|
173
199
|
var globalRootCounter = 0;
|
|
174
|
-
var createMeasureImpl = (prefix, counterRef) => {
|
|
200
|
+
var createMeasureImpl = (prefix, counterRef, scopeOpts) => {
|
|
175
201
|
const counter = counterRef ?? { get value() {
|
|
176
202
|
return globalRootCounter;
|
|
177
203
|
}, set value(v) {
|
|
178
204
|
globalRootCounter = v;
|
|
179
205
|
} };
|
|
206
|
+
const scopeMaxLen = scopeOpts?.maxResultLength;
|
|
180
207
|
let _lastError = null;
|
|
181
|
-
const _measureInternal = async (fnInternal, actionInternal, parentIdChain, depth) => {
|
|
208
|
+
const _measureInternal = async (fnInternal, actionInternal, parentIdChain, depth, onError, inheritedMaxLen) => {
|
|
182
209
|
const start = performance.now();
|
|
183
210
|
const childCounterRef = { value: 0 };
|
|
184
211
|
const label = buildActionLabel(actionInternal);
|
|
185
212
|
const budget = extractBudget(actionInternal);
|
|
186
|
-
const
|
|
187
|
-
const
|
|
213
|
+
const timeout = extractTimeout(actionInternal);
|
|
214
|
+
const localMaxLen = extractMaxResultLength(actionInternal);
|
|
215
|
+
const effectiveMaxLen = localMaxLen ?? inheritedMaxLen;
|
|
216
|
+
const currentId = toAlpha(Number(parentIdChain.pop() ?? 0));
|
|
217
|
+
const fullIdChain = [...parentIdChain.map(String), currentId];
|
|
188
218
|
const idStr = fullIdChain.join("-");
|
|
189
219
|
emit({
|
|
190
220
|
type: "start",
|
|
@@ -193,27 +223,46 @@ var createMeasureImpl = (prefix, counterRef) => {
|
|
|
193
223
|
depth,
|
|
194
224
|
meta: extractMeta(actionInternal)
|
|
195
225
|
}, prefix);
|
|
196
|
-
const measureForNextLevel = createNestedResolver(true, fullIdChain, childCounterRef, depth, _measureInternal, prefix);
|
|
226
|
+
const measureForNextLevel = createNestedResolver(true, fullIdChain, childCounterRef, depth, _measureInternal, prefix, effectiveMaxLen);
|
|
197
227
|
try {
|
|
198
|
-
|
|
228
|
+
let result;
|
|
229
|
+
if (timeout && timeout > 0) {
|
|
230
|
+
result = await Promise.race([
|
|
231
|
+
fnInternal(measureForNextLevel),
|
|
232
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout (${formatDuration(timeout)})`)), timeout))
|
|
233
|
+
]);
|
|
234
|
+
} else {
|
|
235
|
+
result = await fnInternal(measureForNextLevel);
|
|
236
|
+
}
|
|
199
237
|
const duration = performance.now() - start;
|
|
200
|
-
emit({ type: "success", id: idStr, label, depth, duration, result, budget }, prefix);
|
|
238
|
+
emit({ type: "success", id: idStr, label, depth, duration, result, budget, maxResultLength: effectiveMaxLen }, prefix);
|
|
201
239
|
return result;
|
|
202
240
|
} catch (error) {
|
|
203
241
|
const duration = performance.now() - start;
|
|
204
|
-
emit({ type: "error", id: idStr, label, depth, duration, error, budget }, prefix);
|
|
242
|
+
emit({ type: "error", id: idStr, label, depth, duration, error, budget, maxResultLength: effectiveMaxLen }, prefix);
|
|
205
243
|
_lastError = error;
|
|
244
|
+
if (onError) {
|
|
245
|
+
try {
|
|
246
|
+
return onError(error);
|
|
247
|
+
} catch (onErrorError) {
|
|
248
|
+
emit({ type: "error", id: idStr, label: `${label} (onError)`, depth, duration: performance.now() - start, error: onErrorError, budget, maxResultLength: effectiveMaxLen }, prefix);
|
|
249
|
+
_lastError = onErrorError;
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
206
253
|
return null;
|
|
207
254
|
}
|
|
208
255
|
};
|
|
209
|
-
const _measureInternalSync = (fnInternal, actionInternal, parentIdChain, depth) => {
|
|
256
|
+
const _measureInternalSync = (fnInternal, actionInternal, parentIdChain, depth, _onError, inheritedMaxLen) => {
|
|
210
257
|
const start = performance.now();
|
|
211
258
|
const childCounterRef = { value: 0 };
|
|
212
259
|
const label = buildActionLabel(actionInternal);
|
|
213
260
|
const hasNested = fnInternal.length > 0;
|
|
214
261
|
const budget = extractBudget(actionInternal);
|
|
215
|
-
const
|
|
216
|
-
const
|
|
262
|
+
const localMaxLen = extractMaxResultLength(actionInternal);
|
|
263
|
+
const effectiveMaxLen = localMaxLen ?? inheritedMaxLen;
|
|
264
|
+
const currentId = toAlpha(Number(parentIdChain.pop() ?? 0));
|
|
265
|
+
const fullIdChain = [...parentIdChain.map(String), currentId];
|
|
217
266
|
const idStr = fullIdChain.join("-");
|
|
218
267
|
if (hasNested) {
|
|
219
268
|
emit({
|
|
@@ -224,22 +273,22 @@ var createMeasureImpl = (prefix, counterRef) => {
|
|
|
224
273
|
meta: extractMeta(actionInternal)
|
|
225
274
|
}, prefix);
|
|
226
275
|
}
|
|
227
|
-
const measureForNextLevel = createNestedResolver(false, fullIdChain, childCounterRef, depth, _measureInternalSync, prefix);
|
|
276
|
+
const measureForNextLevel = createNestedResolver(false, fullIdChain, childCounterRef, depth, _measureInternalSync, prefix, effectiveMaxLen);
|
|
228
277
|
try {
|
|
229
278
|
const result = fnInternal(measureForNextLevel);
|
|
230
279
|
const duration = performance.now() - start;
|
|
231
|
-
emit({ type: "success", id: idStr, label, depth, duration, result, budget }, prefix);
|
|
280
|
+
emit({ type: "success", id: idStr, label, depth, duration, result, budget, maxResultLength: effectiveMaxLen }, prefix);
|
|
232
281
|
return result;
|
|
233
282
|
} catch (error) {
|
|
234
283
|
const duration = performance.now() - start;
|
|
235
|
-
emit({ type: "error", id: idStr, label, depth, duration, error, budget }, prefix);
|
|
284
|
+
emit({ type: "error", id: idStr, label, depth, duration, error, budget, maxResultLength: effectiveMaxLen }, prefix);
|
|
236
285
|
_lastError = error;
|
|
237
286
|
return null;
|
|
238
287
|
}
|
|
239
288
|
};
|
|
240
|
-
const measureFn = async (arg1, arg2) => {
|
|
289
|
+
const measureFn = async (arg1, arg2, arg3) => {
|
|
241
290
|
if (typeof arg2 === "function") {
|
|
242
|
-
return _measureInternal(arg2, arg1, [counter.value++], 0);
|
|
291
|
+
return _measureInternal(arg2, arg1, [counter.value++], 0, arg3, scopeMaxLen);
|
|
243
292
|
} else {
|
|
244
293
|
const currentId = toAlpha(counter.value++);
|
|
245
294
|
emit({
|
|
@@ -349,7 +398,7 @@ var createMeasureImpl = (prefix, counterRef) => {
|
|
|
349
398
|
};
|
|
350
399
|
const measureSyncFn = (arg1, arg2) => {
|
|
351
400
|
if (typeof arg2 === "function") {
|
|
352
|
-
return _measureInternalSync(arg2, arg1, [counter.value++], 0);
|
|
401
|
+
return _measureInternalSync(arg2, arg1, [counter.value++], 0, undefined, scopeMaxLen);
|
|
353
402
|
} else {
|
|
354
403
|
const currentId = toAlpha(counter.value++);
|
|
355
404
|
emit({
|
|
@@ -385,9 +434,9 @@ var createMeasureImpl = (prefix, counterRef) => {
|
|
|
385
434
|
var globalInstance = createMeasureImpl();
|
|
386
435
|
var measure = globalInstance.measure;
|
|
387
436
|
var measureSync = globalInstance.measureSync;
|
|
388
|
-
var createMeasure = (scopePrefix) => {
|
|
437
|
+
var createMeasure = (scopePrefix, opts) => {
|
|
389
438
|
const scopeCounter = { value: 0 };
|
|
390
|
-
const scoped = createMeasureImpl(scopePrefix, scopeCounter);
|
|
439
|
+
const scoped = createMeasureImpl(scopePrefix, scopeCounter, opts);
|
|
391
440
|
return {
|
|
392
441
|
...scoped,
|
|
393
442
|
resetCounter: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sqlite-zod-orm",
|
|
3
|
-
"version": "3.26.
|
|
3
|
+
"version": "3.26.1",
|
|
4
4
|
"description": "Type-safe SQLite ORM for Bun — Zod schemas, fluent queries, auto relationships, zero SQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"typescript": "^5.0.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"measure-fn": "^3.
|
|
52
|
+
"measure-fn": "^3.10.0",
|
|
53
53
|
"zod": "^3.25.67"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"bun": ">=1.0.0"
|
|
57
57
|
}
|
|
58
|
-
}
|
|
58
|
+
}
|