@@ -3,43 +3,115 @@ use serde::{Deserialize, Serialize};
33use std:: collections:: HashMap ;
44use thiserror:: Error ;
55
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 ) ]
1011pub struct SqliteRequest {
1112 pub package_id : PackageId ,
1213 pub db : String ,
1314 pub action : SqliteAction ,
1415}
1516
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 ) ]
1721pub 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.
1828 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.
1935 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.
2053 Write {
2154 statement : String ,
2255 tx_id : Option < u64 > ,
2356 } ,
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.
2778 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 } ,
3287}
3388
34- #[ derive( Debug , Serialize , Deserialize ) ]
89+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
3590pub enum SqliteResponse {
91+ /// Indicates successful completion of an operation.
92+ /// Sent in response to actions Open, RemoveDb, Write, Query, BeginTx, and Commit.
3693 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)
37103 Read ,
104+ /// Returns the transaction ID for a newly created transaction.
105+ ///
106+ /// # Fields
107+ /// * `tx_id` - The ID of the newly created transaction
38108 BeginTx { tx_id : u64 } ,
109+ /// Indicates an error occurred during the operation.
39110 Err ( SqliteError ) ,
40111}
41112
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 ) ]
43115pub enum SqlValue {
44116 Integer ( i64 ) ,
45117 Real ( f64 ) ,
@@ -49,28 +121,50 @@ pub enum SqlValue {
49121 Null ,
50122}
51123
52- #[ derive( Debug , Serialize , Deserialize , Error ) ]
124+ #[ derive( Clone , Debug , Serialize , Deserialize , Error ) ]
53125pub 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" ) ]
63139 NotAWriteKeyword ,
64- #[ error( "sqlite: NotAReadKeyword " ) ]
140+ #[ error( "read query started with non-existent read keyword " ) ]
65141 NotAReadKeyword ,
66- #[ error( "sqlite: Invalid Parameters " ) ]
142+ #[ error( "parameters blob in read/write was misshapen or contained invalid JSON objects " ) ]
67143 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 ,
74168}
75169
76170/// Sqlite helper struct for a db.
@@ -95,7 +189,7 @@ impl Sqlite {
95189 . body ( serde_json:: to_vec ( & SqliteRequest {
96190 package_id : self . package_id . clone ( ) ,
97191 db : self . db . clone ( ) ,
98- action : SqliteAction :: Read { query } ,
192+ action : SqliteAction :: Query ( query) ,
99193 } ) ?)
100194 . blob_bytes ( serde_json:: to_vec ( & params) ?)
101195 . send_and_await_response ( self . timeout ) ?;
@@ -106,15 +200,11 @@ impl Sqlite {
106200
107201 match response {
108202 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 ) ?;
112204 let values = serde_json:: from_slice :: <
113205 Vec < HashMap < String , serde_json:: Value > > ,
114206 > ( & blob. bytes )
115- . map_err ( |e| SqliteError :: InputError {
116- error : format ! ( "sqlite: gave unparsable response: {}" , e) ,
117- } ) ?;
207+ . map_err ( |_| SqliteError :: MalformedRequest ) ?;
118208 Ok ( values)
119209 }
120210 SqliteResponse :: Err ( error) => Err ( error. into ( ) ) ,
0 commit comments