Skip to content
Open
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
96 changes: 96 additions & 0 deletions packages/db-tauri-sqlite-persisted-collection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# @tanstack/db-tauri-sqlite-persisted-collection

Thin SQLite persistence for Tauri apps using `@tauri-apps/plugin-sql`.

## Public API

- `createTauriSQLitePersistence(...)`
- `persistedCollectionOptions(...)` (re-exported from core)

## Install

```bash
pnpm add @tanstack/db-tauri-sqlite-persisted-collection @tauri-apps/plugin-sql
```

## Consumer-side Tauri setup

Install the official SQL plugin in your Tauri app:

```bash
cd src-tauri
cargo add tauri-plugin-sql --features sqlite
```

Register the plugin in `src-tauri/src/main.rs`:

```rust
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_sql::Builder::default().build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```

Enable the SQL permissions in `src-tauri/capabilities/default.json`:

```json
{
"permissions": ["core:default", "sql:default", "sql:allow-execute"]
}
```

## Quick start

```ts
import Database from '@tauri-apps/plugin-sql'
import { createCollection } from '@tanstack/db'
import {
createTauriSQLitePersistence,
persistedCollectionOptions,
} from '@tanstack/db-tauri-sqlite-persisted-collection'

type Todo = {
id: string
title: string
completed: boolean
}

const database = await Database.load(`sqlite:tanstack-db.sqlite`)

const persistence = createTauriSQLitePersistence({
database,
})

export const todosCollection = createCollection(
persistedCollectionOptions<Todo, string>({
id: `todos`,
getKey: (todo) => todo.id,
persistence,
schemaVersion: 1,
}),
)
```

## Notes

- `createTauriSQLitePersistence` is shared across collections.
- Reuse a single `Database.load('sqlite:...')` handle per SQLite file when using
this package. Opening multiple plugin handles to the same file can reintroduce
SQLite locking behavior outside this package's serialized transaction queue.
- Mode defaults (`sync-present` vs `sync-absent`) are inferred from whether a
`sync` config is present in `persistedCollectionOptions`.
- This package expects a database handle created by
`@tauri-apps/plugin-sql`, typically from `Database.load('sqlite:...')`.
- The database path is resolved by Tauri's SQL plugin, not by this package.
- This package does not publish or require package-specific Rust code. Only the
app-level Tauri SQL plugin registration shown above is required.

## Testing

- `pnpm --filter @tanstack/db-tauri-sqlite-persisted-collection test`
runs the driver and shared adapter contract tests.
- `pnpm --filter @tanstack/db-tauri-sqlite-persisted-collection test:e2e`
builds the repo-local Tauri harness and runs the persisted collection
conformance suite inside a real Tauri runtime.
48 changes: 48 additions & 0 deletions packages/db-tauri-sqlite-persisted-collection/e2e/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri SQLite E2E</title>
</head>
<body>
<main>
<p id="status">Booting Tauri persisted collection e2e runtime</p>
<pre id="details"></pre>
</main>
<script type="module">
const reportUrl = '%VITE_TANSTACK_DB_TAURI_E2E_REPORT_URL%'

if (reportUrl && !reportUrl.startsWith('%')) {
fetch(reportUrl, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
kind: 'status',
phase: 'html-loaded',
}),
}).catch(() => {})
}

import('/src/main.ts').catch((error) => {
if (reportUrl && !reportUrl.startsWith('%')) {
fetch(reportUrl, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
kind: 'status',
phase: 'main-import-failed',
details: {
message: String(error?.message ?? error),
},
}),
}).catch(() => {})
}
})
</script>
</body>
</html>
23 changes: 23 additions & 0 deletions packages/db-tauri-sqlite-persisted-collection/e2e/app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@tanstack/db-tauri-sqlite-persisted-collection-e2e-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite",
"tauri": "tauri"
},
"dependencies": {
"@tauri-apps/api": "^2.10.1",
"@tauri-apps/plugin-sql": "^2.3.2",
"@tanstack/db": "workspace:*",
"@tanstack/db-tauri-sqlite-persisted-collection": "workspace:*"
},
"devDependencies": {
"@tauri-apps/cli": "^2.10.1",
"@types/node": "^25.2.2",
"typescript": "^5.9.3",
"vite": "^7.3.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
/gen
Loading
Loading