Skip to content

Commit 6bb1c0d

Browse files
committed
fix(docs): update documentation for changeset application and backup return types; enhance clarity on SQLite threading modes and API references
1 parent ce8ae58 commit 6bb1c0d

15 files changed

+112
-136
lines changed

doc/advanced-patterns.md

Lines changed: 44 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,8 @@ session.close();
318318

319319
// Apply changes to another database
320320
const replicaDb = new DatabaseSync("replica.db");
321-
const result = replicaDb.applyChangeset(changeset);
322-
console.log(`Applied ${result.changesApplied} changes`);
321+
const success = replicaDb.applyChangeset(changeset);
322+
console.log(`Changeset applied: ${success}`);
323323

324324
db.close();
325325
replicaDb.close();
@@ -345,15 +345,17 @@ function syncDatabases(primaryPath, replicaPath) {
345345
session.close();
346346

347347
// Apply to replica with conflict handling
348-
const result = replica.applyChangeset(changeset, {
349-
onConflict: (conflict) => {
350-
console.log(`Conflict detected:`);
351-
console.log(` Table: ${conflict.table}`);
352-
console.log(` Type: ${conflict.type}`);
353-
console.log(` Old value: ${JSON.stringify(conflict.oldRow)}`);
354-
console.log(` New value: ${JSON.stringify(conflict.newRow)}`);
355-
356-
// Conflict resolution strategies:
348+
const success = replica.applyChangeset(changeset, {
349+
onConflict: (conflictType) => {
350+
// conflictType is a number indicating the type of conflict:
351+
// - SQLITE_CHANGESET_DATA: Row exists but values differ
352+
// - SQLITE_CHANGESET_NOTFOUND: Row not found in target
353+
// - SQLITE_CHANGESET_CONFLICT: Primary key conflict
354+
// - SQLITE_CHANGESET_CONSTRAINT: Constraint violation
355+
// - SQLITE_CHANGESET_FOREIGN_KEY: Foreign key violation
356+
console.log(`Conflict detected, type: ${conflictType}`);
357+
358+
// Conflict resolution strategies (return one of these):
357359
// - SQLITE_CHANGESET_OMIT: Skip this change
358360
// - SQLITE_CHANGESET_REPLACE: Apply the change anyway
359361
// - SQLITE_CHANGESET_ABORT: Stop applying changes
@@ -362,108 +364,55 @@ function syncDatabases(primaryPath, replicaPath) {
362364
},
363365
});
364366

365-
console.log(`Sync complete: ${result.changesApplied} changes applied`);
367+
console.log(`Sync complete: ${success ? "succeeded" : "aborted"}`);
366368

367369
primary.close();
368370
replica.close();
369371
}
370372
```
371373

372-
### Undo/Redo Implementation
374+
### Change Tracking Example
373375

374-
```javascript
375-
class UndoRedoManager {
376-
constructor(db) {
377-
this.db = db;
378-
this.undoStack = [];
379-
this.redoStack = [];
380-
this.session = null;
381-
}
382-
383-
startTracking() {
384-
if (this.session) {
385-
this.endTracking();
386-
}
387-
this.session = this.db.createSession();
388-
}
389-
390-
endTracking(description) {
391-
if (!this.session) return;
392-
393-
const changeset = this.session.changeset();
394-
if (changeset.length > 0) {
395-
this.undoStack.push({
396-
description,
397-
changeset,
398-
inverse: this.session.changesetInvert(changeset),
399-
});
400-
this.redoStack = []; // Clear redo stack on new change
401-
}
402-
403-
this.session.close();
404-
this.session = null;
405-
}
406-
407-
undo() {
408-
const entry = this.undoStack.pop();
409-
if (!entry) return false;
410-
411-
// Apply inverse changeset
412-
this.db.applyChangeset(entry.inverse);
413-
414-
// Move to redo stack
415-
this.redoStack.push(entry);
416-
417-
return true;
418-
}
376+
Sessions track changes that can be applied to other databases for synchronization:
419377

420-
redo() {
421-
const entry = this.redoStack.pop();
422-
if (!entry) return false;
423-
424-
// Apply original changeset
425-
this.db.applyChangeset(entry.changeset);
426-
427-
// Move back to undo stack
428-
this.undoStack.push(entry);
429-
430-
return true;
431-
}
378+
```javascript
379+
const { DatabaseSync } = require("@photostructure/sqlite");
432380

433-
getHistory() {
434-
return {
435-
undo: this.undoStack.map((e) => e.description),
436-
redo: this.redoStack.map((e) => e.description),
437-
};
438-
}
439-
}
381+
const sourceDb = new DatabaseSync("source.db");
382+
const targetDb = new DatabaseSync("target.db");
440383

441-
// Usage
442-
const db = new DatabaseSync("document.db");
443-
const undoRedo = new UndoRedoManager(db);
384+
// Create a session to track changes on the source database
385+
const session = sourceDb.createSession({ table: "documents" });
444386

445-
// Track a change
446-
undoRedo.startTracking();
447-
db.prepare("UPDATE document SET content = ? WHERE id = ?").run(
448-
"New content",
387+
// Make changes to the source
388+
sourceDb.prepare("UPDATE documents SET content = ? WHERE id = ?").run(
389+
"Updated content",
449390
1,
450391
);
451-
undoRedo.endTracking("Update document content");
392+
sourceDb.prepare("INSERT INTO documents (content) VALUES (?)").run(
393+
"New document",
394+
);
395+
396+
// Get the changeset
397+
const changeset = session.changeset();
398+
session.close();
452399

453-
// Track another change
454-
undoRedo.startTracking();
455-
db.prepare("INSERT INTO document (content) VALUES (?)").run("Another document");
456-
undoRedo.endTracking("Add new document");
400+
// Apply changes to target database
401+
const success = targetDb.applyChangeset(changeset, {
402+
onConflict: (conflictType) => {
403+
// Handle conflicts as needed
404+
return constants.SQLITE_CHANGESET_REPLACE;
405+
},
406+
});
457407

458-
// Undo last change
459-
undoRedo.undo();
460-
console.log("Undid: Add new document");
408+
console.log(`Sync ${success ? "succeeded" : "failed"}`);
461409

462-
// Redo
463-
undoRedo.redo();
464-
console.log("Redid: Add new document");
410+
sourceDb.close();
411+
targetDb.close();
465412
```
466413

414+
> **Note:** The `changesetInvert()` function for creating inverse changesets is not currently exposed in the JavaScript API. For undo/redo functionality, consider storing the original data before modifications or using SQLite triggers to maintain a history table.
415+
467416
## Performance Optimization
468417

469418
### URI Configuration for Performance

doc/api-reference.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,10 @@ db.aggregate("custom_avg", {
212212
#### backup()
213213

214214
```typescript
215-
backup(destination: string, options?: BackupOptions): Promise<void>
215+
backup(destination: string, options?: BackupOptions): Promise<number>
216216
```
217217

218-
Creates a backup of the database.
218+
Creates a backup of the database. Returns the total number of pages backed up.
219219

220220
**Options:**
221221

@@ -271,15 +271,26 @@ session.close();
271271
#### applyChangeset()
272272

273273
```typescript
274-
applyChangeset(changeset: Uint8Array, options?: ChangesetOptions): ApplyResult
274+
applyChangeset(changeset: Buffer, options?: ChangesetApplyOptions): boolean
275275
```
276276

277-
Applies a changeset to the database.
277+
Applies a changeset to the database. Returns `true` if successful, `false` if aborted.
278+
279+
**Options:**
280+
281+
```typescript
282+
interface ChangesetApplyOptions {
283+
onConflict?: (conflictType: number) => number; // Returns resolution constant
284+
filter?: (tableName: string) => boolean; // Filter which tables to apply
285+
}
286+
```
278287

279288
```javascript
280-
const result = db.applyChangeset(changeset, {
281-
onConflict: (conflict) => {
282-
console.log(`Conflict on table ${conflict.table}`);
289+
const success = db.applyChangeset(changeset, {
290+
onConflict: (conflictType) => {
291+
// conflictType is one of: SQLITE_CHANGESET_DATA, SQLITE_CHANGESET_NOTFOUND,
292+
// SQLITE_CHANGESET_CONFLICT, SQLITE_CHANGESET_CONSTRAINT, SQLITE_CHANGESET_FOREIGN_KEY
293+
console.log(`Conflict type: ${conflictType}`);
283294
return constants.SQLITE_CHANGESET_REPLACE;
284295
},
285296
});
@@ -314,16 +325,17 @@ db.loadExtension("./custom.so", "sqlite3_custom_init");
314325

315326
### Properties
316327

317-
#### location
328+
#### location()
318329

319330
```typescript
320-
readonly location: string
331+
location(dbName?: string): string | null
321332
```
322333

323-
The path or URI of the database file.
334+
Returns the file path of the database, or `null` for in-memory databases.
324335

325336
```javascript
326-
console.log(db.location); // "myapp.db"
337+
console.log(db.location()); // "myapp.db"
338+
console.log(db.location("main")); // "myapp.db"
327339
```
328340

329341
## StatementSync

doc/extending-sqlite.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,20 +311,21 @@ const userPrefs = db
311311
312312
### Window Functions
313313
314-
Aggregate functions can be used as window functions in SQLite:
314+
Aggregate functions can be used as window functions in SQLite. For full window function support with framed windows (using `OVER (ORDER BY ...)`), you should provide an `inverse` function that reverses the effect of `step`:
315315
316316
```javascript
317-
// Cumulative sum aggregate
317+
// Cumulative sum aggregate with inverse for window function support
318318
db.aggregate("cumsum", {
319319
start: 0,
320320
step: (sum, value) => sum + (value || 0),
321+
inverse: (sum, value) => sum - (value || 0), // Required for window functions
321322
});
322323

323324
// Use as window function
324325
const results = db
325326
.prepare(
326327
`
327-
SELECT
328+
SELECT
328329
date,
329330
amount,
330331
cumsum(amount) OVER (ORDER BY date) as running_total
@@ -335,6 +336,8 @@ const results = db
335336
.all(accountId);
336337
```
337338
339+
> **Note:** Without the `inverse` function, the aggregate will still work but may be less efficient for certain window frame types.
340+
338341
## Loading Extensions
339342
340343
SQLite supports loadable extensions to add functionality at runtime.

doc/features.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Comprehensive list of features and capabilities in @photostructure/sqlite.
1414

1515
## SQLite Version
1616

17-
This package includes SQLite 3.50.4 with extensive compile-time options enabled. For complete build flag documentation, comparison with Node.js, and customization options, see [Build Flags & Configuration](./build-flags.md).
17+
This package includes SQLite 3.51.1 with extensive compile-time options enabled. For complete build flag documentation, comparison with Node.js, and customization options, see [Build Flags & Configuration](./build-flags.md).
1818

1919
## Enabled SQLite Features
2020

@@ -36,8 +36,7 @@ This package includes SQLite 3.50.4 with extensive compile-time options enabled.
3636
- `SQLITE_ENABLE_RTREE` - R\*Tree spatial indexing
3737
- `SQLITE_ENABLE_GEOPOLY` - GeoJSON and polygon functions
3838
- `SQLITE_ENABLE_MATH_FUNCTIONS` - Math functions (sin, cos, sqrt, etc.)
39-
- `SQLITE_ENABLE_REGEXP` - REGEXP operator support
40-
- `SQLITE_ENABLE_SOUNDEX` - Soundex algorithm
39+
- `SQLITE_SOUNDEX` - Soundex algorithm
4140

4241
### Session Extension
4342

doc/internal/worker-implementation.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ Worker thread support is **fully implemented and working** in @photostructure/sq
2222
SQLite supports three threading modes:
2323

2424
- **Single-thread** (`SQLITE_THREADSAFE=0`): No thread safety, one thread only
25-
- **Multi-thread** (`SQLITE_THREADSAFE=2`): Multiple threads, separate connections per thread**CURRENT**
26-
- **Serialized** (`SQLITE_THREADSAFE=1`): Full thread safety with mutexes (default)
25+
- **Multi-thread** (`SQLITE_THREADSAFE=2`): Multiple threads, separate connections per thread
26+
- **Serialized** (`SQLITE_THREADSAFE=1`): Full thread safety with mutexes (default)**CURRENT**
2727

28-
**Current Configuration:** Using `SQLITE_THREADSAFE=2` (multi-thread mode) - the correct choice for worker threads where each thread gets its own database connection.
28+
**Current Configuration:** Using the default `SQLITE_THREADSAFE=1` (serialized mode). This provides full thread safety with mutex protection, which is safe for worker threads where each thread creates its own database connection.
2929

3030
### Implemented Components
3131

doc/library-comparison.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ When choosing a SQLite library for Node.js, you have several excellent options.
3636

3737
### 🏷️ [`node:sqlite`](https://nodejs.org/docs/latest/api/sqlite.html) — Node.js Built-in Module
3838

39-
_The official SQLite module included with Node.js 25.0.0+ (experimental)_
39+
_The official SQLite module included with Node.js 22.5.0+ (experimental)_
4040

4141
**✨ Pros:**
4242

@@ -47,9 +47,8 @@ _The official SQLite module included with Node.js 25.0.0+ (experimental)_
4747

4848
**⚠️ Cons:**
4949

50-
- **Experimental status** — Not yet stable for production use
51-
- **Requires Node.js 25.0.0+** — Won't work on older versions
52-
- **Flag required** — Must use `--experimental-sqlite` to enable
50+
- **Experimental status** — Not yet stable for production use (Stability: 1.1 - Active development)
51+
- **Requires Node.js 22.5.0+** — Won't work on older versions
5352
- **API may change** — Breaking changes possible before stable release
5453
- **Limited real-world usage** — Few production deployments to learn from
5554

@@ -108,8 +107,8 @@ _The original asynchronous SQLite binding for Node.js_
108107
| Feature | @photostructure/sqlite | node:sqlite | better-sqlite3 | sqlite3 |
109108
| ------------------------ | ---------------------- | ------------- | ---------------- | ------------- |
110109
| **API Compatibility** | node:sqlite | - | Custom | Custom |
111-
| **Min Node.js Version** | 20.0.0 | 25.0.0 | 14.0.0 | 10.0.0 |
112-
| **Experimental Flag** | ❌ Not needed | ✅ Required | ❌ Not needed | ❌ Not needed |
110+
| **Min Node.js Version** | 20.0.0 | 22.5.0 | 14.0.0 | 10.0.0 |
111+
| **Experimental Flag** | ❌ Not needed | ❌ Not needed | ❌ Not needed | ❌ Not needed |
113112
| **Synchronous API** |||||
114113
| **Asynchronous API** |||||
115114
| **TypeScript Types** | ✅ Built-in | ✅ Built-in | ✅ Via @types | ✅ Via @types |

doc/migrating-from-better-sqlite3.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,10 @@ const result = db.prepare("PRAGMA cache_size").get();
161161

162162
### Features Only in better-sqlite3
163163

164-
-`.transaction()` helper method
165-
-`.pragma()` convenience method
166-
-`.backup()` method (different API)
167-
- ❌ Virtual table support
168-
-`.loadExtension()` method
164+
-`.transaction()` helper method (use manual `BEGIN`/`COMMIT`/`ROLLBACK`)
165+
-`.pragma()` convenience method (use `db.exec("PRAGMA ...")` or `db.prepare("PRAGMA ...").get()`)
169166
-`.serialize()` method
170-
-`.defaultSafeIntegers()` method
167+
-`.defaultSafeIntegers()` method (use `stmt.setReadBigInts()` instead)
171168
-`.unsafeMode()` method
172169

173170
### Features Only in @photostructure/sqlite

doc/migrating-from-node-sqlite.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Simply change your import statement:
88

99
```javascript
10-
// Before: Using Node.js built-in SQLite (requires Node.js 25.0.0+ and --experimental-sqlite flag)
10+
// Before: Using Node.js built-in SQLite (available in Node.js 22.5.0+)
1111
const { DatabaseSync } = require("node:sqlite");
1212

1313
// After: Using @photostructure/sqlite (works on Node.js 20+ without any flags)
@@ -40,7 +40,7 @@ node app.js
4040

4141
### Broader Node.js Version Support
4242

43-
- **node:sqlite**: Requires Node.js 25.0.0 or higher
43+
- **node:sqlite**: Available in Node.js 22.5.0+ (experimental status)
4444
- **@photostructure/sqlite**: Works with Node.js 20.0.0 or higher
4545

4646
### Same API, Same Behavior

doc/reference/sqlite-api-advanced.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# SQLite Advanced Features API Reference
22

3+
> **⚠️ Important Note:** This documentation describes the **underlying SQLite C library API**, not the JavaScript API exposed by `@photostructure/sqlite`. Most functions documented here (like `sqlite3_blob_open()`, `sqlite3_wal_checkpoint_v2()`) are **NOT directly callable from JavaScript**. Some features like backup and sessions are exposed through the JavaScript API - see [API Reference](../api-reference.md) and [Advanced Patterns](../advanced-patterns.md).
4+
35
This document covers SQLite's advanced APIs including backup operations, blob I/O, sessions, and threading features. This is a machine-generated summary of documentation found on sqlite.org used as a reference during development.
46

57
## Table of Contents

doc/reference/sqlite-api-core.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# SQLite Core API Reference
22

3+
> **⚠️ Important Note:** This documentation describes the **underlying SQLite C library API**, not the JavaScript API exposed by `@photostructure/sqlite`. These C functions are **NOT directly callable from JavaScript**. For the JavaScript API, see [API Reference](../api-reference.md).
4+
35
This document covers the fundamental SQLite C/C++ APIs for database connections, basic operations, and error handling. This is a machine-generated summary of documentation found on sqlite.org used as a reference during development.
46

57
## Table of Contents

0 commit comments

Comments
 (0)