@semics-tech/mongolite 1.0.0 → 1.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 YOUR_NAME
3
+ Copyright (c) 2025 Oliver Breeden
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -32,6 +32,13 @@ A MongoDB-like client backed by SQLite. Use a familiar MongoDB API with the simp
32
32
  npm install @semics-tech/mongolite
33
33
  ```
34
34
 
35
+ Requires **Node.js 22.5.0+** by default — the main entry point is backed by
36
+ Node's built-in `node:sqlite` module, so there's no native addon to install or
37
+ build. On an older Node.js runtime, use the `better-sqlite3`-backed adapter
38
+ instead; see [Native `node:sqlite` vs. `better-sqlite3`](#native-nodesqlite-vs-better-sqlite3) below.
39
+
40
+ Ships both ESM (`import`) and CommonJS (`require`) builds — use whichever your project already uses.
41
+
35
42
  ## Quick Start
36
43
 
37
44
  ```typescript
@@ -112,6 +119,37 @@ await users.insertOne({ name: 'Alice', age: 30 });
112
119
  await client.close();
113
120
  ```
114
121
 
122
+ ### `better-sqlite3` (optional, for Node.js <22.5 or Bun)
123
+
124
+ The default backend above uses Node's built-in `node:sqlite` module, which
125
+ requires Node.js 22.5.0+. If you're on an older Node.js runtime, or you
126
+ simply prefer the more battle-tested native addon, import from the
127
+ `@semics-tech/mongolite/better-sqlite3` entry point instead. `better-sqlite3` is an
128
+ **optional dependency** — install it yourself if it wasn't already pulled in:
129
+
130
+ ```bash
131
+ npm install better-sqlite3
132
+ ```
133
+
134
+ ```typescript
135
+ import { MongoLite } from '@semics-tech/mongolite/better-sqlite3';
136
+
137
+ const client = new MongoLite('./myapp.sqlite');
138
+ await client.connect();
139
+ const users = client.collection('users');
140
+ await users.insertOne({ name: 'Alice', age: 30 });
141
+ await client.close();
142
+ ```
143
+
144
+ <a id="native-nodesqlite-vs-better-sqlite3"></a>
145
+ > **Which one should I use?** `node:sqlite` (the default) is still marked
146
+ > experimental upstream but requires no native build step, which is why it's
147
+ > the default here. `better-sqlite3` is the older, more battle-tested native
148
+ > addon — reach for it if you're stuck on Node.js <22.5, targeting Bun without
149
+ > a `node:sqlite` polyfill, or want to avoid depending on an experimental
150
+ > Node.js API in production. Both implement the same `IDatabaseAdapter`
151
+ > interface, so switching between them is a one-line import change.
152
+
115
153
  ### Browser (via sql.js)
116
154
 
117
155
  Requires [sql.js](https://www.npmjs.com/package/sql.js) (`npm install sql.js`).
@@ -0,0 +1,61 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import type { IDatabaseAdapter, MongoLiteOptions } from '../db.js';
3
+ /**
4
+ * Database adapter backed by Node.js's built-in `node:sqlite` module — no native
5
+ * addon, no prebuilt binary, no `node-gyp`. Requires Node.js 22.5.0+ (the module
6
+ * is marked experimental by Node.js until it graduates to stable).
7
+ *
8
+ * ## Usage
9
+ *
10
+ * ```ts
11
+ * import { MongoLite, NodeSqliteAdapter } from '@semics-tech/mongolite';
12
+ *
13
+ * const client = new MongoLite(new NodeSqliteAdapter('./data.db'));
14
+ * await client.connect();
15
+ * const users = client.collection('users');
16
+ * await users.insertOne({ name: 'Alice', age: 30 });
17
+ * await client.close();
18
+ * ```
19
+ *
20
+ * ## Limitations
21
+ *
22
+ * - **Experimental.** `node:sqlite` is still marked experimental upstream and its
23
+ * API may change between Node.js minor versions.
24
+ * - **Node.js 22.5.0+ only.** Importing this adapter on an older runtime (or on
25
+ * Bun/Deno without a `node:sqlite` polyfill) throws at import time.
26
+ * - Rows are returned with a `null` prototype (per `node:sqlite`'s API). Plain
27
+ * property access (`row.foo`) and `JSON.stringify`/`Object.keys` all work as
28
+ * expected; `row.hasOwnProperty(...)` does not.
29
+ */
30
+ export declare class NodeSqliteAdapter implements IDatabaseAdapter {
31
+ private db;
32
+ private readonly filePath;
33
+ private readonly verbose;
34
+ private readonly readOnly;
35
+ private readonly WAL;
36
+ private openPromise;
37
+ /**
38
+ * @param dbPathOrOptions Path to the SQLite database file (use `':memory:'`
39
+ * for an in-memory database), or an options object mirroring the built-in
40
+ * `better-sqlite3` adapter's `MongoLiteOptions`.
41
+ */
42
+ constructor(dbPathOrOptions: string | MongoLiteOptions);
43
+ /**
44
+ * Opens the database connection if it's not already open.
45
+ */
46
+ connect(): Promise<void>;
47
+ private ensureConnected;
48
+ run(sql: string, params?: unknown[]): Promise<{
49
+ lastID: number;
50
+ changes: number;
51
+ }>;
52
+ get<T>(sql: string, params?: unknown[]): Promise<T | undefined>;
53
+ all<T>(sql: string, params?: unknown[]): Promise<T[]>;
54
+ exec(sql: string): Promise<void>;
55
+ close(): Promise<void>;
56
+ /**
57
+ * Gets the underlying `node:sqlite` `DatabaseSync` instance.
58
+ * Useful for operations not covered by this wrapper.
59
+ */
60
+ getDbInstance(): Promise<DatabaseSync>;
61
+ }
@@ -0,0 +1,196 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ /**
3
+ * Database adapter backed by Node.js's built-in `node:sqlite` module — no native
4
+ * addon, no prebuilt binary, no `node-gyp`. Requires Node.js 22.5.0+ (the module
5
+ * is marked experimental by Node.js until it graduates to stable).
6
+ *
7
+ * ## Usage
8
+ *
9
+ * ```ts
10
+ * import { MongoLite, NodeSqliteAdapter } from '@semics-tech/mongolite';
11
+ *
12
+ * const client = new MongoLite(new NodeSqliteAdapter('./data.db'));
13
+ * await client.connect();
14
+ * const users = client.collection('users');
15
+ * await users.insertOne({ name: 'Alice', age: 30 });
16
+ * await client.close();
17
+ * ```
18
+ *
19
+ * ## Limitations
20
+ *
21
+ * - **Experimental.** `node:sqlite` is still marked experimental upstream and its
22
+ * API may change between Node.js minor versions.
23
+ * - **Node.js 22.5.0+ only.** Importing this adapter on an older runtime (or on
24
+ * Bun/Deno without a `node:sqlite` polyfill) throws at import time.
25
+ * - Rows are returned with a `null` prototype (per `node:sqlite`'s API). Plain
26
+ * property access (`row.foo`) and `JSON.stringify`/`Object.keys` all work as
27
+ * expected; `row.hasOwnProperty(...)` does not.
28
+ */
29
+ export class NodeSqliteAdapter {
30
+ /**
31
+ * @param dbPathOrOptions Path to the SQLite database file (use `':memory:'`
32
+ * for an in-memory database), or an options object mirroring the built-in
33
+ * `better-sqlite3` adapter's `MongoLiteOptions`.
34
+ */
35
+ constructor(dbPathOrOptions) {
36
+ this.db = null;
37
+ this.openPromise = null;
38
+ if (typeof dbPathOrOptions === 'string') {
39
+ this.filePath = dbPathOrOptions;
40
+ this.verbose = false;
41
+ this.readOnly = false;
42
+ this.WAL = false;
43
+ }
44
+ else {
45
+ this.filePath = dbPathOrOptions.filePath;
46
+ this.verbose = dbPathOrOptions.verbose || false;
47
+ this.readOnly = dbPathOrOptions.readOnly || false;
48
+ this.WAL = dbPathOrOptions.WAL || true;
49
+ }
50
+ }
51
+ /**
52
+ * Opens the database connection if it's not already open.
53
+ */
54
+ async connect() {
55
+ if (this.db && this.openPromise) {
56
+ return this.openPromise;
57
+ }
58
+ if (this.db) {
59
+ return Promise.resolve();
60
+ }
61
+ this.openPromise = new Promise((resolve, reject) => {
62
+ try {
63
+ this.db = new DatabaseSync(this.filePath, { readOnly: this.readOnly });
64
+ if (this.WAL && !this.readOnly) {
65
+ this.db.exec('PRAGMA journal_mode = WAL');
66
+ }
67
+ // Register regexp UDF for $regex operator support.
68
+ // WARNING: Patterns are compiled via JavaScript RegExp. User-supplied patterns that are
69
+ // not validated for catastrophic backtracking (ReDoS) could block the event loop.
70
+ // Avoid using untrusted/unvalidated patterns with $regex in security-sensitive contexts.
71
+ this.db.function('regexp', { deterministic: true }, (pattern, value) => {
72
+ if (typeof pattern !== 'string' || value === null || value === undefined)
73
+ return 0;
74
+ try {
75
+ return new RegExp(pattern).test(String(value)) ? 1 : 0;
76
+ }
77
+ catch {
78
+ return 0;
79
+ }
80
+ });
81
+ // Register regexp_flags UDF for $regex with $options support
82
+ this.db.function('regexp_flags', { deterministic: true }, (pattern, flags, value) => {
83
+ if (typeof pattern !== 'string' || value === null || value === undefined)
84
+ return 0;
85
+ try {
86
+ const f = typeof flags === 'string' ? flags : '';
87
+ return new RegExp(pattern, f).test(String(value)) ? 1 : 0;
88
+ }
89
+ catch {
90
+ return 0;
91
+ }
92
+ });
93
+ if (this.verbose) {
94
+ console.log(`SQLite database opened (node:sqlite): ${this.filePath}`);
95
+ }
96
+ resolve();
97
+ }
98
+ catch (err) {
99
+ console.error(`Error opening database ${this.filePath}:`, err.message);
100
+ this.db = null;
101
+ this.openPromise = null;
102
+ reject(err);
103
+ }
104
+ });
105
+ return this.openPromise;
106
+ }
107
+ async ensureConnected() {
108
+ if (!this.db || !this.openPromise) {
109
+ await this.connect();
110
+ }
111
+ else {
112
+ await this.openPromise;
113
+ }
114
+ if (!this.db) {
115
+ throw new Error('Database is not connected. Connection attempt failed.');
116
+ }
117
+ return this.db;
118
+ }
119
+ async run(sql, params = []) {
120
+ const dbInstance = await this.ensureConnected();
121
+ try {
122
+ const result = dbInstance.prepare(sql).run(...params);
123
+ return {
124
+ lastID: Number(result.lastInsertRowid),
125
+ changes: Number(result.changes),
126
+ };
127
+ }
128
+ catch (err) {
129
+ console.error(`Error running SQL: ${sql}`, err);
130
+ throw err;
131
+ }
132
+ }
133
+ async get(sql, params = []) {
134
+ const dbInstance = await this.ensureConnected();
135
+ try {
136
+ return dbInstance.prepare(sql).get(...params);
137
+ }
138
+ catch (err) {
139
+ console.error(`Error getting SQL: ${sql}`, err);
140
+ throw err;
141
+ }
142
+ }
143
+ async all(sql, params = []) {
144
+ const dbInstance = await this.ensureConnected();
145
+ try {
146
+ return dbInstance.prepare(sql).all(...params);
147
+ }
148
+ catch (err) {
149
+ console.error(`Error getting all SQL: ${sql}`, err);
150
+ throw err;
151
+ }
152
+ }
153
+ async exec(sql) {
154
+ const dbInstance = await this.ensureConnected();
155
+ try {
156
+ dbInstance.exec(sql);
157
+ }
158
+ catch (err) {
159
+ console.error(`Error executing SQL: ${sql}`, err);
160
+ throw err;
161
+ }
162
+ }
163
+ async close() {
164
+ if (this.openPromise) {
165
+ await this.openPromise;
166
+ }
167
+ if (this.db) {
168
+ try {
169
+ this.db.close();
170
+ if (this.verbose) {
171
+ console.log(`SQLite database closed (node:sqlite): ${this.filePath}`);
172
+ }
173
+ }
174
+ catch (err) {
175
+ console.error(`Error closing database ${this.filePath}:`, err.message);
176
+ throw err;
177
+ }
178
+ finally {
179
+ this.db = null;
180
+ this.openPromise = null;
181
+ }
182
+ }
183
+ else {
184
+ this.db = null;
185
+ this.openPromise = null;
186
+ }
187
+ }
188
+ /**
189
+ * Gets the underlying `node:sqlite` `DatabaseSync` instance.
190
+ * Useful for operations not covered by this wrapper.
191
+ */
192
+ async getDbInstance() {
193
+ return this.ensureConnected();
194
+ }
195
+ }
196
+ //# 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;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CloudflareDurableObjectAdapter = void 0;
4
+ /**
5
+ * Database adapter that wraps the Cloudflare Durable Objects `SqlStorage` API,
6
+ * allowing MongoLite to be used inside a Cloudflare Durable Object.
7
+ *
8
+ * ## Usage
9
+ *
10
+ * ```ts
11
+ * import { DurableObject } from 'cloudflare:workers';
12
+ * import { MongoLite, CloudflareDurableObjectAdapter } from '@semics-tech/mongolite/cloudflare';
13
+ *
14
+ * export class MyDurableObject extends DurableObject {
15
+ * private client: MongoLite;
16
+ *
17
+ * constructor(ctx: DurableObjectState, env: Env) {
18
+ * super(ctx, env);
19
+ * const adapter = new CloudflareDurableObjectAdapter(ctx.storage.sql);
20
+ * this.client = new MongoLite(adapter);
21
+ * }
22
+ *
23
+ * async fetch(request: Request) {
24
+ * await this.client.connect();
25
+ * const users = this.client.collection('users');
26
+ * await users.insertOne({ name: 'Alice', age: 30 });
27
+ * const user = await users.findOne({ name: 'Alice' });
28
+ * return Response.json(user);
29
+ * }
30
+ * }
31
+ * ```
32
+ *
33
+ * ## Limitations
34
+ *
35
+ * - **`$regex` queries are not supported.** Cloudflare's SQLite does not allow custom
36
+ * SQL functions, so the `regexp()` UDF registered by the default Node.js adapter is
37
+ * unavailable. Queries using `$regex` will throw a SQL error at runtime.
38
+ * - `WAL` mode and most `PRAGMA` statements are not available in Cloudflare Durable
39
+ * Objects (Cloudflare manages this internally).
40
+ * - Change Streams (`collection.watch()`) use SQL triggers and a change-log table.
41
+ * They work in Cloudflare Durable Objects, but the polling mechanism relies on
42
+ * `setInterval`, which is supported in the Workers runtime.
43
+ */
44
+ class CloudflareDurableObjectAdapter {
45
+ /**
46
+ * @param sql The `SqlStorage` instance from a Cloudflare Durable Object context
47
+ * (i.e. `ctx.storage.sql`).
48
+ */
49
+ constructor(sql) {
50
+ this.sql = sql;
51
+ }
52
+ /**
53
+ * No-op: Cloudflare Durable Objects manage the storage lifecycle automatically.
54
+ */
55
+ async connect() {
56
+ // Nothing to do — the SqlStorage instance is already live.
57
+ }
58
+ /**
59
+ * No-op: Cloudflare Durable Objects manage the storage lifecycle automatically.
60
+ */
61
+ async close() {
62
+ // Nothing to do — storage is managed by the Durable Object runtime.
63
+ }
64
+ /**
65
+ * Executes a SQL statement that does not return rows (INSERT, UPDATE, DELETE, DDL).
66
+ */
67
+ async run(sql, params = []) {
68
+ const cursor = this.sql.exec(sql, ...params);
69
+ return { lastID: 0, changes: cursor.rowsWritten };
70
+ }
71
+ /**
72
+ * Executes a SQL query and returns the first matching row, or `undefined`.
73
+ */
74
+ async get(sql, params = []) {
75
+ const rows = this.sql.exec(sql, ...params).toArray();
76
+ return rows[0];
77
+ }
78
+ /**
79
+ * Executes a SQL query and returns all matching rows.
80
+ */
81
+ async all(sql, params = []) {
82
+ return this.sql.exec(sql, ...params).toArray();
83
+ }
84
+ /**
85
+ * Executes a single SQL statement (DDL, transactions, etc.).
86
+ *
87
+ * Cloudflare's `SqlStorage.exec` only supports one statement at a time, and
88
+ * some valid statements (e.g. `CREATE TRIGGER ... BEGIN ...; ...; END;`)
89
+ * contain internal semicolons. Callers must therefore pass exactly one
90
+ * statement per call; this method will not attempt to split multi-statement
91
+ * SQL strings.
92
+ */
93
+ async exec(sql) {
94
+ this.sql.exec(sql);
95
+ }
96
+ }
97
+ exports.CloudflareDurableObjectAdapter = CloudflareDurableObjectAdapter;