1#[cfg(any(feature = "core", feature = "replication", feature = "sync"))]
4use std::path::PathBuf;
5#[cfg(any(feature = "replication", feature = "sync"))]
6use std::time::Duration;
7
8use deadpool::{
9 managed::{CreatePoolError, PoolConfig},
10 Runtime,
11};
12use libsql::Builder;
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16use crate::{Manager, Pool, PoolBuilder};
17
18#[derive(Clone, Debug)]
43#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
44pub struct Config {
45 #[cfg_attr(feature = "serde", serde(flatten))]
47 pub database: Database,
48 #[cfg_attr(feature = "serde", serde(default))]
50 pub pool: PoolConfig,
51}
52
53impl Config {
54 #[must_use]
56 pub fn new(database: Database) -> Self {
57 Self {
58 database,
59 pool: PoolConfig::default(),
60 }
61 }
62
63 pub async fn create_pool(
69 self,
70 runtime: Option<Runtime>,
71 ) -> Result<Pool, CreatePoolError<ConfigError>> {
72 let mut builder = self.builder().await.map_err(CreatePoolError::Config)?;
73 if let Some(runtime) = runtime {
74 builder = builder.runtime(runtime);
75 }
76 builder.build().map_err(CreatePoolError::Build)
77 }
78
79 pub async fn builder(self) -> Result<PoolBuilder, ConfigError> {
85 let config = self.pool;
86 let manager = Manager::from_config(self).await?;
87 Ok(Pool::builder(manager).config(config))
88 }
89}
90
91#[derive(Clone, Debug)]
92#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
93#[cfg_attr(feature = "serde", serde(tag = "database"))]
94pub enum Database {
97 #[cfg(feature = "core")]
99 Local(Local),
100 #[cfg(feature = "replication")]
102 LocalReplica(LocalReplica),
103 #[cfg(feature = "remote")]
105 Remote(Remote),
106 #[cfg(feature = "replication")]
108 RemoteReplica(RemoteReplica),
109 #[cfg(feature = "sync")]
111 SyncedDatabase(SyncedDatabase),
112}
113
114impl Database {
115 pub(crate) async fn libsql_database(&self) -> Result<libsql::Database, libsql::Error> {
116 match self {
117 #[cfg(feature = "core")]
118 Self::Local(x) => x.libsql_database().await,
119 #[cfg(feature = "replication")]
120 Self::LocalReplica(x) => x.libsql_database().await,
121 #[cfg(feature = "remote")]
122 Self::Remote(x) => x.libsql_database().await,
123 #[cfg(feature = "replication")]
124 Self::RemoteReplica(x) => x.libsql_database().await,
125 #[cfg(feature = "sync")]
126 Self::SyncedDatabase(x) => x.libsql_database().await,
127 #[cfg(not(any(
128 feature = "core",
129 feature = "replication",
130 feature = "remote",
131 feature = "sync"
132 )))]
133 _ => compile_error!("At least one of the following features must be enabled: core, replication, remote, sync"),
134 }
135 }
136}
137
138#[cfg(feature = "core")]
139#[derive(Clone, Debug)]
140#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
141#[allow(missing_docs)]
142pub struct Local {
143 pub path: PathBuf,
144 pub encryption_config: Option<EncryptionConfig>,
145 pub flags: Option<OpenFlags>,
146}
147
148#[cfg(feature = "core")]
149impl Local {
150 async fn libsql_database(&self) -> Result<libsql::Database, libsql::Error> {
151 let mut builder = Builder::new_local(&self.path);
152 if let Some(encryption_config) = &self.encryption_config {
153 builder = builder.encryption_config(encryption_config.to_libsql());
154 }
155 if let Some(flags) = &self.flags {
156 builder = builder.flags(flags.to_libsql());
157 }
158 builder.build().await
159 }
160}
161
162#[cfg(any(feature = "core", feature = "replication"))]
163#[derive(Clone, Debug)]
164#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
165#[allow(missing_docs)]
166pub struct EncryptionConfig {
167 pub cipher: Cipher,
168 pub encryption_key: bytes::Bytes,
169}
170
171#[cfg(feature = "core")]
172impl EncryptionConfig {
173 fn to_libsql(&self) -> libsql::EncryptionConfig {
174 libsql::EncryptionConfig {
175 cipher: self.cipher.to_libsql(),
176 encryption_key: self.encryption_key.clone(),
177 }
178 }
179}
180
181#[cfg(any(feature = "core", feature = "replication"))]
182#[derive(Clone, Copy, Debug, Default)]
183#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
184pub enum Cipher {
186 #[default]
187 #[cfg_attr(feature = "serde", serde(rename = "aes256cbc"))]
188 Aes256Cbc,
190}
191
192#[cfg(feature = "core")]
193impl Cipher {
194 fn to_libsql(self) -> libsql::Cipher {
195 match self {
196 Self::Aes256Cbc => libsql::Cipher::Aes256Cbc,
197 }
198 }
199}
200
201#[cfg(any(feature = "core", feature = "replication"))]
202#[derive(Copy, Clone, Debug)]
203#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
204#[allow(missing_docs)]
205pub struct OpenFlags {
206 pub read_only: bool,
207 pub read_write: bool,
208 pub create: bool,
209}
210
211#[cfg(any(feature = "core", feature = "replication"))]
212impl OpenFlags {
213 fn to_libsql(self) -> libsql::OpenFlags {
214 (if self.read_only {
215 libsql::OpenFlags::SQLITE_OPEN_READ_ONLY
216 } else {
217 libsql::OpenFlags::empty()
218 }) | (if self.read_write {
219 libsql::OpenFlags::SQLITE_OPEN_READ_WRITE
220 } else {
221 libsql::OpenFlags::empty()
222 }) | (if self.create {
223 libsql::OpenFlags::SQLITE_OPEN_CREATE
224 } else {
225 libsql::OpenFlags::empty()
226 })
227 }
228}
229
230#[cfg(feature = "replication")]
231#[derive(Clone, Debug)]
232#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
233#[allow(missing_docs)]
234pub struct LocalReplica {
235 pub path: PathBuf,
236 pub encryption_config: Option<EncryptionConfig>,
237 pub flags: Option<OpenFlags>,
238}
239
240#[cfg(feature = "replication")]
241impl LocalReplica {
242 async fn libsql_database(&self) -> Result<libsql::Database, libsql::Error> {
243 let mut builder = Builder::new_local_replica(&self.path);
244 if let Some(flags) = &self.flags {
245 builder = builder.flags(flags.to_libsql());
246 }
247 builder.build().await
249 }
250}
251
252#[cfg(feature = "remote")]
253#[derive(Clone, Debug)]
254#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
255#[allow(missing_docs)]
256pub struct Remote {
257 pub url: String,
258 pub auth_token: String,
259 pub namespace: Option<String>,
260 pub remote_encryption: Option<EncryptionContext>,
261}
262
263#[cfg(feature = "remote")]
264impl Remote {
265 async fn libsql_database(&self) -> Result<libsql::Database, libsql::Error> {
266 let mut builder = Builder::new_remote(self.url.clone(), self.auth_token.clone());
267 if let Some(namespace) = &self.namespace {
269 builder = builder.namespace(namespace);
270 }
271 #[allow(unused)]
272 if let Some(encryption_context) = &self.remote_encryption {
273 #[cfg(feature = "sync")]
274 {
275 builder = builder.remote_encryption(encryption_context.to_libsql());
276 }
277 #[cfg(not(feature = "sync"))]
278 return Err(libsql::Error::Misuse(
279 "Remote encryption unavailable: sync feature of libsql is disabled".into(),
280 ));
281 }
282 builder.build().await
283 }
284}
285
286#[cfg(feature = "replication")]
287#[derive(Clone, Debug)]
288#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
289#[allow(missing_docs)]
290pub struct RemoteReplica {
291 pub path: PathBuf,
292 pub url: String,
293 pub auth_token: String,
294 pub encryption_config: Option<EncryptionConfig>,
296 pub namespace: Option<String>,
298 pub read_your_writes: Option<bool>,
299 pub remote_encryption: Option<EncryptionContext>,
300 pub sync_interval: Option<Duration>,
301 pub sync_protocol: Option<SyncProtocol>,
302}
303
304#[cfg(feature = "replication")]
305impl RemoteReplica {
306 async fn libsql_database(&self) -> Result<libsql::Database, libsql::Error> {
307 let mut builder =
309 Builder::new_remote_replica(&self.path, self.url.clone(), self.auth_token.clone());
310 #[allow(unused)]
312 if let Some(encryption_config) = &self.encryption_config {
313 #[cfg(feature = "core")]
314 {
315 builder = builder.encryption_config(encryption_config.to_libsql());
316 }
317 #[cfg(not(feature = "core"))]
318 return Err(libsql::Error::Misuse("RemoteReplicate::encryption_config unavailable: core feature of libsql is disabled".into()));
319 }
320 if let Some(namespace) = &self.namespace {
322 builder = builder.namespace(namespace);
323 }
324 if let Some(read_your_writes) = self.read_your_writes {
325 builder = builder.read_your_writes(read_your_writes);
326 }
327 #[allow(unused)]
328 if let Some(encryption_context) = &self.remote_encryption {
329 #[cfg(feature = "sync")]
330 {
331 builder = builder.remote_encryption(encryption_context.to_libsql());
332 }
333 #[cfg(not(feature = "sync"))]
334 return Err(libsql::Error::Misuse("RemoteReplication::encryption_context unavailable: sync feature of libsql is disabled".into()));
335 }
336 if let Some(sync_interval) = &self.sync_interval {
337 builder = builder.sync_interval(*sync_interval);
338 }
339 #[allow(unused)]
340 if let Some(sync_protocol) = &self.sync_protocol {
341 #[cfg(feature = "sync")]
342 {
343 builder = builder.sync_protocol(sync_protocol.to_libsql());
344 }
345 #[cfg(not(feature = "sync"))]
346 return Err(libsql::Error::Misuse(
347 "RemoteReplication::sync_protocol unavailable: sync feature of libsql is disabled"
348 .into(),
349 ));
350 }
351 builder.build().await
352 }
353}
354
355#[cfg(any(feature = "remote", feature = "replication", feature = "sync"))]
356#[derive(Clone, Debug)]
357#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
358pub struct EncryptionContext {
360 pub key: EncryptionKey,
362}
363
364#[cfg(feature = "sync")]
365impl EncryptionContext {
366 #[cfg(feature = "sync")]
367 fn to_libsql(&self) -> libsql::EncryptionContext {
368 libsql::EncryptionContext {
369 key: self.key.to_libsql(),
370 }
371 }
372}
373
374#[cfg(any(feature = "remote", feature = "replication", feature = "sync"))]
375#[derive(Clone, Debug)]
376#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
377pub enum EncryptionKey {
379 Base64Encoded(String),
381 Bytes(Vec<u8>),
383}
384
385#[cfg(any(feature = "remote", feature = "sync"))]
386impl EncryptionKey {
387 #[cfg(feature = "sync")]
388 fn to_libsql(&self) -> libsql::EncryptionKey {
389 #[cfg(feature = "sync")]
390 match self {
391 Self::Base64Encoded(string) => libsql::EncryptionKey::Base64Encoded(string.clone()),
392 Self::Bytes(bytes) => libsql::EncryptionKey::Bytes(bytes.clone()),
393 }
394 }
395}
396
397#[cfg(feature = "replication")]
398#[derive(Clone, Copy, Debug)]
399#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
400pub enum SyncProtocol {
402 #[allow(missing_docs)]
403 V1,
404 #[allow(missing_docs)]
405 V2,
406}
407
408#[cfg(all(feature = "replication", feature = "sync"))]
409impl SyncProtocol {
410 fn to_libsql(self) -> libsql::SyncProtocol {
411 match self {
412 Self::V1 => libsql::SyncProtocol::V1,
413 Self::V2 => libsql::SyncProtocol::V2,
414 }
415 }
416}
417
418#[cfg(feature = "sync")]
419#[derive(Clone, Debug)]
420#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
421#[allow(missing_docs)]
422pub struct SyncedDatabase {
423 pub path: PathBuf,
424 pub url: String,
425 pub auth_token: String,
426 pub read_your_writes: Option<bool>,
428 pub remote_encryption: Option<EncryptionContext>,
429 pub remote_writes: Option<bool>,
430 pub set_push_batch_size: Option<u32>,
431 pub sync_interval: Option<Duration>,
432}
433
434#[cfg(feature = "sync")]
435impl SyncedDatabase {
436 async fn libsql_database(&self) -> Result<libsql::Database, libsql::Error> {
437 let mut builder =
438 Builder::new_synced_database(&self.path, self.url.clone(), self.auth_token.clone());
439 if let Some(read_your_writes) = self.read_your_writes {
441 builder = builder.read_your_writes(read_your_writes);
442 }
443 if let Some(encryption_context) = &self.remote_encryption {
444 builder = builder.remote_encryption(encryption_context.to_libsql());
445 }
446 if let Some(remote_writes) = &self.remote_writes {
447 builder = builder.remote_writes(*remote_writes);
448 }
449 if let Some(push_batch_size) = &self.set_push_batch_size {
450 builder = builder.set_push_batch_size(*push_batch_size);
451 }
452 if let Some(sync_interval) = &self.sync_interval {
453 builder = builder.sync_interval(*sync_interval);
454 }
455 builder.build().await
456 }
457}
458
459pub type ConfigError = libsql::Error;