Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/api-package-intros.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ db.close()
\`\`\`

Use [Getting Started](/docs) for native setup and a fuller first query. The [concepts](/docs/concepts/databases-and-connections) and [guides](/docs/guides/parameters-and-results) explain database lifetime, query parameters, and results. For the Node-only test export and its API, see [Test SQLite in Node](/docs/guides/node-test-mock).
`,
'react-native-nitro-sqlite/mock': `This Node-only export runs SQLite tests through \`better-sqlite3\` without loading the React Native module. Install \`better-sqlite3\` as a development dependency and import this module in your test setup. See [Test SQLite in Node](/docs/guides/node-test-mock) for Jest setup, shared connections, prepared statements, transactions, and cleanup.
`,
'react-native-nitro-sqlite-vec': `This optional package adds [sqlite-vec](https://github.com/asg017/sqlite-vec) vector search to Nitro SQLite. Its native code is compiled into the core package's SQLite build. The functions and types below cover availability checks, vector tables, and nearest-neighbor searches.

Expand Down
91 changes: 78 additions & 13 deletions docs/content/docs/guides/node-test-mock.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
---
title: Test SQLite in Node
description: Run SQL in Jest tests with the in-memory SQLite mock.
description: Test shared SQLite connections, statements, and transactions in Node.
---

Use `react-native-nitro-sqlite/mock` to run queries and batches in Node tests without loading the React Native module. Install `better-sqlite3` as a development dependency in your test project. The mock keeps each named database in memory, so close connections or reset the databases between tests. Use device tests for file storage or native scheduling.
SQLite connections are handles to a database file. Separate handles can share committed data, and a transaction can keep a consistent snapshot while another connection writes under [WAL](/docs/guides/multiple-connections).

Use `react-native-nitro-sqlite/mock` to test these behaviors in Node without loading the React Native module. Install `better-sqlite3` as a development dependency in your test project. The mock creates databases in a temporary directory and supports queries, atomic batches, prepared statements, and callback transactions.

## Set up Jest

Expand Down Expand Up @@ -38,20 +40,83 @@ test('stores a note', () => {
})
```

The mock returns query rows through both `results` and `rows`, and supports synchronous and asynchronous queries and [atomic batches](/docs/guides/batch-operations). Bound `undefined` becomes SQL NULL. A query that fails throws from `execute()` or rejects from `executeAsync()`.
The mock returns query rows through both `results` and `rows`, and supports [atomic batches](/docs/guides/batch-operations). Bound `undefined` becomes SQL NULL. A query that fails throws from `execute()` or rejects from `executeAsync()`.

## Share a database between connections

Connections with the same `name` and `location` open the same temporary file. A default connection reserves its name until you close it. Set `connection: 'independent'` to open another handle, and `readOnly: true` to prevent writes. Read-only opens fail if the file does not exist.

```ts
const writer = open({ name: 'notes.sqlite' })
writer.execute('PRAGMA journal_mode = WAL')
writer.execute('CREATE TABLE notes (title TEXT)')
writer.execute('INSERT INTO notes VALUES (?)', ['Draft'])

const reader = open({
name: 'notes.sqlite',
connection: 'independent',
readOnly: true,
})
expect(reader.execute('SELECT title FROM notes').rows.item(0)?.title).toBe(
'Draft',
)

reader.close()
writer.close()
```

`location` selects a relative directory inside the mock's temporary directory. A name must be a file name; paths that escape the temporary directory throw.

Closing a connection preserves its data for reopening. `delete()` closes the connection and removes its database and sidecar files. It throws for a read-only connection or if another open connection uses the file. Close those connections before deleting it.

## Reuse a prepared statement

Preparing SQL once lets you execute it repeatedly with new parameter values. Each execution replaces the previous bindings. Omitted values bind as SQL NULL. Finalize statements before closing the connection.

```ts
const db = open({ name: 'notes.sqlite' })
db.execute('CREATE TABLE notes (title TEXT)')
const insert = db.prepare('INSERT INTO notes VALUES (?)')

await insert.executeAsync(['Draft'])
await insert.executeAsync(['Published'])
insert.finalize()
expect(insert.isFinalized).toBe(true)

db.close()
```

`finalize()` is safe to repeat while the connection is open and idle. Executing a finalized statement or using a statement after its connection closes throws or rejects.

## Commit or roll back a transaction

A transaction groups operations into one commit. The mock keeps a callback transaction exclusive on its connection, including across `await`. Use the supplied `tx` for all database work inside the callback:

```ts
const db = open({ name: 'notes.sqlite' })
db.execute('CREATE TABLE notes (title TEXT)')

const count = await db.transaction(async (tx) => {
await tx.executeAsync('INSERT INTO notes VALUES (?)', ['Draft'])
return tx.execute('SELECT title FROM notes').rows.length
})
expect(count).toBe(1)

db.close()
```

The callback's result resolves after commit. A callback error rolls back its changes. You can call `tx.commit()` or `tx.rollback()` explicitly; subsequent operations on that transaction fail. Await all `tx.executeAsync()` calls before a synchronous transaction operation or before returning from the callback.

Async connection calls run in call order and wait for callback transactions. Synchronous queries, preparation, statement finalization, close, and delete throw while their connection is busy. Awaiting a queued connection call inside its transaction callback deadlocks; use `tx` instead. Independent connections have separate queues.

## Mock API
## Clean up between tests

Import these exports from `react-native-nitro-sqlite/mock`:
Await all pending operations before calling `resetAllDatabases()`. It closes every handle and removes all temporary databases and sidecar files, including files whose connections you already closed. Connections and statements from before the reset cannot execute again.

| Export | Behavior |
| --- | --- |
| `open({ name })` | Opens a named in-memory database and returns a connection. Opening the same name twice before closing it throws. |
| `NitroSQLite.open({ name })` | Calls the same `open()` function. |
| `resetAllDatabases()` | Closes every open mock database and removes its data. |
The reset throws if any connection is busy. Await that work and retry. No connections close when this check fails.

The returned connection implements `execute()`, `executeAsync()`, `executeBatch()`, `executeBatchAsync()`, `close()`, and `delete()`. `delete()` closes the in-memory database. Query methods return the public data of [`QueryResult`](/api/react-native-nitro-sqlite/type-aliases/QueryResult); batch methods return a `rowsAffected` count. Batch commands use the [`BatchQueryCommand`](/api/react-native-nitro-sqlite/interfaces/BatchQueryCommand) shape.
## API reference and limits

## Limits
The generated [mock API reference](/api/react-native-nitro-sqlite/mock) documents `open()`, `NitroSQLite.open()`, `MockConnection`, and `resetAllDatabases()`. Connection methods use the same parameter and result types as the native API.

The mock does not implement independent or read-only connections, files, attachments, prepared statements, callback transactions, or other native methods. Its async methods return promises but execute SQL synchronously in Node.
The mock does not implement attachments, SQL file imports, or direct `NitroSQLite.native` methods. Its SQL runs synchronously on Node's thread; async methods schedule that work and return promises. It uses the SQLite version bundled with `better-sqlite3`, which can differ from the library's native SQLite build. Use device tests for native integration, thread behavior, lock contention, and performance.
8 changes: 8 additions & 0 deletions docs/mock-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "react-native-nitro-sqlite/mock",
"private": true,
"typedocOptions": {
"entryPoints": ["../../packages/react-native-nitro-sqlite/src/mock.ts"],
"tsconfig": "../tsconfig.typedoc.json"
}
}
6 changes: 6 additions & 0 deletions docs/scripts/check-api.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ const requiredExports = {
'TypeOrmNitroSQLiteConnection',
'typeORMDriver',
],
'react-native-nitro-sqlite/mock': [
'open',
'NitroSQLite',
'MockConnection',
'resetAllDatabases',
],
'react-native-nitro-sqlite-vec': [
'VectorColumnType',
'VectorDistanceMetric',
Expand Down
1 change: 1 addition & 0 deletions docs/tsconfig.typedoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"files": [
"../packages/react-native-nitro-sqlite/src/index.ts",
"../packages/react-native-nitro-sqlite/src/mock.ts",
"../packages/react-native-nitro-sqlite-vec/src/index.ts"
]
}
3 changes: 2 additions & 1 deletion docs/typedoc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"entryPoints": [
"../packages/react-native-nitro-sqlite",
"../packages/react-native-nitro-sqlite-vec"
"../packages/react-native-nitro-sqlite-vec",
"./mock-api"
],
"entryPointStrategy": "packages",
"name": "API Reference",
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-nitro-sqlite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"!src/**/__tests__/**",
"!src/**/__mocks__/**",
"!src/mock.ts",
"!src/mock/**",
"!src/specs/**",
"!src/types.ts"
],
Expand Down
Loading
Loading