1use crate::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
3use crate::Result;
4use url::Url;
5
6impl ToSql for Url {
8 #[inline]
9 fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
10 Ok(ToSqlOutput::from(self.as_str()))
11 }
12}
13
14impl FromSql for Url {
16 #[inline]
17 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
18 match value {
19 ValueRef::Text(s) => {
20 let s = std::str::from_utf8(s).map_err(FromSqlError::other)?;
21 Self::parse(s).map_err(FromSqlError::other)
22 }
23 _ => Err(FromSqlError::InvalidType),
24 }
25 }
26}
27
28#[cfg(all(test, not(miri)))]
29mod test {
30 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
31 use wasm_bindgen_test::wasm_bindgen_test as test;
32
33 use crate::{params, Connection, Error, Result};
34 use url::{ParseError, Url};
35
36 fn checked_memory_handle() -> Result<Connection> {
37 let db = Connection::open_in_memory()?;
38 db.execute_batch("CREATE TABLE urls (i INTEGER, v TEXT)")?;
39 Ok(db)
40 }
41
42 fn get_url(db: &Connection, id: i64) -> Result<Url> {
43 db.one_column("SELECT v FROM urls WHERE i = ?", [id])
44 }
45
46 #[test]
47 fn test_sql_url() -> Result<()> {
48 let db = &checked_memory_handle()?;
49
50 let url0 = Url::parse("http://www.example1.com").unwrap();
51 let url1 = Url::parse("http://www.example1.com/👌").unwrap();
52 let url2 = "http://www.example2.com/👌";
53
54 db.execute(
55 "INSERT INTO urls (i, v) VALUES (0, ?1), (1, ?2), (2, ?3), (3, ?4)",
56 params![url0, url1, url2, "illegal"],
59 )?;
60
61 assert_eq!(get_url(db, 0)?, url0);
62
63 assert_eq!(get_url(db, 1)?, url1);
64
65 let out_url2: Url = get_url(db, 2)?;
68 assert_eq!(out_url2, Url::parse(url2).unwrap());
69
70 let err = get_url(db, 3).unwrap_err();
72 match err {
73 Error::FromSqlConversionFailure(_, _, e) => {
74 assert_eq!(
75 *e.downcast::<ParseError>().unwrap(),
76 ParseError::RelativeUrlWithoutBase,
77 );
78 }
79 e => {
80 panic!("Expected conversion failure, got {e}");
81 }
82 }
83 Ok(())
84 }
85}