@@ -3,43 +3,115 @@ use serde::{Deserialize, Serialize};
3
3
use std:: collections:: HashMap ;
4
4
use thiserror:: Error ;
5
5
6
- /// Actions are sent to a specific sqlite database, `db` is the name,
7
- /// `package_id` is the [`PackageId`]. Capabilities are checked, you can access another process's
8
- /// database if it has given you the [`crate::Capability`].
9
- #[ derive( Debug , Serialize , Deserialize ) ]
6
+ /// Actions are sent to a specific SQLite database. `db` is the name,
7
+ /// `package_id` is the [`PackageId`] that created the database. Capabilities
8
+ /// are checked: you can access another process's database if it has given
9
+ /// you the read and/or write capability to do so.
10
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
10
11
pub struct SqliteRequest {
11
12
pub package_id : PackageId ,
12
13
pub db : String ,
13
14
pub action : SqliteAction ,
14
15
}
15
16
16
- #[ derive( Debug , Serialize , Deserialize ) ]
17
+ /// IPC Action format representing operations that can be performed on the
18
+ /// SQLite runtime module. These actions are included in a [`SqliteRequest`]
19
+ /// sent to the `sqlite:distro:sys` runtime module.
20
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
17
21
pub enum SqliteAction {
22
+ /// Opens an existing key-value database or creates a new one if it doesn't exist.
23
+ /// Requires `package_id` in [`SqliteRequest`] to match the package ID of the sender.
24
+ /// The sender will own the database and can remove it with [`SqliteAction::RemoveDb`].
25
+ ///
26
+ /// A successful open will respond with [`SqliteResponse::Ok`]. Any error will be
27
+ /// contained in the [`SqliteResponse::Err`] variant.
18
28
Open ,
29
+ /// Permanently deletes the entire key-value database.
30
+ /// Requires `package_id` in [`SqliteRequest`] to match the package ID of the sender.
31
+ /// Only the owner can remove the database.
32
+ ///
33
+ /// A successful remove will respond with [`SqliteResponse::Ok`]. Any error will be
34
+ /// contained in the [`SqliteResponse::Err`] variant.
19
35
RemoveDb ,
36
+ /// Executes a write statement (INSERT/UPDATE/DELETE)
37
+ ///
38
+ /// * `statement` - SQL statement to execute
39
+ /// * `tx_id` - Optional transaction ID
40
+ /// * blob: Vec<SqlValue> - Parameters for the SQL statement, where SqlValue can be:
41
+ /// - null
42
+ /// - boolean
43
+ /// - i64
44
+ /// - f64
45
+ /// - String
46
+ /// - Vec<u8> (binary data)
47
+ ///
48
+ /// Using this action requires the sender to have the write capability
49
+ /// for the database.
50
+ ///
51
+ /// A successful write will respond with [`SqliteResponse::Ok`]. Any error will be
52
+ /// contained in the [`SqliteResponse::Err`] variant.
20
53
Write {
21
54
statement : String ,
22
55
tx_id : Option < u64 > ,
23
56
} ,
24
- Read {
25
- query : String ,
26
- } ,
57
+ /// Executes a read query (SELECT)
58
+ ///
59
+ /// * blob: Vec<SqlValue> - Parameters for the SQL query, where SqlValue can be:
60
+ /// - null
61
+ /// - boolean
62
+ /// - i64
63
+ /// - f64
64
+ /// - String
65
+ /// - Vec<u8> (binary data)
66
+ ///
67
+ /// Using this action requires the sender to have the read capability
68
+ /// for the database.
69
+ ///
70
+ /// A successful query will respond with [`SqliteResponse::Query`], where the
71
+ /// response blob contains the results of the query. Any error will be contained
72
+ /// in the [`SqliteResponse::Err`] variant.
73
+ Query ( String ) ,
74
+ /// Begins a new transaction for atomic operations.
75
+ ///
76
+ /// Sending this will prompt a [`SqliteResponse::BeginTx`] response with the
77
+ /// transaction ID. Any error will be contained in the [`SqliteResponse::Err`] variant.
27
78
BeginTx ,
28
- Commit {
29
- tx_id : u64 ,
30
- } ,
31
- Backup ,
79
+ /// Commits all operations in the specified transaction.
80
+ ///
81
+ /// # Parameters
82
+ /// * `tx_id` - The ID of the transaction to commit
83
+ ///
84
+ /// A successful commit will respond with [`SqliteResponse::Ok`]. Any error will be
85
+ /// contained in the [`SqliteResponse::Err`] variant.
86
+ Commit { tx_id : u64 } ,
32
87
}
33
88
34
- #[ derive( Debug , Serialize , Deserialize ) ]
89
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
35
90
pub enum SqliteResponse {
91
+ /// Indicates successful completion of an operation.
92
+ /// Sent in response to actions Open, RemoveDb, Write, Query, BeginTx, and Commit.
36
93
Ok ,
94
+ /// Returns the results of a query.
95
+ ///
96
+ /// * blob: Vec<Vec<SqlValue>> - Array of rows, where each row contains SqlValue types:
97
+ /// - null
98
+ /// - boolean
99
+ /// - i64
100
+ /// - f64
101
+ /// - String
102
+ /// - Vec<u8> (binary data)
37
103
Read ,
104
+ /// Returns the transaction ID for a newly created transaction.
105
+ ///
106
+ /// # Fields
107
+ /// * `tx_id` - The ID of the newly created transaction
38
108
BeginTx { tx_id : u64 } ,
109
+ /// Indicates an error occurred during the operation.
39
110
Err ( SqliteError ) ,
40
111
}
41
112
42
- #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
113
+ /// Used in blobs to represent array row values in SQLite.
114
+ #[ derive( Clone , Debug , Serialize , Deserialize , PartialEq ) ]
43
115
pub enum SqlValue {
44
116
Integer ( i64 ) ,
45
117
Real ( f64 ) ,
@@ -49,28 +121,50 @@ pub enum SqlValue {
49
121
Null ,
50
122
}
51
123
52
- #[ derive( Debug , Serialize , Deserialize , Error ) ]
124
+ #[ derive( Clone , Debug , Serialize , Deserialize , Error ) ]
53
125
pub enum SqliteError {
54
- #[ error( "sqlite: DbDoesNotExist" ) ]
55
- NoDb ,
56
- #[ error( "sqlite: NoTx" ) ]
57
- NoTx ,
58
- #[ error( "sqlite: No capability: {error}" ) ]
59
- NoCap { error : String } ,
60
- #[ error( "sqlite: UnexpectedResponse" ) ]
61
- UnexpectedResponse ,
62
- #[ error( "sqlite: NotAWriteKeyword" ) ]
126
+ #[ error( "db [{0}, {1}] does not exist" ) ]
127
+ NoDb ( PackageId , String ) ,
128
+ #[ error( "no transaction {0} found" ) ]
129
+ NoTx ( u64 ) ,
130
+ #[ error( "no write capability for requested DB" ) ]
131
+ NoWriteCap ,
132
+ #[ error( "no read capability for requested DB" ) ]
133
+ NoReadCap ,
134
+ #[ error( "request to open or remove DB with mismatching package ID" ) ]
135
+ MismatchingPackageId ,
136
+ #[ error( "failed to generate capability for new DB" ) ]
137
+ AddCapFailed ,
138
+ #[ error( "write statement started with non-existent write keyword" ) ]
63
139
NotAWriteKeyword ,
64
- #[ error( "sqlite: NotAReadKeyword " ) ]
140
+ #[ error( "read query started with non-existent read keyword " ) ]
65
141
NotAReadKeyword ,
66
- #[ error( "sqlite: Invalid Parameters " ) ]
142
+ #[ error( "parameters blob in read/write was misshapen or contained invalid JSON objects " ) ]
67
143
InvalidParameters ,
68
- #[ error( "sqlite: IO error: {error}" ) ]
69
- IOError { error : String } ,
70
- #[ error( "sqlite: rusqlite error: {error}" ) ]
71
- RusqliteError { error : String } ,
72
- #[ error( "sqlite: input bytes/json/key error: {error}" ) ]
73
- InputError { error : String } ,
144
+ #[ error( "sqlite got a malformed request that failed to deserialize" ) ]
145
+ MalformedRequest ,
146
+ #[ error( "rusqlite error: {0}" ) ]
147
+ RusqliteError ( String ) ,
148
+ #[ error( "IO error: {0}" ) ]
149
+ IOError ( String ) ,
150
+ }
151
+
152
+ /// The JSON parameters contained in all capabilities issued by `sqlite:distro:sys`.
153
+ ///
154
+ /// # Fields
155
+ /// * `kind` - The kind of capability, either [`SqliteCapabilityKind::Read`] or [`SqliteCapabilityKind::Write`]
156
+ /// * `db_key` - The database key, a tuple of the [`PackageId`] that created the database and the database name
157
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
158
+ pub struct SqliteCapabilityParams {
159
+ pub kind : SqliteCapabilityKind ,
160
+ pub db_key : ( PackageId , String ) ,
161
+ }
162
+
163
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
164
+ #[ serde( rename_all = "lowercase" ) ]
165
+ pub enum SqliteCapabilityKind {
166
+ Read ,
167
+ Write ,
74
168
}
75
169
76
170
/// Sqlite helper struct for a db.
@@ -95,7 +189,7 @@ impl Sqlite {
95
189
. body ( serde_json:: to_vec ( & SqliteRequest {
96
190
package_id : self . package_id . clone ( ) ,
97
191
db : self . db . clone ( ) ,
98
- action : SqliteAction :: Read { query } ,
192
+ action : SqliteAction :: Query ( query) ,
99
193
} ) ?)
100
194
. blob_bytes ( serde_json:: to_vec ( & params) ?)
101
195
. send_and_await_response ( self . timeout ) ?;
@@ -106,15 +200,11 @@ impl Sqlite {
106
200
107
201
match response {
108
202
SqliteResponse :: Read => {
109
- let blob = get_blob ( ) . ok_or_else ( || SqliteError :: InputError {
110
- error : "sqlite: no blob" . to_string ( ) ,
111
- } ) ?;
203
+ let blob = get_blob ( ) . ok_or_else ( || SqliteError :: MalformedRequest ) ?;
112
204
let values = serde_json:: from_slice :: <
113
205
Vec < HashMap < String , serde_json:: Value > > ,
114
206
> ( & blob. bytes )
115
- . map_err ( |e| SqliteError :: InputError {
116
- error : format ! ( "sqlite: gave unparsable response: {}" , e) ,
117
- } ) ?;
207
+ . map_err ( |_| SqliteError :: MalformedRequest ) ?;
118
208
Ok ( values)
119
209
}
120
210
SqliteResponse :: Err ( error) => Err ( error. into ( ) ) ,
0 commit comments