@semics-tech/mongolite 1.0.0 → 1.2.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/LICENSE +1 -1
- package/README.md +78 -2
- package/dist/adapters/node-sqlite.d.ts +65 -0
- package/dist/adapters/node-sqlite.js +241 -0
- package/dist/adapters/node-sqlite.js.map +1 -0
- package/dist/better-sqlite3.d.ts +49 -0
- package/dist/better-sqlite3.js +60 -0
- package/dist/better-sqlite3.js.map +1 -0
- package/dist/bin/mongolite-debug.js +0 -0
- package/dist/cjs/adapters/browser.js +106 -0
- package/dist/cjs/adapters/cloudflare.js +97 -0
- package/dist/cjs/adapters/node-sqlite.js +248 -0
- package/dist/cjs/better-sqlite3.js +80 -0
- package/dist/cjs/bin/mongolite-debug.js +152 -0
- package/dist/cjs/changeStream.js +341 -0
- package/dist/cjs/cloudflare.js +59 -0
- package/dist/cjs/collection.js +1748 -0
- package/dist/cjs/cursors/findCursor.js +837 -0
- package/dist/cjs/db.js +307 -0
- package/dist/cjs/debugger/query-debugger.js +297 -0
- package/dist/cjs/index.js +65 -0
- package/dist/cjs/mongo-client.js +58 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/utils/connection-registry.js +122 -0
- package/dist/cjs/utils/indexing.js +45 -0
- package/dist/cjs/utils/projection.js +101 -0
- package/dist/cjs/utils/queryOperators.js +142 -0
- package/dist/collection.d.ts +25 -0
- package/dist/collection.js +53 -14
- package/dist/collection.js.map +1 -1
- package/dist/cursors/findCursor.d.ts +58 -0
- package/dist/cursors/findCursor.js +88 -11
- package/dist/cursors/findCursor.js.map +1 -1
- package/dist/db.d.ts +23 -0
- package/dist/db.js +85 -39
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/utils/connection-registry.d.ts +74 -0
- package/dist/utils/connection-registry.js +117 -0
- package/dist/utils/connection-registry.js.map +1 -0
- package/package.json +20 -10
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -18,12 +18,13 @@ A MongoDB-like client backed by SQLite. Use a familiar MongoDB API with the simp
|
|
|
18
18
|
- **MongoDB-compatible API** — `insertOne`, `findOne`, `updateOne`, `deleteOne`, `find`, `aggregate`, and more
|
|
19
19
|
- **SQLite persistence** — single file, zero configuration, works offline
|
|
20
20
|
- **Automatic `_id` generation** — UUID assigned on insert if not provided
|
|
21
|
-
- **WAL mode** — Write-Ahead Logging for better concurrent read access
|
|
21
|
+
- **WAL mode** — Write-Ahead Logging for better concurrent read access, on by default
|
|
22
|
+
- **Shared connections** — opt into one pooled connection per file per process
|
|
22
23
|
- **Rich query operators** — `$eq`, `$gt`, `$in`, `$and`, `$or`, `$elemMatch`, `$regex`, and more
|
|
23
24
|
- **Update operators** — `$set`, `$inc`, `$push`, `$pull`, `$addToSet`, `$mul`, and more
|
|
24
25
|
- **Indexing** — create, list, and drop indexes including unique and compound indexes
|
|
25
26
|
- **Change streams** — real-time change tracking via `collection.watch()`
|
|
26
|
-
- **JSON safety** — validates documents before insert and
|
|
27
|
+
- **JSON safety** — validates documents before insert, and a corrupted row can't break queries for the rest of the collection
|
|
27
28
|
- **TypeScript** — fully typed with strict mode
|
|
28
29
|
|
|
29
30
|
## Installation
|
|
@@ -32,6 +33,13 @@ A MongoDB-like client backed by SQLite. Use a familiar MongoDB API with the simp
|
|
|
32
33
|
npm install @semics-tech/mongolite
|
|
33
34
|
```
|
|
34
35
|
|
|
36
|
+
Requires **Node.js 22.5.0+** by default — the main entry point is backed by
|
|
37
|
+
Node's built-in `node:sqlite` module, so there's no native addon to install or
|
|
38
|
+
build. On an older Node.js runtime, use the `better-sqlite3`-backed adapter
|
|
39
|
+
instead; see [Native `node:sqlite` vs. `better-sqlite3`](#native-nodesqlite-vs-better-sqlite3) below.
|
|
40
|
+
|
|
41
|
+
Ships both ESM (`import`) and CommonJS (`require`) builds — use whichever your project already uses.
|
|
42
|
+
|
|
35
43
|
## Quick Start
|
|
36
44
|
|
|
37
45
|
```typescript
|
|
@@ -99,6 +107,43 @@ await users.insertOne({ name: 'Alice', age: 30 });
|
|
|
99
107
|
await client.close();
|
|
100
108
|
```
|
|
101
109
|
|
|
110
|
+
### Connection options
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
const client = new MongoLite({
|
|
114
|
+
filePath: './myapp.sqlite',
|
|
115
|
+
WAL: true, // Write-Ahead Logging. Default: true
|
|
116
|
+
busyTimeout: 5000, // ms to wait for a lock before SQLITE_BUSY. Default: 5000
|
|
117
|
+
shared: true, // reuse one connection per file in this process. Default: false
|
|
118
|
+
readOnly: false,
|
|
119
|
+
verbose: false,
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Sharing one connection across a process
|
|
124
|
+
|
|
125
|
+
Applications often end up with several clients pointing at the same database file
|
|
126
|
+
— a module-level client, a background job, a request handler — each opening its
|
|
127
|
+
own connection, and each then hand-rolling an instance cache to avoid the
|
|
128
|
+
resulting lock contention. `shared: true` moves that into the library:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// Both resolve to the same file, so they share a single SQLite connection.
|
|
132
|
+
const a = new MongoLite({ filePath: './app.sqlite', shared: true });
|
|
133
|
+
const b = new MongoLite({ filePath: './app.sqlite', shared: true });
|
|
134
|
+
|
|
135
|
+
await a.close(); // b keeps working — the handle is reference counted
|
|
136
|
+
await b.close(); // last holder out actually closes it
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Connections are only shared when the resolved path *and* every setting that
|
|
140
|
+
changes the handle's behaviour match. `:memory:` databases are never shared,
|
|
141
|
+
since two `:memory:` opens are two unrelated databases.
|
|
142
|
+
|
|
143
|
+
This dedupes connections **within a process only**. Separate processes each get
|
|
144
|
+
their own, so cross-process contention is handled by WAL mode and `busyTimeout`
|
|
145
|
+
instead.
|
|
146
|
+
|
|
102
147
|
### In-memory (tests / ephemeral)
|
|
103
148
|
|
|
104
149
|
```typescript
|
|
@@ -112,6 +157,37 @@ await users.insertOne({ name: 'Alice', age: 30 });
|
|
|
112
157
|
await client.close();
|
|
113
158
|
```
|
|
114
159
|
|
|
160
|
+
### `better-sqlite3` (optional, for Node.js <22.5 or Bun)
|
|
161
|
+
|
|
162
|
+
The default backend above uses Node's built-in `node:sqlite` module, which
|
|
163
|
+
requires Node.js 22.5.0+. If you're on an older Node.js runtime, or you
|
|
164
|
+
simply prefer the more battle-tested native addon, import from the
|
|
165
|
+
`@semics-tech/mongolite/better-sqlite3` entry point instead. `better-sqlite3` is an
|
|
166
|
+
**optional dependency** — install it yourself if it wasn't already pulled in:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npm install better-sqlite3
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { MongoLite } from '@semics-tech/mongolite/better-sqlite3';
|
|
174
|
+
|
|
175
|
+
const client = new MongoLite('./myapp.sqlite');
|
|
176
|
+
await client.connect();
|
|
177
|
+
const users = client.collection('users');
|
|
178
|
+
await users.insertOne({ name: 'Alice', age: 30 });
|
|
179
|
+
await client.close();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
<a id="native-nodesqlite-vs-better-sqlite3"></a>
|
|
183
|
+
> **Which one should I use?** `node:sqlite` (the default) is still marked
|
|
184
|
+
> experimental upstream but requires no native build step, which is why it's
|
|
185
|
+
> the default here. `better-sqlite3` is the older, more battle-tested native
|
|
186
|
+
> addon — reach for it if you're stuck on Node.js <22.5, targeting Bun without
|
|
187
|
+
> a `node:sqlite` polyfill, or want to avoid depending on an experimental
|
|
188
|
+
> Node.js API in production. Both implement the same `IDatabaseAdapter`
|
|
189
|
+
> interface, so switching between them is a one-line import change.
|
|
190
|
+
|
|
115
191
|
### Browser (via sql.js)
|
|
116
192
|
|
|
117
193
|
Requires [sql.js](https://www.npmjs.com/package/sql.js) (`npm install sql.js`).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { IDatabaseAdapter, MongoLiteOptions } from '../db.js';
|
|
3
|
+
/** Exposed for tests and diagnostics. */
|
|
4
|
+
export declare function sharedConnectionCount(): number;
|
|
5
|
+
/**
|
|
6
|
+
* Database adapter backed by Node.js's built-in `node:sqlite` module — no native
|
|
7
|
+
* addon, no prebuilt binary, no `node-gyp`. Requires Node.js 22.5.0+ (the module
|
|
8
|
+
* is marked experimental by Node.js until it graduates to stable).
|
|
9
|
+
*
|
|
10
|
+
* ## Usage
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { MongoLite, NodeSqliteAdapter } from '@semics-tech/mongolite';
|
|
14
|
+
*
|
|
15
|
+
* const client = new MongoLite(new NodeSqliteAdapter('./data.db'));
|
|
16
|
+
* await client.connect();
|
|
17
|
+
* const users = client.collection('users');
|
|
18
|
+
* await users.insertOne({ name: 'Alice', age: 30 });
|
|
19
|
+
* await client.close();
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* ## Limitations
|
|
23
|
+
*
|
|
24
|
+
* - **Experimental.** `node:sqlite` is still marked experimental upstream and its
|
|
25
|
+
* API may change between Node.js minor versions.
|
|
26
|
+
* - **Node.js 22.5.0+ only.** Importing this adapter on an older runtime (or on
|
|
27
|
+
* Bun/Deno without a `node:sqlite` polyfill) throws at import time.
|
|
28
|
+
* - Rows are returned with a `null` prototype (per `node:sqlite`'s API). Plain
|
|
29
|
+
* property access (`row.foo`) and `JSON.stringify`/`Object.keys` all work as
|
|
30
|
+
* expected; `row.hasOwnProperty(...)` does not.
|
|
31
|
+
*/
|
|
32
|
+
export declare class NodeSqliteAdapter implements IDatabaseAdapter {
|
|
33
|
+
private db;
|
|
34
|
+
private readonly filePath;
|
|
35
|
+
private readonly verbose;
|
|
36
|
+
private readonly readOnly;
|
|
37
|
+
private readonly WAL;
|
|
38
|
+
private readonly busyTimeout;
|
|
39
|
+
private readonly shareKey;
|
|
40
|
+
private openPromise;
|
|
41
|
+
/**
|
|
42
|
+
* @param dbPathOrOptions Path to the SQLite database file (use `':memory:'`
|
|
43
|
+
* for an in-memory database), or an options object mirroring the built-in
|
|
44
|
+
* `better-sqlite3` adapter's `MongoLiteOptions`.
|
|
45
|
+
*/
|
|
46
|
+
constructor(dbPathOrOptions: string | MongoLiteOptions);
|
|
47
|
+
/**
|
|
48
|
+
* Opens the database connection if it's not already open.
|
|
49
|
+
*/
|
|
50
|
+
connect(): Promise<void>;
|
|
51
|
+
private ensureConnected;
|
|
52
|
+
run(sql: string, params?: unknown[]): Promise<{
|
|
53
|
+
lastID: number;
|
|
54
|
+
changes: number;
|
|
55
|
+
}>;
|
|
56
|
+
get<T>(sql: string, params?: unknown[]): Promise<T | undefined>;
|
|
57
|
+
all<T>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
58
|
+
exec(sql: string): Promise<void>;
|
|
59
|
+
close(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Gets the underlying `node:sqlite` `DatabaseSync` instance.
|
|
62
|
+
* Useful for operations not covered by this wrapper.
|
|
63
|
+
*/
|
|
64
|
+
getDbInstance(): Promise<DatabaseSync>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ConnectionRegistry, DEFAULT_BUSY_TIMEOUT_MS, buildConnectionKey, isShareablePath, } from '../utils/connection-registry.js';
|
|
4
|
+
/** Shared `node:sqlite` handles for this process, keyed by connection identity. */
|
|
5
|
+
const sharedConnections = new ConnectionRegistry();
|
|
6
|
+
/** Exposed for tests and diagnostics. */
|
|
7
|
+
export function sharedConnectionCount() {
|
|
8
|
+
return sharedConnections.size;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Database adapter backed by Node.js's built-in `node:sqlite` module — no native
|
|
12
|
+
* addon, no prebuilt binary, no `node-gyp`. Requires Node.js 22.5.0+ (the module
|
|
13
|
+
* is marked experimental by Node.js until it graduates to stable).
|
|
14
|
+
*
|
|
15
|
+
* ## Usage
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { MongoLite, NodeSqliteAdapter } from '@semics-tech/mongolite';
|
|
19
|
+
*
|
|
20
|
+
* const client = new MongoLite(new NodeSqliteAdapter('./data.db'));
|
|
21
|
+
* await client.connect();
|
|
22
|
+
* const users = client.collection('users');
|
|
23
|
+
* await users.insertOne({ name: 'Alice', age: 30 });
|
|
24
|
+
* await client.close();
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* ## Limitations
|
|
28
|
+
*
|
|
29
|
+
* - **Experimental.** `node:sqlite` is still marked experimental upstream and its
|
|
30
|
+
* API may change between Node.js minor versions.
|
|
31
|
+
* - **Node.js 22.5.0+ only.** Importing this adapter on an older runtime (or on
|
|
32
|
+
* Bun/Deno without a `node:sqlite` polyfill) throws at import time.
|
|
33
|
+
* - Rows are returned with a `null` prototype (per `node:sqlite`'s API). Plain
|
|
34
|
+
* property access (`row.foo`) and `JSON.stringify`/`Object.keys` all work as
|
|
35
|
+
* expected; `row.hasOwnProperty(...)` does not.
|
|
36
|
+
*/
|
|
37
|
+
export class NodeSqliteAdapter {
|
|
38
|
+
/**
|
|
39
|
+
* @param dbPathOrOptions Path to the SQLite database file (use `':memory:'`
|
|
40
|
+
* for an in-memory database), or an options object mirroring the built-in
|
|
41
|
+
* `better-sqlite3` adapter's `MongoLiteOptions`.
|
|
42
|
+
*/
|
|
43
|
+
constructor(dbPathOrOptions) {
|
|
44
|
+
this.db = null;
|
|
45
|
+
this.openPromise = null;
|
|
46
|
+
let shared;
|
|
47
|
+
if (typeof dbPathOrOptions === 'string') {
|
|
48
|
+
this.filePath = dbPathOrOptions;
|
|
49
|
+
this.verbose = false;
|
|
50
|
+
this.readOnly = false;
|
|
51
|
+
this.WAL = true;
|
|
52
|
+
this.busyTimeout = DEFAULT_BUSY_TIMEOUT_MS;
|
|
53
|
+
shared = false;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.filePath = dbPathOrOptions.filePath;
|
|
57
|
+
this.verbose = dbPathOrOptions.verbose || false;
|
|
58
|
+
this.readOnly = dbPathOrOptions.readOnly || false;
|
|
59
|
+
this.WAL = dbPathOrOptions.WAL ?? true;
|
|
60
|
+
this.busyTimeout = dbPathOrOptions.busyTimeout ?? DEFAULT_BUSY_TIMEOUT_MS;
|
|
61
|
+
shared = dbPathOrOptions.shared ?? false;
|
|
62
|
+
}
|
|
63
|
+
this.shareKey =
|
|
64
|
+
shared && isShareablePath(this.filePath)
|
|
65
|
+
? buildConnectionKey({
|
|
66
|
+
backend: 'node:sqlite',
|
|
67
|
+
filePath: path.resolve(this.filePath),
|
|
68
|
+
readOnly: this.readOnly,
|
|
69
|
+
WAL: this.WAL,
|
|
70
|
+
busyTimeout: this.busyTimeout,
|
|
71
|
+
verbose: this.verbose,
|
|
72
|
+
})
|
|
73
|
+
: null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Opens the database connection if it's not already open.
|
|
77
|
+
*/
|
|
78
|
+
async connect() {
|
|
79
|
+
if (this.db && this.openPromise) {
|
|
80
|
+
return this.openPromise;
|
|
81
|
+
}
|
|
82
|
+
if (this.db) {
|
|
83
|
+
return Promise.resolve();
|
|
84
|
+
}
|
|
85
|
+
this.openPromise = new Promise((resolve, reject) => {
|
|
86
|
+
try {
|
|
87
|
+
// Only runs on a genuinely new connection — when sharing, an existing
|
|
88
|
+
// handle already has its pragmas and UDFs applied.
|
|
89
|
+
const openConnection = () => {
|
|
90
|
+
const db = new DatabaseSync(this.filePath, { readOnly: this.readOnly });
|
|
91
|
+
if (this.WAL && !this.readOnly) {
|
|
92
|
+
db.exec('PRAGMA journal_mode = WAL');
|
|
93
|
+
}
|
|
94
|
+
// Wait rather than immediately throwing SQLITE_BUSY when another
|
|
95
|
+
// connection (often another process) holds a lock.
|
|
96
|
+
if (this.busyTimeout > 0) {
|
|
97
|
+
db.exec(`PRAGMA busy_timeout = ${this.busyTimeout}`);
|
|
98
|
+
}
|
|
99
|
+
// Register regexp UDF for $regex operator support.
|
|
100
|
+
// WARNING: Patterns are compiled via JavaScript RegExp. User-supplied patterns that are
|
|
101
|
+
// not validated for catastrophic backtracking (ReDoS) could block the event loop.
|
|
102
|
+
// Avoid using untrusted/unvalidated patterns with $regex in security-sensitive contexts.
|
|
103
|
+
db.function('regexp', { deterministic: true }, (pattern, value) => {
|
|
104
|
+
if (typeof pattern !== 'string' || value === null || value === undefined)
|
|
105
|
+
return 0;
|
|
106
|
+
try {
|
|
107
|
+
return new RegExp(pattern).test(String(value)) ? 1 : 0;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// Register regexp_flags UDF for $regex with $options support
|
|
114
|
+
db.function('regexp_flags', { deterministic: true }, (pattern, flags, value) => {
|
|
115
|
+
if (typeof pattern !== 'string' || value === null || value === undefined)
|
|
116
|
+
return 0;
|
|
117
|
+
try {
|
|
118
|
+
const f = typeof flags === 'string' ? flags : '';
|
|
119
|
+
return new RegExp(pattern, f).test(String(value)) ? 1 : 0;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
if (this.verbose) {
|
|
126
|
+
console.log(`SQLite database opened (node:sqlite): ${this.filePath}`);
|
|
127
|
+
}
|
|
128
|
+
return db;
|
|
129
|
+
};
|
|
130
|
+
this.db = this.shareKey
|
|
131
|
+
? sharedConnections.acquire(this.shareKey, openConnection)
|
|
132
|
+
: openConnection();
|
|
133
|
+
resolve();
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
console.error(`Error opening database ${this.filePath}:`, err.message);
|
|
137
|
+
this.db = null;
|
|
138
|
+
this.openPromise = null;
|
|
139
|
+
reject(err);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
return this.openPromise;
|
|
143
|
+
}
|
|
144
|
+
async ensureConnected() {
|
|
145
|
+
if (!this.db || !this.openPromise) {
|
|
146
|
+
await this.connect();
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
await this.openPromise;
|
|
150
|
+
}
|
|
151
|
+
if (!this.db) {
|
|
152
|
+
throw new Error('Database is not connected. Connection attempt failed.');
|
|
153
|
+
}
|
|
154
|
+
return this.db;
|
|
155
|
+
}
|
|
156
|
+
async run(sql, params = []) {
|
|
157
|
+
const dbInstance = await this.ensureConnected();
|
|
158
|
+
try {
|
|
159
|
+
const result = dbInstance.prepare(sql).run(...params);
|
|
160
|
+
return {
|
|
161
|
+
lastID: Number(result.lastInsertRowid),
|
|
162
|
+
changes: Number(result.changes),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
console.error(`Error running SQL: ${sql}`, err);
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async get(sql, params = []) {
|
|
171
|
+
const dbInstance = await this.ensureConnected();
|
|
172
|
+
try {
|
|
173
|
+
return dbInstance.prepare(sql).get(...params);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
console.error(`Error getting SQL: ${sql}`, err);
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async all(sql, params = []) {
|
|
181
|
+
const dbInstance = await this.ensureConnected();
|
|
182
|
+
try {
|
|
183
|
+
return dbInstance.prepare(sql).all(...params);
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
console.error(`Error getting all SQL: ${sql}`, err);
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async exec(sql) {
|
|
191
|
+
const dbInstance = await this.ensureConnected();
|
|
192
|
+
try {
|
|
193
|
+
dbInstance.exec(sql);
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
console.error(`Error executing SQL: ${sql}`, err);
|
|
197
|
+
throw err;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async close() {
|
|
201
|
+
if (this.openPromise) {
|
|
202
|
+
await this.openPromise;
|
|
203
|
+
}
|
|
204
|
+
if (this.db) {
|
|
205
|
+
try {
|
|
206
|
+
// When shared, only the last holder actually closes the handle.
|
|
207
|
+
const isLastHolder = this.shareKey
|
|
208
|
+
? sharedConnections.release(this.shareKey, this.db)
|
|
209
|
+
: true;
|
|
210
|
+
if (isLastHolder) {
|
|
211
|
+
this.db.close();
|
|
212
|
+
}
|
|
213
|
+
if (this.verbose) {
|
|
214
|
+
console.log(isLastHolder
|
|
215
|
+
? `SQLite database closed (node:sqlite): ${this.filePath}`
|
|
216
|
+
: `SQLite database released (still in use): ${this.filePath}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
console.error(`Error closing database ${this.filePath}:`, err.message);
|
|
221
|
+
throw err;
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
this.db = null;
|
|
225
|
+
this.openPromise = null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
this.db = null;
|
|
230
|
+
this.openPromise = null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Gets the underlying `node:sqlite` `DatabaseSync` instance.
|
|
235
|
+
* Useful for operations not covered by this wrapper.
|
|
236
|
+
*/
|
|
237
|
+
async getDbInstance() {
|
|
238
|
+
return this.ensureConnected();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=node-sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-sqlite.js","sourceRoot":"","sources":["../../src/adapters/node-sqlite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `better-sqlite3`-backed entry point for MongoLite.
|
|
3
|
+
*
|
|
4
|
+
* The main `@semics-tech/mongolite` entry point defaults to `NodeSqliteAdapter`, backed by
|
|
5
|
+
* Node.js's built-in `node:sqlite` module, which requires Node.js 22.5.0+. Import
|
|
6
|
+
* from `@semics-tech/mongolite/better-sqlite3` instead if you need to run on an older
|
|
7
|
+
* Node.js runtime, or you simply prefer the more battle-tested `better-sqlite3`
|
|
8
|
+
* native addon.
|
|
9
|
+
*
|
|
10
|
+
* `better-sqlite3` is an **optional dependency** of this package — install it
|
|
11
|
+
* yourself if it wasn't already pulled in:
|
|
12
|
+
*
|
|
13
|
+
* ```bash
|
|
14
|
+
* npm install better-sqlite3
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## Usage
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { MongoLite } from '@semics-tech/mongolite/better-sqlite3';
|
|
21
|
+
*
|
|
22
|
+
* const client = new MongoLite('./myapp.sqlite');
|
|
23
|
+
* await client.connect();
|
|
24
|
+
* const users = client.collection('users');
|
|
25
|
+
* await users.insertOne({ name: 'Alice', age: 30 });
|
|
26
|
+
* await client.close();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import type { IDatabaseAdapter, MongoLiteOptions as DBMongoLiteOptions } from './db.js';
|
|
30
|
+
import { MongoLite as MongoLiteBase, MongoLiteBaseOptions } from './mongo-client.js';
|
|
31
|
+
export { MongoLiteCollection } from './collection.js';
|
|
32
|
+
export * from './types.js';
|
|
33
|
+
export { ChangeStream } from './changeStream.js';
|
|
34
|
+
export type { ChangeStreamDocument, ChangeStreamOptions, ChangeOperationType, } from './changeStream.js';
|
|
35
|
+
export type { IDatabaseAdapter } from './db.js';
|
|
36
|
+
export { SQLiteDB } from './db.js';
|
|
37
|
+
export interface MongoLiteClientOptions extends DBMongoLiteOptions {
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* MongoLite client backed by the `better-sqlite3` native addon.
|
|
41
|
+
*
|
|
42
|
+
* You can construct it with:
|
|
43
|
+
* - A file path string — uses the built-in `SQLiteDB` (`better-sqlite3`) adapter.
|
|
44
|
+
* - A `MongoLiteClientOptions` object — uses the built-in adapter with options.
|
|
45
|
+
* - An `IDatabaseAdapter` instance — use a custom adapter for other backends.
|
|
46
|
+
*/
|
|
47
|
+
export declare class MongoLite extends MongoLiteBase {
|
|
48
|
+
constructor(dbPathOrOptions: string | MongoLiteClientOptions | IDatabaseAdapter, options?: MongoLiteBaseOptions);
|
|
49
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `better-sqlite3`-backed entry point for MongoLite.
|
|
3
|
+
*
|
|
4
|
+
* The main `@semics-tech/mongolite` entry point defaults to `NodeSqliteAdapter`, backed by
|
|
5
|
+
* Node.js's built-in `node:sqlite` module, which requires Node.js 22.5.0+. Import
|
|
6
|
+
* from `@semics-tech/mongolite/better-sqlite3` instead if you need to run on an older
|
|
7
|
+
* Node.js runtime, or you simply prefer the more battle-tested `better-sqlite3`
|
|
8
|
+
* native addon.
|
|
9
|
+
*
|
|
10
|
+
* `better-sqlite3` is an **optional dependency** of this package — install it
|
|
11
|
+
* yourself if it wasn't already pulled in:
|
|
12
|
+
*
|
|
13
|
+
* ```bash
|
|
14
|
+
* npm install better-sqlite3
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## Usage
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { MongoLite } from '@semics-tech/mongolite/better-sqlite3';
|
|
21
|
+
*
|
|
22
|
+
* const client = new MongoLite('./myapp.sqlite');
|
|
23
|
+
* await client.connect();
|
|
24
|
+
* const users = client.collection('users');
|
|
25
|
+
* await users.insertOne({ name: 'Alice', age: 30 });
|
|
26
|
+
* await client.close();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import { SQLiteDB } from './db.js';
|
|
30
|
+
import { MongoLite as MongoLiteBase } from './mongo-client.js';
|
|
31
|
+
export { MongoLiteCollection } from './collection.js';
|
|
32
|
+
export * from './types.js';
|
|
33
|
+
export { ChangeStream } from './changeStream.js';
|
|
34
|
+
export { SQLiteDB } from './db.js';
|
|
35
|
+
/**
|
|
36
|
+
* MongoLite client backed by the `better-sqlite3` native addon.
|
|
37
|
+
*
|
|
38
|
+
* You can construct it with:
|
|
39
|
+
* - A file path string — uses the built-in `SQLiteDB` (`better-sqlite3`) adapter.
|
|
40
|
+
* - A `MongoLiteClientOptions` object — uses the built-in adapter with options.
|
|
41
|
+
* - An `IDatabaseAdapter` instance — use a custom adapter for other backends.
|
|
42
|
+
*/
|
|
43
|
+
export class MongoLite extends MongoLiteBase {
|
|
44
|
+
constructor(dbPathOrOptions, options = {}) {
|
|
45
|
+
if (dbPathOrOptions &&
|
|
46
|
+
typeof dbPathOrOptions === 'object' &&
|
|
47
|
+
typeof dbPathOrOptions.connect === 'function' &&
|
|
48
|
+
typeof dbPathOrOptions.run === 'function' &&
|
|
49
|
+
typeof dbPathOrOptions.get === 'function' &&
|
|
50
|
+
typeof dbPathOrOptions.all === 'function' &&
|
|
51
|
+
typeof dbPathOrOptions.exec === 'function' &&
|
|
52
|
+
typeof dbPathOrOptions.close === 'function') {
|
|
53
|
+
super(dbPathOrOptions, options);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
super(new SQLiteDB(dbPathOrOptions), options);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=better-sqlite3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"better-sqlite3.js","sourceRoot":"","sources":["../src/better-sqlite3.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,SAAS,IAAI,aAAa,EAAwB,MAAM,mBAAmB,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOjD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAInC;;;;;;;GAOG;AACH,MAAM,OAAO,SAAU,SAAQ,aAAa;IAC1C,YACE,eAAmE,EACnE,UAAgC,EAAE;QAElC,IACE,eAAe;YACf,OAAO,eAAe,KAAK,QAAQ;YACnC,OAAQ,eAAoC,CAAC,OAAO,KAAK,UAAU;YACnE,OAAQ,eAAoC,CAAC,GAAG,KAAK,UAAU;YAC/D,OAAQ,eAAoC,CAAC,GAAG,KAAK,UAAU;YAC/D,OAAQ,eAAoC,CAAC,GAAG,KAAK,UAAU;YAC/D,OAAQ,eAAoC,CAAC,IAAI,KAAK,UAAU;YAChE,OAAQ,eAAoC,CAAC,KAAK,KAAK,UAAU,EACjE,CAAC;YACD,KAAK,CAAC,eAAmC,EAAE,OAAO,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,QAAQ,CAAC,eAAkD,CAAC,EAAE,OAAO,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;CACF"}
|
|
File without changes
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BrowserSqliteAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Database adapter that wraps a {@link SqlJsDatabase} instance, enabling MongoLite
|
|
6
|
+
* to run in browser environments via [sql.js](https://sql.js.org/).
|
|
7
|
+
*
|
|
8
|
+
* ## Usage
|
|
9
|
+
*
|
|
10
|
+
* Install [sql.js](https://www.npmjs.com/package/sql.js) and initialise it before
|
|
11
|
+
* constructing the adapter:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import initSqlJs from 'sql.js';
|
|
15
|
+
* import { MongoLite, BrowserSqliteAdapter } from '@semics-tech/mongolite';
|
|
16
|
+
*
|
|
17
|
+
* const SQL = await initSqlJs({
|
|
18
|
+
* locateFile: (file) => `https://cdn.jsdelivr.net/npm/sql.js/dist/${file}`,
|
|
19
|
+
* });
|
|
20
|
+
* const sqlJsDb = new SQL.Database(); // in-memory; persist via OPFS or IndexedDB
|
|
21
|
+
*
|
|
22
|
+
* const client = new MongoLite(new BrowserSqliteAdapter(sqlJsDb));
|
|
23
|
+
* await client.connect();
|
|
24
|
+
* const users = client.collection('users');
|
|
25
|
+
* await users.insertOne({ name: 'Alice', age: 30 });
|
|
26
|
+
* await client.close();
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## Limitations
|
|
30
|
+
*
|
|
31
|
+
* - **`$regex` queries are not supported** — sql.js does not ship with a `regexp()`
|
|
32
|
+
* SQL function. Use JS-side filtering as a workaround.
|
|
33
|
+
* - **`lastID` / `changes`** are not exposed by the sql.js API. `run()` always
|
|
34
|
+
* returns `{ lastID: 0, changes: 0 }`, which is safe because MongoLite does not
|
|
35
|
+
* use these values internally.
|
|
36
|
+
* - **Persistence** — by default sql.js stores data in memory. For durable storage
|
|
37
|
+
* use the OPFS back-end or export the database buffer to IndexedDB.
|
|
38
|
+
*/
|
|
39
|
+
class BrowserSqliteAdapter {
|
|
40
|
+
/**
|
|
41
|
+
* @param db An initialised sql.js `Database` instance.
|
|
42
|
+
*/
|
|
43
|
+
constructor(db) {
|
|
44
|
+
this.db = db;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* No-op: sql.js Database is already open on construction.
|
|
48
|
+
*/
|
|
49
|
+
async connect() {
|
|
50
|
+
// Nothing to do — the sql.js Database is ready to use immediately.
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Closes the underlying sql.js Database and frees its WASM memory.
|
|
54
|
+
*/
|
|
55
|
+
async close() {
|
|
56
|
+
this.db.close();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Executes a DML statement (INSERT, UPDATE, DELETE) with optional bound parameters.
|
|
60
|
+
* Returns `{ lastID: 0, changes: 0 }` — sql.js does not expose these values.
|
|
61
|
+
*/
|
|
62
|
+
async run(sql, params = []) {
|
|
63
|
+
this.db.run(sql, params);
|
|
64
|
+
return { lastID: 0, changes: 0 };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Executes a SQL query and returns the first matching row, or `undefined`.
|
|
68
|
+
*/
|
|
69
|
+
async get(sql, params = []) {
|
|
70
|
+
const stmt = this.db.prepare(sql);
|
|
71
|
+
try {
|
|
72
|
+
stmt.bind(params);
|
|
73
|
+
if (stmt.step()) {
|
|
74
|
+
return stmt.getAsObject();
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
stmt.free();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Executes a SQL query and returns all matching rows.
|
|
84
|
+
*/
|
|
85
|
+
async all(sql, params = []) {
|
|
86
|
+
const stmt = this.db.prepare(sql);
|
|
87
|
+
try {
|
|
88
|
+
stmt.bind(params);
|
|
89
|
+
const rows = [];
|
|
90
|
+
while (stmt.step()) {
|
|
91
|
+
rows.push(stmt.getAsObject());
|
|
92
|
+
}
|
|
93
|
+
return rows;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
stmt.free();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Executes one or more SQL statements (DDL, transactions, etc.).
|
|
101
|
+
*/
|
|
102
|
+
async exec(sql) {
|
|
103
|
+
this.db.exec(sql);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.BrowserSqliteAdapter = BrowserSqliteAdapter;
|