diff --git a/core/src/services/mod.rs b/core/src/services/mod.rs index cb84289a38ab..4a3dbbf5bf99 100644 --- a/core/src/services/mod.rs +++ b/core/src/services/mod.rs @@ -215,6 +215,8 @@ pub use self::foundationdb::Foundationdb; mod postgresql; #[cfg(feature = "services-postgresql")] pub use self::postgresql::Postgresql; +#[cfg(feature = "services-postgresql")] +pub use self::postgresql::PostgresqlConfig; #[cfg(feature = "services-atomicserver")] mod atomicserver; diff --git a/core/src/services/postgresql/backend.rs b/core/src/services/postgresql/backend.rs index ac7b82a5a1bf..7e3aafd01c52 100644 --- a/core/src/services/postgresql/backend.rs +++ b/core/src/services/postgresql/backend.rs @@ -24,6 +24,7 @@ use std::sync::Arc; use async_trait::async_trait; use bb8::Pool; use bb8_postgres::PostgresConnectionManager; +use serde::Deserialize; use tokio::sync::OnceCell; use tokio_postgres::Config; @@ -31,23 +32,56 @@ use crate::raw::adapters::kv; use crate::raw::*; use crate::*; -/// [Postgresql](https://www.postgresql.org/) services support. -#[doc = include_str!("docs.md")] -#[derive(Default)] -pub struct PostgresqlBuilder { +/// Config for PostGresQL services support. +#[derive(Default, Deserialize)] +#[serde(default)] +#[non_exhaustive] +pub struct PostgresqlConfig { + /// root of this backend. + /// + /// All operations will happen under this root. + /// + /// default to `/` if not set. + pub root: Option, + /// the connection string of postgres server connection_string: Option, - + /// the table of postgresql table: Option, + /// the key field of postgresql key_field: Option, + /// the value field of postgresql value_field: Option, - root: Option, +} + +impl Debug for PostgresqlConfig { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let mut d = f.debug_struct("PostgresqlConfig"); + + if self.connection_string.is_some() { + d.field("connection_string", &""); + } + + d.field("root", &self.root) + .field("table", &self.table) + .field("key_field", &self.key_field) + .field("value_field", &self.value_field) + .finish() + } +} + +/// [Postgresql](https://www.postgresql.org/) services support. +#[doc = include_str!("docs.md")] +#[derive(Default)] +pub struct PostgresqlBuilder { + config: PostgresqlConfig, } impl Debug for PostgresqlBuilder { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let mut ds = f.debug_struct("Builder"); - ds.field("table", &self.table); - ds.finish() + let mut d = f.debug_struct("PostgresqlBuilder"); + + d.field("config", &self.config); + d.finish() } } @@ -84,7 +118,7 @@ impl PostgresqlBuilder { /// For more information, please visit pub fn connection_string(&mut self, v: &str) -> &mut Self { if !v.is_empty() { - self.connection_string = Some(v.to_string()); + self.config.connection_string = Some(v.to_string()); } self } @@ -94,7 +128,7 @@ impl PostgresqlBuilder { /// default: "/" pub fn root(&mut self, root: &str) -> &mut Self { if !root.is_empty() { - self.root = Some(root.to_owned()); + self.config.root = Some(root.to_owned()); } self } @@ -102,7 +136,7 @@ impl PostgresqlBuilder { /// Set the table name of the postgresql service to read/write. pub fn table(&mut self, table: &str) -> &mut Self { if !table.is_empty() { - self.table = Some(table.to_string()); + self.config.table = Some(table.to_string()); } self } @@ -112,7 +146,7 @@ impl PostgresqlBuilder { /// Default to `key` if not specified. pub fn key_field(&mut self, key_field: &str) -> &mut Self { if !key_field.is_empty() { - self.key_field = Some(key_field.to_string()); + self.config.key_field = Some(key_field.to_string()); } self } @@ -122,7 +156,7 @@ impl PostgresqlBuilder { /// Default to `value` if not specified. pub fn value_field(&mut self, value_field: &str) -> &mut Self { if !value_field.is_empty() { - self.value_field = Some(value_field.to_string()); + self.config.value_field = Some(value_field.to_string()); } self } @@ -133,20 +167,14 @@ impl Builder for PostgresqlBuilder { type Accessor = PostgresqlBackend; fn from_map(map: HashMap) -> Self { - let mut builder = PostgresqlBuilder::default(); - - map.get("connection_string") - .map(|v| builder.connection_string(v)); - map.get("table").map(|v| builder.table(v)); - map.get("key_field").map(|v| builder.key_field(v)); - map.get("value_field").map(|v| builder.value_field(v)); - map.get("root").map(|v| builder.root(v)); + let config = PostgresqlConfig::deserialize(ConfigDeserializer::new(map)) + .expect("config deserialize must succeed"); - builder + PostgresqlBuilder { config } } fn build(&mut self) -> Result { - let conn = match self.connection_string.clone() { + let conn = match self.config.connection_string.clone() { Some(v) => v, None => { return Err( @@ -162,23 +190,24 @@ impl Builder for PostgresqlBuilder { .set_source(err) })?; - let table = match self.table.clone() { + let table = match self.config.table.clone() { Some(v) => v, None => { return Err(Error::new(ErrorKind::ConfigInvalid, "table is empty") .with_context("service", Scheme::Postgresql)) } }; - let key_field = match self.key_field.clone() { + let key_field = match self.config.key_field.clone() { Some(v) => v, None => "key".to_string(), }; - let value_field = match self.value_field.clone() { + let value_field = match self.config.value_field.clone() { Some(v) => v, None => "value".to_string(), }; let root = normalize_root( - self.root + self.config + .root .clone() .unwrap_or_else(|| "/".to_string()) .as_str(), diff --git a/core/src/services/postgresql/mod.rs b/core/src/services/postgresql/mod.rs index 427152a7e367..ca185a4ec3b0 100644 --- a/core/src/services/postgresql/mod.rs +++ b/core/src/services/postgresql/mod.rs @@ -17,3 +17,4 @@ mod backend; pub use backend::PostgresqlBuilder as Postgresql; +pub use backend::PostgresqlConfig;