Skip to content

Latest commit

 

History

History
1123 lines (842 loc) · 29.1 KB

File metadata and controls

1123 lines (842 loc) · 29.1 KB

API reference

Complete API documentation for @photostructure/sqlite. This package provides 100% compatibility with Node.js's built-in SQLite module.

Table of contents

Module exports

The module exports the following items that match node:sqlite:

import {
  DatabaseSync, // Main database class
  StatementSync, // Prepared statement class
  Session, // Session class for changesets
  backup, // Standalone backup function
  constants, // SQLite constants
} from "@photostructure/sqlite";

This package also provides enhancement utilities for (some) better-sqlite3 compatibility:

import {
  enhance, // Add .pragma() and .transaction() to any compatible database
  isEnhanced, // Type guard to check if database has enhanced methods
} from "@photostructure/sqlite";

backup()

backup(
  sourceDb: DatabaseSync,
  destination: string | Buffer | URL,
  options?: BackupOptions
): Promise<number>

Standalone function to create a backup of a database.

Parameters:

  • sourceDb - The database instance to back up
  • destination - Path to the backup file (string, Buffer, or file: URL)
  • options - Optional backup configuration

Returns: A Promise that resolves to the total number of pages backed up.

import { DatabaseSync, backup } from "@photostructure/sqlite";

const db = new DatabaseSync("source.db");

// Create a backup
await backup(db, "backup.db");

// With progress monitoring
await backup(db, "backup.db", {
  rate: 10,
  progress: ({ totalPages, remainingPages }) => {
    console.log(`${totalPages - remainingPages}/${totalPages} pages copied`);
  },
});

Enhancement utilities

These utilities add better-sqlite3-style convenience methods to database instances. They are an extension beyond the node:sqlite API.

enhance()

enhance<T extends EnhanceableDatabaseSync>(db: T): EnhancedDatabaseSync<T>

Adds .pragma() and .transaction() methods to any compatible database instance. This enables better-sqlite3-style convenience methods on node:sqlite DatabaseSync instances or any object with compatible exec(), prepare(), and isTransaction properties.

The enhancement is done by adding methods directly to the instance, not the prototype, so it won't affect other instances or the original class.

Parameters:

  • db - The database instance to enhance

Returns: The same instance with .pragma() and .transaction() methods guaranteed.

import { DatabaseSync, enhance } from "@photostructure/sqlite";

// Enhance a database to add better-sqlite3-style methods
const db = enhance(new DatabaseSync(":memory:"));

// Now you can use .pragma()
db.pragma("journal_mode = WAL");
const cacheSize = db.pragma("cache_size", { simple: true });

// And .transaction()
const insertMany = db.transaction((items) => {
  const stmt = db.prepare("INSERT INTO data (value) VALUES (?)");
  for (const item of items) stmt.run(item);
});
insertMany(["a", "b", "c"]); // All in one transaction

Note: If the database already has .pragma() and .transaction() methods (e.g., if you call enhance() twice), it returns the database unchanged.

isEnhanced()

isEnhanced(db: EnhanceableDatabaseSync): db is EnhancedDatabaseSync

Type guard to check if a database has enhanced methods.

import { isEnhanced } from "@photostructure/sqlite";

if (isEnhanced(db)) {
  // TypeScript knows db has .pragma() and .transaction()
  db.pragma("cache_size", { simple: true });
}

Enhanced methods

When a database is enhanced, it gains these methods:

pragma()

pragma(source: string, options?: PragmaOptions): unknown

Executes a PRAGMA statement and returns its result.

Parameters:

  • source - The PRAGMA command (without "PRAGMA" prefix)
  • options - Optional configuration
    • simple - If true, returns the first column of the first row instead of an array of row objects

Returns: Array of rows, or single value if simple: true.

// Get all rows
const result = db.pragma("table_info(users)");
// [{ cid: 0, name: 'id', type: 'INTEGER', ... }, ...]

// Get simple value
const journalMode = db.pragma("journal_mode", { simple: true });
// 'wal'

// Set a pragma
db.pragma("cache_size = -16000"); // 16MB cache

transaction()

transaction<F extends (...args: any[]) => any>(fn: F): TransactionFunction<F>

Creates a function that always runs inside a transaction. If an exception is thrown, the transaction is rolled back; otherwise, it's committed.

Parameters:

  • fn - The function to wrap in a transaction

Returns: A transaction function with .deferred, .immediate, .exclusive variants.

const insert = db.prepare("INSERT INTO users (name) VALUES (?)");

// Create a transaction function
const insertMany = db.transaction((names) => {
  for (const name of names) {
    insert.run(name);
  }
});

// Use it - automatically wrapped in BEGIN/COMMIT
insertMany(["Alice", "Bob", "Charlie"]);

// Use different transaction modes
insertMany.immediate(["Dave"]); // BEGIN IMMEDIATE
insertMany.exclusive(["Eve"]); // BEGIN EXCLUSIVE
insertMany.deferred(["Frank"]); // BEGIN DEFERRED (default)

Nested transactions: When called inside an existing transaction, uses savepoints automatically:

const outer = db.transaction(() => {
  insert.run("outer");
  try {
    inner(); // Uses SAVEPOINT
  } catch (e) {
    // Inner rolled back, outer continues
  }
});

const inner = db.transaction(() => {
  insert.run("inner");
  throw new Error("rollback inner only");
});

outer(); // "outer" is committed, "inner" is not

DatabaseSync

The main database class for synchronous SQLite operations.

Constructor

new DatabaseSync(location: string, options?: DatabaseSyncOptions)

Creates a new database connection.

Parameters:

  • location - Path to database file. Special values:
    • :memory: - In-memory database
    • "" (empty string) - Temporary on-disk database
    • URI format supported (e.g., file:data.db?mode=ro)
  • options - Optional configuration object

Options:

interface DatabaseSyncOptions {
  open?: boolean; // Open database immediately (default: true)
  readOnly?: boolean; // Open in read-only mode (default: false)
  enableForeignKeyConstraints?: boolean; // Enable foreign keys (default: true)
  enableDoubleQuotedStringLiterals?: boolean; // Allow double-quoted strings (default: false)
  allowExtension?: boolean; // Allow loading extensions (default: false)
  timeout?: number; // Busy timeout in ms (default: 0)
  readBigInts?: boolean; // Return BigInt for INTEGER columns (default: false)
  returnArrays?: boolean; // Return rows as arrays instead of objects (default: false)
  allowBareNamedParameters?: boolean; // Allow $name without : prefix (default: true)
  allowUnknownNamedParameters?: boolean; // Allow unbound named parameters (default: false)
  defensive?: boolean; // Enable defensive mode (default: false)
}

Examples:

// Basic usage
const db = new DatabaseSync("myapp.db");

// In-memory database
const memDb = new DatabaseSync(":memory:");

// Read-only with options
const readOnlyDb = new DatabaseSync("data.db", {
  readOnly: true,
  timeout: 10000,
});

// URI format
const uriDb = new DatabaseSync("file:data.db?mode=ro&cache=private");

Methods

close()

close(): void

Closes the database connection. All prepared statements are finalized automatically.

db.close();
[Symbol.dispose](): void

Implements the disposable interface for automatic resource management. Calls close() internally, ignoring any errors during disposal. Implemented natively in C++ for better performance.

// Automatic cleanup with using statement
using db = new DatabaseSync("myapp.db");
// db.close() called automatically when leaving scope

// Or explicit disposal
db[Symbol.dispose]();

exec()

exec(sql: string): void

Executes one or more SQL statements. Does not return any results.

db.exec(`
  CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
  CREATE INDEX idx_name ON users(name);
`);

prepare()

prepare(sql: string, options?: StatementOptions): StatementSync

Prepares a SQL statement for execution.

Options:

interface StatementOptions {
  expandedSQL?: boolean; // Include expanded SQL (default: false)
  anonymousParameters?: boolean; // Enable anonymous parameters (default: false)
  // Per-statement overrides (Node.js v25+ feature):
  readBigInts?: boolean; // Override database-level BigInt setting
  returnArrays?: boolean; // Override database-level array return setting
  allowBareNamedParameters?: boolean; // Override bare parameter setting
  allowUnknownNamedParameters?: boolean; // Override unknown parameter setting
}

Note: The per-statement override options (readBigInts, returnArrays, allowBareNamedParameters, allowUnknownNamedParameters) are a Node.js v25+ feature. On Node.js v24 and earlier, node:sqlite silently ignores these options. This library implements them for forward compatibility.

const stmt = db.prepare("SELECT * FROM users WHERE id = ?");
const stmtWithExpanded = db.prepare("SELECT * FROM users WHERE id = ?", {
  expandedSQL: true,
});

// Per-statement option overrides (Node.js v25+)
const stmtBigInt = db.prepare("SELECT big_id FROM data", { readBigInts: true });
const stmtArrays = db.prepare("SELECT * FROM users", { returnArrays: true });

function()

function(name: string, options: FunctionOptions | Function, func?: Function): void

Registers a custom scalar SQL function.

Options:

interface FunctionOptions {
  deterministic?: boolean; // Same input always gives same output (default: false)
  directOnly?: boolean; // Cannot be used in triggers/views (default: false)
  useBigIntArguments?: boolean; // Receive BigInt instead of number for INTEGER args (default: false)
  varargs?: boolean; // Accept variable number of arguments (default: false)
}
// Simple function
db.function("double", (x) => x * 2);

// With options
db.function(
  "hash",
  {
    deterministic: true,
    directOnly: true,
  },
  (value) => {
    return crypto.createHash("sha256").update(String(value)).digest("hex");
  },
);

// Variable arguments
db.function("concat", { varargs: true }, (...args) => args.join(""));

aggregate()

aggregate(name: string, options: AggregateOptions): void

Registers a custom aggregate SQL function.

Options:

interface AggregateOptions {
  start: any | (() => any); // Initial value or factory function
  step: (accumulator: any, ...values: any[]) => any; // Called for each row
  result?: (accumulator: any) => any; // Final result transformer (optional)
  inverse?: (accumulator: any, ...values: any[]) => any; // For window functions
  deterministic?: boolean; // Same input always gives same output (default: false)
  directOnly?: boolean; // Cannot be used in triggers/views (default: false)
  useBigIntArguments?: boolean; // Receive BigInt for INTEGER args (default: false)
  varargs?: boolean; // Accept variable number of arguments (default: false)
}
// Sum aggregate
db.aggregate("custom_sum", {
  start: 0,
  step: (sum, value) => sum + value,
  result: (sum) => sum,
});

// Average aggregate
db.aggregate("custom_avg", {
  start: { sum: 0, count: 0 },
  step: (acc, value) => {
    acc.sum += value;
    acc.count += 1;
    return acc;
  },
  result: (acc) => acc.sum / acc.count,
});

// Window function with inverse
db.aggregate("moving_sum", {
  start: 0,
  step: (sum, value) => sum + value,
  inverse: (sum, value) => sum - value, // Remove value leaving window
  result: (sum) => sum,
});

createSession()

createSession(options?: SessionOptions): Session

Creates a session for tracking changes.

Options:

interface SessionOptions {
  table?: string; // Specific table to track
  db?: string; // Database name (default: 'main')
}
const session = db.createSession({ table: "users" });
// Make changes...
const changeset = session.changeset();
session.close();

applyChangeset()

applyChangeset(changeset: Buffer, options?: ChangesetApplyOptions): boolean

Applies a changeset to the database. Returns true if successful, false if aborted.

Options:

interface ChangesetApplyOptions {
  onConflict?: (conflictType: number) => number; // Returns resolution constant
  filter?: (tableName: string) => boolean; // Filter which tables to apply
}
const success = db.applyChangeset(changeset, {
  onConflict: (conflictType) => {
    // conflictType is one of: SQLITE_CHANGESET_DATA, SQLITE_CHANGESET_NOTFOUND,
    // SQLITE_CHANGESET_CONFLICT, SQLITE_CHANGESET_CONSTRAINT, SQLITE_CHANGESET_FOREIGN_KEY
    console.log(`Conflict type: ${conflictType}`);
    return constants.SQLITE_CHANGESET_REPLACE;
  },
});

enableLoadExtension()

enableLoadExtension(enable: boolean): void

Enables or disables extension loading. Requires allowExtension: true in constructor.

db.enableLoadExtension(true);
db.loadExtension("./my-extension.so");
db.enableLoadExtension(false);

loadExtension()

loadExtension(path: string, entryPoint?: string): void

Loads a SQLite extension.

db.loadExtension("./extensions/vector.so");
db.loadExtension("./custom.so", "sqlite3_custom_init");

open()

open(): void

Opens the database connection. Only needed if open: false was passed to the constructor.

const db = new DatabaseSync("myapp.db", { open: false });
// ... configure something ...
db.open();

setAuthorizer()

setAuthorizer(callback: AuthorizerCallback | null): void

Sets an authorizer callback to control access to database operations. Pass null to remove the authorizer.

Callback signature:

type AuthorizerCallback = (
  actionCode: number,
  arg1: string | null,
  arg2: string | null,
  dbName: string | null,
  triggerOrView: string | null,
) => number; // Returns SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE
db.setAuthorizer((action, arg1, arg2, dbName, trigger) => {
  if (action === constants.SQLITE_DROP_TABLE) {
    return constants.SQLITE_DENY; // Prevent dropping tables
  }
  return constants.SQLITE_OK;
});

enableDefensive()

enableDefensive(active: boolean): void

Enables or disables defensive mode, which prevents application bugs from corrupting the database.

db.enableDefensive(true);

createTagStore()

createTagStore(maxSize?: number): SQLTagStore

Creates a SQLTagStore for cached prepared statements using tagged template literals.

const sql = db.createTagStore();
sql.run`INSERT INTO users VALUES (${id}, ${name})`;
const user = sql.get`SELECT * FROM users WHERE id = ${id}`;

Properties

isOpen

readonly isOpen: boolean

Returns true if the database connection is open.

console.log(db.isOpen); // true
db.close();
console.log(db.isOpen); // false

isTransaction

readonly isTransaction: boolean

Returns true if a transaction is currently active.

db.exec("BEGIN");
console.log(db.isTransaction); // true
db.exec("COMMIT");
console.log(db.isTransaction); // false

location()

location(dbName?: string): string | null

Returns the file path of the database, or null for in-memory databases.

console.log(db.location()); // "myapp.db"
console.log(db.location("main")); // "myapp.db"

StatementSync

Represents a prepared SQL statement.

Methods

run()

run(...params: any[]): RunResult

Executes the statement and returns information about changes.

Returns:

interface RunResult {
  changes: number; // Number of rows affected
  lastInsertRowid: number | bigint; // Last inserted row ID
}
const result = stmt.run("Alice", 30);
console.log(`Inserted row ${result.lastInsertRowid}`);

get()

get(...params: any[]): any

Executes the statement and returns the first row.

const user = stmt.get(1);
console.log(user); // { id: 1, name: 'Alice', age: 30 }

all()

all(...params: any[]): any[]

Executes the statement and returns all rows.

const users = stmt.all();
console.log(users); // Array of all user objects

iterate()

iterate(...params: any[]): Iterator<any>

Executes the statement and returns an iterator for the results.

for (const row of stmt.iterate()) {
  console.log(row);
}

columns()

columns(): ColumnInfo[]

Returns metadata about the columns in the result set.

Returns:

interface ColumnInfo {
  column: string | null; // Original column name
  database: string | null; // Database name
  name: string; // Column alias or name
  table: string | null; // Table name
  type: string | null; // Declared type
}
const stmt = db.prepare("SELECT id, name FROM users");
console.log(stmt.columns());
// [
//   { column: 'id', database: 'main', name: 'id', table: 'users', type: 'INTEGER' },
//   { column: 'name', database: 'main', name: 'name', table: 'users', type: 'TEXT' }
// ]

setReadBigInts()

setReadBigInts(enabled: boolean): void

Configures whether INTEGER columns are returned as BigInt values.

stmt.setReadBigInts(true);
const row = stmt.get(1);
console.log(typeof row.id); // "bigint"

setReturnArrays()

setReturnArrays(enabled: boolean): void

Configures whether rows are returned as arrays instead of objects.

stmt.setReturnArrays(true);
const row = stmt.get(1);
console.log(row); // [1, 'Alice', 30] instead of { id: 1, name: 'Alice', age: 30 }

setAllowBareNamedParameters()

setAllowBareNamedParameters(enabled: boolean): void

Configures whether named parameters can be used without the : prefix.

stmt.setAllowBareNamedParameters(true);
stmt.run({ name: "Alice" }); // Works without :name

setAllowUnknownNamedParameters()

setAllowUnknownNamedParameters(enabled: boolean): void

Configures whether unbound named parameters are allowed (they resolve to NULL).

stmt.setAllowUnknownNamedParameters(true);
stmt.run({ name: "Alice" }); // Extra params in object are ignored

Properties

sourceSQL

readonly sourceSQL: string

The original SQL text of the statement.

console.log(stmt.sourceSQL); // "SELECT * FROM users WHERE id = ?"

expandedSQL

readonly expandedSQL: string

The SQL with bound parameters expanded (only if expandedSQL: true option was used).

const stmt = db.prepare("SELECT * FROM users WHERE id = ?", {
  expandedSQL: true,
});
stmt.get(42);
console.log(stmt.expandedSQL); // "SELECT * FROM users WHERE id = 42"

Types and interfaces

DatabaseSyncOptions

interface DatabaseSyncOptions {
  open?: boolean; // Open database immediately (default: true)
  readOnly?: boolean; // Open in read-only mode (default: false)
  enableForeignKeyConstraints?: boolean; // Enable foreign keys (default: true)
  enableDoubleQuotedStringLiterals?: boolean; // Allow double-quoted strings (default: false)
  allowExtension?: boolean; // Allow loading extensions (default: false)
  timeout?: number; // Busy timeout in ms (default: 0)
  readBigInts?: boolean; // Return BigInt for INTEGER columns (default: false)
  returnArrays?: boolean; // Return rows as arrays instead of objects (default: false)
  allowBareNamedParameters?: boolean; // Allow $name without : prefix (default: true)
  allowUnknownNamedParameters?: boolean; // Allow unbound named parameters (default: false)
  defensive?: boolean; // Enable defensive mode (default: false)
}

StatementOptions

interface StatementOptions {
  expandedSQL?: boolean;
  anonymousParameters?: boolean;
}

FunctionOptions

interface FunctionOptions {
  deterministic?: boolean; // Same input always gives same output (default: false)
  directOnly?: boolean; // Cannot be used in triggers/views (default: false)
  useBigIntArguments?: boolean; // Receive BigInt for INTEGER args (default: false)
  varargs?: boolean; // Accept variable number of arguments (default: false)
}

AggregateOptions

interface AggregateOptions {
  start: any | (() => any); // Initial value or factory function
  step: (accumulator: any, ...values: any[]) => any; // Called for each row
  result?: (accumulator: any) => any; // Final result transformer (optional)
  inverse?: (accumulator: any, ...values: any[]) => any; // For window functions
  deterministic?: boolean; // Same input always gives same output (default: false)
  directOnly?: boolean; // Cannot be used in triggers/views (default: false)
  useBigIntArguments?: boolean; // Receive BigInt for INTEGER args (default: false)
  varargs?: boolean; // Accept variable number of arguments (default: false)
}

BackupOptions

interface BackupOptions {
  source?: string; // Source database name (default: 'main')
  target?: string; // Target database name (default: 'main')
  rate?: number; // Pages per iteration (default: 100)
  progress?: (info: { totalPages: number; remainingPages: number }) => void;
}

ColumnInfo

interface ColumnInfo {
  column: string | null; // Original column name
  database: string | null; // Database name
  name: string; // Column alias or name
  table: string | null; // Table name
  type: string | null; // Declared type
}

RunResult

interface RunResult {
  changes: number | bigint; // Number of rows affected
  lastInsertRowid: number | bigint; // Last inserted row ID
}

PragmaOptions

interface PragmaOptions {
  simple?: boolean; // Return first column of first row instead of array
}

TransactionFunction

interface TransactionFunction<F extends (...args: any[]) => any> {
  (...args: Parameters<F>): ReturnType<F>;
  deferred: (...args: Parameters<F>) => ReturnType<F>;
  immediate: (...args: Parameters<F>) => ReturnType<F>;
  exclusive: (...args: Parameters<F>) => ReturnType<F>;
}

EnhanceableDatabaseSync

Minimal interface for a database that can be enhanced:

interface EnhanceableDatabaseSync {
  exec(sql: string): void;
  prepare(sql: string): { all(): unknown[] };
  readonly isTransaction: boolean;
}

EnhancedMethods

Interface for enhanced database methods:

interface EnhancedMethods {
  pragma(source: string, options?: PragmaOptions): unknown;
  transaction<F extends (...args: any[]) => any>(fn: F): TransactionFunction<F>;
}

EnhancedDatabaseSync

A database instance that has been enhanced:

type EnhancedDatabaseSync<T extends EnhanceableDatabaseSync> = T &
  EnhancedMethods;

Constants

The package exports SQLite constants for use with sessions, changesets, and authorization:

import { constants } from "@photostructure/sqlite";

// Conflict resolution constants
constants.SQLITE_CHANGESET_OMIT;
constants.SQLITE_CHANGESET_REPLACE;
constants.SQLITE_CHANGESET_ABORT;

// Authorization result codes
constants.SQLITE_OK;
constants.SQLITE_DENY;
constants.SQLITE_IGNORE;

// Authorization action codes
constants.SQLITE_CREATE_TABLE;
constants.SQLITE_INSERT;
constants.SQLITE_SELECT;
// ... and more

TypeScript type categories

Note: These categorized type interfaces are an extension provided by @photostructure/sqlite. The node:sqlite module exports only a flat constants object without these type categories.

This package provides strongly-typed interfaces for different constant categories, enabling better TypeScript type checking and IntelliSense:

import {
  constants,
  // Type interfaces (not in node:sqlite)
  SqliteConstants,
  SqliteOpenFlags,
  SqliteChangesetResolution,
  SqliteChangesetConflictTypes,
  SqliteAuthorizationResults,
  SqliteAuthorizationActions,
} from "@photostructure/sqlite";

SqliteOpenFlags (extension)

Database open flags. These constants are an extension beyond node:sqlite - the node:sqlite module does not export SQLITE_OPEN_* constants.

Constant Description
SQLITE_OPEN_READONLY Open database for reading only
SQLITE_OPEN_READWRITE Open database for reading and writing
SQLITE_OPEN_CREATE Create database if it doesn't exist
SQLITE_OPEN_URI Interpret filename as URI
SQLITE_OPEN_MEMORY Open in-memory database
SQLITE_OPEN_NOMUTEX Open without mutex
SQLITE_OPEN_FULLMUTEX Open with full mutex
SQLITE_OPEN_SHAREDCACHE Enable shared cache mode
SQLITE_OPEN_PRIVATECACHE Enable private cache mode
SQLITE_OPEN_WAL Open WAL file
... (10 more flags available)

SqliteChangesetResolution (node:sqlite compatible)

Return values for applyChangeset() conflict callbacks:

Constant Description
SQLITE_CHANGESET_OMIT Skip conflicting changes
SQLITE_CHANGESET_REPLACE Replace conflicting changes
SQLITE_CHANGESET_ABORT Abort on conflict

SqliteChangesetConflictTypes (node:sqlite compatible)

Conflict type codes passed to applyChangeset() callbacks:

Constant Description
SQLITE_CHANGESET_DATA Row exists but values differ
SQLITE_CHANGESET_NOTFOUND Row not found in target
SQLITE_CHANGESET_CONFLICT Primary key conflict
SQLITE_CHANGESET_CONSTRAINT Constraint violation
SQLITE_CHANGESET_FOREIGN_KEY Foreign key violation

SqliteAuthorizationResults (node:sqlite compatible)

Return values for setAuthorizer() callbacks:

Constant Description
SQLITE_OK Allow the operation
SQLITE_DENY Deny and abort with error
SQLITE_IGNORE Silently skip the operation

SqliteAuthorizationActions (node:sqlite compatible)

Action codes passed to setAuthorizer() callbacks (34 total):

Constant Description
SQLITE_CREATE_TABLE Create a new table
SQLITE_INSERT Insert rows
SQLITE_SELECT Execute SELECT
SQLITE_UPDATE Update rows
SQLITE_DELETE Delete rows
SQLITE_CREATE_INDEX Create an index
SQLITE_DROP_TABLE Drop a table
SQLITE_PRAGMA Execute PRAGMA
SQLITE_ATTACH Attach a database
SQLITE_DETACH Detach a database
... (24 more action codes)

Using type categories

The categorized types enable strongly-typed function signatures:

import {
  constants,
  SqliteChangesetResolution,
  SqliteChangesetConflictTypes,
} from "@photostructure/sqlite";

function handleConflict(
  conflictType: keyof SqliteChangesetConflictTypes,
): keyof SqliteChangesetResolution {
  if (conflictType === "SQLITE_CHANGESET_DATA") {
    return "SQLITE_CHANGESET_REPLACE";
  }
  return "SQLITE_CHANGESET_OMIT";
}

db.applyChangeset(changeset, {
  onConflict: (type) => constants[handleConflict(type)],
});

Error handling

All errors include additional information:

interface SQLiteError extends Error {
  code: string; // e.g., "SQLITE_CANTOPEN"
  sqliteCode: number; // e.g., 14
  sqliteExtendedCode: number;
  sqliteErrorString: string; // Human-readable description
  systemErrno?: number; // OS error code (when applicable)
}
try {
  db.exec("INVALID SQL");
} catch (error) {
  console.log(error.message); // Full error message
  console.log(error.code); // "SQLITE_ERROR"
  console.log(error.sqliteCode); // 1
  console.log(error.sqliteErrorString); // "SQL logic error"
}

See also