@monlite/core 0.1.0 → 0.3.0
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 +69 -7
- package/dist/index.cjs +220 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +219 -29
- package/dist/index.js.map +1 -1
- package/package.json +16 -3
package/README.md
CHANGED
|
@@ -26,11 +26,18 @@ That's it. No setup. No config. Your data is in `app.db`.
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
npm install @monlite/core
|
|
29
|
-
# or: pnpm add @monlite/core / yarn add @monlite/core
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
monlite
|
|
33
|
-
|
|
31
|
+
**monlite has zero required dependencies.** On **Node 22.5+** it uses the
|
|
32
|
+
built-in [`node:sqlite`](https://nodejs.org/api/sqlite.html) engine out of the
|
|
33
|
+
box. To run on Node 18/20 — or to avoid `node:sqlite`'s experimental warning —
|
|
34
|
+
also install the (optional) native driver:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @monlite/core better-sqlite3
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
See [Drivers & zero dependencies](#drivers--zero-dependencies) below.
|
|
34
41
|
|
|
35
42
|
---
|
|
36
43
|
|
|
@@ -65,6 +72,7 @@ const mem = createDb(":memory:"); // in-memory database
|
|
|
65
72
|
|
|
66
73
|
```ts
|
|
67
74
|
const db = createDb("./app.db", {
|
|
75
|
+
driver: "auto", // "auto" | "better-sqlite3" | "node:sqlite" (default: "auto")
|
|
68
76
|
autoIndex: true, // auto-create indexes on hot JSON paths (default: true)
|
|
69
77
|
autoIndexAfter: 10, // create an index after a path is queried N times (default: 10)
|
|
70
78
|
readonly: false, // open read-only (default: false)
|
|
@@ -242,6 +250,29 @@ const grouped = await users.groupBy({
|
|
|
242
250
|
orderBy: { _count: "desc" },
|
|
243
251
|
});
|
|
244
252
|
// [ { role: "admin", _count: 5, _sum: { age: 140 } }, … ]
|
|
253
|
+
|
|
254
|
+
// groupBy + having (filter groups by an aggregate, like SQL HAVING)
|
|
255
|
+
await users.groupBy({
|
|
256
|
+
by: ["role"],
|
|
257
|
+
_count: true,
|
|
258
|
+
_sum: { age: true },
|
|
259
|
+
having: {
|
|
260
|
+
_count: { gte: 2 }, // keep groups with COUNT(*) >= 2
|
|
261
|
+
_sum: { age: { gt: 50 } }, // and SUM(age) > 50
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
// having comparisons: equals, not, gt, gte, lt, lte — on _count and on
|
|
265
|
+
// _sum/_avg/_min/_max of any field.
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### distinct
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
await users.distinct("role"); // ["admin", "editor"]
|
|
272
|
+
await users.distinct("age", { role: "admin" }); // [28, 31]
|
|
273
|
+
|
|
274
|
+
// Array fields are unwound — each element is a value (like MongoDB):
|
|
275
|
+
await users.distinct("tags"); // ["a", "b", "c"]
|
|
245
276
|
```
|
|
246
277
|
|
|
247
278
|
---
|
|
@@ -276,7 +307,9 @@ await db.$transaction((tx) => {
|
|
|
276
307
|
});
|
|
277
308
|
```
|
|
278
309
|
|
|
279
|
-
Need the raw driver? `db.sqlite` is the underlying
|
|
310
|
+
Need the raw driver? `db.sqlite` is the underlying native handle (a
|
|
311
|
+
`better-sqlite3` `Database` or a `node:sqlite` `DatabaseSync`, depending on the
|
|
312
|
+
active backend), and `db.driverName` tells you which one is in use.
|
|
280
313
|
|
|
281
314
|
---
|
|
282
315
|
|
|
@@ -302,11 +335,39 @@ await db.$collections(); // string[] of collection names
|
|
|
302
335
|
await db.$drop("users"); // drop a collection and its data
|
|
303
336
|
await db.$dropAll(); // drop everything
|
|
304
337
|
await db.$disconnect(); // close the connection
|
|
305
|
-
db.sqlite; // the underlying
|
|
338
|
+
db.sqlite; // the underlying native driver handle
|
|
339
|
+
db.driverName; // "better-sqlite3" | "node:sqlite"
|
|
306
340
|
```
|
|
307
341
|
|
|
308
342
|
---
|
|
309
343
|
|
|
344
|
+
## Drivers & zero dependencies
|
|
345
|
+
|
|
346
|
+
monlite talks to SQLite through a tiny driver adapter, so it runs on two
|
|
347
|
+
interchangeable backends:
|
|
348
|
+
|
|
349
|
+
| Backend | When it's used | Notes |
|
|
350
|
+
|---|---|---|
|
|
351
|
+
| **`node:sqlite`** | Built into Node **22.5+** | **Zero dependencies.** Still flagged experimental by Node, so it prints a one-time `ExperimentalWarning`. |
|
|
352
|
+
| **`better-sqlite3`** | When the package is installed | Battle-tested native driver. Works on Node 18/20/22, no warning. Install it yourself: `npm i better-sqlite3`. |
|
|
353
|
+
|
|
354
|
+
By default (`driver: "auto"`) monlite uses `better-sqlite3` if it's installed,
|
|
355
|
+
otherwise falls back to the built-in `node:sqlite`. Force one explicitly:
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
createDb("./app.db", { driver: "node:sqlite" }); // zero-dep (Node 22.5+)
|
|
359
|
+
createDb("./app.db", { driver: "better-sqlite3" }); // native, no warning
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Both backends pass the exact same test suite, so behavior is identical — pick
|
|
363
|
+
based on your Node version and whether you want the extra dependency.
|
|
364
|
+
|
|
365
|
+
> Want truly zero dependencies on Node 22.5+? Just `npm install @monlite/core`
|
|
366
|
+
> and don't install `better-sqlite3`. To silence the experimental warning,
|
|
367
|
+
> either install `better-sqlite3` or run Node with `--no-warnings`.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
310
371
|
## How it works
|
|
311
372
|
|
|
312
373
|
Every collection is a single SQLite table:
|
|
@@ -325,8 +386,9 @@ and `updated_at` are real columns. SQLite's built-in `json_extract` /
|
|
|
325
386
|
`json_each` power all document queries. No columns are added per field, so
|
|
326
387
|
there is no schema and no migration — ever.
|
|
327
388
|
|
|
328
|
-
All operations are synchronous under the hood (
|
|
329
|
-
exposed as `async` (they return Promises) for API consistency and
|
|
389
|
+
All operations are synchronous under the hood (both SQLite backends are sync)
|
|
390
|
+
but are exposed as `async` (they return Promises) for API consistency and
|
|
391
|
+
future-proofing.
|
|
330
392
|
|
|
331
393
|
### Notes & limitations
|
|
332
394
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var Database = require('better-sqlite3');
|
|
4
3
|
var crypto = require('crypto');
|
|
4
|
+
var module$1 = require('module');
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var Database__default = /*#__PURE__*/_interopDefault(Database);
|
|
9
|
-
|
|
10
|
-
// src/db.ts
|
|
6
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
7
|
+
// src/id.ts
|
|
11
8
|
var PROCESS_UNIQUE = crypto.randomBytes(5);
|
|
12
9
|
var counter = crypto.randomBytes(3).readUIntBE(0, 3);
|
|
13
10
|
function objectId() {
|
|
@@ -382,6 +379,44 @@ function aggregate(ctx, args) {
|
|
|
382
379
|
}
|
|
383
380
|
return result;
|
|
384
381
|
}
|
|
382
|
+
var HAVING_FNS = [
|
|
383
|
+
["_sum", "SUM"],
|
|
384
|
+
["_avg", "AVG"],
|
|
385
|
+
["_min", "MIN"],
|
|
386
|
+
["_max", "MAX"]
|
|
387
|
+
];
|
|
388
|
+
function comparisonSql(expr, cmp2, params) {
|
|
389
|
+
const out = [];
|
|
390
|
+
const ops = [
|
|
391
|
+
["equals", "="],
|
|
392
|
+
["not", "<>"],
|
|
393
|
+
["gt", ">"],
|
|
394
|
+
["gte", ">="],
|
|
395
|
+
["lt", "<"],
|
|
396
|
+
["lte", "<="]
|
|
397
|
+
];
|
|
398
|
+
for (const [key, op] of ops) {
|
|
399
|
+
const v = cmp2[key];
|
|
400
|
+
if (v === void 0) continue;
|
|
401
|
+
params.push(v);
|
|
402
|
+
out.push(`${expr} ${op} ?`);
|
|
403
|
+
}
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
function buildHaving(having, params) {
|
|
407
|
+
const parts = [];
|
|
408
|
+
if (having._count) {
|
|
409
|
+
parts.push(...comparisonSql("COUNT(*)", having._count, params));
|
|
410
|
+
}
|
|
411
|
+
for (const [kind, fn] of HAVING_FNS) {
|
|
412
|
+
const selection = having[kind];
|
|
413
|
+
if (!selection) continue;
|
|
414
|
+
for (const field of Object.keys(selection)) {
|
|
415
|
+
parts.push(...comparisonSql(`${fn}(${fieldExpr(field)})`, selection[field], params));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return parts.join(" AND ");
|
|
419
|
+
}
|
|
385
420
|
function groupBy(ctx, args) {
|
|
386
421
|
if (!Array.isArray(args.by) || args.by.length === 0) {
|
|
387
422
|
throw new Error("groupBy requires a non-empty `by` array");
|
|
@@ -400,6 +435,10 @@ function groupBy(ctx, args) {
|
|
|
400
435
|
const { selects: accSelects, cols } = buildAccumulators(args, ctx.onPath);
|
|
401
436
|
selects.push(...accSelects);
|
|
402
437
|
let sql = `SELECT ${selects.join(", ")} FROM "${ctx.table}" WHERE ${where} GROUP BY ${groupExprs.join(", ")}`;
|
|
438
|
+
if (args.having) {
|
|
439
|
+
const havingSql = buildHaving(args.having, params);
|
|
440
|
+
if (havingSql) sql += ` HAVING ${havingSql}`;
|
|
441
|
+
}
|
|
403
442
|
if (args.orderBy) {
|
|
404
443
|
const parts = [];
|
|
405
444
|
for (const key of Object.keys(args.orderBy)) {
|
|
@@ -445,7 +484,7 @@ var Collection = class {
|
|
|
445
484
|
initialized = false;
|
|
446
485
|
trackPath = (path) => this.mon.autoIndexer.track(this.name, path);
|
|
447
486
|
get db() {
|
|
448
|
-
return this.mon.
|
|
487
|
+
return this.mon.driver;
|
|
449
488
|
}
|
|
450
489
|
ensureTable() {
|
|
451
490
|
if (this.initialized) return;
|
|
@@ -491,13 +530,12 @@ var Collection = class {
|
|
|
491
530
|
const stmt = this.db.prepare(
|
|
492
531
|
`INSERT INTO "${this.name}" (_id, data, created_at, updated_at) VALUES (?, ?, ?, ?)`
|
|
493
532
|
);
|
|
494
|
-
|
|
495
|
-
for (const item of
|
|
533
|
+
this.db.transaction(() => {
|
|
534
|
+
for (const item of args.data) {
|
|
496
535
|
const row = this.prepareInsert(item);
|
|
497
536
|
stmt.run(row._id, row.data, row.created_at, row.updated_at);
|
|
498
537
|
}
|
|
499
538
|
});
|
|
500
|
-
insertAll(args.data);
|
|
501
539
|
return { count: args.data.length };
|
|
502
540
|
}
|
|
503
541
|
/* ------------------------------ read ------------------------------ */
|
|
@@ -537,6 +575,24 @@ var Collection = class {
|
|
|
537
575
|
const row = this.db.prepare(`SELECT COUNT(*) AS n FROM "${this.name}" WHERE ${where}`).get(...params);
|
|
538
576
|
return row.n;
|
|
539
577
|
}
|
|
578
|
+
/**
|
|
579
|
+
* Return the distinct values of a field across the collection. Array fields
|
|
580
|
+
* are unwound (each element counts as a value), matching MongoDB's `distinct`.
|
|
581
|
+
*/
|
|
582
|
+
async distinct(field, where) {
|
|
583
|
+
this.ensureTable();
|
|
584
|
+
const params = [];
|
|
585
|
+
const clause = buildWhere(where, { params, onPath: this.trackPath });
|
|
586
|
+
let sql;
|
|
587
|
+
if (isReserved(field)) {
|
|
588
|
+
sql = `SELECT DISTINCT ${fieldExpr(field)} AS v FROM "${this.name}" WHERE ${clause} ORDER BY v`;
|
|
589
|
+
} else {
|
|
590
|
+
this.trackPath(field);
|
|
591
|
+
sql = `SELECT DISTINCT je.value AS v FROM "${this.name}" CROSS JOIN json_each("${this.name}".data, ${pathLiteral(field)}) je WHERE ${clause} ORDER BY v`;
|
|
592
|
+
}
|
|
593
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
594
|
+
return rows.map((r) => r.v);
|
|
595
|
+
}
|
|
540
596
|
/* ----------------------------- update ----------------------------- */
|
|
541
597
|
runUpdate(where, data, single) {
|
|
542
598
|
this.ensureTable();
|
|
@@ -550,7 +606,7 @@ var Collection = class {
|
|
|
550
606
|
const stmt = this.db.prepare(
|
|
551
607
|
`UPDATE "${this.name}" SET data = ?, updated_at = ? WHERE _id = ?`
|
|
552
608
|
);
|
|
553
|
-
|
|
609
|
+
return this.db.transaction(() => {
|
|
554
610
|
const out = [];
|
|
555
611
|
for (const row of rows) {
|
|
556
612
|
const current = JSON.parse(row.data);
|
|
@@ -565,7 +621,6 @@ var Collection = class {
|
|
|
565
621
|
}
|
|
566
622
|
return out;
|
|
567
623
|
});
|
|
568
|
-
return txn();
|
|
569
624
|
}
|
|
570
625
|
async update(args) {
|
|
571
626
|
return this.runUpdate(args.where, args.data, true)[0] ?? null;
|
|
@@ -595,10 +650,9 @@ var Collection = class {
|
|
|
595
650
|
const rows = this.db.prepare(selectSql).all(...params);
|
|
596
651
|
if (!rows.length) return [];
|
|
597
652
|
const stmt = this.db.prepare(`DELETE FROM "${this.name}" WHERE _id = ?`);
|
|
598
|
-
|
|
653
|
+
this.db.transaction(() => {
|
|
599
654
|
for (const row of rows) stmt.run(row._id);
|
|
600
655
|
});
|
|
601
|
-
txn();
|
|
602
656
|
return rows.map((r) => this.rowToDoc(r));
|
|
603
657
|
}
|
|
604
658
|
async delete(args) {
|
|
@@ -676,6 +730,134 @@ var AutoIndexer = class {
|
|
|
676
730
|
}
|
|
677
731
|
};
|
|
678
732
|
|
|
733
|
+
// src/driver/better-sqlite3.ts
|
|
734
|
+
var BetterSqlite3Driver = class {
|
|
735
|
+
name = "better-sqlite3";
|
|
736
|
+
raw;
|
|
737
|
+
verbose;
|
|
738
|
+
constructor(BetterSqlite3, filename, options) {
|
|
739
|
+
this.verbose = options.verbose;
|
|
740
|
+
this.raw = new BetterSqlite3(filename, {
|
|
741
|
+
readonly: options.readonly ?? false
|
|
742
|
+
});
|
|
743
|
+
if (!options.readonly && (options.wal ?? true)) {
|
|
744
|
+
this.raw.pragma("journal_mode = WAL");
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
exec(sql) {
|
|
748
|
+
this.verbose?.(sql);
|
|
749
|
+
this.raw.exec(sql);
|
|
750
|
+
}
|
|
751
|
+
prepare(sql) {
|
|
752
|
+
this.verbose?.(sql);
|
|
753
|
+
return this.raw.prepare(sql);
|
|
754
|
+
}
|
|
755
|
+
transaction(fn) {
|
|
756
|
+
return this.raw.transaction(fn)();
|
|
757
|
+
}
|
|
758
|
+
close() {
|
|
759
|
+
this.raw.close();
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
// src/driver/node-sqlite.ts
|
|
764
|
+
var NodeSqliteDriver = class {
|
|
765
|
+
name = "node:sqlite";
|
|
766
|
+
raw;
|
|
767
|
+
verbose;
|
|
768
|
+
depth = 0;
|
|
769
|
+
constructor(nodeSqlite, filename, options) {
|
|
770
|
+
this.verbose = options.verbose;
|
|
771
|
+
const { DatabaseSync } = nodeSqlite;
|
|
772
|
+
this.raw = new DatabaseSync(filename, {
|
|
773
|
+
readOnly: options.readonly ?? false
|
|
774
|
+
});
|
|
775
|
+
if (!options.readonly && (options.wal ?? true)) {
|
|
776
|
+
this.raw.exec("PRAGMA journal_mode = WAL");
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
exec(sql) {
|
|
780
|
+
this.verbose?.(sql);
|
|
781
|
+
this.raw.exec(sql);
|
|
782
|
+
}
|
|
783
|
+
prepare(sql) {
|
|
784
|
+
this.verbose?.(sql);
|
|
785
|
+
const stmt = this.raw.prepare(sql);
|
|
786
|
+
return {
|
|
787
|
+
run: (...p) => stmt.run(...p),
|
|
788
|
+
get: (...p) => stmt.get(...p),
|
|
789
|
+
all: (...p) => stmt.all(...p)
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
transaction(fn) {
|
|
793
|
+
const savepoint = `monlite_sp_${this.depth}`;
|
|
794
|
+
if (this.depth === 0) this.raw.exec("BEGIN");
|
|
795
|
+
else this.raw.exec(`SAVEPOINT ${savepoint}`);
|
|
796
|
+
this.depth++;
|
|
797
|
+
try {
|
|
798
|
+
const result = fn();
|
|
799
|
+
this.depth--;
|
|
800
|
+
if (this.depth === 0) this.raw.exec("COMMIT");
|
|
801
|
+
else this.raw.exec(`RELEASE ${savepoint}`);
|
|
802
|
+
return result;
|
|
803
|
+
} catch (err) {
|
|
804
|
+
this.depth--;
|
|
805
|
+
if (this.depth === 0) this.raw.exec("ROLLBACK");
|
|
806
|
+
else this.raw.exec(`ROLLBACK TO ${savepoint}; RELEASE ${savepoint}`);
|
|
807
|
+
throw err;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
close() {
|
|
811
|
+
this.raw.close();
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
// src/driver/index.ts
|
|
816
|
+
var req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
817
|
+
function loadBetterSqlite3() {
|
|
818
|
+
try {
|
|
819
|
+
const mod = req("better-sqlite3");
|
|
820
|
+
return mod?.default ?? mod;
|
|
821
|
+
} catch {
|
|
822
|
+
return null;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
function loadNodeSqlite() {
|
|
826
|
+
try {
|
|
827
|
+
return req("node:sqlite");
|
|
828
|
+
} catch {
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function createDriver(filename, options = {}) {
|
|
833
|
+
const choice = options.driver ?? "auto";
|
|
834
|
+
if (choice === "better-sqlite3") {
|
|
835
|
+
const mod = loadBetterSqlite3();
|
|
836
|
+
if (!mod) {
|
|
837
|
+
throw new MonliteError(
|
|
838
|
+
`driver "better-sqlite3" was requested but the package is not installed. Run \`npm install better-sqlite3\`.`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
return new BetterSqlite3Driver(mod, filename, options);
|
|
842
|
+
}
|
|
843
|
+
if (choice === "node:sqlite") {
|
|
844
|
+
const mod = loadNodeSqlite();
|
|
845
|
+
if (!mod) {
|
|
846
|
+
throw new MonliteError(
|
|
847
|
+
`driver "node:sqlite" is unavailable. It requires Node >= 22.5.`
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
return new NodeSqliteDriver(mod, filename, options);
|
|
851
|
+
}
|
|
852
|
+
const better = loadBetterSqlite3();
|
|
853
|
+
if (better) return new BetterSqlite3Driver(better, filename, options);
|
|
854
|
+
const node = loadNodeSqlite();
|
|
855
|
+
if (node) return new NodeSqliteDriver(node, filename, options);
|
|
856
|
+
throw new MonliteError(
|
|
857
|
+
`No SQLite driver available. Either install better-sqlite3 (\`npm install better-sqlite3\`) or run on Node >= 22.5 for the built-in node:sqlite backend.`
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
|
|
679
861
|
// src/db.ts
|
|
680
862
|
function validateName(name) {
|
|
681
863
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
@@ -697,27 +879,33 @@ function buildTagged(strings, values) {
|
|
|
697
879
|
return { sql, params };
|
|
698
880
|
}
|
|
699
881
|
var Monlite = class {
|
|
700
|
-
/** The
|
|
701
|
-
|
|
882
|
+
/** @internal The active SQLite driver. */
|
|
883
|
+
driver;
|
|
702
884
|
/** @internal */
|
|
703
885
|
autoIndexer;
|
|
704
886
|
collections = /* @__PURE__ */ new Map();
|
|
705
887
|
closed = false;
|
|
706
888
|
constructor(filename, options = {}) {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
readonly: options.readonly
|
|
710
|
-
|
|
889
|
+
this.driver = createDriver(filename, {
|
|
890
|
+
driver: options.driver,
|
|
891
|
+
readonly: options.readonly,
|
|
892
|
+
wal: options.wal,
|
|
893
|
+
verbose: options.verbose
|
|
711
894
|
});
|
|
712
|
-
if (!options.readonly && (options.wal ?? true)) {
|
|
713
|
-
this.sqlite.pragma("journal_mode = WAL");
|
|
714
|
-
}
|
|
715
895
|
this.autoIndexer = new AutoIndexer(
|
|
716
|
-
this.
|
|
896
|
+
this.driver,
|
|
717
897
|
options.autoIndex ?? true,
|
|
718
898
|
options.autoIndexAfter ?? 10
|
|
719
899
|
);
|
|
720
900
|
}
|
|
901
|
+
/** The underlying native database handle (escape hatch). */
|
|
902
|
+
get sqlite() {
|
|
903
|
+
return this.driver.raw;
|
|
904
|
+
}
|
|
905
|
+
/** Name of the active backend: `"better-sqlite3"` or `"node:sqlite"`. */
|
|
906
|
+
get driverName() {
|
|
907
|
+
return this.driver.name;
|
|
908
|
+
}
|
|
721
909
|
/** Get (or lazily create) a typed collection handle. */
|
|
722
910
|
collection(name) {
|
|
723
911
|
this.assertOpen();
|
|
@@ -733,26 +921,26 @@ var Monlite = class {
|
|
|
733
921
|
$queryRaw(strings, ...values) {
|
|
734
922
|
this.assertOpen();
|
|
735
923
|
const { sql, params } = buildTagged(strings, values);
|
|
736
|
-
return Promise.resolve(this.
|
|
924
|
+
return Promise.resolve(this.driver.prepare(sql).all(...params));
|
|
737
925
|
}
|
|
738
926
|
/** Like {@link $queryRaw} but takes a raw SQL string and positional params. */
|
|
739
927
|
$queryRawUnsafe(sql, ...params) {
|
|
740
928
|
this.assertOpen();
|
|
741
929
|
return Promise.resolve(
|
|
742
|
-
this.
|
|
930
|
+
this.driver.prepare(sql).all(...params.map(bindable))
|
|
743
931
|
);
|
|
744
932
|
}
|
|
745
933
|
/** Tagged-template SQL statement returning the number of affected rows. */
|
|
746
934
|
$executeRaw(strings, ...values) {
|
|
747
935
|
this.assertOpen();
|
|
748
936
|
const { sql, params } = buildTagged(strings, values);
|
|
749
|
-
return Promise.resolve(this.
|
|
937
|
+
return Promise.resolve(this.driver.prepare(sql).run(...params).changes);
|
|
750
938
|
}
|
|
751
939
|
/** Like {@link $executeRaw} but takes a raw SQL string and positional params. */
|
|
752
940
|
$executeRawUnsafe(sql, ...params) {
|
|
753
941
|
this.assertOpen();
|
|
754
942
|
return Promise.resolve(
|
|
755
|
-
this.
|
|
943
|
+
this.driver.prepare(sql).run(...params.map(bindable)).changes
|
|
756
944
|
);
|
|
757
945
|
}
|
|
758
946
|
/**
|
|
@@ -761,13 +949,12 @@ var Monlite = class {
|
|
|
761
949
|
*/
|
|
762
950
|
async $transaction(fn) {
|
|
763
951
|
this.assertOpen();
|
|
764
|
-
|
|
765
|
-
return txn();
|
|
952
|
+
return this.driver.transaction(() => fn(this));
|
|
766
953
|
}
|
|
767
954
|
/** List all collection (table) names. */
|
|
768
955
|
$collections() {
|
|
769
956
|
this.assertOpen();
|
|
770
|
-
const rows = this.
|
|
957
|
+
const rows = this.driver.prepare(
|
|
771
958
|
`SELECT name FROM sqlite_master
|
|
772
959
|
WHERE type='table' AND name NOT LIKE 'sqlite_%'
|
|
773
960
|
ORDER BY name`
|
|
@@ -778,7 +965,7 @@ var Monlite = class {
|
|
|
778
965
|
$drop(name) {
|
|
779
966
|
this.assertOpen();
|
|
780
967
|
validateName(name);
|
|
781
|
-
this.
|
|
968
|
+
this.driver.exec(`DROP TABLE IF EXISTS "${name}"`);
|
|
782
969
|
this.collections.delete(name);
|
|
783
970
|
this.autoIndexer.reset(name);
|
|
784
971
|
return Promise.resolve();
|
|
@@ -791,7 +978,7 @@ var Monlite = class {
|
|
|
791
978
|
$disconnect() {
|
|
792
979
|
if (!this.closed) {
|
|
793
980
|
this.closed = true;
|
|
794
|
-
this.
|
|
981
|
+
this.driver.close();
|
|
795
982
|
}
|
|
796
983
|
return Promise.resolve();
|
|
797
984
|
}
|