rocket_sync_db_pools/config.rs
1use rocket::{Rocket, Build};
2use rocket::figment::{self, Figment, providers::Serialized};
3
4use serde::{Serialize, Deserialize};
5
6/// A base `Config` for any `Poolable` type.
7///
8/// For the following configuration:
9///
10/// ```toml
11/// [global.databases.my_database]
12/// url = "postgres://root:root@localhost/my_database"
13/// pool_size = 10
14/// timeout = 5
15/// ```
16///
17/// ...`Config::from("my_database", rocket)` would return the following struct:
18///
19/// ```rust
20/// # use rocket_sync_db_pools::Config;
21/// Config {
22/// url: "postgres://root:root@localhost/my_database".into(),
23/// pool_size: 10,
24/// timeout: 5
25/// };
26/// ```
27///
28/// If you want to implement your own custom database adapter (or other
29/// database-like struct that can be pooled by `r2d2`) and need some more
30/// configurations options, you may need to define a custom `Config` struct.
31/// Note, however, that the configuration values in `Config` are required.
32#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
33pub struct Config {
34 /// Connection URL specified in the Rocket configuration.
35 pub url: String,
36 /// Initial pool size. Defaults to the number of Rocket workers * 4.
37 pub pool_size: u32,
38 /// How long to wait, in seconds, for a new connection before timing out.
39 /// Defaults to `5`.
40 // FIXME: Use `time`.
41 pub timeout: u8,
42}
43
44impl Config {
45 /// Retrieves the database configuration for the database named `name`.
46 ///
47 /// This function is primarily used by the generated code from the
48 /// `#[database]` attribute.
49 ///
50 /// # Example
51 ///
52 /// ```rust
53 /// # #[cfg(feature = "diesel_sqlite_pool")] {
54 /// # use rocket::figment::{Figment, providers::{Format, Toml}};
55 /// // Assume that these are the contents of `Rocket.toml`:
56 /// # let toml = Toml::string(r#"
57 /// [default.databases]
58 /// my_db = { url = "db/db.sqlite", pool_size = 25 }
59 /// my_other_db = { url = "mysql://root:root@localhost/database" }
60 /// # "#).nested();
61 ///
62 /// use rocket::{Rocket, Build};
63 /// use rocket_sync_db_pools::Config;
64 ///
65 /// fn pool(rocket: &Rocket<Build>) {
66 /// let config = Config::from("my_db", rocket).unwrap();
67 /// assert_eq!(config.url, "db/db.sqlite");
68 /// assert_eq!(config.pool_size, 25);
69 ///
70 /// let config = Config::from("my_other_db", rocket).unwrap();
71 /// assert_eq!(config.url, "mysql://root:root@localhost/database");
72 ///
73 /// let workers = rocket.figment().extract_inner::<u32>(rocket::Config::WORKERS);
74 /// assert_eq!(config.pool_size, (workers.unwrap() * 4));
75 ///
76 /// let config = Config::from("unknown_db", rocket);
77 /// assert!(config.is_err())
78 /// }
79 /// #
80 /// # let config = Figment::from(rocket::Config::default()).merge(toml);
81 /// # let rocket = rocket::custom(config);
82 /// # pool(&rocket);
83 /// # }
84 /// ```
85 pub fn from(db_name: &str, rocket: &Rocket<Build>) -> Result<Config, figment::Error> {
86 Config::figment(db_name, rocket).extract::<Self>()
87 }
88
89 /// Returns a `Figment` focused on the configuration for the database with
90 /// name `db_name`.
91 ///
92 /// # Example
93 ///
94 /// ```rust
95 /// use rocket::{Rocket, Build};
96 /// use rocket_sync_db_pools::Config;
97 ///
98 /// fn pool(rocket: &Rocket<Build>) {
99 /// let my_db_figment = Config::figment("my_db", rocket);
100 /// let mysql_prod_figment = Config::figment("mysql_prod", rocket);
101 /// }
102 /// ```
103 pub fn figment(db_name: &str, rocket: &Rocket<Build>) -> Figment {
104 let db_key = format!("databases.{}", db_name);
105 let default_pool_size = rocket.figment()
106 .extract_inner::<u32>(rocket::Config::WORKERS)
107 .map(|workers| workers * 4)
108 .ok();
109
110 let figment = Figment::from(rocket.figment())
111 .focus(&db_key)
112 .join(Serialized::default("timeout", 5));
113
114 match default_pool_size {
115 Some(pool_size) => figment.join(Serialized::default("pool_size", pool_size)),
116 None => figment
117 }
118 }
119}