Skip to content

Commit 9c4408c

Browse files
committed
feat: complete the plugin commands
- Changed some return types to better reflect what the methods do and what they can tell you about what they do - Integration tests and possibly an example app to come next - Migration support coming later
1 parent 07592a0 commit 9c4408c

20 files changed

Lines changed: 689 additions & 112 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 8 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pooling, write serialization, and proper resource management.
1717
* **Optimized Connection Pooling**: Separate read and write pools for concurrent reads,
1818
even while writing
1919
* **Write Serialization**: Exclusive write access through connection manager
20-
* **Migration Support**: Uses SQLx's database migration system (runs during preload)
20+
* **Migration Support**: Uses SQLx's database migration system
2121
* **Custom Configuration**: Configure read pool size and idle timeouts
2222
* **Type Safety**: Full TypeScript bindings
2323
* **Resource Management**: Proper cleanup on application exit
@@ -332,7 +332,7 @@ console.log(`Transfer ID: ${results[2].lastInsertId}`);
332332

333333
**How it works:**
334334

335-
* Automatically executes `BEGIN` before running statements
335+
* Automatically executes `BEGIN IMMEDIATE` before running statements
336336
* Executes all statements in order
337337
* Commits with `COMMIT` if all statements succeed
338338
* Rolls back with `ROLLBACK` if any statement fails
@@ -360,85 +360,8 @@ await db.remove()
360360

361361
## Migrations
362362

363-
Migrations run automatically during database preload at application startup.
364-
365-
### Setting Up Migrations
366-
367-
`src-tauri/src/lib.rs`
368-
369-
```rust
370-
use tauri_plugin_sqlite::{Builder, Migration, MigrationKind};
371-
372-
fn main() {
373-
let migrations = vec![
374-
// Version 1: Create initial schema
375-
Migration {
376-
version: 1,
377-
description: "create_users_table",
378-
sql: vec!["CREATE TABLE users (
379-
id INTEGER PRIMARY KEY AUTOINCREMENT,
380-
name TEXT NOT NULL,
381-
email TEXT NOT NULL UNIQUE,
382-
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
383-
)"],
384-
kind: MigrationKind::Up,
385-
},
386-
// Version 2: Add new column
387-
Migration {
388-
version: 2,
389-
description: "add_users_role",
390-
sql: vec!["ALTER TABLE users ADD COLUMN role TEXT DEFAULT 'user'"],
391-
kind: MigrationKind::Up,
392-
},
393-
// Version 3: Create index and add trigger (multiple statements)
394-
Migration {
395-
version: 3,
396-
description: "create_email_index_and_trigger",
397-
sql: vec![
398-
"CREATE INDEX idx_users_email ON users(email)",
399-
"CREATE TRIGGER update_timestamp AFTER UPDATE ON users
400-
BEGIN
401-
UPDATE users SET created_at = strftime('%s', 'now') WHERE id = NEW.id;
402-
END",
403-
],
404-
kind: MigrationKind::Up,
405-
},
406-
];
407-
408-
tauri::Builder::default()
409-
.plugin(
410-
Builder::new()
411-
.add_migrations("mydb.db", migrations)
412-
.build(),
413-
)
414-
.run(tauri::generate_context!())
415-
.expect("error while running tauri application");
416-
}
417-
```
418-
419-
### Preloading Databases
420-
421-
Add databases to `tauri.conf.json` to connect and run migrations at startup:
422-
423-
```json
424-
{
425-
"plugins": {
426-
"sqlite": {
427-
"preload": ["mydb.db", "cache.db"]
428-
}
429-
}
430-
}
431-
```
432-
433-
When preloaded:
434-
435-
1. The plugin connects to each database
436-
2. Runs any pending migrations defined in `add_migrations()`
437-
3. Keeps the connection open and ready for use
438-
439-
> **Important:** Migrations only run during preload. If you load a database
440-
> dynamically with `Database.load()`, migrations will not run unless it was
441-
> preloaded.
363+
> **Note:** Database migration support is a planned feature and will be added in a
364+
> future release. It will be based on SQLx's migration framework.
442365
443366
## Query Parameter Binding
444367

@@ -526,7 +449,7 @@ const db = Database.get('mydb.db')
526449
// Connection happens on first query
527450
```
528451

529-
##### `Database.closeAll(): Promise<boolean>`
452+
##### `Database.closeAll(): Promise<void>`
530453

531454
Close all database connections.
532455

@@ -578,13 +501,14 @@ if (user) {
578501

579502
##### `close(): Promise<boolean>`
580503

581-
Close this database connection.
504+
Close this database connection. Returns `true` if the database was loaded and closed,
505+
`false` if it wasn't loaded.
582506

583507
```typescript
584508
await db.close()
585509
```
586510

587-
##### `remove(): Promise<boolean>`
511+
##### `remove(): Promise<void>`
588512

589513
Close the connection and permanently delete database file(s).
590514

api-iife.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
fn main() {
2-
// TODO: Add commands to the plugin
3-
tauri_plugin::Builder::new(&["hello"]).build();
2+
tauri_plugin::Builder::new(&[
3+
"load",
4+
"execute",
5+
"execute_transaction",
6+
"fetch_all",
7+
"fetch_one",
8+
"close",
9+
"close_all",
10+
"remove",
11+
])
12+
.build();
413
}

crates/sqlx-sqlite-conn-mgr/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ sqlx = { version = "0.8.6", features = ["runtime-tokio", "sqlite"] }
1111
thiserror = "2.0.17"
1212
tokio = { version = "1.48.0", features = ["full"] }
1313
tracing = { version = "0.1.41", default-features = false, features = ["std", "release_max_level_off"] }
14+
serde = { version = "1.0.228", features = ["derive"] }

crates/sqlx-sqlite-conn-mgr/src/config.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22
33
use std::time::Duration;
44

5+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
6+
7+
/// Serialize Duration as seconds (u64)
8+
mod duration_secs {
9+
use super::*;
10+
11+
pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
12+
where
13+
S: Serializer,
14+
{
15+
serializer.serialize_u64(duration.as_secs())
16+
}
17+
18+
pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
19+
where
20+
D: Deserializer<'de>,
21+
{
22+
let secs = u64::deserialize(deserializer)?;
23+
Ok(Duration::from_secs(secs))
24+
}
25+
}
26+
527
/// Configuration for SqliteDatabase connection pools
628
///
729
/// # Examples
@@ -25,7 +47,7 @@ use std::time::Duration;
2547
/// ..Default::default()
2648
/// };
2749
/// ```
28-
#[derive(Debug, Clone)]
50+
#[derive(Debug, Clone, Serialize, Deserialize)]
2951
pub struct SqliteDatabaseConfig {
3052
/// Maximum number of concurrent read connections
3153
///
@@ -35,12 +57,13 @@ pub struct SqliteDatabaseConfig {
3557
/// Default: 6
3658
pub max_read_connections: u32,
3759

38-
/// Idle timeout for both read and write connections
60+
/// Idle timeout for both read and write connections (in seconds)
3961
///
4062
/// Connections that remain idle for this duration will be closed automatically.
4163
/// This helps prevent resource exhaustion from idle threads.
4264
///
4365
/// Default: 30 seconds
66+
#[serde(with = "duration_secs")]
4467
pub idle_timeout: Duration,
4568
}
4669

guest-js/index.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,17 @@ export default class Database {
265265
*
266266
* Closes the database connection pool(s) for this specific database.
267267
*
268+
* @returns `true` if the database was loaded and successfully closed,
269+
* `false` if the database was not loaded (nothing to close)
270+
*
268271
* @example
269272
* ```ts
270-
* const success = await db.close()
273+
* const wasClosed = await db.close()
274+
* if (wasClosed) {
275+
* console.log('Database closed successfully')
276+
* } else {
277+
* console.log('Database was not loaded')
278+
* }
271279
* ```
272280
*/
273281
async close(): Promise<boolean> {
@@ -284,12 +292,11 @@ export default class Database {
284292
*
285293
* @example
286294
* ```ts
287-
* const success = await Database.closeAll()
295+
* await Database.closeAll()
288296
* ```
289297
*/
290-
static async closeAll(): Promise<boolean> {
291-
const success = await invoke<boolean>('plugin:sqlite|close_all')
292-
return success
298+
static async closeAll(): Promise<void> {
299+
await invoke<void>('plugin:sqlite|close_all')
293300
}
294301

295302
/**
@@ -302,13 +309,12 @@ export default class Database {
302309
*
303310
* @example
304311
* ```ts
305-
* const success = await db.remove()
312+
* await db.remove()
306313
* ```
307314
*/
308-
async remove(): Promise<boolean> {
309-
const success = await invoke<boolean>('plugin:sqlite|remove', {
315+
async remove(): Promise<void> {
316+
await invoke<void>('plugin:sqlite|remove', {
310317
db: this.path
311318
})
312-
return success
313319
}
314320
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Automatically generated - DO NOT EDIT!
2+
3+
"$schema" = "../../schemas/schema.json"
4+
5+
[[permission]]
6+
identifier = "allow-close"
7+
description = "Enables the close command without any pre-configured scope."
8+
commands.allow = ["close"]
9+
10+
[[permission]]
11+
identifier = "deny-close"
12+
description = "Denies the close command without any pre-configured scope."
13+
commands.deny = ["close"]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Automatically generated - DO NOT EDIT!
2+
3+
"$schema" = "../../schemas/schema.json"
4+
5+
[[permission]]
6+
identifier = "allow-close-all"
7+
description = "Enables the close_all command without any pre-configured scope."
8+
commands.allow = ["close_all"]
9+
10+
[[permission]]
11+
identifier = "deny-close-all"
12+
description = "Denies the close_all command without any pre-configured scope."
13+
commands.deny = ["close_all"]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Automatically generated - DO NOT EDIT!
2+
3+
"$schema" = "../../schemas/schema.json"
4+
5+
[[permission]]
6+
identifier = "allow-execute"
7+
description = "Enables the execute command without any pre-configured scope."
8+
commands.allow = ["execute"]
9+
10+
[[permission]]
11+
identifier = "deny-execute"
12+
description = "Denies the execute command without any pre-configured scope."
13+
commands.deny = ["execute"]

0 commit comments

Comments
 (0)