diff --git a/proxy/src/serverless/json.rs b/proxy/src/serverless/json.rs index 9f328a0e1d..d2d6776f37 100644 --- a/proxy/src/serverless/json.rs +++ b/proxy/src/serverless/json.rs @@ -1,9 +1,27 @@ +use serde::Deserialize; +use serde::Deserializer; use serde_json::Map; use serde_json::Value; use tokio_postgres::types::Kind; use tokio_postgres::types::Type; use tokio_postgres::Row; +pub(crate) struct PgText { + pub(crate) value: Vec>, +} +impl<'de> Deserialize<'de> for PgText { + fn deserialize(__deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // TODO: consider avoiding the allocation here. + let value = Deserialize::deserialize(__deserializer)?; + Ok(PgText { + value: json_to_pg_text(value), + }) + } +} + // // Convert json non-string types to strings, so that they can be passed to Postgres // as parameters. diff --git a/proxy/src/serverless/sql_over_http.rs b/proxy/src/serverless/sql_over_http.rs index 9beb6349e2..b4e96d9ef8 100644 --- a/proxy/src/serverless/sql_over_http.rs +++ b/proxy/src/serverless/sql_over_http.rs @@ -26,7 +26,6 @@ use serde::de; use serde::Deserialize; use serde::Deserializer; use serde::Serialize; -use serde_json::Value; use tokio::time; use tokio_postgres::error::DbError; use tokio_postgres::error::ErrorPosition; @@ -60,6 +59,7 @@ use crate::metrics::Metrics; use crate::proxy::run_until_cancelled; use crate::proxy::NeonOptions; use crate::serverless::backend::HttpConnError; +use crate::serverless::json::PgText; use crate::usage_metrics::MetricCounterRecorder; use crate::DbName; use crate::RoleName; @@ -71,7 +71,6 @@ use super::conn_pool::Client; use super::conn_pool::ConnInfo; use super::conn_pool::ConnInfoWithAuth; use super::http_util::json_response; -use super::json::json_to_pg_text; use super::json::pg_text_row_to_json; use super::json::JsonConversionError; @@ -175,21 +174,6 @@ impl<'de> Deserialize<'de> for QueryData { }; } Field::Params => { - #[doc(hidden)] - struct PgText { - value: Vec>, - } - impl<'de> Deserialize<'de> for PgText { - fn deserialize(__deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(PgText { - value: bytes_to_pg_text(__deserializer)?, - }) - } - } - let (query, array_mode) = match state { States::HasPartialQueryData { params: Some(_), .. @@ -380,21 +364,6 @@ impl<'de> Deserialize<'de> for Payload { }; } Field::Params => { - #[doc(hidden)] - struct PgText { - value: Vec>, - } - impl<'de> Deserialize<'de> for PgText { - fn deserialize(__deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(PgText { - value: bytes_to_pg_text(__deserializer)?, - }) - } - } - let (query, array_mode) = match state { States::HasQueries(_) => { return Err(::unknown_field( @@ -499,15 +468,6 @@ static TXN_DEFERRABLE: HeaderName = HeaderName::from_static("neon-batch-deferrab static HEADER_VALUE_TRUE: HeaderValue = HeaderValue::from_static("true"); -fn bytes_to_pg_text<'de, D>(deserializer: D) -> Result>, D::Error> -where - D: Deserializer<'de>, -{ - // TODO: consider avoiding the allocation here. - let json: Vec = Deserialize::deserialize(deserializer)?; - Ok(json_to_pg_text(json)) -} - #[derive(Debug, thiserror::Error)] pub(crate) enum ConnInfoError { #[error("invalid header: {0}")]