Skip to content

Commit 30c0d06

Browse files
committed
Allow static strings in SQLiteError
1 parent 4168795 commit 30c0d06

File tree

7 files changed

+56
-71
lines changed

7 files changed

+56
-71
lines changed

crates/core/src/crud_vtab.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
extern crate alloc;
22

33
use alloc::boxed::Box;
4-
use alloc::string::String;
54
use alloc::sync::Arc;
65
use const_format::formatcp;
76
use core::ffi::{c_char, c_int, c_void, CStr};
@@ -86,7 +85,7 @@ impl VirtualTable {
8685
let current_tx = self
8786
.current_tx
8887
.as_mut()
89-
.ok_or_else(|| SQLiteError(ResultCode::MISUSE, Some(String::from("No tx_id"))))?;
88+
.ok_or_else(|| SQLiteError::misuse("No tx_id"))?;
9089
let db = self.db;
9190

9291
if self.state.is_in_sync_local.load(Ordering::Relaxed) {

crates/core/src/error.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use alloc::{
2+
borrow::Cow,
23
format,
34
string::{String, ToString},
45
};
@@ -8,20 +9,34 @@ use sqlite_nostd::{context, sqlite3, Connection, Context, ResultCode};
89
use crate::bson::BsonError;
910

1011
#[derive(Debug)]
11-
pub struct SQLiteError(pub ResultCode, pub Option<String>);
12+
pub struct SQLiteError(pub ResultCode, pub Option<Cow<'static, str>>);
13+
14+
impl SQLiteError {
15+
pub fn with_description(code: ResultCode, message: impl Into<Cow<'static, str>>) -> Self {
16+
Self(code, Some(message.into()))
17+
}
18+
19+
pub fn misuse(message: impl Into<Cow<'static, str>>) -> Self {
20+
Self::with_description(ResultCode::MISUSE, message)
21+
}
22+
}
1223

1324
impl core::fmt::Display for SQLiteError {
1425
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15-
write!(f, "{:?}", self)
26+
write!(f, "SQLiteError: {:?}", self.0)?;
27+
if let Some(desc) = &self.1 {
28+
write!(f, ", desc: {}", desc)?;
29+
}
30+
Ok(())
1631
}
1732
}
1833

1934
impl SQLiteError {
2035
pub fn apply_to_ctx(self, description: &str, ctx: *mut context) {
2136
let SQLiteError(code, message) = self;
2237

23-
if message.is_some() {
24-
ctx.result_error(&format!("{:} {:}", description, message.unwrap()));
38+
if let Some(msg) = message {
39+
ctx.result_error(&format!("{:} {:}", description, msg));
2540
} else {
2641
let error = ctx.db_handle().errmsg().unwrap();
2742
if error == "not an error" {
@@ -47,7 +62,7 @@ impl<T> PSResult<T> for Result<T, ResultCode> {
4762
if message == "not an error" {
4863
Err(SQLiteError(code, None))
4964
} else {
50-
Err(SQLiteError(code, Some(message)))
65+
Err(SQLiteError(code, Some(message.into())))
5166
}
5267
} else if let Ok(r) = self {
5368
Ok(r)
@@ -65,18 +80,18 @@ impl From<ResultCode> for SQLiteError {
6580

6681
impl From<serde_json::Error> for SQLiteError {
6782
fn from(value: serde_json::Error) -> Self {
68-
SQLiteError(ResultCode::ABORT, Some(value.to_string()))
83+
SQLiteError::with_description(ResultCode::ABORT, value.to_string())
6984
}
7085
}
7186

7287
impl From<core::fmt::Error> for SQLiteError {
7388
fn from(value: core::fmt::Error) -> Self {
74-
SQLiteError(ResultCode::INTERNAL, Some(format!("{}", value)))
89+
SQLiteError::with_description(ResultCode::INTERNAL, format!("{}", value))
7590
}
7691
}
7792

7893
impl From<BsonError> for SQLiteError {
7994
fn from(value: BsonError) -> Self {
80-
SQLiteError(ResultCode::ERROR, Some(value.to_string()))
95+
SQLiteError::with_description(ResultCode::ERROR, value.to_string())
8196
}
8297
}

crates/core/src/kv.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
extern crate alloc;
22

3-
use alloc::format;
43
use alloc::string::{String, ToString};
54
use core::ffi::c_int;
65

@@ -30,9 +29,9 @@ pub fn client_id(db: *mut sqlite::sqlite3) -> Result<String, SQLiteError> {
3029
let client_id = statement.column_text(0)?;
3130
Ok(client_id.to_string())
3231
} else {
33-
Err(SQLiteError(
32+
Err(SQLiteError::with_description(
3433
ResultCode::ABORT,
35-
Some(format!("No client_id found in ps_kv")),
34+
"No client_id found in ps_kv",
3635
))
3736
}
3837
}

crates/core/src/migrations.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,16 @@ CREATE TABLE IF NOT EXISTS ps_migration(id INTEGER PRIMARY KEY, down_migrations
5555
for sql in down_sql {
5656
let rs = local_db.exec_safe(&sql);
5757
if let Err(code) = rs {
58-
return Err(SQLiteError(
58+
return Err(SQLiteError::with_description(
5959
code,
60-
Some(format!(
60+
format!(
6161
"Down migration failed for {:} {:} {:}",
6262
current_version,
6363
sql,
6464
local_db
6565
.errmsg()
6666
.unwrap_or(String::from("Conversion error"))
67-
)),
67+
),
6868
));
6969
}
7070
}
@@ -73,20 +73,20 @@ CREATE TABLE IF NOT EXISTS ps_migration(id INTEGER PRIMARY KEY, down_migrations
7373
current_version_stmt.reset()?;
7474
let rc = current_version_stmt.step()?;
7575
if rc != ResultCode::ROW {
76-
return Err(SQLiteError(
76+
return Err(SQLiteError::with_description(
7777
rc,
78-
Some("Down migration failed - could not get version".to_string()),
78+
"Down migration failed - could not get version",
7979
));
8080
}
8181
let new_version = current_version_stmt.column_int(0);
8282
if new_version >= current_version {
8383
// Database down from version $currentVersion to $version failed - version not updated after dow migration
84-
return Err(SQLiteError(
84+
return Err(SQLiteError::with_description(
8585
ResultCode::ABORT,
86-
Some(format!(
86+
format!(
8787
"Down migration failed - version not updated from {:}",
8888
current_version
89-
)),
89+
),
9090
));
9191
}
9292
current_version = new_version;

crates/core/src/sync/interface.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use core::ffi::{c_int, c_void};
44
use alloc::borrow::Cow;
55
use alloc::boxed::Box;
66
use alloc::rc::Rc;
7-
use alloc::string::ToString;
87
use alloc::sync::Arc;
98
use alloc::{string::String, vec::Vec};
109
use serde::{Deserialize, Serialize};
@@ -141,10 +140,7 @@ pub fn register(db: *mut sqlite::sqlite3, state: Arc<DatabaseState>) -> Result<(
141140
};
142141

143142
if op.value_type() != ColumnType::Text {
144-
return Err(SQLiteError(
145-
ResultCode::MISUSE,
146-
Some("First argument must be a string".to_string()),
147-
));
143+
return Err(SQLiteError::misuse("First argument must be a string"));
148144
}
149145

150146
let op = op.text();
@@ -161,29 +157,20 @@ pub fn register(db: *mut sqlite::sqlite3, state: Arc<DatabaseState>) -> Result<(
161157
data: if payload.value_type() == ColumnType::Text {
162158
payload.text()
163159
} else {
164-
return Err(SQLiteError(
165-
ResultCode::MISUSE,
166-
Some("Second argument must be a string".to_string()),
167-
));
160+
return Err(SQLiteError::misuse("Second argument must be a string"));
168161
},
169162
}),
170163
"line_binary" => SyncControlRequest::SyncEvent(SyncEvent::BinaryLine {
171164
data: if payload.value_type() == ColumnType::Blob {
172165
payload.blob()
173166
} else {
174-
return Err(SQLiteError(
175-
ResultCode::MISUSE,
176-
Some("Second argument must be a byte array".to_string()),
177-
));
167+
return Err(SQLiteError::misuse("Second argument must be a byte array"));
178168
},
179169
}),
180170
"refreshed_token" => SyncControlRequest::SyncEvent(SyncEvent::DidRefreshToken),
181171
"completed_upload" => SyncControlRequest::SyncEvent(SyncEvent::UploadFinished),
182172
_ => {
183-
return Err(SQLiteError(
184-
ResultCode::MISUSE,
185-
Some("Unknown operation".to_string()),
186-
))
173+
return Err(SQLiteError::misuse("Unknown operation"));
187174
}
188175
};
189176

crates/core/src/sync/streaming_sync.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,7 @@ impl SyncClient {
7171
let mut active = ActiveEvent::new(sync_event);
7272

7373
let ClientState::IterationActive(handle) = &mut self.state else {
74-
return Err(SQLiteError(
75-
ResultCode::MISUSE,
76-
Some("No iteration is active".to_string()),
77-
));
74+
return Err(SQLiteError::misuse("No iteration is active"));
7875
};
7976

8077
match handle.run(&mut active) {
@@ -308,11 +305,9 @@ impl StreamingSyncIteration {
308305
}
309306
SyncLine::CheckpointDiff(diff) => {
310307
let Some(target) = target.target_checkpoint_mut() else {
311-
return Err(SQLiteError(
308+
return Err(SQLiteError::with_description(
312309
ResultCode::ABORT,
313-
Some(
314-
"Received checkpoint_diff without previous checkpoint".to_string(),
315-
),
310+
"Received checkpoint_diff without previous checkpoint",
316311
));
317312
};
318313

@@ -329,12 +324,9 @@ impl StreamingSyncIteration {
329324
}
330325
SyncLine::CheckpointComplete(_) => {
331326
let Some(target) = target.target_checkpoint_mut() else {
332-
return Err(SQLiteError(
327+
return Err(SQLiteError::with_description(
333328
ResultCode::ABORT,
334-
Some(
335-
"Received checkpoint complete without previous checkpoint"
336-
.to_string(),
337-
),
329+
"Received checkpoint complete without previous checkpoint",
338330
));
339331
};
340332
let result =
@@ -374,12 +366,9 @@ impl StreamingSyncIteration {
374366
SyncLine::CheckpointPartiallyComplete(complete) => {
375367
let priority = complete.priority;
376368
let Some(target) = target.target_checkpoint_mut() else {
377-
return Err(SQLiteError(
369+
return Err(SQLiteError::with_description(
378370
ResultCode::ABORT,
379-
Some(
380-
"Received checkpoint complete without previous checkpoint"
381-
.to_string(),
382-
),
371+
"Received checkpoint complete without previous checkpoint",
383372
));
384373
};
385374
let result = self.adapter.sync_local(

crates/core/src/sync_local.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use alloc::collections::btree_map::BTreeMap;
22
use alloc::format;
3-
use alloc::string::{String, ToString};
3+
use alloc::string::String;
44
use alloc::vec::Vec;
55
use serde::Deserialize;
66

@@ -504,15 +504,12 @@ impl<'a> PreparedPendingStatement<'a> {
504504
) -> Result<Self, SQLiteError> {
505505
let stmt = db.prepare_v2(&pending.sql)?;
506506
if stmt.bind_parameter_count() as usize != pending.params.len() {
507-
return Err(SQLiteError(
508-
ResultCode::MISUSE,
509-
Some(format!(
510-
"Statement {} has {} parameters, but {} values were provided as sources.",
511-
&pending.sql,
512-
stmt.bind_parameter_count(),
513-
pending.params.len(),
514-
)),
515-
));
507+
return Err(SQLiteError::misuse(format!(
508+
"Statement {} has {} parameters, but {} values were provided as sources.",
509+
&pending.sql,
510+
stmt.bind_parameter_count(),
511+
pending.params.len(),
512+
)));
516513
}
517514

518515
// TODO: Compare number of variables / other validity checks?
@@ -534,9 +531,9 @@ impl<'a> PreparedPendingStatement<'a> {
534531
}
535532
PendingStatementValue::Column(column) => {
536533
let parsed = json_data.as_object().ok_or_else(|| {
537-
SQLiteError(
534+
SQLiteError::with_description(
538535
ResultCode::CONSTRAINT_DATATYPE,
539-
Some("expected oplog data to be an object".to_string()),
536+
"expected oplog data to be an object",
540537
)
541538
})?;
542539

@@ -571,9 +568,8 @@ impl<'a> PreparedPendingStatement<'a> {
571568
self.stmt
572569
.bind_text((i + 1) as i32, id, Destructor::STATIC)?;
573570
} else {
574-
return Err(SQLiteError(
575-
ResultCode::MISUSE,
576-
Some("Raw delete statement parameters must only reference id".to_string()),
571+
return Err(SQLiteError::misuse(
572+
"Raw delete statement parameters must only reference id",
577573
));
578574
}
579575
}

0 commit comments

Comments
 (0)