sqlx_core_oldapi/sqlite/options/
parse.rs1use crate::error::Error;
2use crate::sqlite::SqliteConnectOptions;
3use percent_encoding::percent_decode_str;
4use std::borrow::Cow;
5use std::path::{Path, PathBuf};
6use std::str::FromStr;
7use std::sync::atomic::{AtomicUsize, Ordering};
8
9static IN_MEMORY_DB_SEQ: AtomicUsize = AtomicUsize::new(0);
12
13impl FromStr for SqliteConnectOptions {
14 type Err = Error;
15
16 fn from_str(mut url: &str) -> Result<Self, Self::Err> {
17 let mut options = Self::new();
18
19 url = url
21 .trim_start_matches("sqlite://")
22 .trim_start_matches("sqlite:");
23
24 let mut database_and_params = url.splitn(2, '?');
25
26 let database = database_and_params.next().unwrap_or_default();
27
28 if database == ":memory:" {
29 options.in_memory = true;
30 options.shared_cache = true;
31 let seqno = IN_MEMORY_DB_SEQ.fetch_add(1, Ordering::Relaxed);
32 options.filename = Cow::Owned(PathBuf::from(format!("file:sqlx-in-memory-{}", seqno)));
33 } else {
34 options.filename = Cow::Owned(
36 Path::new(
37 &*percent_decode_str(database)
38 .decode_utf8()
39 .map_err(Error::config)?,
40 )
41 .to_path_buf(),
42 );
43 }
44
45 if let Some(params) = database_and_params.next() {
46 for (key, value) in url::form_urlencoded::parse(params.as_bytes()) {
47 match &*key {
48 "mode" => {
53 match &*value {
54 "ro" => {
55 options.read_only = true;
56 }
57
58 "rw" => {}
60
61 "rwc" => {
62 options.create_if_missing = true;
63 }
64
65 "memory" => {
66 options.in_memory = true;
67 options.shared_cache = true;
68 }
69
70 _ => {
71 return Err(Error::Configuration(
72 format!("unknown value {:?} for `mode`", value).into(),
73 ));
74 }
75 }
76 }
77
78 "cache" => match &*value {
82 "private" => {
83 options.shared_cache = false;
84 }
85
86 "shared" => {
87 options.shared_cache = true;
88 }
89
90 _ => {
91 return Err(Error::Configuration(
92 format!("unknown value {:?} for `cache`", value).into(),
93 ));
94 }
95 },
96
97 "immutable" => match &*value {
98 "true" | "1" => {
99 options.immutable = true;
100 }
101 "false" | "0" => {
102 options.immutable = false;
103 }
104 _ => {
105 return Err(Error::Configuration(
106 format!("unknown value {:?} for `immutable`", value).into(),
107 ));
108 }
109 },
110
111 "vfs" => options.vfs = Some(Cow::Owned(value.into_owned())),
112
113 _ => {
114 return Err(Error::Configuration(
115 format!(
116 "unknown query parameter `{}` while parsing connection URL",
117 key
118 )
119 .into(),
120 ));
121 }
122 }
123 }
124 }
125
126 Ok(options)
127 }
128}
129
130#[test]
131fn test_parse_in_memory() -> Result<(), Error> {
132 let options: SqliteConnectOptions = "sqlite::memory:".parse()?;
133 assert!(options.in_memory);
134 assert!(options.shared_cache);
135
136 let options: SqliteConnectOptions = "sqlite://?mode=memory".parse()?;
137 assert!(options.in_memory);
138 assert!(options.shared_cache);
139
140 let options: SqliteConnectOptions = "sqlite://:memory:".parse()?;
141 assert!(options.in_memory);
142 assert!(options.shared_cache);
143
144 let options: SqliteConnectOptions = "sqlite://?mode=memory&cache=private".parse()?;
145 assert!(options.in_memory);
146 assert!(!options.shared_cache);
147
148 Ok(())
149}
150
151#[test]
152fn test_parse_read_only() -> Result<(), Error> {
153 let options: SqliteConnectOptions = "sqlite://a.db?mode=ro".parse()?;
154 assert!(options.read_only);
155 assert_eq!(&*options.filename.to_string_lossy(), "a.db");
156
157 Ok(())
158}
159
160#[test]
161fn test_parse_shared_in_memory() -> Result<(), Error> {
162 let options: SqliteConnectOptions = "sqlite://a.db?cache=shared".parse()?;
163 assert!(options.shared_cache);
164 assert_eq!(&*options.filename.to_string_lossy(), "a.db");
165
166 Ok(())
167}